# HG changeset patch # User Igor Sysoev # Date 1135544400 -10800 # Node ID 84910468f6de287fe815acce3e4ee6d8b7c8e5dc # Parent 249e67502bf369c672cd832aab05f4232a7126f8 nginx 0.3.18 *) Feature: the "server_names" directive supports the ".domain.tld" names. *) Feature: the "server_names" directive uses the hash for the "*.domain.tld" names and more effective hash for usual names. *) Change: the "server_names_hash_max_size" and "server_names_hash_bucket_size" directives. *) Change: the "server_names_hash" and "server_names_hash_threshold" directives were canceled. *) Feature: the "valid_referers" directive uses the hash site names. *) Change: now the "valid_referers" directive checks the site names only without the URI part. *) Bugfix: some ".domain.tld" names incorrectly processed by the ngx_http_map_module. *) Bugfix: segmentation fault was occurred if configuration file did not exist; bug appeared in 0.3.12. *) Bugfix: on 64-bit platforms segmentation fault may occurred on start; bug appeared in 0.3.16. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,32 @@ + +Changes with nginx 0.3.18 26 Dec 2005 + + *) Feature: the "server_names" directive supports the ".domain.tld" + names. + + *) Feature: the "server_names" directive uses the hash for the + "*.domain.tld" names and more effective hash for usual names. + + *) Change: the "server_names_hash_max_size" and + "server_names_hash_bucket_size" directives. + + *) Change: the "server_names_hash" and "server_names_hash_threshold" + directives were canceled. + + *) Feature: the "valid_referers" directive uses the hash site names. + + *) Change: now the "valid_referers" directive checks the site names + only without the URI part. + + *) Bugfix: some ".domain.tld" names incorrectly processed by the + ngx_http_map_module. + + *) Bugfix: segmentation fault was occurred if configuration file did + not exist; bug appeared in 0.3.12. + + *) Bugfix: on 64-bit platforms segmentation fault may occurred on + start; bug appeared in 0.3.16. + Changes with nginx 0.3.17 18 Dec 2005 @@ -7,7 +36,8 @@ Changes with nginx 0.3.17 *) Feature: the "map" directive supports domain names in the ".domain.tld" form. - *) Bugfix: the timeouts were not used in SSL handshake. + *) Bugfix: the timeouts were not used in SSL handshake; bug appeared in + 0.2.4. *) Bugfix: in the HTTP protocol in the "proxy_pass" directive. @@ -597,7 +627,7 @@ Changes with nginx 0.1.36 "Connection", "Content-Length", or "Authorization" lines, then nginx now returns the 400 error. - *) Change: The "post_accept_timeout" directive was canceled. + *) Change: the "post_accept_timeout" directive was canceled. *) Feature: the "default", "af=", "bl=", "deferred", and "bind" parameters of the "listen" directive. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,32 @@ + +Изменения в nginx 0.3.18 26.12.2005 + + *) Добавление: директива server_names поддерживает имена вида + ".domain.tld". + + *) Добавление: директива server_names использует хэш для имён вида + "*.domain.tld" и более эффективный хэш для обычных имён. + + *) Изменение: директивы server_names_hash_max_size и + server_names_hash_bucket_size. + + *) Изменение: директивы server_names_hash и server_names_hash_threshold + упразднены. + + *) Добавление: директива valid_referers использует хэш для имён сайтов. + + *) Изменение: теперь директива valid_referers проверяет только имена + сайтов без учёта URI. + + *) Исправление: некоторые имена вида ".domain.tld" неверно + обрабатывались модулем ngx_http_map_module. + + *) Исправление: если конфигурационного файла не было, то происходил + segmentation fault; ошибка появилась в 0.3.12. + + *) Исправление: на 64-битных платформах при старте мог произойти + segmentation fault; ошибка появилась в 0.3.16. + Изменения в nginx 0.3.17 18.12.2005 @@ -7,7 +36,8 @@ *) Добавление: директива map поддерживает доменные имена в формате ".domain.tld". - *) Исправление: во время SSL handshake не иcпользовались таймауты. + *) Исправление: во время SSL handshake не иcпользовались таймауты; + ошибка появилась в 0.2.4. *) Исправление: в использовании протокола HTTPS в директиве proxy_pass. diff --git a/auto/lib/pcre/makefile.bcc b/auto/lib/pcre/makefile.bcc --- a/auto/lib/pcre/makefile.bcc +++ b/auto/lib/pcre/makefile.bcc @@ -2,7 +2,7 @@ # Copyright (C) Igor Sysoev -CFLAGS = -q -O2 -tWM $(CPU_OPT) +CFLAGS = -q -O2 -tWM -w-8004 $(CPU_OPT) PCREFLAGS = -DPCRE_STATIC -DPOSIX_MALLOC_THRESHOLD=10 diff --git a/auto/lib/zlib/makefile.bcc b/auto/lib/zlib/makefile.bcc --- a/auto/lib/zlib/makefile.bcc +++ b/auto/lib/zlib/makefile.bcc @@ -2,7 +2,7 @@ # Copyright (C) Igor Sysoev -CFLAGS = -q -O2 -tWM $(CPU_OPT) +CFLAGS = -q -O2 -tWM -w-8004 -w-8012 $(CPU_OPT) zlib.lib: bcc32 -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c \ diff --git a/auto/make b/auto/make --- a/auto/make +++ b/auto/make @@ -320,6 +320,19 @@ END fi +# the addons config.make + +if test -n "$NGX_ADDONS"; then + + for ngx_addon_dir in $NGX_ADDONS + do + if test -f $ngx_addon_dir/config.make; then + . $ngx_addon_dir/config.make + fi + done +fi + + # Win32 resource file if test -n "$NGX_RES"; then diff --git a/auto/os/conf b/auto/os/conf --- a/auto/os/conf +++ b/auto/os/conf @@ -64,7 +64,7 @@ case "$NGX_MACHINE" in NGX_MACH_CACHE_LINE=32 ;; - amd64) + amd64 | x86_64) have=NGX_HAVE_NONALIGNED . auto/have NGX_MACH_CACHE_LINE=64 ;; diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -266,7 +266,6 @@ HTTP_DEPS="src/http/ngx_http.h \ HTTP_SRCS="src/http/ngx_http.c \ src/http/ngx_http_core_module.c \ - src/http/ngx_http_config.c \ src/http/ngx_http_special_response.c \ src/http/ngx_http_request.c \ src/http/ngx_http_parse.c \ diff --git a/conf/nginx.conf b/conf/nginx.conf --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -18,7 +18,7 @@ http { include conf/mime.types; default_type application/octet-stream; - #log_format main '$remote_addr - $remote_user [$time_gmt] $status ' + #log_format main '$remote_addr - $remote_user [$time_local] $status ' # '"$request" $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "http_x_forwarded_for"'; diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.3.17" +#define NGINX_VER "nginx/0.3.18" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -78,7 +78,8 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN); if (fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, - ngx_open_file_n " \"%s\" failed", filename->data); + ngx_open_file_n " \"%s\" failed", + filename->data); return NGX_CONF_ERROR; } @@ -811,6 +812,11 @@ ngx_conf_log_error(ngx_uint_t level, ngx *buf = '\0'; } + if (cf->conf_file == NULL) { + ngx_log_error(level, cf->log, 0, "%s", errstr); + return; + } + ngx_log_error(level, cf->log, 0, "%s in %s:%ui", errstr, cf->conf_file->file.name.data, cf->conf_file->line); } diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -167,6 +167,7 @@ struct ngx_conf_s { ngx_cycle_t *cycle; ngx_pool_t *pool; + ngx_pool_t *temp_pool; ngx_conf_file_t *conf_file; ngx_log_t *log; diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -295,6 +295,9 @@ ngx_open_listening_sockets(ngx_cycle_t * } } + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "bind() %V #%d ", &ls[i].addr_text, s); + if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { err = ngx_socket_errno; diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -162,6 +162,12 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) return NULL; } + conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); + if (conf.temp_pool == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + conf.ctx = cycle->conf_ctx; conf.cycle = cycle; conf.pool = pool; @@ -174,6 +180,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) #endif if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { + ngx_destroy_pool(conf.temp_pool); ngx_destroy_pool(pool); return NULL; } @@ -194,8 +201,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) if (module->init_conf) { if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index]) - == NGX_CONF_ERROR) + == NGX_CONF_ERROR) { + ngx_destroy_pool(conf.temp_pool); ngx_destroy_pool(pool); return NULL; } @@ -421,6 +429,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } if (ngx_test_config) { + ngx_destroy_pool(conf.temp_pool); ngx_destroy_pool(pool); return NULL; } @@ -438,6 +447,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } } + ngx_destroy_pool(conf.temp_pool); ngx_destroy_pool(pool); return NULL; } @@ -521,6 +531,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } } + ngx_destroy_pool(conf.temp_pool); + if (old_cycle->connections == NULL) { /* an old cycle is an init cycle */ ngx_destroy_pool(old_cycle->pool); diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -158,7 +158,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng } } - test = ngx_alloc(hinit->max_size * sizeof(ngx_uint_t), hinit->pool->log); + test = ngx_alloc(hinit->max_size * sizeof(size_t), hinit->pool->log); if (test == NULL) { return NGX_ERROR; } @@ -170,7 +170,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng for (size = start; size < hinit->max_size; size++) { - ngx_memzero(test, size * sizeof(ngx_uint_t)); + ngx_memzero(test, size * sizeof(size_t)); for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { @@ -347,7 +347,7 @@ ngx_int_t ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) { - size_t len; + size_t len, dot_len; ngx_uint_t i, n, dot; ngx_array_t curr_names, next_names; ngx_hash_key_t *name, *next_name; @@ -396,9 +396,11 @@ ngx_hash_wildcard_init(ngx_hash_init_t * #if 0 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, - "wc1: \"%V\"", &name->key); + "wc1: \"%V\" %ui", &name->key, dot); #endif + dot_len = len + 1; + if (dot) { len++; } @@ -427,13 +429,20 @@ ngx_hash_wildcard_init(ngx_hash_init_t * break; } + if (!dot + && names[i].key.len > len + && names[i].key.data[len] != '.') + { + break; + } + next_name = ngx_array_push(&next_names); if (next_name == NULL) { return NGX_ERROR; } - next_name->key.len = names[i].key.len - len; - next_name->key.data = names[i].key.data + len; + next_name->key.len = names[i].key.len - dot_len; + next_name->key.data = names[i].key.data + dot_len; next_name->key_hash= 0; next_name->value = names[i].value; @@ -444,6 +453,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t * } if (next_names.nelts) { + h = *hinit; h.hash = NULL; @@ -459,8 +469,8 @@ ngx_hash_wildcard_init(ngx_hash_init_t * if (names[n].key.len == len) { wdc->value = names[n].value; #if 0 - ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, - "wdc: \"%V\"", wdc->value); + ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, + "wdc: \"%V\"", wdc->value); #endif } @@ -681,3 +691,249 @@ ngx_hash0_init(ngx_hash0_t *hash, ngx_po return NGX_OK; } + + +ngx_int_t +ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type) +{ + ngx_uint_t asize; + + if (type == NGX_HASH_SMALL) { + asize = 4; + ha->hsize = 107; + + } else { + asize = NGX_HASH_LARGE_ASIZE; + ha->hsize = NGX_HASH_LARGE_HSIZE; + } + + if (ngx_array_init(&ha->keys, ha->temp_pool, asize, sizeof(ngx_hash_key_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&ha->dns_wildcards, ha->temp_pool, asize, + sizeof(ngx_hash_key_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + ha->keys_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize); + if (ha->keys_hash == NULL) { + return NGX_ERROR; + } + + ha->dns_wildcards_hash = ngx_pcalloc(ha->temp_pool, + sizeof(ngx_array_t) * ha->hsize); + if (ha->dns_wildcards_hash == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, void *value, + ngx_uint_t flags) +{ + size_t len; + ngx_str_t *name; + ngx_uint_t i, k, n, skip; + ngx_hash_key_t *hk; + u_char buf[2048]; + + if (!(flags & NGX_HASH_WILDCARD_KEY)) { + + /* exact hash */ + + k = 0; + + for (i = 0; i < key->len; i++) { + key->data[i] = ngx_tolower(key->data[i]); + k = ngx_hash(k, key->data[i]); + } + + k %= ha->hsize; + + /* check conflicts in exact hash */ + + name = ha->keys_hash[k].elts; + + if (name) { + for (i = 0; i < ha->keys_hash[k].nelts; i++) { + if (key->len != name[i].len) { + continue; + } + + if (ngx_strncmp(key->data, name[i].data, key->len) == 0) { + return NGX_BUSY; + } + } + + } else { + if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4, + sizeof(ngx_str_t)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + name = ngx_array_push(&ha->keys_hash[k]); + if (name == NULL) { + return NGX_ERROR; + } + + *name = *key; + + hk = ngx_array_push(&ha->keys); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = *key; + hk->key_hash = ngx_hash_key(key->data, key->len); + hk->value = value; + + } else { + + /* wildcard hash */ + + skip = (key->data[0] == '*') ? 2 : 1; + k = 0; + + for (i = skip; i < key->len; i++) { + key->data[i] = ngx_tolower(key->data[i]); + k = ngx_hash(k, key->data[i]); + } + + k %= ha->hsize; + + if (skip == 1) { + + /* check conflicts in exact hash for ".example.com" */ + + name = ha->keys_hash[k].elts; + + if (name) { + len = key->len - skip; + + for (i = 0; i < ha->keys_hash[k].nelts; i++) { + if (len != name[i].len) { + continue; + } + + if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) { + return NGX_BUSY; + } + } + + } else { + if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4, + sizeof(ngx_str_t)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + name = ngx_array_push(&ha->keys_hash[k]); + if (name == NULL) { + return NGX_ERROR; + } + + name->len = key->len - 1; + name->data = ngx_palloc(ha->temp_pool, name->len); + if (name->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(name->data, &key->data[1], name->len); + } + + + /* + * convert "*.example.com" to "com.example.\0" + * and ".example.com" to "com.example\0" + */ + + len = 0; + n = 0; + + for (i = key->len - 1; i; i--) { + if (key->data[i] == '.') { + ngx_memcpy(&buf[n], &key->data[i + 1], len); + n += len; + buf[n++] = '.'; + len = 0; + continue; + } + + len++; + } + + if (len) { + ngx_memcpy(&buf[n], &key->data[1], len); + n += len; + } + + buf[n] = '\0'; + + + /* check conflicts in wildcard hash */ + + name = ha->dns_wildcards_hash[k].elts; + + if (name) { + len = key->len - skip; + + for (i = 0; i < ha->dns_wildcards_hash[k].nelts; i++) { + if (len != name[i].len) { + continue; + } + + if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) { + return NGX_BUSY; + } + } + + } else { + if (ngx_array_init(&ha->dns_wildcards_hash[k], ha->temp_pool, 4, + sizeof(ngx_str_t)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + name = ngx_array_push(&ha->dns_wildcards_hash[k]); + if (name == NULL) { + return NGX_ERROR; + } + + name->len = key->len - skip; + name->data = ngx_palloc(ha->temp_pool, name->len); + if (name->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(name->data, key->data + skip, name->len); + + + ngx_memcpy(key->data, buf, key->len); + key->len--; + + hk = ngx_array_push(&ha->dns_wildcards); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = *key; + hk->key_hash = 0; + hk->value = value; + } + + return NGX_OK; +} diff --git a/src/core/ngx_hash.h b/src/core/ngx_hash.h --- a/src/core/ngx_hash.h +++ b/src/core/ngx_hash.h @@ -54,6 +54,29 @@ typedef struct { } ngx_hash_init_t; +#define NGX_HASH_SMALL 1 +#define NGX_HASH_LARGE 2 + +#define NGX_HASH_LARGE_ASIZE 16384 +#define NGX_HASH_LARGE_HSIZE 10007 + +#define NGX_HASH_WILDCARD_KEY 1 + + +typedef struct { + ngx_uint_t hsize; + + ngx_pool_t *pool; + ngx_pool_t *temp_pool; + + ngx_array_t keys; + ngx_array_t *keys_hash; + + ngx_array_t dns_wildcards; + ngx_array_t *dns_wildcards_hash; +} ngx_hash_keys_arrays_t; + + typedef struct { void **buckets; ngx_uint_t hash_size; @@ -86,6 +109,10 @@ ngx_int_t ngx_hash_wildcard_init(ngx_has ngx_uint_t ngx_hash_key(u_char *data, size_t len); ngx_uint_t ngx_hash_key_lc(u_char *data, size_t len); +ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type); +ngx_int_t ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, + void *value, ngx_uint_t flags); + ngx_int_t ngx_hash0_init(ngx_hash0_t *hash, ngx_pool_t *pool, void *names, ngx_uint_t nelts); diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -16,7 +16,7 @@ typedef struct { typedef struct { - ngx_http_hash_conf_t hash; + ngx_hash_keys_arrays_t keys; ngx_array_t *values_hash; @@ -245,44 +245,20 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } - if (ngx_array_init(&ctx.hash.keys, pool, 16384, sizeof(ngx_hash_key_t)) - != NGX_OK) - { - ngx_destroy_pool(pool); - return NGX_CONF_ERROR; - } + ctx.keys.pool = cf->pool; + ctx.keys.temp_pool = pool; - if (ngx_array_init(&ctx.hash.dns_wildcards, pool, 16384, - sizeof(ngx_hash_key_t)) - != NGX_OK) - { + if (ngx_hash_keys_array_init(&ctx.keys, NGX_HASH_LARGE) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } - ctx.hash.keys_hash = ngx_pcalloc(pool, - sizeof(ngx_array_t) * NGX_HTTP_CONFIG_HASH); - if (ctx.hash.keys_hash == NULL) { - ngx_destroy_pool(pool); - return NGX_CONF_ERROR; - } - - ctx.hash.dns_hash = ngx_pcalloc(pool, - sizeof(ngx_array_t) * NGX_HTTP_CONFIG_HASH); - if (ctx.hash.dns_hash == NULL) { - ngx_destroy_pool(pool); - return NGX_CONF_ERROR; - } - - ctx.values_hash = ngx_pcalloc(pool, - sizeof(ngx_array_t) * NGX_HTTP_CONFIG_HASH); + ctx.values_hash = ngx_pcalloc(pool, sizeof(ngx_array_t) * ctx.keys.hsize); if (ctx.values_hash == NULL) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } - ctx.hash.pool = cf->pool; - ctx.hash.temp_pool = pool; ctx.default_value = NULL; ctx.hostnames = 0; @@ -298,7 +274,6 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c if (rv != NGX_CONF_OK) { ngx_destroy_pool(pool); - return rv; } @@ -308,13 +283,14 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c hash.name = "map_hash"; hash.pool = cf->pool; - if (ctx.hash.keys.nelts) { + if (ctx.keys.keys.nelts) { hash.hash = &map->hash; hash.temp_pool = NULL; - if (ngx_hash_init(&hash, ctx.hash.keys.elts, ctx.hash.keys.nelts) + if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts) != NGX_OK) { + ngx_destroy_pool(pool); return NGX_CONF_ERROR; } } @@ -322,19 +298,20 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c map->default_value = ctx.default_value ? ctx.default_value: &ngx_http_variable_null_value; - if (ctx.hash.dns_wildcards.nelts) { + if (ctx.keys.dns_wildcards.nelts) { - ngx_qsort(ctx.hash.dns_wildcards.elts, - (size_t) ctx.hash.dns_wildcards.nelts, + ngx_qsort(ctx.keys.dns_wildcards.elts, + (size_t) ctx.keys.dns_wildcards.nelts, sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards); hash.hash = NULL; hash.temp_pool = pool; - if (ngx_hash_wildcard_init(&hash, ctx.hash.dns_wildcards.elts, - ctx.hash.dns_wildcards.nelts) + if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wildcards.elts, + ctx.keys.dns_wildcards.nelts) != NGX_OK) { + ngx_destroy_pool(pool); return NGX_CONF_ERROR; } @@ -408,7 +385,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command key = ngx_hash(key, value[1].data[i]); } - key %= NGX_HTTP_CONFIG_HASH; + key %= ctx->keys.hsize; vp = ctx->values_hash[key].elts; @@ -433,13 +410,13 @@ ngx_http_map(ngx_conf_t *cf, ngx_command } } - var = ngx_palloc(ctx->hash.pool, sizeof(ngx_http_variable_value_t)); + var = ngx_palloc(ctx->keys.pool, sizeof(ngx_http_variable_value_t)); if (var == NULL) { return NGX_CONF_ERROR; } var->len = value[1].len; - var->data = ngx_pstrdup(ctx->hash.pool, &value[1]); + var->data = ngx_pstrdup(ctx->keys.pool, &value[1]); if (var->data == NULL) { return NGX_CONF_ERROR; } @@ -492,10 +469,10 @@ found: return NGX_CONF_ERROR; } - flags = NGX_HTTP_WILDCARD_HASH; + flags = NGX_HASH_WILDCARD_KEY; } - rc = ngx_http_config_add_hash(&ctx->hash, &value[0], var, flags); + rc = ngx_hash_add_key(&ctx->keys, &value[0], var, flags); if (rc == NGX_OK) { return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -1925,8 +1925,8 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ ngx_http_proxy_loc_conf_t *plcf = conf; size_t add; + u_short port; ngx_str_t *value, *url; - ngx_uint_t port; ngx_inet_upstream_t inet_upstream; ngx_http_core_loc_conf_t *clcf; #if (NGX_HTTP_SSL) diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -10,15 +10,13 @@ typedef struct { - ngx_str_t name; - ngx_uint_t wildcard; -} ngx_http_referer_t; + ngx_hash_t hash; + ngx_hash_wildcard_t *dns_wildcards; -typedef struct { - ngx_array_t *referers; /* ngx_http_referer_t */ + ngx_flag_t no_referer; + ngx_flag_t blocked_referer; - ngx_flag_t no_referer; - ngx_flag_t blocked_referer; + ngx_hash_keys_arrays_t *keys; } ngx_http_referer_conf_t; @@ -27,6 +25,10 @@ static char * ngx_http_referer_merge_con void *child); static char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, + ngx_str_t *value); +static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one, + const void *two); static ngx_command_t ngx_http_referer_commands[] = { @@ -77,21 +79,22 @@ static ngx_int_t ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - u_char *ref; - size_t len; - ngx_uint_t i, n; - ngx_http_referer_t *refs; - ngx_http_referer_conf_t *cf; + u_char *p, *ref; + size_t len; + ngx_http_referer_conf_t *rlcf; - cf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); + rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); - if (cf->referers == NULL) { + if (rlcf->hash.buckets == NULL + && rlcf->dns_wildcards == NULL + && rlcf->dns_wildcards->hash.buckets == NULL) + { *v = ngx_http_variable_null_value; return NGX_OK; } if (r->headers_in.referer == NULL) { - if (cf->no_referer) { + if (rlcf->no_referer) { *v = ngx_http_variable_null_value; return NGX_OK; @@ -107,7 +110,7 @@ ngx_http_referer_variable(ngx_http_reque if (len < sizeof("http://i.ru") - 1 || (ngx_strncasecmp(ref, "http://", 7) != 0)) { - if (cf->blocked_referer) { + if (rlcf->blocked_referer) { *v = ngx_http_variable_null_value; return NGX_OK; @@ -120,37 +123,25 @@ ngx_http_referer_variable(ngx_http_reque len -= 7; ref += 7; - refs = cf->referers->elts; - for (i = 0; i < cf->referers->nelts; i++ ){ - - if (refs[i].name.len > len) { - continue; + for (p = ref; p < ref + len; p++) { + if (*p == '/' || *p == ':') { + break; } + } - if (refs[i].wildcard) { - for (n = 0; n < len; n++) { - if (ref[n] == '/' || ref[n] == ':') { - break; - } + len = p - ref; - if (ref[n] != '.') { - continue; - } + if (rlcf->hash.buckets) { + if (ngx_hash_find(&rlcf->hash, ngx_hash_key_lc(ref, len), ref, len)) { + *v = ngx_http_variable_null_value; + return NGX_OK; + } + } - if (ngx_strncmp(&ref[n], refs[i].name.data, - refs[i].name.len) == 0) - { - *v = ngx_http_variable_null_value; - return NGX_OK; - } - } - - } else { - if (ngx_strncasecmp(refs[i].name.data, ref, refs[i].name.len) == 0) - { - *v = ngx_http_variable_null_value; - return NGX_OK; - } + if (rlcf->dns_wildcards && rlcf->dns_wildcards->hash.buckets) { + if (ngx_hash_find_wildcard(rlcf->dns_wildcards, ref, len)) { + *v = ngx_http_variable_null_value; + return NGX_OK; } } @@ -165,12 +156,11 @@ ngx_http_referer_create_conf(ngx_conf_t { ngx_http_referer_conf_t *conf; - conf = ngx_palloc(cf->pool, sizeof(ngx_http_referer_conf_t)); + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_referer_conf_t)); if (conf == NULL) { return NGX_CONF_ERROR; } - conf->referers = NULL; conf->no_referer = NGX_CONF_UNSET; conf->blocked_referer = NGX_CONF_UNSET; @@ -184,10 +174,53 @@ ngx_http_referer_merge_conf(ngx_conf_t * ngx_http_referer_conf_t *prev = parent; ngx_http_referer_conf_t *conf = child; - if (conf->referers == NULL) { - conf->referers = prev->referers; + ngx_hash_init_t hash; + + if (conf->keys == NULL) { + conf->hash = prev->hash; + conf->dns_wildcards = prev->dns_wildcards; + ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); + + return NGX_CONF_OK; + } + + hash.key = ngx_hash_key_lc; + hash.max_size = 2048; /* TODO: referer_hash_max_size; */ + hash.bucket_size = 64; /* TODO: referer_hash_bucket_size; */ + hash.name = "referers_hash"; + hash.pool = cf->pool; + + if (conf->keys->keys.nelts) { + hash.hash = &conf->hash; + hash.temp_pool = NULL; + + if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + + if (conf->keys->dns_wildcards.nelts) { + + ngx_qsort(conf->keys->dns_wildcards.elts, + (size_t) conf->keys->dns_wildcards.nelts, + sizeof(ngx_hash_key_t), + ngx_http_cmp_referer_wildcards); + + hash.hash = NULL; + hash.temp_pool = cf->temp_pool; + + if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wildcards.elts, + conf->keys->dns_wildcards.nelts) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + conf->dns_wildcards = (ngx_hash_wildcard_t *) hash.hash; } if (conf->no_referer == NGX_CONF_UNSET) { @@ -205,11 +238,11 @@ ngx_http_referer_merge_conf(ngx_conf_t * static char * ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_referer_conf_t *lcf = conf; + ngx_http_referer_conf_t *rlcf = conf; - ngx_uint_t i, server_names; + u_char *p; ngx_str_t *value, name; - ngx_http_referer_t *ref; + ngx_uint_t i, n; ngx_http_variable_t *var; ngx_http_server_name_t *sn; ngx_http_core_srv_conf_t *cscf; @@ -225,19 +258,21 @@ ngx_http_valid_referers(ngx_conf_t *cf, var->handler = ngx_http_referer_variable; - cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); + if (rlcf->keys == NULL) { + rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t)); + if (rlcf->keys == NULL) { + return NGX_CONF_ERROR; + } - if (lcf->referers == NULL) { - lcf->referers = ngx_array_create(cf->pool, - cf->args->nelts + cscf->server_names.nelts, - sizeof(ngx_http_referer_t)); - if (lcf->referers == NULL) { + rlcf->keys->pool = cf->pool; + rlcf->keys->temp_pool = cf->pool; + + if (ngx_hash_keys_array_init(rlcf->keys, NGX_HASH_SMALL) != NGX_OK) { return NGX_CONF_ERROR; } } value = cf->args->elts; - server_names = 0; for (i = 1; i < cf->args->nelts; i++) { if (value[i].len == 0) { @@ -247,64 +282,90 @@ ngx_http_valid_referers(ngx_conf_t *cf, } if (ngx_strcmp(value[i].data, "none") == 0) { - lcf->no_referer = 1; + rlcf->no_referer = 1; continue; } if (ngx_strcmp(value[i].data, "blocked") == 0) { - lcf->blocked_referer = 1; + rlcf->blocked_referer = 1; continue; } if (ngx_strcmp(value[i].data, "server_names") == 0) { - server_names = 1; - continue; - } + + cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); - ref = ngx_array_push(lcf->referers); - if (ref == NULL) { - return NGX_CONF_ERROR; - } + sn = cscf->server_names.elts; + for (n = 0; n < cscf->server_names.nelts; n++) { + if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name) != NGX_OK) { + return NGX_CONF_ERROR; + } + } - if (value[i].data[0] != '*') { - ref->name = value[i]; - ref->wildcard = 0; continue; } + p = (u_char *) ngx_strstr(value[i].data, "/"); - if (value[i].data[1] != '.') { + if (p) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid wildcard referer \"%V\"", &value[i]); - return NGX_CONF_ERROR; + "URI part \"%s\" is deprecated, ignored", p); + + value[i].len = p - value[i].data; } - ref->name.len = value[i].len - 1; - ref->name.data = value[i].data + 1; - ref->wildcard = 1; - } - - if (!server_names) { - return NGX_CONF_OK; - } - - sn = cscf->server_names.elts; - for (i = 0; i < cscf->server_names.nelts; i++) { - ref = ngx_array_push(lcf->referers); - if (ref == NULL) { + if (ngx_http_add_referer(cf, rlcf->keys, &value[i]) != NGX_OK) { return NGX_CONF_ERROR; } - - ref->name.len = sn[i].name.len + 1; - ref->name.data = ngx_palloc(cf->pool, ref->name.len); - if (ref->name.data == NULL) { - return NGX_CONF_ERROR; - } - - ngx_memcpy(ref->name.data, sn[i].name.data, sn[i].name.len); - ref->name.data[sn[i].name.len] = '/'; - ref->wildcard = sn[i].wildcard; } return NGX_CONF_OK; } + + +static char * +ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, + ngx_str_t *value) +{ + u_char ch; + ngx_int_t rc; + ngx_uint_t flags; + + ch = value->data[0]; + + if ((ch == '*' && (value->len < 3 || value->data[1] != '.')) + || (ch == '.' && value->len < 2)) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid DNS wildcard \"%V\"", value); + + return NGX_CONF_ERROR; + } + + flags = (ch == '*' || ch == '.') ? NGX_HASH_WILDCARD_KEY : 0; + + rc = ngx_hash_add_key(keys, value, (void *) 4, flags); + + if (rc == NGX_OK) { + return NGX_CONF_OK; + } + + if (rc == NGX_BUSY) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "conflicting parameter \"%V\"", value); + } + + return NGX_CONF_ERROR; +} + + +static int ngx_libc_cdecl +ngx_http_cmp_referer_wildcards(const void *one, const void *two) +{ + ngx_hash_key_t *first, *second; + + first = (ngx_hash_key_t *) one; + second = (ngx_hash_key_t *) two; + + return ngx_strcmp(first->key.data, second->key.data); +} diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -14,18 +14,22 @@ static char *ngx_http_block(ngx_conf_t * static int ngx_libc_cdecl ngx_cmp_server_names(const void *one, const void *two); static ngx_int_t ngx_http_add_address(ngx_conf_t *cf, - ngx_http_in_port_t *in_port, ngx_http_listen_t *lscf, + ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *lscf, ngx_http_core_srv_conf_t *cscf); static ngx_int_t ngx_http_add_names(ngx_conf_t *cf, - ngx_http_in_addr_t *in_addr, ngx_http_core_srv_conf_t *cscf); + ngx_http_conf_in_addr_t *in_addr, ngx_http_core_srv_conf_t *cscf); 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); - -ngx_uint_t ngx_http_max_module; +static int ngx_libc_cdecl 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_total_requests; -uint64_t ngx_http_total_sent; +ngx_uint_t ngx_http_max_module; + +ngx_uint_t ngx_http_total_requests; +uint64_t ngx_http_total_sent; ngx_int_t (*ngx_http_top_header_filter) (ngx_http_request_t *r); @@ -72,19 +76,24 @@ static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - ngx_uint_t mi, m, s, l, p, a, n, key; - ngx_uint_t port_found, addr_found; - ngx_uint_t virtual_names, separate_binding; + u_char ch; + ngx_int_t rc; + ngx_uint_t mi, m, s, l, p, a, n, i; + ngx_uint_t last, bind_all, done; ngx_conf_t pcf; ngx_array_t in_ports; + ngx_hash_init_t hash; ngx_listening_t *ls; ngx_http_listen_t *lscf; ngx_http_module_t *module; + ngx_http_in_port_t *hip; ngx_http_handler_pt *h; ngx_http_conf_ctx_t *ctx; - ngx_http_in_port_t *in_port, *inport; - ngx_http_in_addr_t *in_addr, *inaddr; - ngx_http_server_name_t *s_name, *name; + 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_virtual_names_t *vn; ngx_http_core_srv_conf_t **cscfp, *cscf; ngx_http_core_loc_conf_t *clcf; ngx_http_core_main_conf_t *cmcf; @@ -414,7 +423,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * to quickly find the server core module configuration at run-time */ - if (ngx_array_init(&in_ports, cf->pool, 2, sizeof(ngx_http_in_port_t)) + if (ngx_array_init(&in_ports, cf->temp_pool, 2, + sizeof(ngx_http_conf_in_port_t)) != NGX_OK) { return NGX_CONF_ERROR; @@ -430,137 +440,85 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma lscf = cscfp[s]->listen.elts; for (l = 0; l < cscfp[s]->listen.nelts; l++) { - port_found = 0; - /* AF_INET only */ in_port = in_ports.elts; for (p = 0; p < in_ports.nelts; p++) { - if (lscf[l].port == in_port[p].port) { + if (lscf[l].port != in_port[p].port) { + continue; + } - /* the port is already in the port list */ - - port_found = 1; - addr_found = 0; + /* the port is already in the port list */ - in_addr = in_port[p].addrs.elts; - for (a = 0; a < in_port[p].addrs.nelts; a++) { + 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 (lscf[l].addr != in_addr[a].addr) { + continue; + } - /* the address is already in the address list */ + /* the address is already in the address list */ - if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) - != NGX_OK) - { - return NGX_CONF_ERROR; - } + if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) != NGX_OK) + { + return NGX_CONF_ERROR; + } - /* - * check the duplicate "default" server - * for this address:port - */ + /* + * check the duplicate "default" server + * for this address:port + */ - if (lscf[l].conf.default_server) { + if (lscf[l].conf.default_server) { - if (in_addr[a].conf.default_server) { - ngx_log_error(NGX_LOG_ERR, cf->log, 0, + if (in_addr[a].default_server) { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, "the duplicate default server in %V:%d", &lscf[l].file_name, lscf[l].line); - return NGX_CONF_ERROR; - } - - in_addr[a].core_srv_conf = cscfp[s]; - in_addr[a].conf.default_server = 1; - } - - addr_found = 1; - - break; - - } else if (in_addr[a].addr == INADDR_ANY) { - - /* the INADDR_ANY is always the last address */ - - inaddr = ngx_array_push(&in_port[p].addrs); - if (inaddr == NULL) { - return NGX_CONF_ERROR; - } - in_addr = in_port[p].addrs.elts; + return NGX_CONF_ERROR; + } - /* - * the INADDR_ANY must be the last resort - * so we move it to the end of the address list - * and put the new address in its place - */ - - ngx_memcpy(inaddr, &in_addr[a], - sizeof(ngx_http_in_addr_t)); - - in_addr[a].addr = lscf[l].addr; - in_addr[a].names.elts = NULL; - in_addr[a].hash = NULL; - in_addr[a].wildcards.elts = NULL; - in_addr[a].core_srv_conf = cscfp[s]; - in_addr[a].conf = lscf[l].conf; - - if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - addr_found = 1; - - break; - } + in_addr[a].core_srv_conf = cscfp[s]; + in_addr[a].default_server = 1; } - if (!addr_found) { - - /* - * add the address to the addresses list that - * bound to this port - */ - - if (ngx_http_add_address(cf, &in_port[p], &lscf[l], - cscfp[s]) != NGX_OK) - { - return NGX_CONF_ERROR; - } - } - } - } - - if (!port_found) { - - /* add the port to the in_port list */ - - in_port = ngx_array_push(&in_ports); - if (in_port == NULL) { - return NGX_CONF_ERROR; + goto found; } - in_port->port = lscf[l].port; - in_port->addrs.elts = NULL; + /* + * add the address to the addresses list that + * bound to this port + */ - in_port->port_text.data = ngx_palloc(cf->pool, 7); - if (in_port->port_text.data == NULL) { - return NGX_CONF_ERROR; - } - - in_port->port_text.len = ngx_sprintf(in_port->port_text.data, - ":%d", in_port->port) - - in_port->port_text.data; - - if (ngx_http_add_address(cf, in_port, &lscf[l], cscfp[s]) + if (ngx_http_add_address(cf, &in_port[p], &lscf[l], cscfp[s]) != NGX_OK) { return NGX_CONF_ERROR; } + + goto found; } + + /* add the port to the in_port list */ + + in_port = ngx_array_push(&in_ports); + if (in_port == NULL) { + return NGX_CONF_ERROR; + } + + in_port->port = lscf[l].port; + in_port->addrs.elts = NULL; + + if (ngx_http_add_address(cf, in_port, &lscf[l], cscfp[s]) != NGX_OK) + { + return NGX_CONF_ERROR; + } + + found: + + continue; } } @@ -572,7 +530,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma in_port = in_ports.elts; for (p = 0; p < in_ports.nelts; p++) { - separate_binding = 0; + ngx_qsort(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 @@ -582,33 +541,13 @@ 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 (in_addr[a].conf.bind) { - separate_binding = 1; - } - - virtual_names = 0; - name = in_addr[a].names.elts; for (n = 0; n < in_addr[a].names.nelts; n++) { if (in_addr[a].core_srv_conf != name[n].core_srv_conf || name[n].core_srv_conf->restrict_host_names != NGX_HTTP_RESTRICT_HOST_OFF) { - virtual_names = 1; - break; - } - } - - if (!virtual_names) { - name = in_addr[a].wildcards.elts; - for (n = 0; n < in_addr[a].wildcards.nelts; n++) { - if (in_addr[a].core_srv_conf != name[n].core_srv_conf - || name[n].core_srv_conf->restrict_host_names - != NGX_HTTP_RESTRICT_HOST_OFF) - { - virtual_names = 1; - break; - } + goto virtual_names; } } @@ -618,65 +557,132 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * then we do not need to check them at run-time at all */ - if (!virtual_names) { - in_addr[a].names.nelts = 0; - continue; + in_addr[a].names.nelts = 0; + + continue; + + virtual_names: + + ha.temp_pool = ngx_create_pool(16384, cf->log); + if (ha.temp_pool == NULL) { + return NGX_CONF_ERROR; } + ha.pool = cf->pool; - ngx_qsort(in_addr[a].names.elts, in_addr[a].names.nelts, - sizeof(ngx_http_server_name_t), ngx_cmp_server_names); + if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) { + ngx_destroy_pool(ha.temp_pool); + return NGX_CONF_ERROR; + } + name = in_addr[a].names.elts; + for (s = 0; s < in_addr[a].names.nelts; s++) { - /* create a hash for many names */ + ch = name[s].name.data[0]; - if (in_addr[a].names.nelts > cmcf->server_names_hash_threshold) { - in_addr[a].hash = ngx_palloc(cf->pool, - cmcf->server_names_hash - * sizeof(ngx_array_t)); - if (in_addr[a].hash == NULL) { + if (ch == '*' || ch == '.') { + continue; + } + + rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf, + 0); + + if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } - for (n = 0; n < cmcf->server_names_hash; n++) { - if (ngx_array_init(&in_addr[a].hash[n], cf->pool, 4, - sizeof(ngx_http_server_name_t)) != NGX_OK) - { - return NGX_CONF_ERROR; - } + if (rc == NGX_BUSY) { + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "conflicting server name \"%V\", ignored", + &name[s].name); + } + } + + for (s = 0; s < in_addr[a].names.nelts; s++) { + + ch = name[s].name.data[0]; + + if (ch != '*' && ch != '.') { + continue; + } + + 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; } - name = in_addr[a].names.elts; - for (s = 0; s < in_addr[a].names.nelts; s++) { - ngx_http_server_names_hash_key(key, name[s].name.data, - name[s].name.len, - cmcf->server_names_hash); + if (rc == NGX_BUSY) { + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "conflicting server name \"%V\", ignored", + &name[s].name); + } + } - s_name = ngx_array_push(&in_addr[a].hash[key]); - if (s_name == NULL) { - return NGX_CONF_ERROR; - } - name = in_addr[a].names.elts; + 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; - *s_name = name[s]; + 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_wildcards.nelts) { + + ngx_qsort(ha.dns_wildcards.elts, + (size_t) ha.dns_wildcards.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_wildcards.elts, + ha.dns_wildcards.nelts) + != NGX_OK) + { + ngx_destroy_pool(ha.temp_pool); + return NGX_CONF_ERROR; + } + + in_addr[a].dns_wildcards = (ngx_hash_wildcard_t *) hash.hash; + } + + ngx_destroy_pool(ha.temp_pool); } + 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[a - 1].addr == INADDR_ANY && !separate_binding) { - a--; + if (in_addr[last - 1].addr == INADDR_ANY) { + in_addr[last - 1].bind = 1; + bind_all = 0; } else { - a = 0; + bind_all = 1; } - in_addr = in_port[p].addrs.elts; - while (a < in_port[p].addrs.nelts) { + 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); @@ -705,68 +711,98 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } #endif - ls->backlog = in_addr[a].conf.backlog; - ls->rcvbuf = in_addr[a].conf.rcvbuf; - ls->sndbuf = in_addr[a].conf.sndbuf; + 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].conf.accept_filter; + 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].conf.deferred_accept; + ls->deferred_accept = in_addr[a].listen_conf->deferred_accept; #endif ls->ctx = ctx; - if (in_port[p].addrs.nelts > 1) { - - in_addr = in_port[p].addrs.elts; - if (in_addr[in_port[p].addrs.nelts - 1].addr != INADDR_ANY) { + hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t)); + if (hip == NULL) { + return NGX_CONF_ERROR; + } - /* - * if this port has not the "*:port" binding then create - * the separate ngx_http_in_port_t for the all bindings - */ + 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; + } - inport = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t)); - if (inport == 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; - inport->port = in_port[p].port; - inport->port_text = in_port[p].port_text; + in_addr = in_port[p].addrs.elts; - /* init list of the addresses ... */ + if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) { + hip->naddrs = 1; + done = 0; - if (ngx_array_init(&inport->addrs, cf->pool, 1, - sizeof(ngx_http_in_addr_t)) != NGX_OK) - { - return NGX_CONF_ERROR; - } + } else if (in_port[p].addrs.nelts > 1 + && in_addr[last - 1].addr == INADDR_ANY) + { + hip->naddrs = last; + done = 1; - /* ... and set up it with the first address */ - - inport->addrs.nelts = 1; - inport->addrs.elts = in_port[p].addrs.elts; + } else { + hip->naddrs = 1; + done = 0; + } - ls->servers = inport; - - /* prepare for the next cycle */ +#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 - in_port[p].addrs.elts = (char *) in_port[p].addrs.elts - + in_port[p].addrs.size; - in_port[p].addrs.nelts--; + hip->addrs = ngx_pcalloc(cf->pool, + hip->naddrs * sizeof(ngx_http_in_addr_t)); + if (hip->addrs == NULL) { + return NGX_CONF_ERROR; + } - in_addr = (ngx_http_in_addr_t *) in_port[p].addrs.elts; - a = 0; + 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].dns_wildcards == NULL + || in_addr[i].dns_wildcards->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->hash = in_addr[i].hash; + vn->dns_wildcards = in_addr[i].dns_wildcards; } - ls->servers = &in_port[p]; - a++; + if (done) { + break; + } + + in_addr++; + in_port[p].addrs.elts = in_addr; + last--; + + a = 0; } } @@ -785,12 +821,12 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0, "%s:%d %p", address, in_port[p].port, in_addr[a].core_srv_conf); - s_name = in_addr[a].names.elts; + 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, &s_name[n].name, - s_name[n].core_srv_conf); + address, in_port[p].port, &name[n].name, + name[n].core_srv_conf); } } } @@ -801,30 +837,20 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } -static int ngx_libc_cdecl -ngx_cmp_server_names(const void *one, const void *two) -{ - ngx_http_server_name_t *first = (ngx_http_server_name_t *) one; - ngx_http_server_name_t *second = (ngx_http_server_name_t *) two; - - return ngx_strcmp(first->name.data, second->name.data); -} - - /* * add the server address, the server names and the server core module * configurations to the port (in_port) */ static ngx_int_t -ngx_http_add_address(ngx_conf_t *cf, ngx_http_in_port_t *in_port, +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_in_addr_t *in_addr; + ngx_http_conf_in_addr_t *in_addr; if (in_port->addrs.elts == NULL) { - if (ngx_array_init(&in_port->addrs, cf->pool, 4, - sizeof(ngx_http_in_addr_t)) != NGX_OK) + if (ngx_array_init(&in_port->addrs, cf->temp_pool, 4, + sizeof(ngx_http_conf_in_addr_t)) != NGX_OK) { return NGX_ERROR; } @@ -836,11 +862,14 @@ ngx_http_add_address(ngx_conf_t *cf, ngx } in_addr->addr = lscf->addr; + in_addr->hash.buckets = NULL; + in_addr->hash.size = 0; + in_addr->dns_wildcards = NULL; in_addr->names.elts = NULL; - in_addr->hash = NULL; - in_addr->wildcards.elts = NULL; in_addr->core_srv_conf = cscf; - in_addr->conf = lscf->conf; + in_addr->default_server = lscf->conf.default_server; + in_addr->bind = lscf->conf.bind; + in_addr->listen_conf = &lscf->conf; #if (NGX_DEBUG) { @@ -861,23 +890,14 @@ ngx_http_add_address(ngx_conf_t *cf, ngx */ static ngx_int_t -ngx_http_add_names(ngx_conf_t *cf, ngx_http_in_addr_t *in_addr, +ngx_http_add_names(ngx_conf_t *cf, ngx_http_conf_in_addr_t *in_addr, ngx_http_core_srv_conf_t *cscf) { ngx_uint_t i, n; - ngx_array_t *array; ngx_http_server_name_t *server_names, *name; if (in_addr->names.elts == NULL) { - if (ngx_array_init(&in_addr->names, cf->pool, 4, - sizeof(ngx_http_server_name_t)) != NGX_OK) - { - return NGX_ERROR; - } - } - - if (in_addr->wildcards.elts == NULL) { - if (ngx_array_init(&in_addr->wildcards, cf->pool, 1, + if (ngx_array_init(&in_addr->names, cf->temp_pool, 4, sizeof(ngx_http_server_name_t)) != NGX_OK) { return NGX_ERROR; @@ -895,17 +915,8 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "name: %V", &server_names[i].name); - /* TODO: duplicate names can be checked here */ - - if (server_names[i].wildcard) { - array = &in_addr->wildcards; - - } else { - array = &in_addr->names; - } - - name = ngx_array_push(array); + name = ngx_array_push(&in_addr->names); if (name == NULL) { return NGX_ERROR; } @@ -926,7 +937,7 @@ ngx_http_merge_locations(ngx_conf_t *cf, ngx_uint_t i; ngx_http_core_loc_conf_t **clcfp; - clcfp = /* (ngx_http_core_loc_conf_t **) */ locations->elts; + clcfp = locations->elts; for (i = 0; i < locations->nelts; i++) { rv = module->merge_loc_conf(cf, loc_conf[ctx_index], @@ -944,3 +955,44 @@ ngx_http_merge_locations(ngx_conf_t *cf, return NGX_CONF_OK; } + + +static int ngx_libc_cdecl +ngx_http_cmp_conf_in_addrs(const void *one, const void *two) +{ + ngx_http_conf_in_addr_t *first, *second; + + first = (ngx_http_conf_in_addr_t *) one; + second = (ngx_http_conf_in_addr_t *) two; + + if (first->addr == INADDR_ANY) { + /* the INADDR_ANY must be the last resort, shift it to the end */ + return 1; + } + + if (first->bind && !second->bind) { + /* shift explicit bind()ed addresses to the start */ + return -1; + } + + if (!first->bind && second->bind) { + /* shift explicit bind()ed addresses to the start */ + return 1; + } + + /* do not sort by default */ + + return 0; +} + + +static int ngx_libc_cdecl +ngx_http_cmp_dns_wildcards(const void *one, const void *two) +{ + ngx_hash_key_t *first, *second; + + first = (ngx_hash_key_t *) one; + second = (ngx_hash_key_t *) two; + + return ngx_strcmp(first->key.data, second->key.data); +} diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -16,7 +16,6 @@ typedef struct ngx_http_request_s ngx_http_request_t; typedef struct ngx_http_upstream_s ngx_http_upstream_t; typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; -typedef struct ngx_http_in_addr_s ngx_http_in_addr_t; typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); diff --git a/src/http/ngx_http_config.c b/src/http/ngx_http_config.c deleted file mode 100644 --- a/src/http/ngx_http_config.c +++ /dev/null @@ -1,214 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include - - -ngx_int_t -ngx_http_config_add_hash(ngx_http_hash_conf_t *h, ngx_str_t *key, void *value, - ngx_uint_t flags) -{ - size_t len; - ngx_str_t *name; - ngx_uint_t i, k, n, skip; - ngx_hash_key_t *hk; - u_char buf[2048]; - - if (!(flags & NGX_HTTP_WILDCARD_HASH)) { - - /* exact hash */ - - k = 0; - - for (i = 0; i < key->len; i++) { - key->data[i] = ngx_tolower(key->data[i]); - k = ngx_hash(k, key->data[i]); - } - - k %= NGX_HTTP_CONFIG_HASH; - - /* check conflicts in exact hash */ - - name = h->keys_hash[k].elts; - - if (name) { - for (i = 0; i < h->keys_hash[k].nelts; i++) { - if (key->len != name[i].len) { - continue; - } - - if (ngx_strncmp(key->data, name[i].data, key->len) == 0) { - return NGX_BUSY; - } - } - - } else { - if (ngx_array_init(&h->keys_hash[k], h->temp_pool, 4, - sizeof(ngx_str_t)) - != NGX_OK) - { - return NGX_ERROR; - } - } - - name = ngx_array_push(&h->keys_hash[k]); - if (name == NULL) { - return NGX_ERROR; - } - - *name = *key; - - hk = ngx_array_push(&h->keys); - if (hk == NULL) { - return NGX_ERROR; - } - - hk->key = *key; - hk->key_hash = ngx_hash_key(key->data, key->len); - hk->value = value; - - } else { - - /* wildcard hash */ - - skip = (key->data[0] == '*') ? 2 : 1; - k = 0; - - for (i = skip; i < key->len; i++) { - key->data[i] = ngx_tolower(key->data[i]); - k = ngx_hash(k, key->data[i]); - } - - k %= NGX_HTTP_CONFIG_HASH; - - if (skip == 1) { - - /* check conflicts in exact hash for ".example.com" */ - - name = h->keys_hash[k].elts; - - if (name) { - len = key->len - skip; - - for (i = 0; i < h->keys_hash[k].nelts; i++) { - if (len != name[i].len) { - continue; - } - - if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) { - return NGX_BUSY; - } - } - - } else { - if (ngx_array_init(&h->keys_hash[k], h->temp_pool, 4, - sizeof(ngx_str_t)) - != NGX_OK) - { - return NGX_ERROR; - } - } - - name = ngx_array_push(&h->keys_hash[k]); - if (name == NULL) { - return NGX_ERROR; - } - - name->len = key->len - 1; - name->data = ngx_palloc(h->temp_pool, name->len); - if (name->data == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(name->data, &key->data[1], name->len); - } - - - /* - * convert "*.example.com" to "com.example.\0" - * and ".example.com" to "com.example\0" - */ - - len = 0; - n = 0; - - for (i = key->len - 1; i; i--) { - if (key->data[i] == '.') { - ngx_memcpy(&buf[n], &key->data[i + 1], len); - n += len; - buf[n++] = '.'; - len = 0; - continue; - } - - len++; - } - - if (len) { - ngx_memcpy(&buf[n], &key->data[1], len); - n += len; - } - - buf[n] = '\0'; - - - /* check conflicts in wildcard hash */ - - name = h->dns_hash[k].elts; - - if (name) { - len = key->len - skip; - - for (i = 0; i < h->dns_hash[k].nelts; i++) { - if (len != name[i].len) { - continue; - } - - if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) { - return NGX_BUSY; - } - } - - } else { - if (ngx_array_init(&h->dns_hash[k], h->temp_pool, 4, - sizeof(ngx_str_t)) - != NGX_OK) - { - return NGX_ERROR; - } - } - - name = ngx_array_push(&h->dns_hash[k]); - if (name == NULL) { - return NGX_ERROR; - } - - name->len = key->len - skip; - name->data = ngx_palloc(h->temp_pool, name->len); - if (name->data == NULL) { - return NGX_ERROR; - } - ngx_memcpy(name->data, key->data + skip, name->len); - - - ngx_memcpy(key->data, buf, key->len); - key->len--; - - hk = ngx_array_push(&h->dns_wildcards); - if (hk == NULL) { - return NGX_ERROR; - } - - hk->key = *key; - hk->key_hash = 0; - hk->value = value; - } - - return NGX_OK; -} diff --git a/src/http/ngx_http_config.h b/src/http/ngx_http_config.h --- a/src/http/ngx_http_config.h +++ b/src/http/ngx_http_config.h @@ -72,25 +72,4 @@ typedef struct { cycle->conf_ctx[ngx_http_module.index])->main_conf[module.ctx_index] -#define NGX_HTTP_CONFIG_HASH 10007 - -#define NGX_HTTP_WILDCARD_HASH 1 - -typedef struct { - ngx_pool_t *pool; - ngx_pool_t *temp_pool; - - ngx_array_t keys; - ngx_array_t *keys_hash; - - ngx_array_t dns_wildcards; - ngx_array_t *dns_hash; -} ngx_http_hash_conf_t; - - -ngx_int_t ngx_http_config_add_hash(ngx_http_hash_conf_t *h, ngx_str_t *key, - void *value, ngx_uint_t flags); - - - #endif /* _NGX_HTTP_CONFIG_H_INCLUDED_ */ diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -73,18 +73,18 @@ static ngx_conf_enum_t ngx_http_restric static ngx_command_t ngx_http_core_commands[] = { - { ngx_string("server_names_hash"), + { ngx_string("server_names_hash_max_size"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, NGX_HTTP_MAIN_CONF_OFFSET, - offsetof(ngx_http_core_main_conf_t, server_names_hash), + offsetof(ngx_http_core_main_conf_t, server_names_hash_max_size), NULL }, - { ngx_string("server_names_hash_threshold"), + { ngx_string("server_names_hash_bucket_size"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, NGX_HTTP_MAIN_CONF_OFFSET, - offsetof(ngx_http_core_main_conf_t, server_names_hash_threshold), + offsetof(ngx_http_core_main_conf_t, server_names_hash_bucket_size), NULL }, { ngx_string("server"), @@ -1715,8 +1715,8 @@ ngx_http_core_create_main_conf(ngx_conf_ return NGX_CONF_ERROR; } - cmcf->server_names_hash = NGX_CONF_UNSET_UINT; - cmcf->server_names_hash_threshold = NGX_CONF_UNSET_UINT; + cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT; + cmcf->server_names_hash_bucket_size = NGX_CONF_UNSET_UINT; return cmcf; } @@ -1727,14 +1727,17 @@ ngx_http_core_init_main_conf(ngx_conf_t { ngx_http_core_main_conf_t *cmcf = conf; - if (cmcf->server_names_hash == NGX_CONF_UNSET_UINT) { - cmcf->server_names_hash = 1009; + if (cmcf->server_names_hash_max_size == NGX_CONF_UNSET_UINT) { + cmcf->server_names_hash_max_size = 512; } - if (cmcf->server_names_hash_threshold == NGX_CONF_UNSET_UINT) { - cmcf->server_names_hash_threshold = 50; + if (cmcf->server_names_hash_bucket_size == NGX_CONF_UNSET_UINT) { + cmcf->server_names_hash_bucket_size = ngx_cacheline_size; } + cmcf->server_names_hash_bucket_size = + ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size); + return NGX_CONF_OK; } @@ -1756,19 +1759,20 @@ ngx_http_core_create_srv_conf(ngx_conf_t */ if (ngx_array_init(&cscf->locations, cf->pool, 4, sizeof(void *)) - == NGX_ERROR) + == NGX_ERROR) { return NGX_CONF_ERROR; } if (ngx_array_init(&cscf->listen, cf->pool, 4, sizeof(ngx_http_listen_t)) - == NGX_ERROR) + == NGX_ERROR) { return NGX_CONF_ERROR; } if (ngx_array_init(&cscf->server_names, cf->pool, 4, - sizeof(ngx_http_server_name_t)) == NGX_ERROR) + sizeof(ngx_http_server_name_t)) + == NGX_ERROR) { return NGX_CONF_ERROR; } @@ -1790,9 +1794,8 @@ ngx_http_core_merge_srv_conf(ngx_conf_t ngx_http_core_srv_conf_t *prev = parent; ngx_http_core_srv_conf_t *conf = child; - ngx_http_listen_t *ls; - ngx_http_server_name_t *sn; - ngx_http_core_main_conf_t *cmcf; + ngx_http_listen_t *ls; + ngx_http_server_name_t *sn; /* TODO: it does not merge, it inits only */ @@ -1837,13 +1840,6 @@ ngx_http_core_merge_srv_conf(ngx_conf_t sn->name.len = ngx_strlen(sn->name.data); sn->core_srv_conf = conf; - sn->wildcard = 0; - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - if (cmcf->max_server_name_len < sn->name.len) { - cmcf->max_server_name_len = sn->name.len; - } } ngx_conf_merge_size_value(conf->connection_pool_size, @@ -2279,49 +2275,60 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx static char * ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_core_srv_conf_t *scf = conf; - - ngx_uint_t i; - ngx_str_t *value; - ngx_http_server_name_t *sn; - ngx_http_core_main_conf_t *cmcf; - - /* TODO: warn about duplicate 'server_name' directives */ - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + ngx_http_core_srv_conf_t *cscf = conf; + + u_char ch; + ngx_str_t *value, name; + ngx_uint_t i; + ngx_http_server_name_t *sn; value = cf->args->elts; - for (i = 1; i < cf->args->nelts; i++) { - if (value[i].len == 0) { + ch = value[1].data[0]; + + if (cscf->server_name.data == NULL && value[1].len) { + if (ch == '*') { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "server name \"%V\" is invalid " - "in \"%V\" directive", - &value[i], &cmd->name); + "first server name \"%V\" must not be wildcard", + &value[1]); return NGX_CONF_ERROR; } - sn = ngx_array_push(&scf->server_names); + name = value[1]; + + if (ch == '.') { + name.len--; + name.data++; + } + + cscf->server_name.len = name.len; + cscf->server_name.data = ngx_pstrdup(cf->pool, &name); + if (cscf->server_name.data == NULL) { + return NGX_CONF_ERROR; + } + } + + for (i = 1; i < cf->args->nelts; i++) { + + ch = value[i].data[0]; + + if (value[i].len == 0 + || (ch == '*' && (value[i].len < 3 || value[i].data[1] != '.')) + || (ch == '.' && value[i].len < 2)) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "server name \"%V\" is invalid", &value[i]); + return NGX_CONF_ERROR; + } + + sn = ngx_array_push(&cscf->server_names); if (sn == NULL) { return NGX_CONF_ERROR; } sn->name.len = value[i].len; sn->name.data = value[i].data; - sn->core_srv_conf = scf; - - if (sn->name.data[0] == '*') { - sn->name.len--; - sn->name.data++; - sn->wildcard = 1; - - } else { - sn->wildcard = 0; - } - - if (cmcf->max_server_name_len < sn->name.len) { - cmcf->max_server_name_len = sn->name.len; - } + sn->core_srv_conf = cscf; } return NGX_CONF_OK; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -73,10 +73,8 @@ typedef struct { ngx_hash0_t headers_in_hash; ngx_hash0_t variables_hash; - ngx_uint_t server_names_hash; - ngx_uint_t server_names_hash_threshold; - - size_t max_server_name_len; + ngx_uint_t server_names_hash_max_size; + ngx_uint_t server_names_hash_bucket_size; ngx_array_t variables; /* ngx_http_variable_t */ ngx_array_t all_variables; /* ngx_http_variable_t */ @@ -99,6 +97,8 @@ typedef struct { /* server ctx */ ngx_http_conf_ctx_t *ctx; + ngx_str_t server_name; + size_t connection_pool_size; size_t request_pool_size; size_t client_header_buffer_size; @@ -115,45 +115,53 @@ typedef struct { /* list of structures to find core_srv_conf quickly at run time */ + +typedef struct { + in_addr_t addr; + /* the default server configuration for this address:port */ + ngx_http_core_srv_conf_t *core_srv_conf; + ngx_http_virtual_names_t *virtual_names; +} ngx_http_in_addr_t; + + typedef struct { in_port_t port; ngx_str_t port_text; - ngx_array_t addrs; /* array of ngx_http_in_addr_t */ + ngx_http_in_addr_t *addrs; + ngx_uint_t naddrs; } ngx_http_in_port_t; -struct ngx_http_in_addr_s { +typedef struct { + in_port_t port; + ngx_array_t addrs; /* array of ngx_http_conf_in_addr_t */ +} ngx_http_conf_in_port_t; + + +typedef struct { in_addr_t addr; - ngx_array_t names; /* array of ngx_http_server_name_t */ - ngx_array_t *hash; /* hash of ngx_http_server_name_t */ - ngx_array_t wildcards; /* array of ngx_http_server_name_t */ + ngx_hash_t hash; + ngx_hash_wildcard_t *dns_wildcards; + + ngx_array_t names; /* array of ngx_http_server_name_t */ /* the default server configuration for this address:port */ ngx_http_core_srv_conf_t *core_srv_conf; - ngx_http_listen_conf_t conf; -}; + unsigned default_server:1; + unsigned bind:1; + + ngx_http_listen_conf_t *listen_conf; +} ngx_http_conf_in_addr_t; typedef struct { ngx_str_t name; ngx_http_core_srv_conf_t *core_srv_conf; /* virtual name server conf */ - - ngx_uint_t wildcard; /* unsigned wildcard:1 */ } ngx_http_server_name_t; -#define ngx_http_server_names_hash_key(key, name, len, prime) \ - { \ - ngx_uint_t n0; \ - for (key = 0, n0 = 0; n0 < len; n0++) { \ - key += name[n0]; \ - } \ - key %= prime; \ - } - - typedef struct { ngx_int_t status; ngx_int_t overwrite; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -203,11 +203,10 @@ void ngx_http_init_request(ngx_event_t * struct sockaddr_in sin; ngx_connection_t *c; ngx_http_request_t *r; - ngx_http_in_port_t *in_port; - ngx_http_in_addr_t *in_addr; + ngx_http_in_port_t *hip; + ngx_http_in_addr_t *hia; ngx_http_log_ctx_t *ctx; ngx_http_connection_t *hc; - ngx_http_server_name_t *server_name; ngx_http_core_srv_conf_t *cscf; ngx_http_core_loc_conf_t *clcf; ngx_http_core_main_conf_t *cmcf; @@ -269,15 +268,15 @@ void ngx_http_init_request(ngx_event_t * /* AF_INET only */ - in_port = c->servers; - in_addr = in_port->addrs.elts; - - r->port = in_port->port; - r->port_text = &in_port->port_text; + hip = c->servers; + hia = hip->addrs; + + r->port = hip->port; + r->port_text = &hip->port_text; i = 0; - if (in_port->addrs.nelts > 1) { + if (hip->naddrs > 1) { /* * There are several addresses on this port and one of them @@ -308,25 +307,27 @@ void ngx_http_init_request(ngx_event_t * /* the last in_port->addrs address is "*" */ - for ( /* void */ ; i < in_port->addrs.nelts - 1; i++) { - if (in_addr[i].addr == r->in_addr) { + for ( /* void */ ; i < hip->naddrs - 1; i++) { + if (hia[i].addr == r->in_addr) { break; } } } else { - r->in_addr = in_addr[0].addr; + r->in_addr = hia[0].addr; } - r->virtual_names = &in_addr[i]; + r->virtual_names = hia[i].virtual_names; /* the default server configuration for the address:port */ - cscf = in_addr[i].core_srv_conf; + cscf = hia[i].core_srv_conf; r->main_conf = cscf->ctx->main_conf; r->srv_conf = cscf->ctx->srv_conf; r->loc_conf = cscf->ctx->loc_conf; + r->server_name = cscf->server_name; + rev->handler = ngx_http_process_request_line; #if (NGX_HTTP_SSL) @@ -350,9 +351,6 @@ void ngx_http_init_request(ngx_event_t * #endif - server_name = cscf->server_names.elts; - r->server_name = server_name->name; - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); c->log->file = clcf->err_log->file; if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { @@ -1321,78 +1319,35 @@ ngx_http_process_request_header(ngx_http static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r) { - ngx_int_t rc; - ngx_uint_t i, n, key; - ngx_http_server_name_t *name; - ngx_http_core_loc_conf_t *clcf; - ngx_http_core_srv_conf_t *cscf; - ngx_http_core_main_conf_t *cmcf; - - if (r->virtual_names->hash) { - cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - - ngx_http_server_names_hash_key(key, - r->headers_in.host->value.data, - r->headers_in.host_name_len, - cmcf->server_names_hash); - - name = r->virtual_names->hash[key].elts; - n = r->virtual_names->hash[key].nelts; - - } else { - name = r->virtual_names->names.elts; - n = r->virtual_names->names.nelts; + size_t len; + u_char *host; + ngx_http_virtual_names_t *vn; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + + vn = r->virtual_names; + + if (vn == NULL) { + return NGX_OK; } - for (i = 0; i < n; i++) { - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "server name: %V", &name[i].name); - - if (r->headers_in.host_name_len != name[i].name.len) { - continue; - } - - rc = ngx_strncmp(r->headers_in.host->value.data, - name[i].name.data, name[i].name.len); - - if (rc == 0) { - r->server_name = name[i].name; + host = r->headers_in.host->value.data; + len = r->headers_in.host_name_len; + + /* STUB: ngx_hash_key() here is STUB */ + + if (vn->hash.buckets) { + cscf = ngx_hash_find(&vn->hash, ngx_hash_key(host, len), host, len); + if (cscf) { goto found; } - - if (rc < 0) { - /* the server names are lexicographically sorted */ - break; - } } - if (r->virtual_names->wildcards.nelts) { - - name = r->virtual_names->wildcards.elts; - for (i = 0; i < r->virtual_names->wildcards.nelts; i++) { - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "server name: %V", &name[i].name); - - if (r->headers_in.host_name_len <= name[i].name.len) { - continue; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "server name: %s", - r->headers_in.host->value.data - + (r->headers_in.host_name_len - name[i].name.len)); - - if (ngx_strncmp(r->headers_in.host->value.data - + (r->headers_in.host_name_len - name[i].name.len), - name[i].name.data, name[i].name.len) == 0) - { - r->server_name.len = r->headers_in.host_name_len; - r->server_name.data = r->headers_in.host->value.data; - - goto found; - } + if (vn->dns_wildcards && vn->dns_wildcards->hash.buckets) { + cscf = ngx_hash_find_wildcard(vn->dns_wildcards, host, len); + + if (cscf) { + goto found; } } @@ -1406,8 +1361,11 @@ ngx_http_find_virtual_server(ngx_http_re found: - r->srv_conf = name[i].core_srv_conf->ctx->srv_conf; - r->loc_conf = name[i].core_srv_conf->ctx->loc_conf; + r->server_name.len = len; + r->server_name.data = host; + + r->srv_conf = cscf->ctx->srv_conf; + r->loc_conf = cscf->ctx->loc_conf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); r->connection->log->file = clcf->err_log->file; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -250,14 +250,20 @@ typedef struct { } ngx_http_connection_t; +typedef struct { + ngx_hash_t hash; + ngx_hash_wildcard_t *dns_wildcards; +} ngx_http_virtual_names_t; + + typedef void (*ngx_http_cleanup_pt)(void *data); typedef struct ngx_http_cleanup_s ngx_http_cleanup_t; struct ngx_http_cleanup_s { - ngx_http_cleanup_pt handler; - void *data; - ngx_http_cleanup_t *next; + ngx_http_cleanup_pt handler; + void *data; + ngx_http_cleanup_t *next; }; @@ -325,7 +331,7 @@ struct ngx_http_request_s { ngx_uint_t port; ngx_str_t *port_text; /* ":80" */ ngx_str_t server_name; - ngx_http_in_addr_t *virtual_names; + ngx_http_virtual_names_t *virtual_names; ngx_uint_t phase; ngx_int_t phase_handler; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -344,7 +344,7 @@ ngx_http_upstream_init(ngx_http_request_ u->state->response_time = tp->sec * 1000 + tp->msec; - cln = ngx_http_cleanup_add(r, sizeof(void *)); + cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return;