Mercurial > hg > nginx-mail
diff src/http/ngx_http.c @ 378:820f6378fc00 NGINX_0_7_1
nginx 0.7.1
*) Change: now locations are searched in a tree.
*) Change: the "optimize_server_names" directive was canceled due to
the "server_name_in_redirect" directive introduction.
*) Change: some long deprecated directives are not supported anymore.
*) Change: the "none" parameter in the "ssl_session_cache" directive;
now this is default parameter.
Thanks to Rob Mueller.
*) Bugfix: worker processes might not catch reconfiguration and log
rotation signals.
*) Bugfix: nginx could not be built on latest Fedora 9 Linux.
Thanks to Roxis.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 26 May 2008 00:00:00 +0400 |
parents | 6639b93e81b2 |
children | bc21d9cd9c54 |
line wrap: on
line diff
--- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -11,22 +11,48 @@ static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_http_init_phases(ngx_conf_t *cf, + ngx_http_core_main_conf_t *cmcf); +static ngx_int_t ngx_http_init_headers_in_hash(ngx_conf_t *cf, + ngx_http_core_main_conf_t *cmcf); +static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf, + ngx_http_core_main_conf_t *cmcf); + +static ngx_int_t ngx_http_init_server_lists(ngx_conf_t *cf, + ngx_array_t *servers, ngx_array_t *in_ports); static ngx_int_t ngx_http_add_address(ngx_conf_t *cf, - ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *lscf, - ngx_http_core_srv_conf_t *cscf); + ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_port_t *in_port, + ngx_http_listen_t *listen); static ngx_int_t ngx_http_add_names(ngx_conf_t *cf, - ngx_http_conf_in_addr_t *in_addr, ngx_http_core_srv_conf_t *cscf); + ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_addr_t *in_addr); + static char *ngx_http_merge_locations(ngx_conf_t *cf, - ngx_array_t *locations, void **loc_conf, ngx_http_module_t *module, + ngx_queue_t *locations, void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index); +static ngx_int_t ngx_http_init_locations(ngx_conf_t *cf, + ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf); +static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf, + ngx_http_core_loc_conf_t *pclcf); +static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one, + const ngx_queue_t *two); +static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf, + ngx_queue_t *locations); +static void ngx_http_create_locations_list(ngx_queue_t *locations, + ngx_queue_t *q); +static ngx_http_location_tree_node_t * + ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations, + size_t prefix); + +static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf, + ngx_http_core_main_conf_t *cmcf, ngx_array_t *in_ports); static ngx_int_t ngx_http_cmp_conf_in_addrs(const void *one, const void *two); static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one, const void *two); -ngx_uint_t ngx_http_max_module; +static ngx_int_t ngx_http_init_listening(ngx_conf_t *cf, + ngx_http_conf_in_port_t *in_port); -ngx_uint_t ngx_http_total_requests; -uint64_t ngx_http_total_sent; +ngx_uint_t ngx_http_max_module; ngx_int_t (*ngx_http_top_header_filter) (ngx_http_request_t *r); @@ -73,34 +99,14 @@ static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - ngx_int_t rc, j; - ngx_uint_t mi, m, s, l, p, a, i, n; - ngx_uint_t find_config_index, use_rewrite, use_access; - ngx_uint_t last, bind_all, done; + ngx_uint_t mi, m, s; ngx_conf_t pcf; - ngx_array_t headers_in, in_ports; - ngx_hash_key_t *hk; - ngx_hash_init_t hash; - ngx_listening_t *ls; - ngx_http_listen_t *lscf; + ngx_array_t in_ports; ngx_http_module_t *module; - ngx_http_header_t *header; - ngx_http_in_port_t *hip; - ngx_http_handler_pt *h; ngx_http_conf_ctx_t *ctx; - ngx_http_conf_in_port_t *in_port; - ngx_http_conf_in_addr_t *in_addr; - ngx_hash_keys_arrays_t ha; - ngx_http_server_name_t *name; - ngx_http_phase_handler_t *ph; - ngx_http_virtual_names_t *vn; - ngx_http_core_srv_conf_t **cscfp, *cscf; ngx_http_core_loc_conf_t *clcf; - ngx_http_phase_handler_pt checker; + ngx_http_core_srv_conf_t **cscfp; ngx_http_core_main_conf_t *cmcf; -#if (NGX_PCRE) - ngx_uint_t regex; -#endif /* the main http context */ @@ -199,7 +205,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } module = ngx_modules[m]->ctx; - mi = ngx_modules[m]->ctx_index; if (module->preconfiguration) { if (module->preconfiguration(cf) != NGX_OK) { @@ -215,8 +220,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma rv = ngx_conf_parse(cf, NULL); if (rv != NGX_CONF_OK) { - *cf = pcf; - return rv; + goto failed; } /* @@ -240,8 +244,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (module->init_main_conf) { rv = module->init_main_conf(cf, ctx->main_conf[mi]); if (rv != NGX_CONF_OK) { - *cf = pcf; - return rv; + goto failed; } } @@ -250,12 +253,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* merge the server{}s' srv_conf's */ if (module->merge_srv_conf) { - rv = module->merge_srv_conf(cf, - ctx->srv_conf[mi], + rv = module->merge_srv_conf(cf, ctx->srv_conf[mi], cscfp[s]->ctx->srv_conf[mi]); if (rv != NGX_CONF_OK) { - *cf = pcf; - return rv; + goto failed; } } @@ -263,112 +264,48 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* merge the server{}'s loc_conf */ - rv = module->merge_loc_conf(cf, - ctx->loc_conf[mi], + rv = module->merge_loc_conf(cf, ctx->loc_conf[mi], cscfp[s]->ctx->loc_conf[mi]); if (rv != NGX_CONF_OK) { - *cf = pcf; - return rv; + goto failed; } /* merge the locations{}' loc_conf's */ - rv = ngx_http_merge_locations(cf, &cscfp[s]->locations, + clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; + + rv = ngx_http_merge_locations(cf, clcf->locations, cscfp[s]->ctx->loc_conf, module, mi); if (rv != NGX_CONF_OK) { - *cf = pcf; - return rv; + goto failed; } } } } - /* init lists of the handlers */ - - if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } + /* create location trees */ + for (s = 0; s < cmcf->servers.nelts; s++) { - if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - + clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; - if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - + if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) { + return NGX_CONF_ERROR; + } - if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - - if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers, - cf->pool, 2, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; + if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { + return NGX_CONF_ERROR; + } } - if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, - cf->pool, 4, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - - if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) - != NGX_OK) - { + if (ngx_http_init_phases(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } - - if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - for (header = ngx_http_headers_in; header->name.len; header++) { - hk = ngx_array_push(&headers_in); - if (hk == NULL) { - return NGX_CONF_ERROR; - } - - hk->key = header->name; - hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len); - hk->value = header; - } - - hash.hash = &cmcf->headers_in_hash; - hash.key = ngx_hash_key_lc; - hash.max_size = 512; - hash.bucket_size = ngx_align(64, ngx_cacheline_size); - hash.name = "headers_in_hash"; - hash.pool = cf->pool; - hash.temp_pool = NULL; - - if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) { + if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -379,7 +316,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } module = ngx_modules[m]->ctx; - mi = ngx_modules[m]->ctx_index; if (module->postconfiguration) { if (module->postconfiguration(cf) != NGX_OK) { @@ -400,6 +336,148 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma *cf = pcf; + if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) { + return NGX_CONF_ERROR; + } + + + /* + * create the lists of ports, addresses and server names + * to find quickly the server core module configuration at run-time + */ + + /* AF_INET only */ + + if (ngx_http_init_server_lists(cf, &cmcf->servers, &in_ports) != NGX_OK) { + return NGX_CONF_ERROR; + } + + + /* optimize the lists of ports, addresses and server names */ + + /* AF_INET only */ + + if (ngx_http_optimize_servers(cf, cmcf, &in_ports) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; + +failed: + + *cf = pcf; + + return rv; +} + + +static ngx_int_t +ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) +{ + if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers, + cf->pool, 2, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, + cf->pool, 4, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_init_headers_in_hash(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) +{ + ngx_array_t headers_in; + ngx_hash_key_t *hk; + ngx_hash_init_t hash; + ngx_http_header_t *header; + + if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + for (header = ngx_http_headers_in; header->name.len; header++) { + hk = ngx_array_push(&headers_in); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = header->name; + hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len); + hk->value = header; + } + + hash.hash = &cmcf->headers_in_hash; + hash.key = ngx_hash_key_lc; + hash.max_size = 512; + hash.bucket_size = ngx_align(64, ngx_cacheline_size); + hash.name = "headers_in_hash"; + hash.pool = cf->pool; + hash.temp_pool = NULL; + + if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) +{ + ngx_int_t j; + ngx_uint_t i, n; + ngx_uint_t find_config_index, use_rewrite, use_access; + ngx_http_handler_pt *h; + ngx_http_phase_handler_t *ph; + ngx_http_phase_handler_pt checker; + cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1; cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1; find_config_index = 0; @@ -415,7 +493,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ph = ngx_pcalloc(cf->pool, n * sizeof(ngx_http_phase_handler_t) + sizeof(void *)); if (ph == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } cmcf->phase_engine.handlers = ph; @@ -493,35 +571,548 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } } + return NGX_OK; +} - /* - * create the lists of ports, addresses and server names - * to quickly find the server core module configuration at run-time - */ + +static char * +ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations, + void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index) +{ + char *rv; + ngx_queue_t *q; + ngx_http_core_loc_conf_t *clcf; + ngx_http_location_queue_t *lq; + + if (locations == NULL) { + return NGX_CONF_OK; + } + + for (q = ngx_queue_head(locations); + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) + { + lq = (ngx_http_location_queue_t *) q; + + clcf = lq->exact ? lq->exact : lq->inclusive; + + rv = module->merge_loc_conf(cf, loc_conf[ctx_index], + clcf->loc_conf[ctx_index]); + if (rv != NGX_CONF_OK) { + return rv; + } + + rv = ngx_http_merge_locations(cf, clcf->locations, clcf->loc_conf, + module, ctx_index); + if (rv != NGX_CONF_OK) { + return rv; + } + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + ngx_http_core_loc_conf_t *pclcf) +{ + ngx_uint_t n; + ngx_queue_t *q, *locations, *named, tail; + ngx_http_core_loc_conf_t *clcf; + ngx_http_location_queue_t *lq; + ngx_http_core_loc_conf_t **clcfp; +#if (NGX_PCRE) + ngx_uint_t r; + ngx_queue_t *regex; +#endif + + locations = pclcf->locations; + + if (locations == NULL) { + return NGX_OK; + } + + ngx_queue_sort(locations, ngx_http_cmp_locations); + + named = NULL; + n = 0; +#if (NGX_PCRE) + regex = NULL; + r = 0; +#endif + + for (q = ngx_queue_head(locations); + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) + { + lq = (ngx_http_location_queue_t *) q; + + clcf = lq->exact ? lq->exact : lq->inclusive; + + if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) { + return NGX_ERROR; + } + +#if (NGX_PCRE) + + if (clcf->regex) { + r++; + + if (regex == NULL) { + regex = q; + } + + continue; + } + +#endif + + if (clcf->named) { + n++; + + if (named == NULL) { + named = q; + } + + continue; + } + + if (clcf->noname) { + break; + } + } + + if (q != ngx_queue_sentinel(locations)) { + ngx_queue_split(locations, q, &tail); + } + + if (named) { + clcfp = ngx_palloc(cf->pool, + (n + 1) * sizeof(ngx_http_core_loc_conf_t **)); + if (clcfp == NULL) { + return NGX_ERROR; + } + + cscf->named_locations = clcfp; + + for (q = named; + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) + { + lq = (ngx_http_location_queue_t *) q; + + *(clcfp++) = lq->exact; + } + + *clcfp = NULL; + + ngx_queue_split(locations, named, &tail); + } + +#if (NGX_PCRE) + + if (regex) { + + clcfp = ngx_palloc(cf->pool, + (r + 1) * sizeof(ngx_http_core_loc_conf_t **)); + if (clcfp == NULL) { + return NGX_ERROR; + } + + pclcf->regex_locations = clcfp; + + for (q = regex; + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) + { + lq = (ngx_http_location_queue_t *) q; + + *(clcfp++) = lq->exact; + } + + *clcfp = NULL; + + ngx_queue_split(locations, regex, &tail); + } + +#endif + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_init_static_location_trees(ngx_conf_t *cf, + ngx_http_core_loc_conf_t *pclcf) +{ + ngx_queue_t *q, *locations; + ngx_http_core_loc_conf_t *clcf; + ngx_http_location_queue_t *lq; + + locations = pclcf->locations; + + if (locations == NULL) { + return NGX_OK; + } + + if (ngx_queue_empty(locations)) { + return NGX_OK; + } + + for (q = ngx_queue_head(locations); + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) + { + lq = (ngx_http_location_queue_t *) q; + + clcf = lq->exact ? lq->exact : lq->inclusive; + + if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { + return NGX_ERROR; + } + } + + if (ngx_http_join_exact_locations(cf, locations) != NGX_OK) { + return NGX_ERROR; + } + + ngx_http_create_locations_list(locations, ngx_queue_head(locations)); + + pclcf->static_locations = ngx_http_create_locations_tree(cf, locations, 0); + if (pclcf->static_locations == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations, + ngx_http_core_loc_conf_t *clcf) +{ + ngx_http_location_queue_t *lq; + + if (*locations == NULL) { + *locations = ngx_palloc(cf->temp_pool, + sizeof(ngx_http_location_queue_t)); + if (*locations == NULL) { + return NGX_ERROR; + } + + ngx_queue_init(*locations); + } + + lq = ngx_palloc(cf->temp_pool, sizeof(ngx_http_location_queue_t)); + if (lq == NULL) { + return NGX_ERROR; + } + + if (clcf->exact_match +#if (NGX_PCRE) + || clcf->regex +#endif + || clcf->named || clcf->noname) + { + lq->exact = clcf; + lq->inclusive = NULL; + + } else { + lq->exact = NULL; + lq->inclusive = clcf; + } + + lq->name = &clcf->name; + lq->file_name = cf->conf_file->file.name.data; + lq->line = cf->conf_file->line; + + ngx_queue_init(&lq->list); + + ngx_queue_insert_tail(*locations, &lq->queue); - if (ngx_array_init(&in_ports, cf->temp_pool, 2, + return NGX_OK; +} + + +static ngx_int_t +ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two) +{ + ngx_int_t rc; + ngx_http_core_loc_conf_t *first, *second; + ngx_http_location_queue_t *lq1, *lq2; + + lq1 = (ngx_http_location_queue_t *) one; + lq2 = (ngx_http_location_queue_t *) two; + + first = lq1->exact ? lq1->exact : lq1->inclusive; + second = lq2->exact ? lq2->exact : lq2->inclusive; + + if (first->noname && !second->noname) { + /* shift no named locations to the end */ + return 1; + } + + if (!first->noname && second->noname) { + /* shift no named locations to the end */ + return -1; + } + + if (first->noname || second->noname) { + /* do not sort no named locations */ + return 0; + } + + if (first->named && !second->named) { + /* shift named locations to the end */ + return 1; + } + + if (!first->named && second->named) { + /* shift named locations to the end */ + return -1; + } + + if (first->named && second->named) { + return ngx_strcmp(first->name.data, second->name.data); + } + +#if (NGX_PCRE) + + if (first->regex && !second->regex) { + /* shift the regex matches to the end */ + return 1; + } + + if (!first->regex && second->regex) { + /* shift the regex matches to the end */ + return -1; + } + + if (first->regex || second->regex) { + /* do not sort the regex matches */ + return 0; + } + +#endif + + rc = ngx_strcmp(first->name.data, second->name.data); + + if (rc == 0 && !first->exact_match && second->exact_match) { + /* an exact match must be before the same inclusive one */ + return 1; + } + + return rc; +} + + +static ngx_int_t +ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations) +{ + ngx_queue_t *q, *x; + ngx_http_location_queue_t *lq, *lx; + + q = ngx_queue_head(locations); + + while (q != ngx_queue_last(locations)) { + + x = ngx_queue_next(q); + + lq = (ngx_http_location_queue_t *) q; + lx = (ngx_http_location_queue_t *) x; + + if (ngx_strcmp(lq->name->data, lx->name->data) == 0) { + + if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "duplicate location \"%V\" in %s:%ui", + lx->name, lx->file_name, lx->line); + + return NGX_ERROR; + } + + lq->inclusive = lx->inclusive; + + ngx_queue_remove(x); + + continue; + } + + q = ngx_queue_next(q); + } + + return NGX_OK; +} + + +static void +ngx_http_create_locations_list(ngx_queue_t *locations, ngx_queue_t *q) +{ + u_char *name; + size_t len; + ngx_queue_t *x, tail; + ngx_http_location_queue_t *lq, *lx; + + if (q == ngx_queue_last(locations)) { + return; + } + + lq = (ngx_http_location_queue_t *) q; + + if (lq->inclusive == NULL) { + ngx_http_create_locations_list(locations, ngx_queue_next(q)); + return; + } + + len = lq->name->len; + name = lq->name->data; + + for (x = ngx_queue_next(q); + x != ngx_queue_sentinel(locations); + x = ngx_queue_next(x)) + { + lx = (ngx_http_location_queue_t *) x; + + if (len > lx->name->len + || (ngx_strncmp(name, lx->name->data, len) != 0)) + { + break; + } + } + + q = ngx_queue_next(q); + + if (q == x) { + ngx_http_create_locations_list(locations, x); + return; + } + + ngx_queue_split(locations, q, &tail); + ngx_queue_add(&lq->list, &tail); + + if (x == ngx_queue_sentinel(locations)) { + ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list)); + return; + } + + ngx_queue_split(&lq->list, x, &tail); + ngx_queue_add(locations, &tail); + + ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list)); + + ngx_http_create_locations_list(locations, x); +} + + +/* + * to keep cache locality for left leaf nodes, allocate nodes in following + * order: node, left subtree, right subtree, inclusive subtree + */ + +static ngx_http_location_tree_node_t * +ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations, + size_t prefix) +{ + size_t len; + ngx_queue_t *q, tail; + ngx_http_location_queue_t *lq; + ngx_http_location_tree_node_t *node; + + q = ngx_queue_middle(locations); + + lq = (ngx_http_location_queue_t *) q; + len = lq->name->len - prefix; + + node = ngx_pcalloc(cf->pool, + offsetof(ngx_http_location_tree_node_t, name) + len); + if (node == NULL) { + return NULL; + } + + node->exact = lq->exact; + node->inclusive = lq->inclusive; + + node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect) + || (lq->inclusive && lq->inclusive->auto_redirect)); + + node->len = (u_char) len; + ngx_memcpy(node->name, &lq->name->data[prefix], len); + + ngx_queue_split(locations, q, &tail); + + if (ngx_queue_empty(locations)) { + /* + * ngx_queue_split() insures that if left part is empty, + * then right one is empty too + */ + goto inclusive; + } + + node->left = ngx_http_create_locations_tree(cf, locations, prefix); + if (node->left == NULL) { + return NULL; + } + + ngx_queue_remove(q); + + if (ngx_queue_empty(&tail)) { + goto inclusive; + } + + node->right = ngx_http_create_locations_tree(cf, &tail, prefix); + if (node->right == NULL) { + return NULL; + } + +inclusive: + + if (ngx_queue_empty(&lq->list)) { + return node; + } + + node->tree = ngx_http_create_locations_tree(cf, &lq->list, prefix + len); + if (node->tree == NULL) { + return NULL; + } + + return node; +} + + +static ngx_int_t +ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers, + ngx_array_t *in_ports) +{ + ngx_uint_t s, l, p, a; + ngx_http_listen_t *listen; + ngx_http_conf_in_port_t *in_port; + ngx_http_conf_in_addr_t *in_addr; + ngx_http_core_srv_conf_t **cscfp; + + if (ngx_array_init(in_ports, cf->temp_pool, 2, sizeof(ngx_http_conf_in_port_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } /* "server" directives */ - cscfp = cmcf->servers.elts; - for (s = 0; s < cmcf->servers.nelts; s++) { + cscfp = servers->elts; + for (s = 0; s < servers->nelts; s++) { /* "listen" directives */ - lscf = cscfp[s]->listen.elts; + listen = cscfp[s]->listen.elts; for (l = 0; l < cscfp[s]->listen.nelts; l++) { /* AF_INET only */ - in_port = in_ports.elts; - for (p = 0; p < in_ports.nelts; p++) { + in_port = in_ports->elts; + for (p = 0; p < in_ports->nelts; p++) { - if (lscf[l].port != in_port[p].port) { + if (listen[l].port != in_port[p].port) { continue; } @@ -530,15 +1121,15 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma in_addr = in_port[p].addrs.elts; for (a = 0; a < in_port[p].addrs.nelts; a++) { - if (lscf[l].addr != in_addr[a].addr) { + if (listen[l].addr != in_addr[a].addr) { continue; } /* the address is already in the address list */ - if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) != NGX_OK) + if (ngx_http_add_names(cf, cscfp[s], &in_addr[a]) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } /* @@ -546,14 +1137,14 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * for this address:port */ - if (lscf[l].conf.default_server) { + if (listen[l].conf.default_server) { if (in_addr[a].default_server) { ngx_log_error(NGX_LOG_ERR, cf->log, 0, "the duplicate default server in %s:%ui", - lscf[l].file_name, lscf[l].line); + listen[l].file_name, listen[l].line); - return NGX_CONF_ERROR; + return NGX_ERROR; } in_addr[a].core_srv_conf = cscfp[s]; @@ -568,10 +1159,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * bound to this port */ - if (ngx_http_add_address(cf, &in_port[p], &lscf[l], cscfp[s]) + if (ngx_http_add_address(cf, cscfp[s], &in_port[p], &listen[l]) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } goto found; @@ -579,17 +1170,18 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* add the port to the in_port list */ - in_port = ngx_array_push(&in_ports); + in_port = ngx_array_push(in_ports); if (in_port == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } - in_port->port = lscf[l].port; + in_port->port = listen[l].port; in_port->addrs.elts = NULL; - if (ngx_http_add_address(cf, in_port, &lscf[l], cscfp[s]) != NGX_OK) + if (ngx_http_add_address(cf, cscfp[s], in_port, &listen[l]) + != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } found: @@ -598,364 +1190,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } } - - /* optimize the lists of ports, addresses and server names */ - - /* AF_INET only */ - - in_port = in_ports.elts; - for (p = 0; p < in_ports.nelts; p++) { - - ngx_sort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts, - sizeof(ngx_http_conf_in_addr_t), ngx_http_cmp_conf_in_addrs); - - /* - * check whether all name-based servers have the same configuraiton - * as the default server, - * or some servers disable optimizing the server names - */ - - in_addr = in_port[p].addrs.elts; - for (a = 0; a < in_port[p].addrs.nelts; a++) { - - name = in_addr[a].names.elts; - for (s = 0; s < in_addr[a].names.nelts; s++) { - - if (in_addr[a].core_srv_conf != name[s].core_srv_conf - || name[s].core_srv_conf->optimize_server_names == 0) - { - goto virtual_names; - } - } - - /* - * if all name-based servers have the same configuration - * as the default server, - * and no servers disable optimizing the server names - * then we do not need to check them at run-time at all - */ - - in_addr[a].names.nelts = 0; - - continue; - - virtual_names: - - ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t)); - - ha.temp_pool = ngx_create_pool(16384, cf->log); - if (ha.temp_pool == NULL) { - return NGX_CONF_ERROR; - } - - ha.pool = cf->pool; - - if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) { - ngx_destroy_pool(ha.temp_pool); - return NGX_CONF_ERROR; - } - -#if (NGX_PCRE) - regex = 0; -#endif - - name = in_addr[a].names.elts; - - for (s = 0; s < in_addr[a].names.nelts; s++) { - -#if (NGX_PCRE) - if (name[s].regex) { - regex++; - continue; - } -#endif - - rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf, - NGX_HASH_WILDCARD_KEY); - - if (rc == NGX_ERROR) { - return NGX_CONF_ERROR; - } - - if (rc == NGX_DECLINED) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "invalid server name or wildcard \"%V\" on %s", - &name[s].name, in_addr[a].listen_conf->addr); - return NGX_CONF_ERROR; - } - - if (rc == NGX_BUSY) { - ngx_log_error(NGX_LOG_WARN, cf->log, 0, - "conflicting server name \"%V\" on %s, ignored", - &name[s].name, in_addr[a].listen_conf->addr); - } - } - - hash.key = ngx_hash_key_lc; - hash.max_size = cmcf->server_names_hash_max_size; - hash.bucket_size = cmcf->server_names_hash_bucket_size; - hash.name = "server_names_hash"; - hash.pool = cf->pool; - - if (ha.keys.nelts) { - hash.hash = &in_addr[a].hash; - hash.temp_pool = NULL; - - if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) - { - ngx_destroy_pool(ha.temp_pool); - return NGX_CONF_ERROR; - } - } - - if (ha.dns_wc_head.nelts) { - - ngx_qsort(ha.dns_wc_head.elts, - (size_t) ha.dns_wc_head.nelts, - sizeof(ngx_hash_key_t), - ngx_http_cmp_dns_wildcards); - - hash.hash = NULL; - hash.temp_pool = ha.temp_pool; - - if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts, - ha.dns_wc_head.nelts) - != NGX_OK) - { - ngx_destroy_pool(ha.temp_pool); - return NGX_CONF_ERROR; - } - - in_addr[a].wc_head = (ngx_hash_wildcard_t *) hash.hash; - } - - if (ha.dns_wc_tail.nelts) { - - ngx_qsort(ha.dns_wc_tail.elts, - (size_t) ha.dns_wc_tail.nelts, - sizeof(ngx_hash_key_t), - ngx_http_cmp_dns_wildcards); - - hash.hash = NULL; - hash.temp_pool = ha.temp_pool; - - if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts, - ha.dns_wc_tail.nelts) - != NGX_OK) - { - ngx_destroy_pool(ha.temp_pool); - return NGX_CONF_ERROR; - } - - in_addr[a].wc_tail = (ngx_hash_wildcard_t *) hash.hash; - } - - ngx_destroy_pool(ha.temp_pool); - -#if (NGX_PCRE) - - if (regex == 0) { - continue; - } - - in_addr[a].nregex = regex; - in_addr[a].regex = ngx_palloc(cf->pool, - regex * sizeof(ngx_http_server_name_t)); - - if (in_addr[a].regex == NULL) { - return NGX_CONF_ERROR; - } - - for (i = 0, s = 0; s < in_addr[a].names.nelts; s++) { - if (name[s].regex) { - in_addr[a].regex[i++] = name[s]; - } - } -#endif - } - - in_addr = in_port[p].addrs.elts; - last = in_port[p].addrs.nelts; - - /* - * if there is the binding to the "*:port" then we need to bind() - * to the "*:port" only and ignore the other bindings - */ - - if (in_addr[last - 1].addr == INADDR_ANY) { - in_addr[last - 1].bind = 1; - bind_all = 0; - - } else { - bind_all = 1; - } - - for (a = 0; a < last; /* void */ ) { - - if (!bind_all && !in_addr[a].bind) { - a++; - continue; - } - - ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr, - in_port[p].port); - if (ls == NULL) { - return NGX_CONF_ERROR; - } - - ls->addr_ntop = 1; - - ls->handler = ngx_http_init_connection; - - cscf = in_addr[a].core_srv_conf; - ls->pool_size = cscf->connection_pool_size; - ls->post_accept_timeout = cscf->client_header_timeout; - - clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; - - ls->log = *clcf->err_log; - ls->log.data = &ls->addr_text; - ls->log.handler = ngx_accept_log_error; - -#if (NGX_WIN32) - { - ngx_iocp_conf_t *iocpcf; - - iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); - if (iocpcf->acceptex_read) { - ls->post_accept_buffer_size = cscf->client_header_buffer_size; - } - } -#endif - - ls->backlog = in_addr[a].listen_conf->backlog; - ls->rcvbuf = in_addr[a].listen_conf->rcvbuf; - ls->sndbuf = in_addr[a].listen_conf->sndbuf; - -#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) - ls->accept_filter = in_addr[a].listen_conf->accept_filter; -#endif - -#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) - ls->deferred_accept = in_addr[a].listen_conf->deferred_accept; -#endif - - hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t)); - if (hip == NULL) { - return NGX_CONF_ERROR; - } - - hip->port = in_port[p].port; - - hip->port_text.data = ngx_palloc(cf->pool, 7); - if (hip->port_text.data == NULL) { - return NGX_CONF_ERROR; - } - - ls->servers = hip; - - hip->port_text.len = ngx_sprintf(hip->port_text.data, ":%d", - hip->port) - - hip->port_text.data; - - in_addr = in_port[p].addrs.elts; - - if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) { - hip->naddrs = 1; - done = 0; - - } else if (in_port[p].addrs.nelts > 1 - && in_addr[last - 1].addr == INADDR_ANY) - { - hip->naddrs = last; - done = 1; - - } else { - hip->naddrs = 1; - done = 0; - } - -#if 0 - ngx_log_error(NGX_LOG_ALERT, cf->log, 0, - "%ui: %V %d %ui %ui", - a, &ls->addr_text, in_addr[a].bind, - hip->naddrs, last); -#endif - - hip->addrs = ngx_pcalloc(cf->pool, - hip->naddrs * sizeof(ngx_http_in_addr_t)); - if (hip->addrs == NULL) { - return NGX_CONF_ERROR; - } - - for (i = 0; i < hip->naddrs; i++) { - hip->addrs[i].addr = in_addr[i].addr; - hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf; - - if (in_addr[i].hash.buckets == NULL - && (in_addr[i].wc_head == NULL - || in_addr[i].wc_head->hash.buckets == NULL) - && (in_addr[i].wc_head == NULL - || in_addr[i].wc_head->hash.buckets == NULL)) - { - continue; - } - - vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t)); - if (vn == NULL) { - return NGX_CONF_ERROR; - } - hip->addrs[i].virtual_names = vn; - - vn->names.hash = in_addr[i].hash; - vn->names.wc_head = in_addr[i].wc_head; - vn->names.wc_tail = in_addr[i].wc_tail; -#if (NGX_PCRE) - vn->nregex = in_addr[i].nregex; - vn->regex = in_addr[i].regex; -#endif - } - - if (done) { - break; - } - - in_addr++; - in_port[p].addrs.elts = in_addr; - last--; - - a = 0; - } - } - -#if 0 - { - u_char address[20]; - ngx_uint_t p, a; - - in_port = in_ports.elts; - for (p = 0; p < in_ports.nelts; p++) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "port: %d %p", in_port[p].port, &in_port[p]); - in_addr = in_port[p].addrs.elts; - for (a = 0; a < in_port[p].addrs.nelts; a++) { - ngx_inet_ntop(AF_INET, &in_addr[a].addr, address, 20); - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "%s:%d %p", - address, in_port[p].port, in_addr[a].core_srv_conf); - name = in_addr[a].names.elts; - for (n = 0; n < in_addr[a].names.nelts; n++) { - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "%s:%d %V %p", - address, in_port[p].port, &name[n].name, - name[n].core_srv_conf); - } - } - } - } -#endif - - return NGX_CONF_OK; + return NGX_OK; } @@ -965,8 +1200,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma */ static ngx_int_t -ngx_http_add_address(ngx_conf_t *cf, ngx_http_conf_in_port_t *in_port, - ngx_http_listen_t *lscf, ngx_http_core_srv_conf_t *cscf) +ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *listen) { ngx_http_conf_in_addr_t *in_addr; @@ -984,7 +1219,7 @@ ngx_http_add_address(ngx_conf_t *cf, ngx return NGX_ERROR; } - in_addr->addr = lscf->addr; + in_addr->addr = listen->addr; in_addr->hash.buckets = NULL; in_addr->hash.size = 0; in_addr->wc_head = NULL; @@ -995,9 +1230,9 @@ ngx_http_add_address(ngx_conf_t *cf, ngx in_addr->regex = NULL; #endif in_addr->core_srv_conf = cscf; - in_addr->default_server = lscf->conf.default_server; - in_addr->bind = lscf->conf.bind; - in_addr->listen_conf = &lscf->conf; + in_addr->default_server = listen->conf.default_server; + in_addr->bind = listen->conf.bind; + in_addr->listen_conf = &listen->conf; #if (NGX_DEBUG) { @@ -1008,7 +1243,7 @@ ngx_http_add_address(ngx_conf_t *cf, ngx } #endif - return ngx_http_add_names(cf, in_addr, cscf); + return ngx_http_add_names(cf, cscf, in_addr); } @@ -1018,8 +1253,8 @@ ngx_http_add_address(ngx_conf_t *cf, ngx */ static ngx_int_t -ngx_http_add_names(ngx_conf_t *cf, ngx_http_conf_in_addr_t *in_addr, - ngx_http_core_srv_conf_t *cscf) +ngx_http_add_names(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + ngx_http_conf_in_addr_t *in_addr) { ngx_uint_t i, n; ngx_http_server_name_t *server_names, *name; @@ -1057,35 +1292,196 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h } -static char * -ngx_http_merge_locations(ngx_conf_t *cf, ngx_array_t *locations, - void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index) +static ngx_int_t +ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, + ngx_array_t *in_ports) { - char *rv; - ngx_uint_t i; - ngx_http_core_loc_conf_t **clcfp; + ngx_int_t rc; + ngx_uint_t s, p, a, i; + ngx_hash_init_t hash; + ngx_http_server_name_t *name; + ngx_hash_keys_arrays_t ha; + ngx_http_conf_in_port_t *in_port; + ngx_http_conf_in_addr_t *in_addr; +#if (NGX_PCRE) + ngx_uint_t regex; +#endif + + in_port = in_ports->elts; + for (p = 0; p < in_ports->nelts; p++) { + + ngx_sort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts, + sizeof(ngx_http_conf_in_addr_t), ngx_http_cmp_conf_in_addrs); + + /* + * check whether all name-based servers have + * the same configuraiton as the default server + */ + + in_addr = in_port[p].addrs.elts; + for (a = 0; a < in_port[p].addrs.nelts; a++) { + + name = in_addr[a].names.elts; + for (s = 0; s < in_addr[a].names.nelts; s++) { + + if (in_addr[a].core_srv_conf != name[s].core_srv_conf) { + goto virtual_names; + } + } + + /* + * if all name-based servers have the same configuration + * as the default server, then we do not need to check + * them at run-time at all + */ + + in_addr[a].names.nelts = 0; + + continue; + + virtual_names: + + ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t)); + + ha.temp_pool = ngx_create_pool(16384, cf->log); + if (ha.temp_pool == NULL) { + return NGX_ERROR; + } + + ha.pool = cf->pool; + + if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) { + goto failed; + } + +#if (NGX_PCRE) + regex = 0; +#endif + + name = in_addr[a].names.elts; + + for (s = 0; s < in_addr[a].names.nelts; s++) { + +#if (NGX_PCRE) + if (name[s].regex) { + regex++; + continue; + } +#endif + + rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf, + NGX_HASH_WILDCARD_KEY); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } - clcfp = locations->elts; + if (rc == NGX_DECLINED) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "invalid server name or wildcard \"%V\" on %s", + &name[s].name, in_addr[a].listen_conf->addr); + return NGX_ERROR; + } + + if (rc == NGX_BUSY) { + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "conflicting server name \"%V\" on %s, ignored", + &name[s].name, in_addr[a].listen_conf->addr); + } + } + + hash.key = ngx_hash_key_lc; + hash.max_size = cmcf->server_names_hash_max_size; + hash.bucket_size = cmcf->server_names_hash_bucket_size; + hash.name = "server_names_hash"; + hash.pool = cf->pool; + + if (ha.keys.nelts) { + hash.hash = &in_addr[a].hash; + hash.temp_pool = NULL; + + if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) + { + goto failed; + } + } + + if (ha.dns_wc_head.nelts) { + + ngx_qsort(ha.dns_wc_head.elts, + (size_t) ha.dns_wc_head.nelts, + sizeof(ngx_hash_key_t), + ngx_http_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = ha.temp_pool; - for (i = 0; i < locations->nelts; i++) { - rv = module->merge_loc_conf(cf, loc_conf[ctx_index], - clcfp[i]->loc_conf[ctx_index]); - if (rv != NGX_CONF_OK) { - return rv; + if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts, + ha.dns_wc_head.nelts) + != NGX_OK) + { + goto failed; + } + + in_addr[a].wc_head = (ngx_hash_wildcard_t *) hash.hash; + } + + if (ha.dns_wc_tail.nelts) { + + ngx_qsort(ha.dns_wc_tail.elts, + (size_t) ha.dns_wc_tail.nelts, + sizeof(ngx_hash_key_t), + ngx_http_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = ha.temp_pool; + + if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts, + ha.dns_wc_tail.nelts) + != NGX_OK) + { + goto failed; + } + + in_addr[a].wc_tail = (ngx_hash_wildcard_t *) hash.hash; + } + + ngx_destroy_pool(ha.temp_pool); + +#if (NGX_PCRE) + + if (regex == 0) { + continue; + } + + in_addr[a].nregex = regex; + in_addr[a].regex = ngx_palloc(cf->pool, + regex * sizeof(ngx_http_server_name_t)); + + if (in_addr[a].regex == NULL) { + return NGX_ERROR; + } + + for (i = 0, s = 0; s < in_addr[a].names.nelts; s++) { + if (name[s].regex) { + in_addr[a].regex[i++] = name[s]; + } + } +#endif } - if (clcfp[i]->locations == NULL) { - continue; - } - - rv = ngx_http_merge_locations(cf, clcfp[i]->locations, - clcfp[i]->loc_conf, module, ctx_index); - if (rv != NGX_CONF_OK) { - return rv; + if (ngx_http_init_listening(cf, &in_port[p]) != NGX_OK) { + return NGX_ERROR; } } - return NGX_CONF_OK; + return NGX_OK; + +failed: + + ngx_destroy_pool(ha.temp_pool); + + return NGX_ERROR; } @@ -1128,3 +1524,165 @@ ngx_http_cmp_dns_wildcards(const void *o return ngx_strcmp(first->key.data, second->key.data); } + + +static ngx_int_t +ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_in_port_t *in_port) +{ + ngx_uint_t i, a, last, bind_all, done; + ngx_listening_t *ls; + ngx_http_in_port_t *hip; + ngx_http_conf_in_addr_t *in_addr; + ngx_http_virtual_names_t *vn; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + + in_addr = in_port->addrs.elts; + last = in_port->addrs.nelts; + + /* + * if there is a binding to a "*:port" then we need to bind() + * to the "*:port" only and ignore other bindings + */ + + if (in_addr[last - 1].addr == INADDR_ANY) { + in_addr[last - 1].bind = 1; + bind_all = 0; + + } else { + bind_all = 1; + } + + a = 0; + + while (a < last) { + + if (!bind_all && !in_addr[a].bind) { + a++; + continue; + } + + ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr, + in_port->port); + if (ls == NULL) { + return NGX_ERROR; + } + + ls->addr_ntop = 1; + + ls->handler = ngx_http_init_connection; + + cscf = in_addr[a].core_srv_conf; + ls->pool_size = cscf->connection_pool_size; + ls->post_accept_timeout = cscf->client_header_timeout; + + clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; + + ls->log = *clcf->err_log; + ls->log.data = &ls->addr_text; + ls->log.handler = ngx_accept_log_error; + +#if (NGX_WIN32) + { + ngx_iocp_conf_t *iocpcf; + + iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); + if (iocpcf->acceptex_read) { + ls->post_accept_buffer_size = cscf->client_header_buffer_size; + } + } +#endif + + ls->backlog = in_addr[a].listen_conf->backlog; + ls->rcvbuf = in_addr[a].listen_conf->rcvbuf; + ls->sndbuf = in_addr[a].listen_conf->sndbuf; + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + ls->accept_filter = in_addr[a].listen_conf->accept_filter; +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + ls->deferred_accept = in_addr[a].listen_conf->deferred_accept; +#endif + + hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t)); + if (hip == NULL) { + return NGX_ERROR; + } + + hip->port = in_port->port; + + hip->port_text.data = ngx_palloc(cf->pool, 7); + if (hip->port_text.data == NULL) { + return NGX_ERROR; + } + + ls->servers = hip; + + hip->port_text.len = ngx_sprintf(hip->port_text.data, ":%d", hip->port) + - hip->port_text.data; + + in_addr = in_port->addrs.elts; + + if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) { + hip->naddrs = 1; + done = 0; + + } else if (in_port->addrs.nelts > 1 + && in_addr[last - 1].addr == INADDR_ANY) + { + hip->naddrs = last; + done = 1; + + } else { + hip->naddrs = 1; + done = 0; + } + + hip->addrs = ngx_pcalloc(cf->pool, + hip->naddrs * sizeof(ngx_http_in_addr_t)); + if (hip->addrs == NULL) { + return NGX_ERROR; + } + + for (i = 0; i < hip->naddrs; i++) { + hip->addrs[i].addr = in_addr[i].addr; + hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf; + + if (in_addr[i].hash.buckets == NULL + && (in_addr[i].wc_head == NULL + || in_addr[i].wc_head->hash.buckets == NULL) + && (in_addr[i].wc_head == NULL + || in_addr[i].wc_head->hash.buckets == NULL)) + { + continue; + } + + vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t)); + if (vn == NULL) { + return NGX_ERROR; + } + hip->addrs[i].virtual_names = vn; + + vn->names.hash = in_addr[i].hash; + vn->names.wc_head = in_addr[i].wc_head; + vn->names.wc_tail = in_addr[i].wc_tail; +#if (NGX_PCRE) + vn->nregex = in_addr[i].nregex; + vn->regex = in_addr[i].regex; +#endif + } + + if (done) { + return NGX_OK; + } + + in_addr++; + in_port->addrs.elts = in_addr; + last--; + + a = 0; + } + + return NGX_OK; +}