changeset 593:425af804d968 release-0.3.18

nginx-0.3.18-RELEASE import *) 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; the bug had appeared in 0.3.12. *) Bugfix: on 64-bit platforms segmentation fault may occurred on start; the bug had appeared in 0.3.16.
author Igor Sysoev <igor@sysoev.ru>
date Mon, 26 Dec 2005 17:07:48 +0000
parents 8b2e7f727cd0
children 6248cd598b13
files auto/lib/pcre/makefile.bcc auto/lib/zlib/makefile.bcc auto/make auto/os/conf auto/sources conf/nginx.conf docs/xml/nginx/changes.xml src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_conf_file.h src/core/ngx_connection.c src/core/ngx_cycle.c src/core/ngx_hash.c src/core/ngx_hash.h src/http/modules/ngx_http_map_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_referer_module.c src/http/ngx_http.c src/http/ngx_http.h src/http/ngx_http_config.c src/http/ngx_http_config.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_upstream.c
diffstat 26 files changed, 1061 insertions(+), 814 deletions(-) [+]
line wrap: on
line diff
--- 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
 
 
--- 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 \
--- 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
--- 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
     ;;
--- 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 \
--- 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"';
 
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -9,6 +9,101 @@
 <title lang="en">nginx changelog</title>
 
 
+<changes ver="0.3.18" date="26.12.2005">
+
+<change type="feature">
+<para lang="ru">
+директива server_names поддерживает имена вида ".domain.tld".
+</para>
+<para lang="en">
+the "server_names" directive supports the ".domain.tld" names.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива server_names использует хэш для имён вида "*.domain.tld"
+и более эффективный хэш для обычных имён.
+</para>
+<para lang="en">
+the "server_names" directive uses the hash for the "*.domain.tld" names
+and more effective hash for usual names.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+директивы server_names_hash_max_size и server_names_hash_bucket_size.
+</para>
+<para lang="en">
+the "server_names_hash_max_size" and "server_names_hash_bucket_size" directives.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+директивы server_names_hash и server_names_hash_threshold упразднены.
+</para>
+<para lang="en">
+the "server_names_hash" and "server_names_hash_threshold" directives
+were canceled.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива valid_referers использует хэш для имён сайтов.
+</para>
+<para lang="en">
+the "valid_referers" directive uses the hash site names.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+теперь директива valid_referers проверяет только имена сайтов без учёта URI.
+</para>
+<para lang="en">
+now the "valid_referers" directive checks the site names only without
+the URI part.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+некоторые имена вида ".domain.tld" неверно обрабатывались модулем
+ngx_http_map_module.
+</para>
+<para lang="en">
+some ".domain.tld" names incorrectly processed by the ngx_http_map_module.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если конфигурационного файла не было, то происходил segmentation fault;
+ошибка появилась в 0.3.12.
+</para>
+<para lang="en">
+segmentation fault was occurred if configuration file did not exist;
+bug appeared in 0.3.12.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+на 64-битных платформах при старте мог произойти segmentation fault;
+ошибка появилась в 0.3.16.
+</para>
+<para lang="en">
+on 64-bit platforms segmentation fault may occurred on start;
+bug appeared in 0.3.16.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="0.3.17" date="18.12.2005">
 
 <change type="change">
@@ -31,10 +126,12 @@ the "map" directive supports domain name
 
 <change type="bugfix">
 <para lang="ru">
-во время SSL handshake не иcпользовались таймауты.
-</para>
-<para lang="en">
-the timeouts were not used in SSL handshake.
+во время SSL handshake не иcпользовались таймауты;
+ошибка появилась в 0.2.4.
+</para>
+<para lang="en">
+the timeouts were not used in SSL handshake;
+bug appeared in 0.2.4.
 </para>
 </change>
 
@@ -1978,7 +2075,7 @@ or "Authorization" lines, then nginx now
 директива post_accept_timeout упразднена.
 </para>
 <para lang="en">
-The "post_accept_timeout" directive was canceled.
+the "post_accept_timeout" directive was canceled.
 </para>
 </change>
 
--- 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"
--- 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);
 }
--- 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;
 
--- 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;
 
--- 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);
--- 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;
+}
--- 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);
--- 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;
--- 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)
--- 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);
+}
--- 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);
+}
--- 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);
deleted file mode 100644
--- a/src/http/ngx_http_config.c
+++ /dev/null
@@ -1,214 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_event.h>
-#include <ngx_http.h>
-
-
-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;
-}
--- 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_ */
--- 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;
--- 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;
--- 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;
--- 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;
--- 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;