Annotation of embedaddon/nginx/src/http/modules/ngx_http_browser_module.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_http.h>
                     11: 
                     12: 
                     13: /*
                     14:  * The module can check browser versions conforming to the following formats:
                     15:  * X, X.X, X.X.X, and X.X.X.X.  The maximum values of each format may be
                     16:  * 4000, 4000.99, 4000.99.99, and 4000.99.99.99.
                     17:  */
                     18: 
                     19: 
                     20: #define  NGX_HTTP_MODERN_BROWSER   0
                     21: #define  NGX_HTTP_ANCIENT_BROWSER  1
                     22: 
                     23: 
                     24: typedef struct {
                     25:     u_char                      browser[12];
                     26:     size_t                      skip;
                     27:     size_t                      add;
                     28:     u_char                      name[12];
                     29: } ngx_http_modern_browser_mask_t;
                     30: 
                     31: 
                     32: typedef struct {
                     33:     ngx_uint_t                  version;
                     34:     size_t                      skip;
                     35:     size_t                      add;
                     36:     u_char                      name[12];
                     37: } ngx_http_modern_browser_t;
                     38: 
                     39: 
                     40: typedef struct {
                     41:     ngx_str_t                   name;
                     42:     ngx_http_get_variable_pt    handler;
                     43:     uintptr_t                   data;
                     44: } ngx_http_browser_variable_t;
                     45: 
                     46: 
                     47: typedef struct {
                     48:     ngx_array_t                *modern_browsers;
                     49:     ngx_array_t                *ancient_browsers;
                     50:     ngx_http_variable_value_t  *modern_browser_value;
                     51:     ngx_http_variable_value_t  *ancient_browser_value;
                     52: 
                     53:     unsigned                    modern_unlisted_browsers:1;
                     54:     unsigned                    netscape4:1;
                     55: } ngx_http_browser_conf_t;
                     56: 
                     57: 
                     58: static ngx_int_t ngx_http_msie_variable(ngx_http_request_t *r,
                     59:     ngx_http_variable_value_t *v, uintptr_t data);
                     60: static ngx_int_t ngx_http_browser_variable(ngx_http_request_t *r,
                     61:     ngx_http_variable_value_t *v, uintptr_t data);
                     62: 
                     63: static ngx_uint_t ngx_http_browser(ngx_http_request_t *r,
                     64:     ngx_http_browser_conf_t *cf);
                     65: 
                     66: static ngx_int_t ngx_http_browser_add_variable(ngx_conf_t *cf);
                     67: static void *ngx_http_browser_create_conf(ngx_conf_t *cf);
                     68: static char *ngx_http_browser_merge_conf(ngx_conf_t *cf, void *parent,
                     69:     void *child);
                     70: static int ngx_libc_cdecl ngx_http_modern_browser_sort(const void *one,
                     71:     const void *two);
                     72: static char *ngx_http_modern_browser(ngx_conf_t *cf, ngx_command_t *cmd,
                     73:     void *conf);
                     74: static char *ngx_http_ancient_browser(ngx_conf_t *cf, ngx_command_t *cmd,
                     75:     void *conf);
                     76: static char *ngx_http_modern_browser_value(ngx_conf_t *cf, ngx_command_t *cmd,
                     77:     void *conf);
                     78: static char *ngx_http_ancient_browser_value(ngx_conf_t *cf, ngx_command_t *cmd,
                     79:     void *conf);
                     80: 
                     81: 
                     82: static ngx_command_t  ngx_http_browser_commands[] = {
                     83: 
                     84:     { ngx_string("modern_browser"),
                     85:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
                     86:       ngx_http_modern_browser,
                     87:       NGX_HTTP_LOC_CONF_OFFSET,
                     88:       0,
                     89:       NULL },
                     90: 
                     91:     { ngx_string("ancient_browser"),
                     92:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
                     93:       ngx_http_ancient_browser,
                     94:       NGX_HTTP_LOC_CONF_OFFSET,
                     95:       0,
                     96:       NULL },
                     97: 
                     98:     { ngx_string("modern_browser_value"),
                     99:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    100:       ngx_http_modern_browser_value,
                    101:       NGX_HTTP_LOC_CONF_OFFSET,
                    102:       0,
                    103:       NULL },
                    104: 
                    105:     { ngx_string("ancient_browser_value"),
                    106:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    107:       ngx_http_ancient_browser_value,
                    108:       NGX_HTTP_LOC_CONF_OFFSET,
                    109:       0,
                    110:       NULL },
                    111: 
                    112:       ngx_null_command
                    113: };
                    114: 
                    115: 
                    116: static ngx_http_module_t  ngx_http_browser_module_ctx = {
                    117:     ngx_http_browser_add_variable,         /* preconfiguration */
                    118:     NULL,                                  /* postconfiguration */
                    119: 
                    120:     NULL,                                  /* create main configuration */
                    121:     NULL,                                  /* init main configuration */
                    122: 
                    123:     NULL,                                  /* create server configuration */
                    124:     NULL,                                  /* merge server configuration */
                    125: 
                    126:     ngx_http_browser_create_conf,          /* create location configuration */
                    127:     ngx_http_browser_merge_conf            /* merge location configuration */
                    128: };
                    129: 
                    130: 
                    131: ngx_module_t  ngx_http_browser_module = {
                    132:     NGX_MODULE_V1,
                    133:     &ngx_http_browser_module_ctx,          /* module context */
                    134:     ngx_http_browser_commands,             /* module directives */
                    135:     NGX_HTTP_MODULE,                       /* module type */
                    136:     NULL,                                  /* init master */
                    137:     NULL,                                  /* init module */
                    138:     NULL,                                  /* init process */
                    139:     NULL,                                  /* init thread */
                    140:     NULL,                                  /* exit thread */
                    141:     NULL,                                  /* exit process */
                    142:     NULL,                                  /* exit master */
                    143:     NGX_MODULE_V1_PADDING
                    144: };
                    145: 
                    146: 
                    147: static ngx_http_modern_browser_mask_t  ngx_http_modern_browser_masks[] = {
                    148: 
                    149:     /* Opera must be the first browser to check */
                    150: 
                    151:     /*
                    152:      * "Opera/7.50 (X11; FreeBSD i386; U)  [en]"
                    153:      * "Mozilla/5.0 (X11; FreeBSD i386; U) Opera 7.50  [en]"
                    154:      * "Mozilla/4.0 (compatible; MSIE 6.0; X11; FreeBSD i386) Opera 7.50  [en]"
                    155:      * "Opera/8.0 (Windows NT 5.1; U; ru)"
                    156:      * "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; en) Opera 8.0"
                    157:      * "Opera/9.01 (X11; FreeBSD 6 i386; U; en)"
                    158:      */
                    159: 
                    160:     { "opera",
                    161:       0,
                    162:       sizeof("Opera ") - 1,
                    163:       "Opera"},
                    164: 
                    165:     /* "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)" */
                    166: 
                    167:     { "msie",
                    168:       sizeof("Mozilla/4.0 (compatible; ") - 1,
                    169:       sizeof("MSIE ") - 1,
                    170:       "MSIE "},
                    171: 
                    172:     /*
                    173:      * "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.0) Gecko/20020610"
                    174:      * "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.5) Gecko/20031006"
                    175:      * "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.6) Gecko/20040206
                    176:      *              Firefox/0.8"
                    177:      * "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU; rv:1.7.8)
                    178:      *              Gecko/20050511 Firefox/1.0.4"
                    179:      * "Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.8.0.5) Gecko/20060729
                    180:      *              Firefox/1.5.0.5"
                    181:      */
                    182: 
                    183:     { "gecko",
                    184:       sizeof("Mozilla/5.0 (") - 1,
                    185:       sizeof("rv:") - 1,
                    186:       "rv:"},
                    187: 
                    188:     /*
                    189:      * "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ru-ru) AppleWebKit/125.2
                    190:      *              (KHTML, like Gecko) Safari/125.7"
                    191:      * "Mozilla/5.0 (SymbianOS/9.1; U; en-us) AppleWebKit/413
                    192:      *              (KHTML, like Gecko) Safari/413"
                    193:      * "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418
                    194:      *              (KHTML, like Gecko) Safari/417.9.3"
                    195:      * "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ru-ru) AppleWebKit/418.8
                    196:      *              (KHTML, like Gecko) Safari/419.3"
                    197:      */
                    198: 
                    199:     { "safari",
                    200:       sizeof("Mozilla/5.0 (") - 1,
                    201:       sizeof("Safari/") - 1,
                    202:       "Safari/"},
                    203: 
                    204:     /*
                    205:      * "Mozilla/5.0 (compatible; Konqueror/3.1; Linux)"
                    206:      * "Mozilla/5.0 (compatible; Konqueror/3.4; Linux) KHTML/3.4.2 (like Gecko)"
                    207:      * "Mozilla/5.0 (compatible; Konqueror/3.5; FreeBSD) KHTML/3.5.1
                    208:      *              (like Gecko)"
                    209:      */
                    210: 
                    211:     { "konqueror",
                    212:       sizeof("Mozilla/5.0 (compatible; ") - 1,
                    213:       sizeof("Konqueror/") - 1,
                    214:       "Konqueror/"},
                    215: 
                    216:     { "", 0, 0, "" }
                    217: 
                    218: };
                    219: 
                    220: 
                    221: static ngx_http_browser_variable_t  ngx_http_browsers[] = {
                    222:     { ngx_string("msie"), ngx_http_msie_variable, 0 },
                    223:     { ngx_string("modern_browser"), ngx_http_browser_variable,
                    224:           NGX_HTTP_MODERN_BROWSER },
                    225:     { ngx_string("ancient_browser"), ngx_http_browser_variable,
                    226:           NGX_HTTP_ANCIENT_BROWSER },
                    227:     { ngx_null_string, NULL, 0 }
                    228: };
                    229: 
                    230: 
                    231: static ngx_int_t
                    232: ngx_http_browser_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
                    233:     uintptr_t data)
                    234: {
                    235:     ngx_uint_t                rc;
                    236:     ngx_http_browser_conf_t  *cf;
                    237: 
                    238:     cf = ngx_http_get_module_loc_conf(r, ngx_http_browser_module);
                    239: 
                    240:     rc = ngx_http_browser(r, cf);
                    241: 
                    242:     if (data == NGX_HTTP_MODERN_BROWSER && rc == NGX_HTTP_MODERN_BROWSER) {
                    243:         *v = *cf->modern_browser_value;
                    244:         return NGX_OK;
                    245:     }
                    246: 
                    247:     if (data == NGX_HTTP_ANCIENT_BROWSER && rc == NGX_HTTP_ANCIENT_BROWSER) {
                    248:         *v = *cf->ancient_browser_value;
                    249:         return NGX_OK;
                    250:     }
                    251: 
                    252:     *v = ngx_http_variable_null_value;
                    253:     return NGX_OK;
                    254: }
                    255: 
                    256: 
                    257: static ngx_uint_t
                    258: ngx_http_browser(ngx_http_request_t *r, ngx_http_browser_conf_t *cf)
                    259: {
                    260:     size_t                      len;
                    261:     u_char                     *name, *ua, *last, c;
                    262:     ngx_str_t                  *ancient;
                    263:     ngx_uint_t                  i, version, ver, scale;
                    264:     ngx_http_modern_browser_t  *modern;
                    265: 
                    266:     if (r->headers_in.user_agent == NULL) {
                    267:         if (cf->modern_unlisted_browsers) {
                    268:             return NGX_HTTP_MODERN_BROWSER;
                    269:         }
                    270: 
                    271:         return NGX_HTTP_ANCIENT_BROWSER;
                    272:     }
                    273: 
                    274:     ua = r->headers_in.user_agent->value.data;
                    275:     len = r->headers_in.user_agent->value.len;
                    276:     last = ua + len;
                    277: 
                    278:     if (cf->modern_browsers) {
                    279:         modern = cf->modern_browsers->elts;
                    280: 
                    281:         for (i = 0; i < cf->modern_browsers->nelts; i++) {
                    282:             name = ua + modern[i].skip;
                    283: 
                    284:             if (name >= last) {
                    285:                 continue;
                    286:             }
                    287: 
                    288:             name = (u_char *) ngx_strstr(name, modern[i].name);
                    289: 
                    290:             if (name == NULL) {
                    291:                 continue;
                    292:             }
                    293: 
                    294:             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    295:                            "browser: \"%s\"", name);
                    296: 
                    297:             name += modern[i].add;
                    298: 
                    299:             if (name >= last) {
                    300:                 continue;
                    301:             }
                    302: 
                    303:             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    304:                            "version: \"%ui\" \"%s\"", modern[i].version, name);
                    305: 
                    306:             version = 0;
                    307:             ver = 0;
                    308:             scale = 1000000;
                    309: 
                    310:             while (name < last) {
                    311: 
                    312:                 c = *name++;
                    313: 
                    314:                 if (c >= '0' && c <= '9') {
                    315:                     ver = ver * 10 + (c - '0');
                    316:                     continue;
                    317:                 }
                    318: 
                    319:                 if (c == '.') {
                    320:                     version += ver * scale;
                    321: 
                    322:                     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    323:                                    "version: \"%ui\" \"%ui\"",
                    324:                                    modern[i].version, version);
                    325: 
                    326:                     if (version > modern[i].version) {
                    327:                         return NGX_HTTP_MODERN_BROWSER;
                    328:                     }
                    329: 
                    330:                     ver = 0;
                    331:                     scale /= 100;
                    332:                     continue;
                    333:                 }
                    334: 
                    335:                 break;
                    336:             }
                    337: 
                    338:             version += ver * scale;
                    339: 
                    340:             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    341:                            "version: \"%ui\" \"%ui\"",
                    342:                            modern[i].version, version);
                    343: 
                    344:             if (version >= modern[i].version) {
                    345:                 return NGX_HTTP_MODERN_BROWSER;
                    346:             }
                    347: 
                    348:             return NGX_HTTP_ANCIENT_BROWSER;
                    349:         }
                    350: 
                    351:         if (!cf->modern_unlisted_browsers) {
                    352:             return NGX_HTTP_ANCIENT_BROWSER;
                    353:         }
                    354:     }
                    355: 
                    356:     if (cf->netscape4) {
                    357:         if (len > sizeof("Mozilla/4.72 ") - 1
                    358:             && ngx_strncmp(ua, "Mozilla/", sizeof("Mozilla/") - 1) == 0
                    359:             && ua[8] > '0' && ua[8] < '5')
                    360:         {
                    361:             return NGX_HTTP_ANCIENT_BROWSER;
                    362:         }
                    363:     }
                    364: 
                    365:     if (cf->ancient_browsers) {
                    366:         ancient = cf->ancient_browsers->elts;
                    367: 
                    368:         for (i = 0; i < cf->ancient_browsers->nelts; i++) {
                    369:             if (len >= ancient[i].len
                    370:                 && ngx_strstr(ua, ancient[i].data) != NULL)
                    371:             {
                    372:                 return NGX_HTTP_ANCIENT_BROWSER;
                    373:             }
                    374:         }
                    375:     }
                    376: 
                    377:     if (cf->modern_unlisted_browsers) {
                    378:         return NGX_HTTP_MODERN_BROWSER;
                    379:     }
                    380: 
                    381:     return NGX_HTTP_ANCIENT_BROWSER;
                    382: }
                    383: 
                    384: 
                    385: static ngx_int_t
                    386: ngx_http_msie_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
                    387:     uintptr_t data)
                    388: {
                    389:     if (r->headers_in.msie) {
                    390:         *v = ngx_http_variable_true_value;
                    391:         return NGX_OK;
                    392:     }
                    393: 
                    394:     *v = ngx_http_variable_null_value;
                    395:     return NGX_OK;
                    396: }
                    397: 
                    398: 
                    399: static ngx_int_t
                    400: ngx_http_browser_add_variable(ngx_conf_t *cf)
                    401: {
                    402:     ngx_http_browser_variable_t   *var;
                    403:     ngx_http_variable_t           *v;
                    404: 
                    405:     for (var = ngx_http_browsers; var->name.len; var++) {
                    406: 
                    407:         v = ngx_http_add_variable(cf, &var->name, NGX_HTTP_VAR_CHANGEABLE);
                    408:         if (v == NULL) {
                    409:             return NGX_ERROR;
                    410:         }
                    411: 
                    412:         v->get_handler = var->handler;
                    413:         v->data = var->data;
                    414:     }
                    415: 
                    416:     return NGX_OK;
                    417: }
                    418: 
                    419: 
                    420: static void *
                    421: ngx_http_browser_create_conf(ngx_conf_t *cf)
                    422: {
                    423:     ngx_http_browser_conf_t  *conf;
                    424: 
                    425:     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_browser_conf_t));
                    426:     if (conf == NULL) {
                    427:         return NULL;
                    428:     }
                    429: 
                    430:     /*
                    431:      * set by ngx_pcalloc():
                    432:      *
                    433:      *     conf->modern_browsers = NULL;
                    434:      *     conf->ancient_browsers = NULL;
                    435:      *     conf->modern_browser_value = NULL;
                    436:      *     conf->ancient_browser_value = NULL;
                    437:      *
                    438:      *     conf->modern_unlisted_browsers = 0;
                    439:      *     conf->netscape4 = 0;
                    440:      */
                    441: 
                    442:     return conf;
                    443: }
                    444: 
                    445: 
                    446: static char *
                    447: ngx_http_browser_merge_conf(ngx_conf_t *cf, void *parent, void *child)
                    448: {
                    449:     ngx_http_browser_conf_t *prev = parent;
                    450:     ngx_http_browser_conf_t *conf = child;
                    451: 
                    452:     ngx_uint_t                  i, n;
                    453:     ngx_http_modern_browser_t  *browsers, *opera;
                    454: 
                    455:     /*
                    456:      * At the merge the skip field is used to store the browser slot,
                    457:      * it will be used in sorting and then will overwritten
                    458:      * with a real skip value.  The zero value means Opera.
                    459:      */
                    460: 
                    461:     if (conf->modern_browsers == NULL && conf->modern_unlisted_browsers == 0) {
                    462:         conf->modern_browsers = prev->modern_browsers;
                    463:         conf->modern_unlisted_browsers = prev->modern_unlisted_browsers;
                    464: 
                    465:     } else if (conf->modern_browsers != NULL) {
                    466:         browsers = conf->modern_browsers->elts;
                    467: 
                    468:         for (i = 0; i < conf->modern_browsers->nelts; i++) {
                    469:             if (browsers[i].skip == 0) {
                    470:                 goto found;
                    471:             }
                    472:         }
                    473: 
                    474:         /*
                    475:          * Opera may contain MSIE string, so if Opera was not enumerated
                    476:          * as modern browsers, then add it and set a unreachable version
                    477:          */
                    478: 
                    479:         opera = ngx_array_push(conf->modern_browsers);
                    480:         if (opera == NULL) {
                    481:             return NGX_CONF_ERROR;
                    482:         }
                    483: 
                    484:         opera->skip = 0;
                    485:         opera->version = 4001000000U;
                    486: 
                    487:         browsers = conf->modern_browsers->elts;
                    488: 
                    489: found:
                    490: 
                    491:         ngx_qsort(browsers, (size_t) conf->modern_browsers->nelts,
                    492:                   sizeof(ngx_http_modern_browser_t),
                    493:                   ngx_http_modern_browser_sort);
                    494: 
                    495:         for (i = 0; i < conf->modern_browsers->nelts; i++) {
                    496:              n = browsers[i].skip;
                    497: 
                    498:              browsers[i].skip = ngx_http_modern_browser_masks[n].skip;
                    499:              browsers[i].add = ngx_http_modern_browser_masks[n].add;
                    500:              (void) ngx_cpystrn(browsers[i].name,
                    501:                                 ngx_http_modern_browser_masks[n].name, 12);
                    502:         }
                    503:     }
                    504: 
                    505:     if (conf->ancient_browsers == NULL && conf->netscape4 == 0) {
                    506:         conf->ancient_browsers = prev->ancient_browsers;
                    507:         conf->netscape4 = prev->netscape4;
                    508:     }
                    509: 
                    510:     if (conf->modern_browser_value == NULL) {
                    511:         conf->modern_browser_value = prev->modern_browser_value;
                    512:     }
                    513: 
                    514:     if (conf->modern_browser_value == NULL) {
                    515:         conf->modern_browser_value = &ngx_http_variable_true_value;
                    516:     }
                    517: 
                    518:     if (conf->ancient_browser_value == NULL) {
                    519:         conf->ancient_browser_value = prev->ancient_browser_value;
                    520:     }
                    521: 
                    522:     if (conf->ancient_browser_value == NULL) {
                    523:         conf->ancient_browser_value = &ngx_http_variable_true_value;
                    524:     }
                    525: 
                    526:     return NGX_CONF_OK;
                    527: }
                    528: 
                    529: 
                    530: static int ngx_libc_cdecl
                    531: ngx_http_modern_browser_sort(const void *one, const void *two)
                    532: {
                    533:     ngx_http_modern_browser_t *first = (ngx_http_modern_browser_t *) one;
                    534:     ngx_http_modern_browser_t *second = (ngx_http_modern_browser_t *) two;
                    535: 
                    536:     return (first->skip - second->skip);
                    537: }
                    538: 
                    539: 
                    540: static char *
                    541: ngx_http_modern_browser(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    542: {
                    543:     ngx_http_browser_conf_t *bcf = conf;
                    544: 
                    545:     u_char                           c;
                    546:     ngx_str_t                       *value;
                    547:     ngx_uint_t                       i, n, version, ver, scale;
                    548:     ngx_http_modern_browser_t       *browser;
                    549:     ngx_http_modern_browser_mask_t  *mask;
                    550: 
                    551:     value = cf->args->elts;
                    552: 
                    553:     if (cf->args->nelts == 2) {
                    554:         if (ngx_strcmp(value[1].data, "unlisted") == 0) {
                    555:             bcf->modern_unlisted_browsers = 1;
                    556:             return NGX_CONF_OK;
                    557:         }
                    558: 
                    559:         return NGX_CONF_ERROR;
                    560:     }
                    561: 
                    562:     if (bcf->modern_browsers == NULL) {
                    563:         bcf->modern_browsers = ngx_array_create(cf->pool, 5,
                    564:                                             sizeof(ngx_http_modern_browser_t));
                    565:         if (bcf->modern_browsers == NULL) {
                    566:             return NGX_CONF_ERROR;
                    567:         }
                    568:     }
                    569: 
                    570:     browser = ngx_array_push(bcf->modern_browsers);
                    571:     if (browser == NULL) {
                    572:         return NGX_CONF_ERROR;
                    573:     }
                    574: 
                    575:     mask = ngx_http_modern_browser_masks;
                    576: 
                    577:     for (n = 0; mask[n].browser[0] != '\0'; n++) {
                    578:         if (ngx_strcasecmp(mask[n].browser, value[1].data) == 0) {
                    579:             goto found;
                    580:         }
                    581:     }
                    582: 
                    583:     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    584:                        "unknown browser name \"%V\"", &value[1]);
                    585: 
                    586:     return NGX_CONF_ERROR;
                    587: 
                    588: found:
                    589: 
                    590:     /*
                    591:      * at this stage the skip field is used to store the browser slot,
                    592:      * it will be used in sorting in merge stage and then will overwritten
                    593:      * with a real value
                    594:      */
                    595: 
                    596:     browser->skip = n;
                    597: 
                    598:     version = 0;
                    599:     ver = 0;
                    600:     scale = 1000000;
                    601: 
                    602:     for (i = 0; i < value[2].len; i++) {
                    603: 
                    604:         c = value[2].data[i];
                    605: 
                    606:         if (c >= '0' && c <= '9') {
                    607:             ver = ver * 10 + (c - '0');
                    608:             continue;
                    609:         }
                    610: 
                    611:         if (c == '.') {
                    612:             version += ver * scale;
                    613:             ver = 0;
                    614:             scale /= 100;
                    615:             continue;
                    616:         }
                    617: 
                    618:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    619:                            "invalid browser version \"%V\"", &value[2]);
                    620: 
                    621:         return NGX_CONF_ERROR;
                    622:     }
                    623: 
                    624:     version += ver * scale;
                    625: 
                    626:     browser->version = version;
                    627: 
                    628:     return NGX_CONF_OK;
                    629: }
                    630: 
                    631: 
                    632: static char *
                    633: ngx_http_ancient_browser(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    634: {
                    635:     ngx_http_browser_conf_t *bcf = conf;
                    636: 
                    637:     ngx_str_t   *value, *browser;
                    638:     ngx_uint_t   i;
                    639: 
                    640:     value = cf->args->elts;
                    641: 
                    642:     for (i = 1; i < cf->args->nelts; i++) {
                    643:         if (ngx_strcmp(value[i].data, "netscape4") == 0) {
                    644:             bcf->netscape4 = 1;
                    645:             continue;
                    646:         }
                    647: 
                    648:         if (bcf->ancient_browsers == NULL) {
                    649:             bcf->ancient_browsers = ngx_array_create(cf->pool, 4,
                    650:                                                      sizeof(ngx_str_t));
                    651:             if (bcf->ancient_browsers == NULL) {
                    652:                 return NGX_CONF_ERROR;
                    653:             }
                    654:         }
                    655: 
                    656:         browser = ngx_array_push(bcf->ancient_browsers);
                    657:         if (browser == NULL) {
                    658:             return NGX_CONF_ERROR;
                    659:         }
                    660: 
                    661:         *browser = value[i];
                    662:     }
                    663: 
                    664:     return NGX_CONF_OK;
                    665: }
                    666: 
                    667: 
                    668: static char *
                    669: ngx_http_modern_browser_value(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    670: {
                    671:     ngx_http_browser_conf_t *bcf = conf;
                    672: 
                    673:     ngx_str_t  *value;
                    674: 
                    675:     bcf->modern_browser_value = ngx_palloc(cf->pool,
                    676:                                            sizeof(ngx_http_variable_value_t));
                    677:     if (bcf->modern_browser_value == NULL) {
                    678:         return NGX_CONF_ERROR;
                    679:     }
                    680: 
                    681:     value = cf->args->elts;
                    682: 
                    683:     bcf->modern_browser_value->len = value[1].len;
                    684:     bcf->modern_browser_value->valid = 1;
                    685:     bcf->modern_browser_value->no_cacheable = 0;
                    686:     bcf->modern_browser_value->not_found = 0;
                    687:     bcf->modern_browser_value->data = value[1].data;
                    688: 
                    689:     return NGX_CONF_OK;
                    690: }
                    691: 
                    692: 
                    693: static char *
                    694: ngx_http_ancient_browser_value(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    695: {
                    696:     ngx_http_browser_conf_t *bcf = conf;
                    697: 
                    698:     ngx_str_t  *value;
                    699: 
                    700:     bcf->ancient_browser_value = ngx_palloc(cf->pool,
                    701:                                             sizeof(ngx_http_variable_value_t));
                    702:     if (bcf->ancient_browser_value == NULL) {
                    703:         return NGX_CONF_ERROR;
                    704:     }
                    705: 
                    706:     value = cf->args->elts;
                    707: 
                    708:     bcf->ancient_browser_value->len = value[1].len;
                    709:     bcf->ancient_browser_value->valid = 1;
                    710:     bcf->ancient_browser_value->no_cacheable = 0;
                    711:     bcf->ancient_browser_value->not_found = 0;
                    712:     bcf->ancient_browser_value->data = value[1].data;
                    713: 
                    714:     return NGX_CONF_OK;
                    715: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>