Annotation of embedaddon/nginx/src/http/ngx_http.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: static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
! 14: static ngx_int_t ngx_http_init_phases(ngx_conf_t *cf,
! 15: ngx_http_core_main_conf_t *cmcf);
! 16: static ngx_int_t ngx_http_init_headers_in_hash(ngx_conf_t *cf,
! 17: ngx_http_core_main_conf_t *cmcf);
! 18: static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf,
! 19: ngx_http_core_main_conf_t *cmcf);
! 20:
! 21: static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf,
! 22: ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port,
! 23: ngx_http_listen_opt_t *lsopt);
! 24: static ngx_int_t ngx_http_add_address(ngx_conf_t *cf,
! 25: ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port,
! 26: ngx_http_listen_opt_t *lsopt);
! 27: static ngx_int_t ngx_http_add_server(ngx_conf_t *cf,
! 28: ngx_http_core_srv_conf_t *cscf, ngx_http_conf_addr_t *addr);
! 29:
! 30: static char *ngx_http_merge_servers(ngx_conf_t *cf,
! 31: ngx_http_core_main_conf_t *cmcf, ngx_http_module_t *module,
! 32: ngx_uint_t ctx_index);
! 33: static char *ngx_http_merge_locations(ngx_conf_t *cf,
! 34: ngx_queue_t *locations, void **loc_conf, ngx_http_module_t *module,
! 35: ngx_uint_t ctx_index);
! 36: static ngx_int_t ngx_http_init_locations(ngx_conf_t *cf,
! 37: ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf);
! 38: static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf,
! 39: ngx_http_core_loc_conf_t *pclcf);
! 40: static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one,
! 41: const ngx_queue_t *two);
! 42: static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf,
! 43: ngx_queue_t *locations);
! 44: static void ngx_http_create_locations_list(ngx_queue_t *locations,
! 45: ngx_queue_t *q);
! 46: static ngx_http_location_tree_node_t *
! 47: ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations,
! 48: size_t prefix);
! 49:
! 50: static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf,
! 51: ngx_http_core_main_conf_t *cmcf, ngx_array_t *ports);
! 52: static ngx_int_t ngx_http_server_names(ngx_conf_t *cf,
! 53: ngx_http_core_main_conf_t *cmcf, ngx_http_conf_addr_t *addr);
! 54: static ngx_int_t ngx_http_cmp_conf_addrs(const void *one, const void *two);
! 55: static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one,
! 56: const void *two);
! 57:
! 58: static ngx_int_t ngx_http_init_listening(ngx_conf_t *cf,
! 59: ngx_http_conf_port_t *port);
! 60: static ngx_listening_t *ngx_http_add_listening(ngx_conf_t *cf,
! 61: ngx_http_conf_addr_t *addr);
! 62: static ngx_int_t ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,
! 63: ngx_http_conf_addr_t *addr);
! 64: #if (NGX_HAVE_INET6)
! 65: static ngx_int_t ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport,
! 66: ngx_http_conf_addr_t *addr);
! 67: #endif
! 68:
! 69: ngx_uint_t ngx_http_max_module;
! 70:
! 71:
! 72: ngx_int_t (*ngx_http_top_header_filter) (ngx_http_request_t *r);
! 73: ngx_int_t (*ngx_http_top_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
! 74:
! 75:
! 76: ngx_str_t ngx_http_html_default_types[] = {
! 77: ngx_string("text/html"),
! 78: ngx_null_string
! 79: };
! 80:
! 81:
! 82: static ngx_command_t ngx_http_commands[] = {
! 83:
! 84: { ngx_string("http"),
! 85: NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
! 86: ngx_http_block,
! 87: 0,
! 88: 0,
! 89: NULL },
! 90:
! 91: ngx_null_command
! 92: };
! 93:
! 94:
! 95: static ngx_core_module_t ngx_http_module_ctx = {
! 96: ngx_string("http"),
! 97: NULL,
! 98: NULL
! 99: };
! 100:
! 101:
! 102: ngx_module_t ngx_http_module = {
! 103: NGX_MODULE_V1,
! 104: &ngx_http_module_ctx, /* module context */
! 105: ngx_http_commands, /* module directives */
! 106: NGX_CORE_MODULE, /* module type */
! 107: NULL, /* init master */
! 108: NULL, /* init module */
! 109: NULL, /* init process */
! 110: NULL, /* init thread */
! 111: NULL, /* exit thread */
! 112: NULL, /* exit process */
! 113: NULL, /* exit master */
! 114: NGX_MODULE_V1_PADDING
! 115: };
! 116:
! 117:
! 118: static char *
! 119: ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 120: {
! 121: char *rv;
! 122: ngx_uint_t mi, m, s;
! 123: ngx_conf_t pcf;
! 124: ngx_http_module_t *module;
! 125: ngx_http_conf_ctx_t *ctx;
! 126: ngx_http_core_loc_conf_t *clcf;
! 127: ngx_http_core_srv_conf_t **cscfp;
! 128: ngx_http_core_main_conf_t *cmcf;
! 129:
! 130: /* the main http context */
! 131:
! 132: ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
! 133: if (ctx == NULL) {
! 134: return NGX_CONF_ERROR;
! 135: }
! 136:
! 137: *(ngx_http_conf_ctx_t **) conf = ctx;
! 138:
! 139:
! 140: /* count the number of the http modules and set up their indices */
! 141:
! 142: ngx_http_max_module = 0;
! 143: for (m = 0; ngx_modules[m]; m++) {
! 144: if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
! 145: continue;
! 146: }
! 147:
! 148: ngx_modules[m]->ctx_index = ngx_http_max_module++;
! 149: }
! 150:
! 151:
! 152: /* the http main_conf context, it is the same in the all http contexts */
! 153:
! 154: ctx->main_conf = ngx_pcalloc(cf->pool,
! 155: sizeof(void *) * ngx_http_max_module);
! 156: if (ctx->main_conf == NULL) {
! 157: return NGX_CONF_ERROR;
! 158: }
! 159:
! 160:
! 161: /*
! 162: * the http null srv_conf context, it is used to merge
! 163: * the server{}s' srv_conf's
! 164: */
! 165:
! 166: ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
! 167: if (ctx->srv_conf == NULL) {
! 168: return NGX_CONF_ERROR;
! 169: }
! 170:
! 171:
! 172: /*
! 173: * the http null loc_conf context, it is used to merge
! 174: * the server{}s' loc_conf's
! 175: */
! 176:
! 177: ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
! 178: if (ctx->loc_conf == NULL) {
! 179: return NGX_CONF_ERROR;
! 180: }
! 181:
! 182:
! 183: /*
! 184: * create the main_conf's, the null srv_conf's, and the null loc_conf's
! 185: * of the all http modules
! 186: */
! 187:
! 188: for (m = 0; ngx_modules[m]; m++) {
! 189: if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
! 190: continue;
! 191: }
! 192:
! 193: module = ngx_modules[m]->ctx;
! 194: mi = ngx_modules[m]->ctx_index;
! 195:
! 196: if (module->create_main_conf) {
! 197: ctx->main_conf[mi] = module->create_main_conf(cf);
! 198: if (ctx->main_conf[mi] == NULL) {
! 199: return NGX_CONF_ERROR;
! 200: }
! 201: }
! 202:
! 203: if (module->create_srv_conf) {
! 204: ctx->srv_conf[mi] = module->create_srv_conf(cf);
! 205: if (ctx->srv_conf[mi] == NULL) {
! 206: return NGX_CONF_ERROR;
! 207: }
! 208: }
! 209:
! 210: if (module->create_loc_conf) {
! 211: ctx->loc_conf[mi] = module->create_loc_conf(cf);
! 212: if (ctx->loc_conf[mi] == NULL) {
! 213: return NGX_CONF_ERROR;
! 214: }
! 215: }
! 216: }
! 217:
! 218: pcf = *cf;
! 219: cf->ctx = ctx;
! 220:
! 221: for (m = 0; ngx_modules[m]; m++) {
! 222: if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
! 223: continue;
! 224: }
! 225:
! 226: module = ngx_modules[m]->ctx;
! 227:
! 228: if (module->preconfiguration) {
! 229: if (module->preconfiguration(cf) != NGX_OK) {
! 230: return NGX_CONF_ERROR;
! 231: }
! 232: }
! 233: }
! 234:
! 235: /* parse inside the http{} block */
! 236:
! 237: cf->module_type = NGX_HTTP_MODULE;
! 238: cf->cmd_type = NGX_HTTP_MAIN_CONF;
! 239: rv = ngx_conf_parse(cf, NULL);
! 240:
! 241: if (rv != NGX_CONF_OK) {
! 242: goto failed;
! 243: }
! 244:
! 245: /*
! 246: * init http{} main_conf's, merge the server{}s' srv_conf's
! 247: * and its location{}s' loc_conf's
! 248: */
! 249:
! 250: cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
! 251: cscfp = cmcf->servers.elts;
! 252:
! 253: for (m = 0; ngx_modules[m]; m++) {
! 254: if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
! 255: continue;
! 256: }
! 257:
! 258: module = ngx_modules[m]->ctx;
! 259: mi = ngx_modules[m]->ctx_index;
! 260:
! 261: /* init http{} main_conf's */
! 262:
! 263: if (module->init_main_conf) {
! 264: rv = module->init_main_conf(cf, ctx->main_conf[mi]);
! 265: if (rv != NGX_CONF_OK) {
! 266: goto failed;
! 267: }
! 268: }
! 269:
! 270: rv = ngx_http_merge_servers(cf, cmcf, module, mi);
! 271: if (rv != NGX_CONF_OK) {
! 272: goto failed;
! 273: }
! 274: }
! 275:
! 276:
! 277: /* create location trees */
! 278:
! 279: for (s = 0; s < cmcf->servers.nelts; s++) {
! 280:
! 281: clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
! 282:
! 283: if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
! 284: return NGX_CONF_ERROR;
! 285: }
! 286:
! 287: if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
! 288: return NGX_CONF_ERROR;
! 289: }
! 290: }
! 291:
! 292:
! 293: if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
! 294: return NGX_CONF_ERROR;
! 295: }
! 296:
! 297: if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {
! 298: return NGX_CONF_ERROR;
! 299: }
! 300:
! 301:
! 302: for (m = 0; ngx_modules[m]; m++) {
! 303: if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
! 304: continue;
! 305: }
! 306:
! 307: module = ngx_modules[m]->ctx;
! 308:
! 309: if (module->postconfiguration) {
! 310: if (module->postconfiguration(cf) != NGX_OK) {
! 311: return NGX_CONF_ERROR;
! 312: }
! 313: }
! 314: }
! 315:
! 316: if (ngx_http_variables_init_vars(cf) != NGX_OK) {
! 317: return NGX_CONF_ERROR;
! 318: }
! 319:
! 320: /*
! 321: * http{}'s cf->ctx was needed while the configuration merging
! 322: * and in postconfiguration process
! 323: */
! 324:
! 325: *cf = pcf;
! 326:
! 327:
! 328: if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
! 329: return NGX_CONF_ERROR;
! 330: }
! 331:
! 332:
! 333: /* optimize the lists of ports, addresses and server names */
! 334:
! 335: if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
! 336: return NGX_CONF_ERROR;
! 337: }
! 338:
! 339: return NGX_CONF_OK;
! 340:
! 341: failed:
! 342:
! 343: *cf = pcf;
! 344:
! 345: return rv;
! 346: }
! 347:
! 348:
! 349: static ngx_int_t
! 350: ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
! 351: {
! 352: if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers,
! 353: cf->pool, 1, sizeof(ngx_http_handler_pt))
! 354: != NGX_OK)
! 355: {
! 356: return NGX_ERROR;
! 357: }
! 358:
! 359: if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers,
! 360: cf->pool, 1, sizeof(ngx_http_handler_pt))
! 361: != NGX_OK)
! 362: {
! 363: return NGX_ERROR;
! 364: }
! 365:
! 366: if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
! 367: cf->pool, 1, sizeof(ngx_http_handler_pt))
! 368: != NGX_OK)
! 369: {
! 370: return NGX_ERROR;
! 371: }
! 372:
! 373: if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers,
! 374: cf->pool, 1, sizeof(ngx_http_handler_pt))
! 375: != NGX_OK)
! 376: {
! 377: return NGX_ERROR;
! 378: }
! 379:
! 380: if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,
! 381: cf->pool, 2, sizeof(ngx_http_handler_pt))
! 382: != NGX_OK)
! 383: {
! 384: return NGX_ERROR;
! 385: }
! 386:
! 387: if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
! 388: cf->pool, 4, sizeof(ngx_http_handler_pt))
! 389: != NGX_OK)
! 390: {
! 391: return NGX_ERROR;
! 392: }
! 393:
! 394: if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers,
! 395: cf->pool, 1, sizeof(ngx_http_handler_pt))
! 396: != NGX_OK)
! 397: {
! 398: return NGX_ERROR;
! 399: }
! 400:
! 401: return NGX_OK;
! 402: }
! 403:
! 404:
! 405: static ngx_int_t
! 406: ngx_http_init_headers_in_hash(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
! 407: {
! 408: ngx_array_t headers_in;
! 409: ngx_hash_key_t *hk;
! 410: ngx_hash_init_t hash;
! 411: ngx_http_header_t *header;
! 412:
! 413: if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
! 414: != NGX_OK)
! 415: {
! 416: return NGX_ERROR;
! 417: }
! 418:
! 419: for (header = ngx_http_headers_in; header->name.len; header++) {
! 420: hk = ngx_array_push(&headers_in);
! 421: if (hk == NULL) {
! 422: return NGX_ERROR;
! 423: }
! 424:
! 425: hk->key = header->name;
! 426: hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
! 427: hk->value = header;
! 428: }
! 429:
! 430: hash.hash = &cmcf->headers_in_hash;
! 431: hash.key = ngx_hash_key_lc;
! 432: hash.max_size = 512;
! 433: hash.bucket_size = ngx_align(64, ngx_cacheline_size);
! 434: hash.name = "headers_in_hash";
! 435: hash.pool = cf->pool;
! 436: hash.temp_pool = NULL;
! 437:
! 438: if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
! 439: return NGX_ERROR;
! 440: }
! 441:
! 442: return NGX_OK;
! 443: }
! 444:
! 445:
! 446: static ngx_int_t
! 447: ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
! 448: {
! 449: ngx_int_t j;
! 450: ngx_uint_t i, n;
! 451: ngx_uint_t find_config_index, use_rewrite, use_access;
! 452: ngx_http_handler_pt *h;
! 453: ngx_http_phase_handler_t *ph;
! 454: ngx_http_phase_handler_pt checker;
! 455:
! 456: cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1;
! 457: cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1;
! 458: find_config_index = 0;
! 459: use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
! 460: use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;
! 461:
! 462: n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;
! 463:
! 464: for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
! 465: n += cmcf->phases[i].handlers.nelts;
! 466: }
! 467:
! 468: ph = ngx_pcalloc(cf->pool,
! 469: n * sizeof(ngx_http_phase_handler_t) + sizeof(void *));
! 470: if (ph == NULL) {
! 471: return NGX_ERROR;
! 472: }
! 473:
! 474: cmcf->phase_engine.handlers = ph;
! 475: n = 0;
! 476:
! 477: for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
! 478: h = cmcf->phases[i].handlers.elts;
! 479:
! 480: switch (i) {
! 481:
! 482: case NGX_HTTP_SERVER_REWRITE_PHASE:
! 483: if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) {
! 484: cmcf->phase_engine.server_rewrite_index = n;
! 485: }
! 486: checker = ngx_http_core_rewrite_phase;
! 487:
! 488: break;
! 489:
! 490: case NGX_HTTP_FIND_CONFIG_PHASE:
! 491: find_config_index = n;
! 492:
! 493: ph->checker = ngx_http_core_find_config_phase;
! 494: n++;
! 495: ph++;
! 496:
! 497: continue;
! 498:
! 499: case NGX_HTTP_REWRITE_PHASE:
! 500: if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) {
! 501: cmcf->phase_engine.location_rewrite_index = n;
! 502: }
! 503: checker = ngx_http_core_rewrite_phase;
! 504:
! 505: break;
! 506:
! 507: case NGX_HTTP_POST_REWRITE_PHASE:
! 508: if (use_rewrite) {
! 509: ph->checker = ngx_http_core_post_rewrite_phase;
! 510: ph->next = find_config_index;
! 511: n++;
! 512: ph++;
! 513: }
! 514:
! 515: continue;
! 516:
! 517: case NGX_HTTP_ACCESS_PHASE:
! 518: checker = ngx_http_core_access_phase;
! 519: n++;
! 520: break;
! 521:
! 522: case NGX_HTTP_POST_ACCESS_PHASE:
! 523: if (use_access) {
! 524: ph->checker = ngx_http_core_post_access_phase;
! 525: ph->next = n;
! 526: ph++;
! 527: }
! 528:
! 529: continue;
! 530:
! 531: case NGX_HTTP_TRY_FILES_PHASE:
! 532: if (cmcf->try_files) {
! 533: ph->checker = ngx_http_core_try_files_phase;
! 534: n++;
! 535: ph++;
! 536: }
! 537:
! 538: continue;
! 539:
! 540: case NGX_HTTP_CONTENT_PHASE:
! 541: checker = ngx_http_core_content_phase;
! 542: break;
! 543:
! 544: default:
! 545: checker = ngx_http_core_generic_phase;
! 546: }
! 547:
! 548: n += cmcf->phases[i].handlers.nelts;
! 549:
! 550: for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {
! 551: ph->checker = checker;
! 552: ph->handler = h[j];
! 553: ph->next = n;
! 554: ph++;
! 555: }
! 556: }
! 557:
! 558: return NGX_OK;
! 559: }
! 560:
! 561:
! 562: static char *
! 563: ngx_http_merge_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
! 564: ngx_http_module_t *module, ngx_uint_t ctx_index)
! 565: {
! 566: char *rv;
! 567: ngx_uint_t s;
! 568: ngx_http_conf_ctx_t *ctx, saved;
! 569: ngx_http_core_loc_conf_t *clcf;
! 570: ngx_http_core_srv_conf_t **cscfp;
! 571:
! 572: cscfp = cmcf->servers.elts;
! 573: ctx = (ngx_http_conf_ctx_t *) cf->ctx;
! 574: saved = *ctx;
! 575: rv = NGX_CONF_OK;
! 576:
! 577: for (s = 0; s < cmcf->servers.nelts; s++) {
! 578:
! 579: /* merge the server{}s' srv_conf's */
! 580:
! 581: ctx->srv_conf = cscfp[s]->ctx->srv_conf;
! 582:
! 583: if (module->merge_srv_conf) {
! 584: rv = module->merge_srv_conf(cf, saved.srv_conf[ctx_index],
! 585: cscfp[s]->ctx->srv_conf[ctx_index]);
! 586: if (rv != NGX_CONF_OK) {
! 587: goto failed;
! 588: }
! 589: }
! 590:
! 591: if (module->merge_loc_conf) {
! 592:
! 593: /* merge the server{}'s loc_conf */
! 594:
! 595: ctx->loc_conf = cscfp[s]->ctx->loc_conf;
! 596:
! 597: rv = module->merge_loc_conf(cf, saved.loc_conf[ctx_index],
! 598: cscfp[s]->ctx->loc_conf[ctx_index]);
! 599: if (rv != NGX_CONF_OK) {
! 600: goto failed;
! 601: }
! 602:
! 603: /* merge the locations{}' loc_conf's */
! 604:
! 605: clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
! 606:
! 607: rv = ngx_http_merge_locations(cf, clcf->locations,
! 608: cscfp[s]->ctx->loc_conf,
! 609: module, ctx_index);
! 610: if (rv != NGX_CONF_OK) {
! 611: goto failed;
! 612: }
! 613: }
! 614: }
! 615:
! 616: failed:
! 617:
! 618: *ctx = saved;
! 619:
! 620: return rv;
! 621: }
! 622:
! 623:
! 624: static char *
! 625: ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations,
! 626: void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index)
! 627: {
! 628: char *rv;
! 629: ngx_queue_t *q;
! 630: ngx_http_conf_ctx_t *ctx, saved;
! 631: ngx_http_core_loc_conf_t *clcf;
! 632: ngx_http_location_queue_t *lq;
! 633:
! 634: if (locations == NULL) {
! 635: return NGX_CONF_OK;
! 636: }
! 637:
! 638: ctx = (ngx_http_conf_ctx_t *) cf->ctx;
! 639: saved = *ctx;
! 640:
! 641: for (q = ngx_queue_head(locations);
! 642: q != ngx_queue_sentinel(locations);
! 643: q = ngx_queue_next(q))
! 644: {
! 645: lq = (ngx_http_location_queue_t *) q;
! 646:
! 647: clcf = lq->exact ? lq->exact : lq->inclusive;
! 648: ctx->loc_conf = clcf->loc_conf;
! 649:
! 650: rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
! 651: clcf->loc_conf[ctx_index]);
! 652: if (rv != NGX_CONF_OK) {
! 653: return rv;
! 654: }
! 655:
! 656: rv = ngx_http_merge_locations(cf, clcf->locations, clcf->loc_conf,
! 657: module, ctx_index);
! 658: if (rv != NGX_CONF_OK) {
! 659: return rv;
! 660: }
! 661: }
! 662:
! 663: *ctx = saved;
! 664:
! 665: return NGX_CONF_OK;
! 666: }
! 667:
! 668:
! 669: static ngx_int_t
! 670: ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
! 671: ngx_http_core_loc_conf_t *pclcf)
! 672: {
! 673: ngx_uint_t n;
! 674: ngx_queue_t *q, *locations, *named, tail;
! 675: ngx_http_core_loc_conf_t *clcf;
! 676: ngx_http_location_queue_t *lq;
! 677: ngx_http_core_loc_conf_t **clcfp;
! 678: #if (NGX_PCRE)
! 679: ngx_uint_t r;
! 680: ngx_queue_t *regex;
! 681: #endif
! 682:
! 683: locations = pclcf->locations;
! 684:
! 685: if (locations == NULL) {
! 686: return NGX_OK;
! 687: }
! 688:
! 689: ngx_queue_sort(locations, ngx_http_cmp_locations);
! 690:
! 691: named = NULL;
! 692: n = 0;
! 693: #if (NGX_PCRE)
! 694: regex = NULL;
! 695: r = 0;
! 696: #endif
! 697:
! 698: for (q = ngx_queue_head(locations);
! 699: q != ngx_queue_sentinel(locations);
! 700: q = ngx_queue_next(q))
! 701: {
! 702: lq = (ngx_http_location_queue_t *) q;
! 703:
! 704: clcf = lq->exact ? lq->exact : lq->inclusive;
! 705:
! 706: if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) {
! 707: return NGX_ERROR;
! 708: }
! 709:
! 710: #if (NGX_PCRE)
! 711:
! 712: if (clcf->regex) {
! 713: r++;
! 714:
! 715: if (regex == NULL) {
! 716: regex = q;
! 717: }
! 718:
! 719: continue;
! 720: }
! 721:
! 722: #endif
! 723:
! 724: if (clcf->named) {
! 725: n++;
! 726:
! 727: if (named == NULL) {
! 728: named = q;
! 729: }
! 730:
! 731: continue;
! 732: }
! 733:
! 734: if (clcf->noname) {
! 735: break;
! 736: }
! 737: }
! 738:
! 739: if (q != ngx_queue_sentinel(locations)) {
! 740: ngx_queue_split(locations, q, &tail);
! 741: }
! 742:
! 743: if (named) {
! 744: clcfp = ngx_palloc(cf->pool,
! 745: (n + 1) * sizeof(ngx_http_core_loc_conf_t **));
! 746: if (clcfp == NULL) {
! 747: return NGX_ERROR;
! 748: }
! 749:
! 750: cscf->named_locations = clcfp;
! 751:
! 752: for (q = named;
! 753: q != ngx_queue_sentinel(locations);
! 754: q = ngx_queue_next(q))
! 755: {
! 756: lq = (ngx_http_location_queue_t *) q;
! 757:
! 758: *(clcfp++) = lq->exact;
! 759: }
! 760:
! 761: *clcfp = NULL;
! 762:
! 763: ngx_queue_split(locations, named, &tail);
! 764: }
! 765:
! 766: #if (NGX_PCRE)
! 767:
! 768: if (regex) {
! 769:
! 770: clcfp = ngx_palloc(cf->pool,
! 771: (r + 1) * sizeof(ngx_http_core_loc_conf_t **));
! 772: if (clcfp == NULL) {
! 773: return NGX_ERROR;
! 774: }
! 775:
! 776: pclcf->regex_locations = clcfp;
! 777:
! 778: for (q = regex;
! 779: q != ngx_queue_sentinel(locations);
! 780: q = ngx_queue_next(q))
! 781: {
! 782: lq = (ngx_http_location_queue_t *) q;
! 783:
! 784: *(clcfp++) = lq->exact;
! 785: }
! 786:
! 787: *clcfp = NULL;
! 788:
! 789: ngx_queue_split(locations, regex, &tail);
! 790: }
! 791:
! 792: #endif
! 793:
! 794: return NGX_OK;
! 795: }
! 796:
! 797:
! 798: static ngx_int_t
! 799: ngx_http_init_static_location_trees(ngx_conf_t *cf,
! 800: ngx_http_core_loc_conf_t *pclcf)
! 801: {
! 802: ngx_queue_t *q, *locations;
! 803: ngx_http_core_loc_conf_t *clcf;
! 804: ngx_http_location_queue_t *lq;
! 805:
! 806: locations = pclcf->locations;
! 807:
! 808: if (locations == NULL) {
! 809: return NGX_OK;
! 810: }
! 811:
! 812: if (ngx_queue_empty(locations)) {
! 813: return NGX_OK;
! 814: }
! 815:
! 816: for (q = ngx_queue_head(locations);
! 817: q != ngx_queue_sentinel(locations);
! 818: q = ngx_queue_next(q))
! 819: {
! 820: lq = (ngx_http_location_queue_t *) q;
! 821:
! 822: clcf = lq->exact ? lq->exact : lq->inclusive;
! 823:
! 824: if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
! 825: return NGX_ERROR;
! 826: }
! 827: }
! 828:
! 829: if (ngx_http_join_exact_locations(cf, locations) != NGX_OK) {
! 830: return NGX_ERROR;
! 831: }
! 832:
! 833: ngx_http_create_locations_list(locations, ngx_queue_head(locations));
! 834:
! 835: pclcf->static_locations = ngx_http_create_locations_tree(cf, locations, 0);
! 836: if (pclcf->static_locations == NULL) {
! 837: return NGX_ERROR;
! 838: }
! 839:
! 840: return NGX_OK;
! 841: }
! 842:
! 843:
! 844: ngx_int_t
! 845: ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
! 846: ngx_http_core_loc_conf_t *clcf)
! 847: {
! 848: ngx_http_location_queue_t *lq;
! 849:
! 850: if (*locations == NULL) {
! 851: *locations = ngx_palloc(cf->temp_pool,
! 852: sizeof(ngx_http_location_queue_t));
! 853: if (*locations == NULL) {
! 854: return NGX_ERROR;
! 855: }
! 856:
! 857: ngx_queue_init(*locations);
! 858: }
! 859:
! 860: lq = ngx_palloc(cf->temp_pool, sizeof(ngx_http_location_queue_t));
! 861: if (lq == NULL) {
! 862: return NGX_ERROR;
! 863: }
! 864:
! 865: if (clcf->exact_match
! 866: #if (NGX_PCRE)
! 867: || clcf->regex
! 868: #endif
! 869: || clcf->named || clcf->noname)
! 870: {
! 871: lq->exact = clcf;
! 872: lq->inclusive = NULL;
! 873:
! 874: } else {
! 875: lq->exact = NULL;
! 876: lq->inclusive = clcf;
! 877: }
! 878:
! 879: lq->name = &clcf->name;
! 880: lq->file_name = cf->conf_file->file.name.data;
! 881: lq->line = cf->conf_file->line;
! 882:
! 883: ngx_queue_init(&lq->list);
! 884:
! 885: ngx_queue_insert_tail(*locations, &lq->queue);
! 886:
! 887: return NGX_OK;
! 888: }
! 889:
! 890:
! 891: static ngx_int_t
! 892: ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two)
! 893: {
! 894: ngx_int_t rc;
! 895: ngx_http_core_loc_conf_t *first, *second;
! 896: ngx_http_location_queue_t *lq1, *lq2;
! 897:
! 898: lq1 = (ngx_http_location_queue_t *) one;
! 899: lq2 = (ngx_http_location_queue_t *) two;
! 900:
! 901: first = lq1->exact ? lq1->exact : lq1->inclusive;
! 902: second = lq2->exact ? lq2->exact : lq2->inclusive;
! 903:
! 904: if (first->noname && !second->noname) {
! 905: /* shift no named locations to the end */
! 906: return 1;
! 907: }
! 908:
! 909: if (!first->noname && second->noname) {
! 910: /* shift no named locations to the end */
! 911: return -1;
! 912: }
! 913:
! 914: if (first->noname || second->noname) {
! 915: /* do not sort no named locations */
! 916: return 0;
! 917: }
! 918:
! 919: if (first->named && !second->named) {
! 920: /* shift named locations to the end */
! 921: return 1;
! 922: }
! 923:
! 924: if (!first->named && second->named) {
! 925: /* shift named locations to the end */
! 926: return -1;
! 927: }
! 928:
! 929: if (first->named && second->named) {
! 930: return ngx_strcmp(first->name.data, second->name.data);
! 931: }
! 932:
! 933: #if (NGX_PCRE)
! 934:
! 935: if (first->regex && !second->regex) {
! 936: /* shift the regex matches to the end */
! 937: return 1;
! 938: }
! 939:
! 940: if (!first->regex && second->regex) {
! 941: /* shift the regex matches to the end */
! 942: return -1;
! 943: }
! 944:
! 945: if (first->regex || second->regex) {
! 946: /* do not sort the regex matches */
! 947: return 0;
! 948: }
! 949:
! 950: #endif
! 951:
! 952: rc = ngx_strcmp(first->name.data, second->name.data);
! 953:
! 954: if (rc == 0 && !first->exact_match && second->exact_match) {
! 955: /* an exact match must be before the same inclusive one */
! 956: return 1;
! 957: }
! 958:
! 959: return rc;
! 960: }
! 961:
! 962:
! 963: static ngx_int_t
! 964: ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations)
! 965: {
! 966: ngx_queue_t *q, *x;
! 967: ngx_http_location_queue_t *lq, *lx;
! 968:
! 969: q = ngx_queue_head(locations);
! 970:
! 971: while (q != ngx_queue_last(locations)) {
! 972:
! 973: x = ngx_queue_next(q);
! 974:
! 975: lq = (ngx_http_location_queue_t *) q;
! 976: lx = (ngx_http_location_queue_t *) x;
! 977:
! 978: if (ngx_strcmp(lq->name->data, lx->name->data) == 0) {
! 979:
! 980: if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) {
! 981: ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
! 982: "duplicate location \"%V\" in %s:%ui",
! 983: lx->name, lx->file_name, lx->line);
! 984:
! 985: return NGX_ERROR;
! 986: }
! 987:
! 988: lq->inclusive = lx->inclusive;
! 989:
! 990: ngx_queue_remove(x);
! 991:
! 992: continue;
! 993: }
! 994:
! 995: q = ngx_queue_next(q);
! 996: }
! 997:
! 998: return NGX_OK;
! 999: }
! 1000:
! 1001:
! 1002: static void
! 1003: ngx_http_create_locations_list(ngx_queue_t *locations, ngx_queue_t *q)
! 1004: {
! 1005: u_char *name;
! 1006: size_t len;
! 1007: ngx_queue_t *x, tail;
! 1008: ngx_http_location_queue_t *lq, *lx;
! 1009:
! 1010: if (q == ngx_queue_last(locations)) {
! 1011: return;
! 1012: }
! 1013:
! 1014: lq = (ngx_http_location_queue_t *) q;
! 1015:
! 1016: if (lq->inclusive == NULL) {
! 1017: ngx_http_create_locations_list(locations, ngx_queue_next(q));
! 1018: return;
! 1019: }
! 1020:
! 1021: len = lq->name->len;
! 1022: name = lq->name->data;
! 1023:
! 1024: for (x = ngx_queue_next(q);
! 1025: x != ngx_queue_sentinel(locations);
! 1026: x = ngx_queue_next(x))
! 1027: {
! 1028: lx = (ngx_http_location_queue_t *) x;
! 1029:
! 1030: if (len > lx->name->len
! 1031: || (ngx_strncmp(name, lx->name->data, len) != 0))
! 1032: {
! 1033: break;
! 1034: }
! 1035: }
! 1036:
! 1037: q = ngx_queue_next(q);
! 1038:
! 1039: if (q == x) {
! 1040: ngx_http_create_locations_list(locations, x);
! 1041: return;
! 1042: }
! 1043:
! 1044: ngx_queue_split(locations, q, &tail);
! 1045: ngx_queue_add(&lq->list, &tail);
! 1046:
! 1047: if (x == ngx_queue_sentinel(locations)) {
! 1048: ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list));
! 1049: return;
! 1050: }
! 1051:
! 1052: ngx_queue_split(&lq->list, x, &tail);
! 1053: ngx_queue_add(locations, &tail);
! 1054:
! 1055: ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list));
! 1056:
! 1057: ngx_http_create_locations_list(locations, x);
! 1058: }
! 1059:
! 1060:
! 1061: /*
! 1062: * to keep cache locality for left leaf nodes, allocate nodes in following
! 1063: * order: node, left subtree, right subtree, inclusive subtree
! 1064: */
! 1065:
! 1066: static ngx_http_location_tree_node_t *
! 1067: ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations,
! 1068: size_t prefix)
! 1069: {
! 1070: size_t len;
! 1071: ngx_queue_t *q, tail;
! 1072: ngx_http_location_queue_t *lq;
! 1073: ngx_http_location_tree_node_t *node;
! 1074:
! 1075: q = ngx_queue_middle(locations);
! 1076:
! 1077: lq = (ngx_http_location_queue_t *) q;
! 1078: len = lq->name->len - prefix;
! 1079:
! 1080: node = ngx_palloc(cf->pool,
! 1081: offsetof(ngx_http_location_tree_node_t, name) + len);
! 1082: if (node == NULL) {
! 1083: return NULL;
! 1084: }
! 1085:
! 1086: node->left = NULL;
! 1087: node->right = NULL;
! 1088: node->tree = NULL;
! 1089: node->exact = lq->exact;
! 1090: node->inclusive = lq->inclusive;
! 1091:
! 1092: node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect)
! 1093: || (lq->inclusive && lq->inclusive->auto_redirect));
! 1094:
! 1095: node->len = (u_char) len;
! 1096: ngx_memcpy(node->name, &lq->name->data[prefix], len);
! 1097:
! 1098: ngx_queue_split(locations, q, &tail);
! 1099:
! 1100: if (ngx_queue_empty(locations)) {
! 1101: /*
! 1102: * ngx_queue_split() insures that if left part is empty,
! 1103: * then right one is empty too
! 1104: */
! 1105: goto inclusive;
! 1106: }
! 1107:
! 1108: node->left = ngx_http_create_locations_tree(cf, locations, prefix);
! 1109: if (node->left == NULL) {
! 1110: return NULL;
! 1111: }
! 1112:
! 1113: ngx_queue_remove(q);
! 1114:
! 1115: if (ngx_queue_empty(&tail)) {
! 1116: goto inclusive;
! 1117: }
! 1118:
! 1119: node->right = ngx_http_create_locations_tree(cf, &tail, prefix);
! 1120: if (node->right == NULL) {
! 1121: return NULL;
! 1122: }
! 1123:
! 1124: inclusive:
! 1125:
! 1126: if (ngx_queue_empty(&lq->list)) {
! 1127: return node;
! 1128: }
! 1129:
! 1130: node->tree = ngx_http_create_locations_tree(cf, &lq->list, prefix + len);
! 1131: if (node->tree == NULL) {
! 1132: return NULL;
! 1133: }
! 1134:
! 1135: return node;
! 1136: }
! 1137:
! 1138:
! 1139: ngx_int_t
! 1140: ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
! 1141: ngx_http_listen_opt_t *lsopt)
! 1142: {
! 1143: in_port_t p;
! 1144: ngx_uint_t i;
! 1145: struct sockaddr *sa;
! 1146: struct sockaddr_in *sin;
! 1147: ngx_http_conf_port_t *port;
! 1148: ngx_http_core_main_conf_t *cmcf;
! 1149: #if (NGX_HAVE_INET6)
! 1150: struct sockaddr_in6 *sin6;
! 1151: #endif
! 1152:
! 1153: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
! 1154:
! 1155: if (cmcf->ports == NULL) {
! 1156: cmcf->ports = ngx_array_create(cf->temp_pool, 2,
! 1157: sizeof(ngx_http_conf_port_t));
! 1158: if (cmcf->ports == NULL) {
! 1159: return NGX_ERROR;
! 1160: }
! 1161: }
! 1162:
! 1163: sa = &lsopt->u.sockaddr;
! 1164:
! 1165: switch (sa->sa_family) {
! 1166:
! 1167: #if (NGX_HAVE_INET6)
! 1168: case AF_INET6:
! 1169: sin6 = &lsopt->u.sockaddr_in6;
! 1170: p = sin6->sin6_port;
! 1171: break;
! 1172: #endif
! 1173:
! 1174: #if (NGX_HAVE_UNIX_DOMAIN)
! 1175: case AF_UNIX:
! 1176: p = 0;
! 1177: break;
! 1178: #endif
! 1179:
! 1180: default: /* AF_INET */
! 1181: sin = &lsopt->u.sockaddr_in;
! 1182: p = sin->sin_port;
! 1183: break;
! 1184: }
! 1185:
! 1186: port = cmcf->ports->elts;
! 1187: for (i = 0; i < cmcf->ports->nelts; i++) {
! 1188:
! 1189: if (p != port[i].port || sa->sa_family != port[i].family) {
! 1190: continue;
! 1191: }
! 1192:
! 1193: /* a port is already in the port list */
! 1194:
! 1195: return ngx_http_add_addresses(cf, cscf, &port[i], lsopt);
! 1196: }
! 1197:
! 1198: /* add a port to the port list */
! 1199:
! 1200: port = ngx_array_push(cmcf->ports);
! 1201: if (port == NULL) {
! 1202: return NGX_ERROR;
! 1203: }
! 1204:
! 1205: port->family = sa->sa_family;
! 1206: port->port = p;
! 1207: port->addrs.elts = NULL;
! 1208:
! 1209: return ngx_http_add_address(cf, cscf, port, lsopt);
! 1210: }
! 1211:
! 1212:
! 1213: static ngx_int_t
! 1214: ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
! 1215: ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
! 1216: {
! 1217: u_char *p;
! 1218: size_t len, off;
! 1219: ngx_uint_t i, default_server;
! 1220: struct sockaddr *sa;
! 1221: ngx_http_conf_addr_t *addr;
! 1222: #if (NGX_HAVE_UNIX_DOMAIN)
! 1223: struct sockaddr_un *saun;
! 1224: #endif
! 1225: #if (NGX_HTTP_SSL)
! 1226: ngx_uint_t ssl;
! 1227: #endif
! 1228: #if (NGX_HTTP_SPDY)
! 1229: ngx_uint_t spdy;
! 1230: #endif
! 1231:
! 1232: /*
! 1233: * we cannot compare whole sockaddr struct's as kernel
! 1234: * may fill some fields in inherited sockaddr struct's
! 1235: */
! 1236:
! 1237: sa = &lsopt->u.sockaddr;
! 1238:
! 1239: switch (sa->sa_family) {
! 1240:
! 1241: #if (NGX_HAVE_INET6)
! 1242: case AF_INET6:
! 1243: off = offsetof(struct sockaddr_in6, sin6_addr);
! 1244: len = 16;
! 1245: break;
! 1246: #endif
! 1247:
! 1248: #if (NGX_HAVE_UNIX_DOMAIN)
! 1249: case AF_UNIX:
! 1250: off = offsetof(struct sockaddr_un, sun_path);
! 1251: len = sizeof(saun->sun_path);
! 1252: break;
! 1253: #endif
! 1254:
! 1255: default: /* AF_INET */
! 1256: off = offsetof(struct sockaddr_in, sin_addr);
! 1257: len = 4;
! 1258: break;
! 1259: }
! 1260:
! 1261: p = lsopt->u.sockaddr_data + off;
! 1262:
! 1263: addr = port->addrs.elts;
! 1264:
! 1265: for (i = 0; i < port->addrs.nelts; i++) {
! 1266:
! 1267: if (ngx_memcmp(p, addr[i].opt.u.sockaddr_data + off, len) != 0) {
! 1268: continue;
! 1269: }
! 1270:
! 1271: /* the address is already in the address list */
! 1272:
! 1273: if (ngx_http_add_server(cf, cscf, &addr[i]) != NGX_OK) {
! 1274: return NGX_ERROR;
! 1275: }
! 1276:
! 1277: /* preserve default_server bit during listen options overwriting */
! 1278: default_server = addr[i].opt.default_server;
! 1279:
! 1280: #if (NGX_HTTP_SSL)
! 1281: ssl = lsopt->ssl || addr[i].opt.ssl;
! 1282: #endif
! 1283: #if (NGX_HTTP_SPDY)
! 1284: spdy = lsopt->spdy || addr[i].opt.spdy;
! 1285: #endif
! 1286:
! 1287: if (lsopt->set) {
! 1288:
! 1289: if (addr[i].opt.set) {
! 1290: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1291: "duplicate listen options for %s", addr[i].opt.addr);
! 1292: return NGX_ERROR;
! 1293: }
! 1294:
! 1295: addr[i].opt = *lsopt;
! 1296: }
! 1297:
! 1298: /* check the duplicate "default" server for this address:port */
! 1299:
! 1300: if (lsopt->default_server) {
! 1301:
! 1302: if (default_server) {
! 1303: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1304: "a duplicate default server for %s", addr[i].opt.addr);
! 1305: return NGX_ERROR;
! 1306: }
! 1307:
! 1308: default_server = 1;
! 1309: addr[i].default_server = cscf;
! 1310: }
! 1311:
! 1312: addr[i].opt.default_server = default_server;
! 1313: #if (NGX_HTTP_SSL)
! 1314: addr[i].opt.ssl = ssl;
! 1315: #endif
! 1316: #if (NGX_HTTP_SPDY)
! 1317: addr[i].opt.spdy = spdy;
! 1318: #endif
! 1319:
! 1320: return NGX_OK;
! 1321: }
! 1322:
! 1323: /* add the address to the addresses list that bound to this port */
! 1324:
! 1325: return ngx_http_add_address(cf, cscf, port, lsopt);
! 1326: }
! 1327:
! 1328:
! 1329: /*
! 1330: * add the server address, the server names and the server core module
! 1331: * configurations to the port list
! 1332: */
! 1333:
! 1334: static ngx_int_t
! 1335: ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
! 1336: ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
! 1337: {
! 1338: ngx_http_conf_addr_t *addr;
! 1339:
! 1340: if (port->addrs.elts == NULL) {
! 1341: if (ngx_array_init(&port->addrs, cf->temp_pool, 4,
! 1342: sizeof(ngx_http_conf_addr_t))
! 1343: != NGX_OK)
! 1344: {
! 1345: return NGX_ERROR;
! 1346: }
! 1347: }
! 1348:
! 1349: #if (NGX_HTTP_SPDY && NGX_HTTP_SSL && !defined TLSEXT_TYPE_next_proto_neg)
! 1350: if (lsopt->spdy && lsopt->ssl) {
! 1351: ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
! 1352: "nginx was built without OpenSSL NPN support, "
! 1353: "SPDY is not enabled for %s", lsopt->addr);
! 1354: }
! 1355: #endif
! 1356:
! 1357: addr = ngx_array_push(&port->addrs);
! 1358: if (addr == NULL) {
! 1359: return NGX_ERROR;
! 1360: }
! 1361:
! 1362: addr->opt = *lsopt;
! 1363: addr->hash.buckets = NULL;
! 1364: addr->hash.size = 0;
! 1365: addr->wc_head = NULL;
! 1366: addr->wc_tail = NULL;
! 1367: #if (NGX_PCRE)
! 1368: addr->nregex = 0;
! 1369: addr->regex = NULL;
! 1370: #endif
! 1371: addr->default_server = cscf;
! 1372: addr->servers.elts = NULL;
! 1373:
! 1374: return ngx_http_add_server(cf, cscf, addr);
! 1375: }
! 1376:
! 1377:
! 1378: /* add the server core module configuration to the address:port */
! 1379:
! 1380: static ngx_int_t
! 1381: ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
! 1382: ngx_http_conf_addr_t *addr)
! 1383: {
! 1384: ngx_uint_t i;
! 1385: ngx_http_core_srv_conf_t **server;
! 1386:
! 1387: if (addr->servers.elts == NULL) {
! 1388: if (ngx_array_init(&addr->servers, cf->temp_pool, 4,
! 1389: sizeof(ngx_http_core_srv_conf_t *))
! 1390: != NGX_OK)
! 1391: {
! 1392: return NGX_ERROR;
! 1393: }
! 1394:
! 1395: } else {
! 1396: server = addr->servers.elts;
! 1397: for (i = 0; i < addr->servers.nelts; i++) {
! 1398: if (server[i] == cscf) {
! 1399: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 1400: "a duplicate listen %s", addr->opt.addr);
! 1401: return NGX_ERROR;
! 1402: }
! 1403: }
! 1404: }
! 1405:
! 1406: server = ngx_array_push(&addr->servers);
! 1407: if (server == NULL) {
! 1408: return NGX_ERROR;
! 1409: }
! 1410:
! 1411: *server = cscf;
! 1412:
! 1413: return NGX_OK;
! 1414: }
! 1415:
! 1416:
! 1417: static ngx_int_t
! 1418: ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
! 1419: ngx_array_t *ports)
! 1420: {
! 1421: ngx_uint_t p, a;
! 1422: ngx_http_conf_port_t *port;
! 1423: ngx_http_conf_addr_t *addr;
! 1424:
! 1425: if (ports == NULL) {
! 1426: return NGX_OK;
! 1427: }
! 1428:
! 1429: port = ports->elts;
! 1430: for (p = 0; p < ports->nelts; p++) {
! 1431:
! 1432: ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,
! 1433: sizeof(ngx_http_conf_addr_t), ngx_http_cmp_conf_addrs);
! 1434:
! 1435: /*
! 1436: * check whether all name-based servers have the same
! 1437: * configuration as a default server for given address:port
! 1438: */
! 1439:
! 1440: addr = port[p].addrs.elts;
! 1441: for (a = 0; a < port[p].addrs.nelts; a++) {
! 1442:
! 1443: if (addr[a].servers.nelts > 1
! 1444: #if (NGX_PCRE)
! 1445: || addr[a].default_server->captures
! 1446: #endif
! 1447: )
! 1448: {
! 1449: if (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) {
! 1450: return NGX_ERROR;
! 1451: }
! 1452: }
! 1453: }
! 1454:
! 1455: if (ngx_http_init_listening(cf, &port[p]) != NGX_OK) {
! 1456: return NGX_ERROR;
! 1457: }
! 1458: }
! 1459:
! 1460: return NGX_OK;
! 1461: }
! 1462:
! 1463:
! 1464: static ngx_int_t
! 1465: ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
! 1466: ngx_http_conf_addr_t *addr)
! 1467: {
! 1468: ngx_int_t rc;
! 1469: ngx_uint_t n, s;
! 1470: ngx_hash_init_t hash;
! 1471: ngx_hash_keys_arrays_t ha;
! 1472: ngx_http_server_name_t *name;
! 1473: ngx_http_core_srv_conf_t **cscfp;
! 1474: #if (NGX_PCRE)
! 1475: ngx_uint_t regex, i;
! 1476:
! 1477: regex = 0;
! 1478: #endif
! 1479:
! 1480: ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t));
! 1481:
! 1482: ha.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);
! 1483: if (ha.temp_pool == NULL) {
! 1484: return NGX_ERROR;
! 1485: }
! 1486:
! 1487: ha.pool = cf->pool;
! 1488:
! 1489: if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) {
! 1490: goto failed;
! 1491: }
! 1492:
! 1493: cscfp = addr->servers.elts;
! 1494:
! 1495: for (s = 0; s < addr->servers.nelts; s++) {
! 1496:
! 1497: name = cscfp[s]->server_names.elts;
! 1498:
! 1499: for (n = 0; n < cscfp[s]->server_names.nelts; n++) {
! 1500:
! 1501: #if (NGX_PCRE)
! 1502: if (name[n].regex) {
! 1503: regex++;
! 1504: continue;
! 1505: }
! 1506: #endif
! 1507:
! 1508: rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server,
! 1509: NGX_HASH_WILDCARD_KEY);
! 1510:
! 1511: if (rc == NGX_ERROR) {
! 1512: return NGX_ERROR;
! 1513: }
! 1514:
! 1515: if (rc == NGX_DECLINED) {
! 1516: ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
! 1517: "invalid server name or wildcard \"%V\" on %s",
! 1518: &name[n].name, addr->opt.addr);
! 1519: return NGX_ERROR;
! 1520: }
! 1521:
! 1522: if (rc == NGX_BUSY) {
! 1523: ngx_log_error(NGX_LOG_WARN, cf->log, 0,
! 1524: "conflicting server name \"%V\" on %s, ignored",
! 1525: &name[n].name, addr->opt.addr);
! 1526: }
! 1527: }
! 1528: }
! 1529:
! 1530: hash.key = ngx_hash_key_lc;
! 1531: hash.max_size = cmcf->server_names_hash_max_size;
! 1532: hash.bucket_size = cmcf->server_names_hash_bucket_size;
! 1533: hash.name = "server_names_hash";
! 1534: hash.pool = cf->pool;
! 1535:
! 1536: if (ha.keys.nelts) {
! 1537: hash.hash = &addr->hash;
! 1538: hash.temp_pool = NULL;
! 1539:
! 1540: if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) {
! 1541: goto failed;
! 1542: }
! 1543: }
! 1544:
! 1545: if (ha.dns_wc_head.nelts) {
! 1546:
! 1547: ngx_qsort(ha.dns_wc_head.elts, (size_t) ha.dns_wc_head.nelts,
! 1548: sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards);
! 1549:
! 1550: hash.hash = NULL;
! 1551: hash.temp_pool = ha.temp_pool;
! 1552:
! 1553: if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts,
! 1554: ha.dns_wc_head.nelts)
! 1555: != NGX_OK)
! 1556: {
! 1557: goto failed;
! 1558: }
! 1559:
! 1560: addr->wc_head = (ngx_hash_wildcard_t *) hash.hash;
! 1561: }
! 1562:
! 1563: if (ha.dns_wc_tail.nelts) {
! 1564:
! 1565: ngx_qsort(ha.dns_wc_tail.elts, (size_t) ha.dns_wc_tail.nelts,
! 1566: sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards);
! 1567:
! 1568: hash.hash = NULL;
! 1569: hash.temp_pool = ha.temp_pool;
! 1570:
! 1571: if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts,
! 1572: ha.dns_wc_tail.nelts)
! 1573: != NGX_OK)
! 1574: {
! 1575: goto failed;
! 1576: }
! 1577:
! 1578: addr->wc_tail = (ngx_hash_wildcard_t *) hash.hash;
! 1579: }
! 1580:
! 1581: ngx_destroy_pool(ha.temp_pool);
! 1582:
! 1583: #if (NGX_PCRE)
! 1584:
! 1585: if (regex == 0) {
! 1586: return NGX_OK;
! 1587: }
! 1588:
! 1589: addr->nregex = regex;
! 1590: addr->regex = ngx_palloc(cf->pool, regex * sizeof(ngx_http_server_name_t));
! 1591: if (addr->regex == NULL) {
! 1592: return NGX_ERROR;
! 1593: }
! 1594:
! 1595: i = 0;
! 1596:
! 1597: for (s = 0; s < addr->servers.nelts; s++) {
! 1598:
! 1599: name = cscfp[s]->server_names.elts;
! 1600:
! 1601: for (n = 0; n < cscfp[s]->server_names.nelts; n++) {
! 1602: if (name[n].regex) {
! 1603: addr->regex[i++] = name[n];
! 1604: }
! 1605: }
! 1606: }
! 1607:
! 1608: #endif
! 1609:
! 1610: return NGX_OK;
! 1611:
! 1612: failed:
! 1613:
! 1614: ngx_destroy_pool(ha.temp_pool);
! 1615:
! 1616: return NGX_ERROR;
! 1617: }
! 1618:
! 1619:
! 1620: static ngx_int_t
! 1621: ngx_http_cmp_conf_addrs(const void *one, const void *two)
! 1622: {
! 1623: ngx_http_conf_addr_t *first, *second;
! 1624:
! 1625: first = (ngx_http_conf_addr_t *) one;
! 1626: second = (ngx_http_conf_addr_t *) two;
! 1627:
! 1628: if (first->opt.wildcard) {
! 1629: /* a wildcard address must be the last resort, shift it to the end */
! 1630: return 1;
! 1631: }
! 1632:
! 1633: if (second->opt.wildcard) {
! 1634: /* a wildcard address must be the last resort, shift it to the end */
! 1635: return -1;
! 1636: }
! 1637:
! 1638: if (first->opt.bind && !second->opt.bind) {
! 1639: /* shift explicit bind()ed addresses to the start */
! 1640: return -1;
! 1641: }
! 1642:
! 1643: if (!first->opt.bind && second->opt.bind) {
! 1644: /* shift explicit bind()ed addresses to the start */
! 1645: return 1;
! 1646: }
! 1647:
! 1648: /* do not sort by default */
! 1649:
! 1650: return 0;
! 1651: }
! 1652:
! 1653:
! 1654: static int ngx_libc_cdecl
! 1655: ngx_http_cmp_dns_wildcards(const void *one, const void *two)
! 1656: {
! 1657: ngx_hash_key_t *first, *second;
! 1658:
! 1659: first = (ngx_hash_key_t *) one;
! 1660: second = (ngx_hash_key_t *) two;
! 1661:
! 1662: return ngx_dns_strcmp(first->key.data, second->key.data);
! 1663: }
! 1664:
! 1665:
! 1666: static ngx_int_t
! 1667: ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)
! 1668: {
! 1669: ngx_uint_t i, last, bind_wildcard;
! 1670: ngx_listening_t *ls;
! 1671: ngx_http_port_t *hport;
! 1672: ngx_http_conf_addr_t *addr;
! 1673:
! 1674: addr = port->addrs.elts;
! 1675: last = port->addrs.nelts;
! 1676:
! 1677: /*
! 1678: * If there is a binding to an "*:port" then we need to bind() to
! 1679: * the "*:port" only and ignore other implicit bindings. The bindings
! 1680: * have been already sorted: explicit bindings are on the start, then
! 1681: * implicit bindings go, and wildcard binding is in the end.
! 1682: */
! 1683:
! 1684: if (addr[last - 1].opt.wildcard) {
! 1685: addr[last - 1].opt.bind = 1;
! 1686: bind_wildcard = 1;
! 1687:
! 1688: } else {
! 1689: bind_wildcard = 0;
! 1690: }
! 1691:
! 1692: i = 0;
! 1693:
! 1694: while (i < last) {
! 1695:
! 1696: if (bind_wildcard && !addr[i].opt.bind) {
! 1697: i++;
! 1698: continue;
! 1699: }
! 1700:
! 1701: ls = ngx_http_add_listening(cf, &addr[i]);
! 1702: if (ls == NULL) {
! 1703: return NGX_ERROR;
! 1704: }
! 1705:
! 1706: hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t));
! 1707: if (hport == NULL) {
! 1708: return NGX_ERROR;
! 1709: }
! 1710:
! 1711: ls->servers = hport;
! 1712:
! 1713: if (i == last - 1) {
! 1714: hport->naddrs = last;
! 1715:
! 1716: } else {
! 1717: hport->naddrs = 1;
! 1718: i = 0;
! 1719: }
! 1720:
! 1721: switch (ls->sockaddr->sa_family) {
! 1722:
! 1723: #if (NGX_HAVE_INET6)
! 1724: case AF_INET6:
! 1725: if (ngx_http_add_addrs6(cf, hport, addr) != NGX_OK) {
! 1726: return NGX_ERROR;
! 1727: }
! 1728: break;
! 1729: #endif
! 1730: default: /* AF_INET */
! 1731: if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {
! 1732: return NGX_ERROR;
! 1733: }
! 1734: break;
! 1735: }
! 1736:
! 1737: addr++;
! 1738: last--;
! 1739: }
! 1740:
! 1741: return NGX_OK;
! 1742: }
! 1743:
! 1744:
! 1745: static ngx_listening_t *
! 1746: ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
! 1747: {
! 1748: ngx_listening_t *ls;
! 1749: ngx_http_core_loc_conf_t *clcf;
! 1750: ngx_http_core_srv_conf_t *cscf;
! 1751:
! 1752: ls = ngx_create_listening(cf, &addr->opt.u.sockaddr, addr->opt.socklen);
! 1753: if (ls == NULL) {
! 1754: return NULL;
! 1755: }
! 1756:
! 1757: ls->addr_ntop = 1;
! 1758:
! 1759: ls->handler = ngx_http_init_connection;
! 1760:
! 1761: cscf = addr->default_server;
! 1762: ls->pool_size = cscf->connection_pool_size;
! 1763: ls->post_accept_timeout = cscf->client_header_timeout;
! 1764:
! 1765: clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
! 1766:
! 1767: ls->logp = clcf->error_log;
! 1768: ls->log.data = &ls->addr_text;
! 1769: ls->log.handler = ngx_accept_log_error;
! 1770:
! 1771: #if (NGX_WIN32)
! 1772: {
! 1773: ngx_iocp_conf_t *iocpcf = NULL;
! 1774:
! 1775: if (ngx_get_conf(cf->cycle->conf_ctx, ngx_events_module)) {
! 1776: iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module);
! 1777: }
! 1778: if (iocpcf && iocpcf->acceptex_read) {
! 1779: ls->post_accept_buffer_size = cscf->client_header_buffer_size;
! 1780: }
! 1781: }
! 1782: #endif
! 1783:
! 1784: ls->backlog = addr->opt.backlog;
! 1785: ls->rcvbuf = addr->opt.rcvbuf;
! 1786: ls->sndbuf = addr->opt.sndbuf;
! 1787:
! 1788: ls->keepalive = addr->opt.so_keepalive;
! 1789: #if (NGX_HAVE_KEEPALIVE_TUNABLE)
! 1790: ls->keepidle = addr->opt.tcp_keepidle;
! 1791: ls->keepintvl = addr->opt.tcp_keepintvl;
! 1792: ls->keepcnt = addr->opt.tcp_keepcnt;
! 1793: #endif
! 1794:
! 1795: #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
! 1796: ls->accept_filter = addr->opt.accept_filter;
! 1797: #endif
! 1798:
! 1799: #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
! 1800: ls->deferred_accept = addr->opt.deferred_accept;
! 1801: #endif
! 1802:
! 1803: #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
! 1804: ls->ipv6only = addr->opt.ipv6only;
! 1805: #endif
! 1806:
! 1807: #if (NGX_HAVE_SETFIB)
! 1808: ls->setfib = addr->opt.setfib;
! 1809: #endif
! 1810:
! 1811: return ls;
! 1812: }
! 1813:
! 1814:
! 1815: static ngx_int_t
! 1816: ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,
! 1817: ngx_http_conf_addr_t *addr)
! 1818: {
! 1819: ngx_uint_t i;
! 1820: ngx_http_in_addr_t *addrs;
! 1821: struct sockaddr_in *sin;
! 1822: ngx_http_virtual_names_t *vn;
! 1823:
! 1824: hport->addrs = ngx_pcalloc(cf->pool,
! 1825: hport->naddrs * sizeof(ngx_http_in_addr_t));
! 1826: if (hport->addrs == NULL) {
! 1827: return NGX_ERROR;
! 1828: }
! 1829:
! 1830: addrs = hport->addrs;
! 1831:
! 1832: for (i = 0; i < hport->naddrs; i++) {
! 1833:
! 1834: sin = &addr[i].opt.u.sockaddr_in;
! 1835: addrs[i].addr = sin->sin_addr.s_addr;
! 1836: addrs[i].conf.default_server = addr[i].default_server;
! 1837: #if (NGX_HTTP_SSL)
! 1838: addrs[i].conf.ssl = addr[i].opt.ssl;
! 1839: #endif
! 1840: #if (NGX_HTTP_SPDY)
! 1841: addrs[i].conf.spdy = addr[i].opt.spdy;
! 1842: #endif
! 1843:
! 1844: if (addr[i].hash.buckets == NULL
! 1845: && (addr[i].wc_head == NULL
! 1846: || addr[i].wc_head->hash.buckets == NULL)
! 1847: && (addr[i].wc_tail == NULL
! 1848: || addr[i].wc_tail->hash.buckets == NULL)
! 1849: #if (NGX_PCRE)
! 1850: && addr[i].nregex == 0
! 1851: #endif
! 1852: )
! 1853: {
! 1854: continue;
! 1855: }
! 1856:
! 1857: vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));
! 1858: if (vn == NULL) {
! 1859: return NGX_ERROR;
! 1860: }
! 1861:
! 1862: addrs[i].conf.virtual_names = vn;
! 1863:
! 1864: vn->names.hash = addr[i].hash;
! 1865: vn->names.wc_head = addr[i].wc_head;
! 1866: vn->names.wc_tail = addr[i].wc_tail;
! 1867: #if (NGX_PCRE)
! 1868: vn->nregex = addr[i].nregex;
! 1869: vn->regex = addr[i].regex;
! 1870: #endif
! 1871: }
! 1872:
! 1873: return NGX_OK;
! 1874: }
! 1875:
! 1876:
! 1877: #if (NGX_HAVE_INET6)
! 1878:
! 1879: static ngx_int_t
! 1880: ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport,
! 1881: ngx_http_conf_addr_t *addr)
! 1882: {
! 1883: ngx_uint_t i;
! 1884: ngx_http_in6_addr_t *addrs6;
! 1885: struct sockaddr_in6 *sin6;
! 1886: ngx_http_virtual_names_t *vn;
! 1887:
! 1888: hport->addrs = ngx_pcalloc(cf->pool,
! 1889: hport->naddrs * sizeof(ngx_http_in6_addr_t));
! 1890: if (hport->addrs == NULL) {
! 1891: return NGX_ERROR;
! 1892: }
! 1893:
! 1894: addrs6 = hport->addrs;
! 1895:
! 1896: for (i = 0; i < hport->naddrs; i++) {
! 1897:
! 1898: sin6 = &addr[i].opt.u.sockaddr_in6;
! 1899: addrs6[i].addr6 = sin6->sin6_addr;
! 1900: addrs6[i].conf.default_server = addr[i].default_server;
! 1901: #if (NGX_HTTP_SSL)
! 1902: addrs6[i].conf.ssl = addr[i].opt.ssl;
! 1903: #endif
! 1904: #if (NGX_HTTP_SPDY)
! 1905: addrs6[i].conf.spdy = addr[i].opt.spdy;
! 1906: #endif
! 1907:
! 1908: if (addr[i].hash.buckets == NULL
! 1909: && (addr[i].wc_head == NULL
! 1910: || addr[i].wc_head->hash.buckets == NULL)
! 1911: && (addr[i].wc_tail == NULL
! 1912: || addr[i].wc_tail->hash.buckets == NULL)
! 1913: #if (NGX_PCRE)
! 1914: && addr[i].nregex == 0
! 1915: #endif
! 1916: )
! 1917: {
! 1918: continue;
! 1919: }
! 1920:
! 1921: vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));
! 1922: if (vn == NULL) {
! 1923: return NGX_ERROR;
! 1924: }
! 1925:
! 1926: addrs6[i].conf.virtual_names = vn;
! 1927:
! 1928: vn->names.hash = addr[i].hash;
! 1929: vn->names.wc_head = addr[i].wc_head;
! 1930: vn->names.wc_tail = addr[i].wc_tail;
! 1931: #if (NGX_PCRE)
! 1932: vn->nregex = addr[i].nregex;
! 1933: vn->regex = addr[i].regex;
! 1934: #endif
! 1935: }
! 1936:
! 1937: return NGX_OK;
! 1938: }
! 1939:
! 1940: #endif
! 1941:
! 1942:
! 1943: char *
! 1944: ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 1945: {
! 1946: char *p = conf;
! 1947:
! 1948: ngx_array_t **types;
! 1949: ngx_str_t *value, *default_type;
! 1950: ngx_uint_t i, n, hash;
! 1951: ngx_hash_key_t *type;
! 1952:
! 1953: types = (ngx_array_t **) (p + cmd->offset);
! 1954:
! 1955: if (*types == (void *) -1) {
! 1956: return NGX_CONF_OK;
! 1957: }
! 1958:
! 1959: default_type = cmd->post;
! 1960:
! 1961: if (*types == NULL) {
! 1962: *types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t));
! 1963: if (*types == NULL) {
! 1964: return NGX_CONF_ERROR;
! 1965: }
! 1966:
! 1967: if (default_type) {
! 1968: type = ngx_array_push(*types);
! 1969: if (type == NULL) {
! 1970: return NGX_CONF_ERROR;
! 1971: }
! 1972:
! 1973: type->key = *default_type;
! 1974: type->key_hash = ngx_hash_key(default_type->data,
! 1975: default_type->len);
! 1976: type->value = (void *) 4;
! 1977: }
! 1978: }
! 1979:
! 1980: value = cf->args->elts;
! 1981:
! 1982: for (i = 1; i < cf->args->nelts; i++) {
! 1983:
! 1984: if (value[i].len == 1 && value[i].data[0] == '*') {
! 1985: *types = (void *) -1;
! 1986: return NGX_CONF_OK;
! 1987: }
! 1988:
! 1989: hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len);
! 1990: value[i].data[value[i].len] = '\0';
! 1991:
! 1992: type = (*types)->elts;
! 1993: for (n = 0; n < (*types)->nelts; n++) {
! 1994:
! 1995: if (ngx_strcmp(value[i].data, type[n].key.data) == 0) {
! 1996: ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
! 1997: "duplicate MIME type \"%V\"", &value[i]);
! 1998: continue;
! 1999: }
! 2000: }
! 2001:
! 2002: type = ngx_array_push(*types);
! 2003: if (type == NULL) {
! 2004: return NGX_CONF_ERROR;
! 2005: }
! 2006:
! 2007: type->key = value[i];
! 2008: type->key_hash = hash;
! 2009: type->value = (void *) 4;
! 2010: }
! 2011:
! 2012: return NGX_CONF_OK;
! 2013: }
! 2014:
! 2015:
! 2016: char *
! 2017: ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t **keys, ngx_hash_t *types_hash,
! 2018: ngx_array_t **prev_keys, ngx_hash_t *prev_types_hash,
! 2019: ngx_str_t *default_types)
! 2020: {
! 2021: ngx_hash_init_t hash;
! 2022:
! 2023: if (*keys) {
! 2024:
! 2025: if (*keys == (void *) -1) {
! 2026: return NGX_CONF_OK;
! 2027: }
! 2028:
! 2029: hash.hash = types_hash;
! 2030: hash.key = NULL;
! 2031: hash.max_size = 2048;
! 2032: hash.bucket_size = 64;
! 2033: hash.name = "test_types_hash";
! 2034: hash.pool = cf->pool;
! 2035: hash.temp_pool = NULL;
! 2036:
! 2037: if (ngx_hash_init(&hash, (*keys)->elts, (*keys)->nelts) != NGX_OK) {
! 2038: return NGX_CONF_ERROR;
! 2039: }
! 2040:
! 2041: return NGX_CONF_OK;
! 2042: }
! 2043:
! 2044: if (prev_types_hash->buckets == NULL) {
! 2045:
! 2046: if (*prev_keys == NULL) {
! 2047:
! 2048: if (ngx_http_set_default_types(cf, prev_keys, default_types)
! 2049: != NGX_OK)
! 2050: {
! 2051: return NGX_CONF_ERROR;
! 2052: }
! 2053:
! 2054: } else if (*prev_keys == (void *) -1) {
! 2055: *keys = *prev_keys;
! 2056: return NGX_CONF_OK;
! 2057: }
! 2058:
! 2059: hash.hash = prev_types_hash;
! 2060: hash.key = NULL;
! 2061: hash.max_size = 2048;
! 2062: hash.bucket_size = 64;
! 2063: hash.name = "test_types_hash";
! 2064: hash.pool = cf->pool;
! 2065: hash.temp_pool = NULL;
! 2066:
! 2067: if (ngx_hash_init(&hash, (*prev_keys)->elts, (*prev_keys)->nelts)
! 2068: != NGX_OK)
! 2069: {
! 2070: return NGX_CONF_ERROR;
! 2071: }
! 2072: }
! 2073:
! 2074: *types_hash = *prev_types_hash;
! 2075:
! 2076: return NGX_CONF_OK;
! 2077:
! 2078: }
! 2079:
! 2080:
! 2081: ngx_int_t
! 2082: ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types,
! 2083: ngx_str_t *default_type)
! 2084: {
! 2085: ngx_hash_key_t *type;
! 2086:
! 2087: *types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t));
! 2088: if (*types == NULL) {
! 2089: return NGX_ERROR;
! 2090: }
! 2091:
! 2092: while (default_type->len) {
! 2093:
! 2094: type = ngx_array_push(*types);
! 2095: if (type == NULL) {
! 2096: return NGX_ERROR;
! 2097: }
! 2098:
! 2099: type->key = *default_type;
! 2100: type->key_hash = ngx_hash_key(default_type->data,
! 2101: default_type->len);
! 2102: type->value = (void *) 4;
! 2103:
! 2104: default_type++;
! 2105: }
! 2106:
! 2107: return NGX_OK;
! 2108: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>