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