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>