Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 /*
0014  * The module can check browser versions conforming to the following formats:
0015  * X, X.X, X.X.X, and X.X.X.X.  The maximum values of each format may be
0016  * 4000, 4000.99, 4000.99.99, and 4000.99.99.99.
0017  */
0018 
0019 
0020 #define  NGX_HTTP_MODERN_BROWSER   0
0021 #define  NGX_HTTP_ANCIENT_BROWSER  1
0022 
0023 
0024 typedef struct {
0025     u_char                      browser[12];
0026     size_t                      skip;
0027     size_t                      add;
0028     u_char                      name[12];
0029 } ngx_http_modern_browser_mask_t;
0030 
0031 
0032 typedef struct {
0033     ngx_uint_t                  version;
0034     size_t                      skip;
0035     size_t                      add;
0036     u_char                      name[12];
0037 } ngx_http_modern_browser_t;
0038 
0039 
0040 typedef struct {
0041     ngx_array_t                *modern_browsers;
0042     ngx_array_t                *ancient_browsers;
0043     ngx_http_variable_value_t  *modern_browser_value;
0044     ngx_http_variable_value_t  *ancient_browser_value;
0045 
0046     unsigned                    modern_unlisted_browsers:1;
0047     unsigned                    netscape4:1;
0048 } ngx_http_browser_conf_t;
0049 
0050 
0051 static ngx_int_t ngx_http_msie_variable(ngx_http_request_t *r,
0052     ngx_http_variable_value_t *v, uintptr_t data);
0053 static ngx_int_t ngx_http_browser_variable(ngx_http_request_t *r,
0054     ngx_http_variable_value_t *v, uintptr_t data);
0055 
0056 static ngx_uint_t ngx_http_browser(ngx_http_request_t *r,
0057     ngx_http_browser_conf_t *cf);
0058 
0059 static ngx_int_t ngx_http_browser_add_variables(ngx_conf_t *cf);
0060 static void *ngx_http_browser_create_conf(ngx_conf_t *cf);
0061 static char *ngx_http_browser_merge_conf(ngx_conf_t *cf, void *parent,
0062     void *child);
0063 static int ngx_libc_cdecl ngx_http_modern_browser_sort(const void *one,
0064     const void *two);
0065 static char *ngx_http_modern_browser(ngx_conf_t *cf, ngx_command_t *cmd,
0066     void *conf);
0067 static char *ngx_http_ancient_browser(ngx_conf_t *cf, ngx_command_t *cmd,
0068     void *conf);
0069 static char *ngx_http_modern_browser_value(ngx_conf_t *cf, ngx_command_t *cmd,
0070     void *conf);
0071 static char *ngx_http_ancient_browser_value(ngx_conf_t *cf, ngx_command_t *cmd,
0072     void *conf);
0073 
0074 
0075 static ngx_command_t  ngx_http_browser_commands[] = {
0076 
0077     { ngx_string("modern_browser"),
0078       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
0079       ngx_http_modern_browser,
0080       NGX_HTTP_LOC_CONF_OFFSET,
0081       0,
0082       NULL },
0083 
0084     { ngx_string("ancient_browser"),
0085       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0086       ngx_http_ancient_browser,
0087       NGX_HTTP_LOC_CONF_OFFSET,
0088       0,
0089       NULL },
0090 
0091     { ngx_string("modern_browser_value"),
0092       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0093       ngx_http_modern_browser_value,
0094       NGX_HTTP_LOC_CONF_OFFSET,
0095       0,
0096       NULL },
0097 
0098     { ngx_string("ancient_browser_value"),
0099       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0100       ngx_http_ancient_browser_value,
0101       NGX_HTTP_LOC_CONF_OFFSET,
0102       0,
0103       NULL },
0104 
0105       ngx_null_command
0106 };
0107 
0108 
0109 static ngx_http_module_t  ngx_http_browser_module_ctx = {
0110     ngx_http_browser_add_variables,        /* preconfiguration */
0111     NULL,                                  /* postconfiguration */
0112 
0113     NULL,                                  /* create main configuration */
0114     NULL,                                  /* init main configuration */
0115 
0116     NULL,                                  /* create server configuration */
0117     NULL,                                  /* merge server configuration */
0118 
0119     ngx_http_browser_create_conf,          /* create location configuration */
0120     ngx_http_browser_merge_conf            /* merge location configuration */
0121 };
0122 
0123 
0124 ngx_module_t  ngx_http_browser_module = {
0125     NGX_MODULE_V1,
0126     &ngx_http_browser_module_ctx,          /* module context */
0127     ngx_http_browser_commands,             /* module directives */
0128     NGX_HTTP_MODULE,                       /* module type */
0129     NULL,                                  /* init master */
0130     NULL,                                  /* init module */
0131     NULL,                                  /* init process */
0132     NULL,                                  /* init thread */
0133     NULL,                                  /* exit thread */
0134     NULL,                                  /* exit process */
0135     NULL,                                  /* exit master */
0136     NGX_MODULE_V1_PADDING
0137 };
0138 
0139 
0140 static ngx_http_modern_browser_mask_t  ngx_http_modern_browser_masks[] = {
0141 
0142     /* Opera must be the first browser to check */
0143 
0144     /*
0145      * "Opera/7.50 (X11; FreeBSD i386; U)  [en]"
0146      * "Mozilla/5.0 (X11; FreeBSD i386; U) Opera 7.50  [en]"
0147      * "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.50  [en]"
0148      * "Opera/8.0 (Windows NT 5.1; U; ru)"
0149      * "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; en) Opera 8.0"
0150      * "Opera/9.01 (X11; FreeBSD 6 i386; U; en)"
0151      */
0152 
0153     { "opera",
0154       0,
0155       sizeof("Opera ") - 1,
0156       "Opera"},
0157 
0158     /* "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" */
0159 
0160     { "msie",
0161       sizeof("Mozilla/4.0 (compatible; ") - 1,
0162       sizeof("MSIE ") - 1,
0163       "MSIE "},
0164 
0165     /*
0166      * "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020610"
0167      * "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.5) Gecko/20031006"
0168      * "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.6) Gecko/20040206
0169      *              Firefox/0.8"
0170      * "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.8)
0171      *              Gecko/20050511 Firefox/1.0.4"
0172      * "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.0.5) Gecko/20060729
0173      *              Firefox/1.5.0.5"
0174      */
0175 
0176     { "gecko",
0177       sizeof("Mozilla/5.0 (") - 1,
0178       sizeof("rv:") - 1,
0179       "rv:"},
0180 
0181     /*
0182      * "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ru-ru) AppleWebKit/125.2
0183      *              (KHTML, like Gecko) Safari/125.7"
0184      * "Mozilla/5.0 (SymbianOS/9.1; U; en-us) AppleWebKit/413
0185      *              (KHTML, like Gecko) Safari/413"
0186      * "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418
0187      *              (KHTML, like Gecko) Safari/417.9.3"
0188      * "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ru-ru) AppleWebKit/418.8
0189      *              (KHTML, like Gecko) Safari/419.3"
0190      */
0191 
0192     { "safari",
0193       sizeof("Mozilla/5.0 (") - 1,
0194       sizeof("Safari/") - 1,
0195       "Safari/"},
0196 
0197     /*
0198      * "Mozilla/5.0 (compatible; Konqueror/3.1; Linux)"
0199      * "Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.2 (like Gecko)"
0200      * "Mozilla/5.0 (compatible; Konqueror/3.5; FreeBSD) KHTML/3.5.1
0201      *              (like Gecko)"
0202      */
0203 
0204     { "konqueror",
0205       sizeof("Mozilla/5.0 (compatible; ") - 1,
0206       sizeof("Konqueror/") - 1,
0207       "Konqueror/"},
0208 
0209     { "", 0, 0, "" }
0210 
0211 };
0212 
0213 
0214 static ngx_http_variable_t  ngx_http_browser_vars[] = {
0215 
0216     { ngx_string("msie"), NULL, ngx_http_msie_variable,
0217       0, NGX_HTTP_VAR_CHANGEABLE, 0 },
0218 
0219     { ngx_string("modern_browser"), NULL, ngx_http_browser_variable,
0220       NGX_HTTP_MODERN_BROWSER, NGX_HTTP_VAR_CHANGEABLE, 0 },
0221 
0222     { ngx_string("ancient_browser"), NULL, ngx_http_browser_variable,
0223       NGX_HTTP_ANCIENT_BROWSER, NGX_HTTP_VAR_CHANGEABLE, 0 },
0224 
0225       ngx_http_null_variable
0226 };
0227 
0228 
0229 static ngx_int_t
0230 ngx_http_browser_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
0231     uintptr_t data)
0232 {
0233     ngx_uint_t                rc;
0234     ngx_http_browser_conf_t  *cf;
0235 
0236     cf = ngx_http_get_module_loc_conf(r, ngx_http_browser_module);
0237 
0238     rc = ngx_http_browser(r, cf);
0239 
0240     if (data == NGX_HTTP_MODERN_BROWSER && rc == NGX_HTTP_MODERN_BROWSER) {
0241         *v = *cf->modern_browser_value;
0242         return NGX_OK;
0243     }
0244 
0245     if (data == NGX_HTTP_ANCIENT_BROWSER && rc == NGX_HTTP_ANCIENT_BROWSER) {
0246         *v = *cf->ancient_browser_value;
0247         return NGX_OK;
0248     }
0249 
0250     *v = ngx_http_variable_null_value;
0251     return NGX_OK;
0252 }
0253 
0254 
0255 static ngx_uint_t
0256 ngx_http_browser(ngx_http_request_t *r, ngx_http_browser_conf_t *cf)
0257 {
0258     size_t                      len;
0259     u_char                     *name, *ua, *last, c;
0260     ngx_str_t                  *ancient;
0261     ngx_uint_t                  i, version, ver, scale;
0262     ngx_http_modern_browser_t  *modern;
0263 
0264     if (r->headers_in.user_agent == NULL) {
0265         if (cf->modern_unlisted_browsers) {
0266             return NGX_HTTP_MODERN_BROWSER;
0267         }
0268 
0269         return NGX_HTTP_ANCIENT_BROWSER;
0270     }
0271 
0272     ua = r->headers_in.user_agent->value.data;
0273     len = r->headers_in.user_agent->value.len;
0274     last = ua + len;
0275 
0276     if (cf->modern_browsers) {
0277         modern = cf->modern_browsers->elts;
0278 
0279         for (i = 0; i < cf->modern_browsers->nelts; i++) {
0280             name = ua + modern[i].skip;
0281 
0282             if (name >= last) {
0283                 continue;
0284             }
0285 
0286             name = (u_char *) ngx_strstr(name, modern[i].name);
0287 
0288             if (name == NULL) {
0289                 continue;
0290             }
0291 
0292             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0293                            "browser: \"%s\"", name);
0294 
0295             name += modern[i].add;
0296 
0297             if (name >= last) {
0298                 continue;
0299             }
0300 
0301             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0302                            "version: \"%ui\" \"%s\"", modern[i].version, name);
0303 
0304             version = 0;
0305             ver = 0;
0306             scale = 1000000;
0307 
0308             while (name < last) {
0309 
0310                 c = *name++;
0311 
0312                 if (c >= '0' && c <= '9') {
0313                     ver = ver * 10 + (c - '0');
0314                     continue;
0315                 }
0316 
0317                 if (c == '.') {
0318                     version += ver * scale;
0319 
0320                     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0321                                    "version: \"%ui\" \"%ui\"",
0322                                    modern[i].version, version);
0323 
0324                     if (version > modern[i].version) {
0325                         return NGX_HTTP_MODERN_BROWSER;
0326                     }
0327 
0328                     ver = 0;
0329                     scale /= 100;
0330                     continue;
0331                 }
0332 
0333                 break;
0334             }
0335 
0336             version += ver * scale;
0337 
0338             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0339                            "version: \"%ui\" \"%ui\"",
0340                            modern[i].version, version);
0341 
0342             if (version >= modern[i].version) {
0343                 return NGX_HTTP_MODERN_BROWSER;
0344             }
0345 
0346             return NGX_HTTP_ANCIENT_BROWSER;
0347         }
0348 
0349         if (!cf->modern_unlisted_browsers) {
0350             return NGX_HTTP_ANCIENT_BROWSER;
0351         }
0352     }
0353 
0354     if (cf->netscape4) {
0355         if (len > sizeof("Mozilla/4.72 ") - 1
0356             && ngx_strncmp(ua, "Mozilla/", sizeof("Mozilla/") - 1) == 0
0357             && ua[8] > '0' && ua[8] < '5')
0358         {
0359             return NGX_HTTP_ANCIENT_BROWSER;
0360         }
0361     }
0362 
0363     if (cf->ancient_browsers) {
0364         ancient = cf->ancient_browsers->elts;
0365 
0366         for (i = 0; i < cf->ancient_browsers->nelts; i++) {
0367             if (len >= ancient[i].len
0368                 && ngx_strstr(ua, ancient[i].data) != NULL)
0369             {
0370                 return NGX_HTTP_ANCIENT_BROWSER;
0371             }
0372         }
0373     }
0374 
0375     if (cf->modern_unlisted_browsers) {
0376         return NGX_HTTP_MODERN_BROWSER;
0377     }
0378 
0379     return NGX_HTTP_ANCIENT_BROWSER;
0380 }
0381 
0382 
0383 static ngx_int_t
0384 ngx_http_msie_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
0385     uintptr_t data)
0386 {
0387     if (r->headers_in.msie) {
0388         *v = ngx_http_variable_true_value;
0389         return NGX_OK;
0390     }
0391 
0392     *v = ngx_http_variable_null_value;
0393     return NGX_OK;
0394 }
0395 
0396 
0397 static ngx_int_t
0398 ngx_http_browser_add_variables(ngx_conf_t *cf)
0399 {
0400     ngx_http_variable_t  *var, *v;
0401 
0402     for (v = ngx_http_browser_vars; v->name.len; v++) {
0403 
0404         var = ngx_http_add_variable(cf, &v->name, v->flags);
0405         if (var == NULL) {
0406             return NGX_ERROR;
0407         }
0408 
0409         var->get_handler = v->get_handler;
0410         var->data = v->data;
0411     }
0412 
0413     return NGX_OK;
0414 }
0415 
0416 
0417 static void *
0418 ngx_http_browser_create_conf(ngx_conf_t *cf)
0419 {
0420     ngx_http_browser_conf_t  *conf;
0421 
0422     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_browser_conf_t));
0423     if (conf == NULL) {
0424         return NULL;
0425     }
0426 
0427     /*
0428      * set by ngx_pcalloc():
0429      *
0430      *     conf->modern_browsers = NULL;
0431      *     conf->ancient_browsers = NULL;
0432      *     conf->modern_browser_value = NULL;
0433      *     conf->ancient_browser_value = NULL;
0434      *
0435      *     conf->modern_unlisted_browsers = 0;
0436      *     conf->netscape4 = 0;
0437      */
0438 
0439     return conf;
0440 }
0441 
0442 
0443 static char *
0444 ngx_http_browser_merge_conf(ngx_conf_t *cf, void *parent, void *child)
0445 {
0446     ngx_http_browser_conf_t *prev = parent;
0447     ngx_http_browser_conf_t *conf = child;
0448 
0449     ngx_uint_t                  i, n;
0450     ngx_http_modern_browser_t  *browsers, *opera;
0451 
0452     /*
0453      * At the merge the skip field is used to store the browser slot,
0454      * it will be used in sorting and then will overwritten
0455      * with a real skip value.  The zero value means Opera.
0456      */
0457 
0458     if (conf->modern_browsers == NULL && conf->modern_unlisted_browsers == 0) {
0459         conf->modern_browsers = prev->modern_browsers;
0460         conf->modern_unlisted_browsers = prev->modern_unlisted_browsers;
0461 
0462     } else if (conf->modern_browsers != NULL) {
0463         browsers = conf->modern_browsers->elts;
0464 
0465         for (i = 0; i < conf->modern_browsers->nelts; i++) {
0466             if (browsers[i].skip == 0) {
0467                 goto found;
0468             }
0469         }
0470 
0471         /*
0472          * Opera may contain MSIE string, so if Opera was not enumerated
0473          * as modern browsers, then add it and set a unreachable version
0474          */
0475 
0476         opera = ngx_array_push(conf->modern_browsers);
0477         if (opera == NULL) {
0478             return NGX_CONF_ERROR;
0479         }
0480 
0481         opera->skip = 0;
0482         opera->version = 4001000000U;
0483 
0484         browsers = conf->modern_browsers->elts;
0485 
0486 found:
0487 
0488         ngx_qsort(browsers, (size_t) conf->modern_browsers->nelts,
0489                   sizeof(ngx_http_modern_browser_t),
0490                   ngx_http_modern_browser_sort);
0491 
0492         for (i = 0; i < conf->modern_browsers->nelts; i++) {
0493              n = browsers[i].skip;
0494 
0495              browsers[i].skip = ngx_http_modern_browser_masks[n].skip;
0496              browsers[i].add = ngx_http_modern_browser_masks[n].add;
0497              (void) ngx_cpystrn(browsers[i].name,
0498                                 ngx_http_modern_browser_masks[n].name, 12);
0499         }
0500     }
0501 
0502     if (conf->ancient_browsers == NULL && conf->netscape4 == 0) {
0503         conf->ancient_browsers = prev->ancient_browsers;
0504         conf->netscape4 = prev->netscape4;
0505     }
0506 
0507     if (conf->modern_browser_value == NULL) {
0508         conf->modern_browser_value = prev->modern_browser_value;
0509     }
0510 
0511     if (conf->modern_browser_value == NULL) {
0512         conf->modern_browser_value = &ngx_http_variable_true_value;
0513     }
0514 
0515     if (conf->ancient_browser_value == NULL) {
0516         conf->ancient_browser_value = prev->ancient_browser_value;
0517     }
0518 
0519     if (conf->ancient_browser_value == NULL) {
0520         conf->ancient_browser_value = &ngx_http_variable_true_value;
0521     }
0522 
0523     return NGX_CONF_OK;
0524 }
0525 
0526 
0527 static int ngx_libc_cdecl
0528 ngx_http_modern_browser_sort(const void *one, const void *two)
0529 {
0530     ngx_http_modern_browser_t *first = (ngx_http_modern_browser_t *) one;
0531     ngx_http_modern_browser_t *second = (ngx_http_modern_browser_t *) two;
0532 
0533     return (first->skip - second->skip);
0534 }
0535 
0536 
0537 static char *
0538 ngx_http_modern_browser(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0539 {
0540     ngx_http_browser_conf_t *bcf = conf;
0541 
0542     u_char                           c;
0543     ngx_str_t                       *value;
0544     ngx_uint_t                       i, n, version, ver, scale;
0545     ngx_http_modern_browser_t       *browser;
0546     ngx_http_modern_browser_mask_t  *mask;
0547 
0548     value = cf->args->elts;
0549 
0550     if (cf->args->nelts == 2) {
0551         if (ngx_strcmp(value[1].data, "unlisted") == 0) {
0552             bcf->modern_unlisted_browsers = 1;
0553             return NGX_CONF_OK;
0554         }
0555 
0556         return NGX_CONF_ERROR;
0557     }
0558 
0559     if (bcf->modern_browsers == NULL) {
0560         bcf->modern_browsers = ngx_array_create(cf->pool, 5,
0561                                             sizeof(ngx_http_modern_browser_t));
0562         if (bcf->modern_browsers == NULL) {
0563             return NGX_CONF_ERROR;
0564         }
0565     }
0566 
0567     browser = ngx_array_push(bcf->modern_browsers);
0568     if (browser == NULL) {
0569         return NGX_CONF_ERROR;
0570     }
0571 
0572     mask = ngx_http_modern_browser_masks;
0573 
0574     for (n = 0; mask[n].browser[0] != '\0'; n++) {
0575         if (ngx_strcasecmp(mask[n].browser, value[1].data) == 0) {
0576             goto found;
0577         }
0578     }
0579 
0580     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0581                        "unknown browser name \"%V\"", &value[1]);
0582 
0583     return NGX_CONF_ERROR;
0584 
0585 found:
0586 
0587     /*
0588      * at this stage the skip field is used to store the browser slot,
0589      * it will be used in sorting in merge stage and then will overwritten
0590      * with a real value
0591      */
0592 
0593     browser->skip = n;
0594 
0595     version = 0;
0596     ver = 0;
0597     scale = 1000000;
0598 
0599     for (i = 0; i < value[2].len; i++) {
0600 
0601         c = value[2].data[i];
0602 
0603         if (c >= '0' && c <= '9') {
0604             ver = ver * 10 + (c - '0');
0605             continue;
0606         }
0607 
0608         if (c == '.') {
0609             version += ver * scale;
0610             ver = 0;
0611             scale /= 100;
0612             continue;
0613         }
0614 
0615         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0616                            "invalid browser version \"%V\"", &value[2]);
0617 
0618         return NGX_CONF_ERROR;
0619     }
0620 
0621     version += ver * scale;
0622 
0623     browser->version = version;
0624 
0625     return NGX_CONF_OK;
0626 }
0627 
0628 
0629 static char *
0630 ngx_http_ancient_browser(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0631 {
0632     ngx_http_browser_conf_t *bcf = conf;
0633 
0634     ngx_str_t   *value, *browser;
0635     ngx_uint_t   i;
0636 
0637     value = cf->args->elts;
0638 
0639     for (i = 1; i < cf->args->nelts; i++) {
0640         if (ngx_strcmp(value[i].data, "netscape4") == 0) {
0641             bcf->netscape4 = 1;
0642             continue;
0643         }
0644 
0645         if (bcf->ancient_browsers == NULL) {
0646             bcf->ancient_browsers = ngx_array_create(cf->pool, 4,
0647                                                      sizeof(ngx_str_t));
0648             if (bcf->ancient_browsers == NULL) {
0649                 return NGX_CONF_ERROR;
0650             }
0651         }
0652 
0653         browser = ngx_array_push(bcf->ancient_browsers);
0654         if (browser == NULL) {
0655             return NGX_CONF_ERROR;
0656         }
0657 
0658         *browser = value[i];
0659     }
0660 
0661     return NGX_CONF_OK;
0662 }
0663 
0664 
0665 static char *
0666 ngx_http_modern_browser_value(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0667 {
0668     ngx_http_browser_conf_t *bcf = conf;
0669 
0670     ngx_str_t  *value;
0671 
0672     bcf->modern_browser_value = ngx_palloc(cf->pool,
0673                                            sizeof(ngx_http_variable_value_t));
0674     if (bcf->modern_browser_value == NULL) {
0675         return NGX_CONF_ERROR;
0676     }
0677 
0678     value = cf->args->elts;
0679 
0680     bcf->modern_browser_value->len = value[1].len;
0681     bcf->modern_browser_value->valid = 1;
0682     bcf->modern_browser_value->no_cacheable = 0;
0683     bcf->modern_browser_value->not_found = 0;
0684     bcf->modern_browser_value->data = value[1].data;
0685 
0686     return NGX_CONF_OK;
0687 }
0688 
0689 
0690 static char *
0691 ngx_http_ancient_browser_value(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0692 {
0693     ngx_http_browser_conf_t *bcf = conf;
0694 
0695     ngx_str_t  *value;
0696 
0697     bcf->ancient_browser_value = ngx_palloc(cf->pool,
0698                                             sizeof(ngx_http_variable_value_t));
0699     if (bcf->ancient_browser_value == NULL) {
0700         return NGX_CONF_ERROR;
0701     }
0702 
0703     value = cf->args->elts;
0704 
0705     bcf->ancient_browser_value->len = value[1].len;
0706     bcf->ancient_browser_value->valid = 1;
0707     bcf->ancient_browser_value->no_cacheable = 0;
0708     bcf->ancient_browser_value->not_found = 0;
0709     bcf->ancient_browser_value->data = value[1].data;
0710 
0711     return NGX_CONF_OK;
0712 }