Annotation of embedaddon/nginx/src/http/modules/ngx_http_browser_module.c, revision 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>