nginx-0.1.13-RELEASE import

    *) Feature: the server_names_hash and server_names_hash_threshold
       directives.

    *) Bugfix: the *.domain.tld names in the "server_name" directive did
       not work.

    *) Bugfix: the %request_length log parameter logged the incorrect
       length.
diff --git a/src/http/modules/ngx_http_charset_filter.c b/src/http/modules/ngx_http_charset_filter.c
index cf9d3d2..0aea91e 100644
--- a/src/http/modules/ngx_http_charset_filter.c
+++ b/src/http/modules/ngx_http_charset_filter.c
@@ -147,12 +147,6 @@
         return ngx_http_next_header_filter(r);
     }
 
-#if 0
-    if (lcf->default_charset.len == 0) {
-        return ngx_http_next_header_filter(r);
-    }
-#endif
-
     if (r->headers_out.content_type == NULL) {
         return ngx_http_next_header_filter(r);
     }
@@ -559,12 +553,36 @@
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
     ngx_conf_merge_value(conf->autodetect, prev->autodetect, 0);
 
+
+    if (conf->default_charset == NGX_CONF_UNSET) {
+        conf->default_charset = prev->default_charset;
+    }
+
     if (conf->source_charset == NGX_CONF_UNSET) {
         conf->source_charset = prev->source_charset;
     }
 
-    ngx_conf_merge_value(conf->default_charset, prev->default_charset,
-                         conf->source_charset);
+    if (conf->default_charset == NGX_CONF_UNSET
+        && conf->source_charset != NGX_CONF_UNSET)
+    {
+        conf->default_charset = conf->source_charset;
+    }
+
+    if (conf->source_charset == NGX_CONF_UNSET
+        && conf->default_charset != NGX_CONF_UNSET)
+    {
+        conf->source_charset = conf->default_charset;
+    }
+
+    if (conf->enable
+        && (conf->default_charset == NGX_CONF_UNSET
+            || conf->source_charset == NGX_CONF_UNSET))
+    {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "the \"source_charset\" or \"default_charset\" "
+                           "must be specified when \"charset\" is on");
+        return NGX_CONF_ERROR;
+    }
 
     return NGX_CONF_OK;
 }
diff --git a/src/http/modules/ngx_http_headers_filter.c b/src/http/modules/ngx_http_headers_filter.c
index e86f6ae..ab33414 100644
--- a/src/http/modules/ngx_http_headers_filter.c
+++ b/src/http/modules/ngx_http_headers_filter.c
@@ -128,8 +128,8 @@
                     cc->value.data = (u_char *) "no-cache";
 
                 } else {
-                    cc->value.data = ngx_palloc(r->pool,
-                                          sizeof("max-age=") + TIME_T_LEN + 1);
+                    cc->value.data = ngx_palloc(r->pool, sizeof("max-age=")
+                                                         + NGX_TIME_T_LEN + 1);
                     if (cc->value.data == NULL) {
                         return NGX_ERROR;
                     }
diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c
index 651dfa6..62e348e 100644
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -11,6 +11,7 @@
 
 
 static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_proxy_cache_get(ngx_http_proxy_ctx_t *p);
 
 static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r,
                                               u_char *buf, uintptr_t data);
@@ -147,14 +148,14 @@
       offsetof(ngx_http_proxy_loc_conf_t, busy_buffers_size),
       NULL },
 
-#if (NGX_HTTP_FILE_CACHE)
+#if 0
 
     { ngx_string("proxy_cache_path"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
       ngx_conf_set_path_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_proxy_loc_conf_t, cache_path),
-      ngx_garbage_collector_http_cache_handler },
+      (void *) ngx_http_cache_cleaner_handler },
 
 #endif
 
@@ -351,17 +352,19 @@
     /* TODO: we currently support reverse proxy only */
     p->accel = 1;
 
-    ngx_init_array(p->states, r->pool, p->lcf->peers->number,
-                   sizeof(ngx_http_proxy_state_t),
-                   NGX_HTTP_INTERNAL_SERVER_ERROR);
+    if (ngx_array_init(&p->states, r->pool, p->lcf->peers->number,
+                                  sizeof(ngx_http_proxy_state_t)) == NGX_ERROR)
+    {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
-    if (!(p->state = ngx_push_array(&p->states))) {
+    if (!(p->state = ngx_array_push(&p->states))) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
     ngx_memzero(p->state, sizeof(ngx_http_proxy_state_t));
 
-#if (NGX_HTTP_FILE_CACHE)
+#if 0
 
     if (!p->lcf->cache
         || (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD))
@@ -387,7 +390,7 @@
         return ngx_http_proxy_request_upstream(p);
     }
 
-    return ngx_http_proxy_get_cached_response(p);
+    return ngx_http_proxy_cache_get(p);
 
 #else
 
@@ -399,6 +402,52 @@
 }
 
 
+#if 0
+
+static ngx_int_t ngx_http_proxy_cache_get(ngx_http_proxy_ctx_t *p)
+{
+    u_char                          *last;
+    ngx_http_request_t              *r;
+    ngx_http_cache_ctx_t             ctx;
+    ngx_http_proxy_upstream_conf_t  *u;
+
+    r = p->request;
+    u = p->lcf->upstream;
+
+    ctx.key.len = u->url.len + r->uri.len - u->location->len + r->args.len;
+    if (!(ctx.key.data = ngx_palloc(r->pool, ctx.key.len))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    last = ngx_cpymem(ctx.key.data, u->url.data, u->url.len);
+
+    last = ngx_cpymem(last, r->uri.data + u->location->len,
+                      r->uri.len - u->location->len);
+
+    if (r->args.len > 0) {
+        *(last++) = '?';
+        last = ngx_cpymem(last, r->args.data, r->args.len);
+    }
+
+    p->header_in = ngx_create_temp_buf(r->pool, p->lcf->header_buffer_size);
+    if (p->header_in == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+    p->header_in->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
+
+    ctx.buf = p->header_in;
+    ctx.path = p->lcf->cache_path;
+    ctx.file = 1;
+    ctx.primary = 1;
+
+    ngx_http_cache_get(r, &ctx);
+
+    return ngx_http_proxy_request_upstream(p);
+}
+
+#endif
+
+
 void ngx_http_proxy_check_broken_connection(ngx_event_t *ev)
 {
     int                    n;
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index a550acb..21d2e55 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -11,6 +11,7 @@
 
 
 static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static int 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,
@@ -69,7 +70,7 @@
 {
     char                        *rv;
     ngx_uint_t                   mi, m, s, l, p, a, n;
-    ngx_uint_t                   port_found, addr_found, virtual_names;
+    ngx_uint_t                   port_found, addr_found, virtual_names, key;
     ngx_conf_t                   pcf;
     ngx_array_t                  in_ports;
     ngx_listening_t             *ls;
@@ -92,7 +93,9 @@
     ngx_memzero(&in_ports, sizeof(ngx_array_t));
 #endif
 
+
     /* the main http context */
+
     ngx_test_null(ctx,
                   ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)),
                   NGX_CONF_ERROR);
@@ -111,6 +114,7 @@
     }
 
     /* the main http main_conf, it's the same in the all http contexts */
+
     ngx_test_null(ctx->main_conf,
                   ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
                   NGX_CONF_ERROR);
@@ -376,6 +380,8 @@
 
                             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].default_server = lscf[l].default_server;
                             in_addr[a].core_srv_conf = cscfp[s];
 
@@ -464,6 +470,19 @@
                 }
             }
 
+            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;
+                    }
+                }
+            }
+
             /*
              * if all name-based servers have the same configuration
              * as the default server, and no servers restrict the host names
@@ -472,12 +491,50 @@
 
             if (!virtual_names) {
                 in_addr[a].names.nelts = 0;
+                continue;
+            }
+
+
+            ngx_qsort(in_addr[a].names.elts, in_addr[a].names.nelts,
+                      sizeof(ngx_http_server_name_t), ngx_cmp_server_names);
+
+
+            /* create a hash for many names */
+
+            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) {
+                    return NGX_CONF_ERROR;
+                }
+
+                for (n = 0; n < cmcf->server_names_hash; n++) {
+                    if (ngx_array_init(&in_addr[a].hash[n], cf->pool, 5,
+                                  sizeof(ngx_http_server_name_t)) == 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 (!(s_name = ngx_array_push(&in_addr[a].hash[key]))) {
+                        return NGX_CONF_ERROR;
+                    }
+
+                    *s_name = name[s];
+                }
             }
         }
 
         /*
-         * if there's the binding to "*:port" then we need to bind()
-         * to "*:port" only and ignore the other bindings
+         * 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) {
@@ -604,6 +661,15 @@
 }
 
 
+static int 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)
@@ -630,6 +696,8 @@
 
     in_addr->addr = lscf->addr;
     in_addr->names.elts = NULL;
+    in_addr->hash = NULL;
+    in_addr->wildcards.elts = NULL;
     in_addr->default_server = lscf->default_server;
     in_addr->core_srv_conf = cscf;
 
@@ -655,7 +723,8 @@
                                     ngx_http_in_addr_t *in_addr,
                                     ngx_http_core_srv_conf_t *cscf)
 {
-    ngx_uint_t               i;
+    ngx_uint_t               i, n;
+    ngx_array_t             *array;
     ngx_http_server_name_t  *server_names, *name;
 
     if (in_addr->names.elts == NULL) {
@@ -666,15 +735,36 @@
         }
     }
 
+    if (in_addr->wildcards.elts == NULL) {
+        if (ngx_array_init(&in_addr->wildcards, cf->pool, 10,
+                                  sizeof(ngx_http_server_name_t)) == NGX_ERROR)
+        {
+            return NGX_ERROR;
+        }
+    }
+
     server_names = cscf->server_names.elts;
     for (i = 0; i < cscf->server_names.nelts; i++) {
 
+        for (n = 0; n < server_names[i].name.len; n++) {
+            server_names[i].name.data[n] =
+                                     ngx_tolower(server_names[i].name.data[n]);
+        }
+
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                        "name: %V", &server_names[i].name);
 
         /* TODO: duplicate names can be checked here */
 
-        if (!(name = ngx_array_push(&in_addr->names))) {
+
+        if (server_names[i].wildcard) {
+            array = &in_addr->wildcards;
+
+        } else {
+            array = &in_addr->names;
+        }
+
+        if (!(name = ngx_array_push(array))) {
             return NGX_ERROR;
         }
 
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index 46194f3..42550aa 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -14,6 +14,7 @@
 
 typedef struct ngx_http_request_s  ngx_http_request_t;
 typedef struct ngx_http_cleanup_s  ngx_http_cleanup_t;
+typedef struct ngx_http_in_addr_s  ngx_http_in_addr_t;
 
 #if (NGX_HTTP_CACHE)
 #include <ngx_http_cache.h>
diff --git a/src/http/ngx_http_cache.c b/src/http/ngx_http_cache.c
index abdeae9..8471459 100644
--- a/src/http/ngx_http_cache.c
+++ b/src/http/ngx_http_cache.c
@@ -9,6 +9,7 @@
 #include <ngx_http.h>
 
 
+#if 0
 
 static ngx_http_module_t  ngx_http_cache_module_ctx = {
     NULL,                                  /* pre conf */
@@ -30,9 +31,101 @@
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
     NULL,                                  /* init module */
-    NULL                                   /* init child */
+    NULL                                   /* init process */
 };
 
+#endif
+
+
+static ngx_int_t ngx_http_cache_create(ngx_http_request_t *r)
+{
+    ngx_str_t  *key;
+
+    if (!(r->cache = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)))) {
+        return NGX_ERROR;
+    }
+
+    if (ngx_array_init(&r->cache->key, r->pool, 5, sizeof(ngx_str_t))
+                                                                  == NGX_ERROR)
+    {
+        return NGX_ERROR;
+    }
+
+    /* preallocate the primary key */
+
+    if (!(key = ngx_array_push(&r->cache->key))) {
+        return NGX_ERROR;
+    }
+
+    key->len = 0;
+    key->data = NULL;
+
+    /*
+     * we use offsetof() because sizeof() pads the struct size to the int size
+     */
+
+    r->cache->header_size = offsetof(ngx_http_cache_header_t, key);
+
+    r->cache->log = r->connection->log;
+    r->cache->file.log = r->connection->log;
+
+    return NGX_OK;
+}
+
+
+ngx_int_t ngx_http_cache_get(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx)
+{
+    ngx_str_t         *key;
+    ngx_http_cache_t  *c;
+
+    if (r->cache == NULL) {
+        if (ngx_http_cache_create(r) == NGX_ERROR) {
+            return NGX_ABORT;
+        }
+    }
+
+    c = r->cache;
+    key = c->key.elts;
+
+    if (ctx->primary) {
+        key[0] = ctx->key;
+        c->header_size += ctx->key.len;
+        c->key_len += ctx->key.len;
+        c->buf = ctx->buf;
+
+    } else {
+        if (key[0].len == 0) {
+            key[0] = r->uri;
+            c->header_size += r->uri.len;
+            c->key_len += ctx->key.len;
+        }
+
+        if (!(key = ngx_array_push(&r->cache->key))) {
+            return NGX_ABORT;
+        }
+
+        c->header_size += ctx->key.len;
+        c->key_len += ctx->key.len;
+    }
+
+#if 0
+
+    if (ctx->memory) {
+        ngx_http_memory_cache_get(r, ctx);
+    }
+
+#endif
+
+    if (ctx->file) {
+        return ngx_http_file_cache_get(r, ctx);
+    }
+
+    return NGX_DECLINED;
+}
+
+
+#if 0
+
 
 ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *hash,
                                      ngx_http_cleanup_t *cleanup,
@@ -478,3 +571,6 @@
 
     return NGX_CONF_OK;
 }
+
+
+#endif
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
index c882b30..fb446e4 100644
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -88,18 +88,25 @@
     time_t                    last_modified;
     time_t                    date;
     off_t                     length;
-    ssize_t                   header_size;
+    size_t                    key_len;
     size_t                    file_start;
+    ngx_file_uniq_t           uniq;
     ngx_log_t                *log;
 
     /* STUB */
+    ssize_t                   header_size;
     ngx_str_t                 key0;
 } ngx_http_cache_t;
 
 
 typedef struct {
-    ngx_path_t                path;
+    ngx_path_t               *path;
     ngx_str_t                 key;
+    ngx_buf_t                *buf;
+
+    unsigned                  file:1;
+    unsigned                  memory:1;
+    unsigned                  primary:1;
 } ngx_http_cache_ctx_t;
 
 
@@ -108,6 +115,17 @@
 #define NGX_HTTP_CACHE_THE_SAME  3
 
 
+ngx_int_t ngx_http_cache_get(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx);
+
+ngx_int_t ngx_http_file_cache_get(ngx_http_request_t *r,
+                                  ngx_http_cache_ctx_t *ctx);
+
+ngx_int_t ngx_http_file_cache_open(ngx_http_cache_t *c);
+
+ngx_int_t ngx_http_cache_cleaner_handler(ngx_gc_t *gc, ngx_str_t *name,
+                                         ngx_dir_t *dir);
+
+
 #if 0
 
 ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *cache,
@@ -125,17 +143,12 @@
 void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash,
                            ngx_http_cache_t *cache, ngx_log_t *log);
 
-int ngx_http_cache_get_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx);
-int ngx_http_cache_open_file(ngx_http_cache_ctx_t *ctx, ngx_file_uniq_t uniq);
 int ngx_http_cache_update_file(ngx_http_request_t *r,ngx_http_cache_ctx_t *ctx,
                                ngx_str_t *temp_file);
 
 int ngx_http_send_cached(ngx_http_request_t *r);
 
 
-int ngx_garbage_collector_http_cache_handler(ngx_gc_t *gc, ngx_str_t *name,
-                                             ngx_dir_t *dir);
-
 char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 #endif
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index e3ccd8f..478bb08 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -60,6 +60,20 @@
 
 static ngx_command_t  ngx_http_core_commands[] = {
 
+    { ngx_string("server_names_hash"),
+      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),
+      NULL },
+
+    { ngx_string("server_names_hash_threshold"),
+      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),
+      NULL },
+
     { ngx_string("server"),
       NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
       ngx_server_block,
@@ -1244,17 +1258,24 @@
                    5, sizeof(ngx_http_core_srv_conf_t *),
                    NGX_CONF_ERROR);
 
+    cmcf->server_names_hash = NGX_CONF_UNSET_UINT;
+    cmcf->server_names_hash_threshold = NGX_CONF_UNSET_UINT;
+
     return cmcf;
 }
 
 
 static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf)
 {
-#if 0
     ngx_http_core_main_conf_t *cmcf = conf;
 
-    /* TODO: remove it if no directives */
-#endif
+    if (cmcf->server_names_hash == NGX_CONF_UNSET_UINT) {
+        cmcf->server_names_hash = 1009;
+    }
+
+    if (cmcf->server_names_hash_threshold == NGX_CONF_UNSET_UINT) {
+        cmcf->server_names_hash_threshold = 50;
+    }
 
     return NGX_CONF_OK;
 }
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index a70b472..138067d 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -14,13 +14,13 @@
 
 
 typedef struct {
-    in_addr_t  addr;
-    in_port_t  port;
-    int        family;
-    ngx_str_t  file_name;
-    int        line;
+    in_addr_t                  addr;
+    in_port_t                  port;
+    int                        family;
+    ngx_str_t                  file_name;
+    ngx_int_t                  line;
 
-    unsigned   default_server:1;
+    unsigned                   default_server:1;
 } ngx_http_listen_t;
 
 
@@ -37,18 +37,21 @@
 
 
 typedef struct {
-    ngx_array_t          handlers;
-    ngx_int_t            type;                /* NGX_OK, NGX_DECLINED */
+    ngx_array_t                handlers;
+    ngx_int_t                  type;                /* NGX_OK, NGX_DECLINED */
 } ngx_http_phase_t;
 
 
 typedef struct {
-    ngx_array_t       servers;         /* array of ngx_http_core_srv_conf_t */
+    ngx_array_t                servers; /* array of ngx_http_core_srv_conf_t */
 
-    ngx_http_phase_t  phases[NGX_HTTP_LAST_PHASE];
-    ngx_array_t       index_handlers;
+    ngx_http_phase_t           phases[NGX_HTTP_LAST_PHASE];
+    ngx_array_t                index_handlers;
 
-    size_t            max_server_name_len;
+    ngx_uint_t                 server_names_hash;
+    ngx_uint_t                 server_names_hash_threshold;
+
+    size_t                     max_server_name_len;
 } ngx_http_core_main_conf_t;
 
 
@@ -57,62 +60,76 @@
      * array of ngx_http_core_loc_conf_t, used in the translation handler
      * and in the merge phase
      */
-    ngx_array_t           locations;
+    ngx_array_t                locations;
 
     /* "listen", array of ngx_http_listen_t */
-    ngx_array_t           listen;
+    ngx_array_t                listen;
 
     /* "server_name", array of ngx_http_server_name_t */
-    ngx_array_t           server_names;
+    ngx_array_t                server_names;
 
     /* server ctx */
-    ngx_http_conf_ctx_t  *ctx;
+    ngx_http_conf_ctx_t       *ctx;
 
-    size_t                connection_pool_size;
-    size_t                request_pool_size;
-    size_t                client_header_buffer_size;
+    size_t                     connection_pool_size;
+    size_t                     request_pool_size;
+    size_t                     client_header_buffer_size;
 
-    ngx_bufs_t            large_client_header_buffers;
+    ngx_bufs_t                 large_client_header_buffers;
 
-    ngx_msec_t            post_accept_timeout;
-    ngx_msec_t            client_header_timeout;
+    ngx_msec_t                 post_accept_timeout;
+    ngx_msec_t                 client_header_timeout;
 
-    ngx_uint_t            restrict_host_names;
+    ngx_uint_t                 restrict_host_names;
 } ngx_http_core_srv_conf_t;
 
 
 /* list of structures to find core_srv_conf quickly at run time */
 
 typedef struct {
-    in_port_t     port;
-    ngx_str_t     port_text;
-    ngx_array_t   addrs;       /* array of ngx_http_in_addr_t */
+    in_port_t                  port;
+    ngx_str_t                  port_text;
+    ngx_array_t                addrs;       /* array of ngx_http_in_addr_t */
 } ngx_http_in_port_t;
 
 
-typedef struct {
+struct ngx_http_in_addr_s {
     in_addr_t                  addr;
+
     ngx_array_t                names;     /* array of ngx_http_server_name_t */
-    ngx_http_core_srv_conf_t  *core_srv_conf;  /* default server conf
-                                                  for this address:port */
+    ngx_array_t               *hash;      /* hash of ngx_http_server_name_t */
+    ngx_array_t                wildcards;  /* 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_uint_t                 default_server; /* unsigned  default_server:1; */
-} ngx_http_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_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  n;                                                  \
+            for (key = 0, n = 0; n < len; n++) {                            \
+                key += name[n];                                             \
+            }                                                               \
+            key %= prime;                                                   \
+        }
+
+
 #define NGX_HTTP_TYPES_HASH_PRIME  13
 
 #define ngx_http_types_hash_key(key, ext)                                   \
         {                                                                   \
-            u_int n;                                                        \
+            ngx_uint_t  n;                                                  \
             for (key = 0, n = 0; n < ext.len; n++) {                        \
                 key += ext.data[n];                                         \
             }                                                               \
@@ -120,15 +137,15 @@
         }
 
 typedef struct {
-    ngx_str_t  exten;
-    ngx_str_t  type;
+    ngx_str_t     exten;
+    ngx_str_t     type;
 } ngx_http_type_t;
 
 
 typedef struct {
-    ngx_int_t  status;
-    ngx_int_t  overwrite;
-    ngx_str_t  uri;
+    ngx_int_t     status;
+    ngx_int_t     overwrite;
+    ngx_str_t     uri;
 } ngx_http_err_page_t;
 
 
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 1b258c9..df40c43 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -22,138 +22,151 @@
 #endif
 
 
-#if 0
-
-int ngx_http_cache_get_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx)
+ngx_int_t ngx_http_file_cache_get(ngx_http_request_t *r,
+                                  ngx_http_cache_ctx_t *ctx)
 {
-    MD5_CTX  md5;
+    ngx_uint_t         i;
+    ngx_str_t         *key;
+    ngx_http_cache_t  *c;
+    MD5_CTX            md5;
 
-    /* we use offsetof() because sizeof() pads struct size to int size */
-    ctx->header_size = offsetof(ngx_http_cache_header_t, key)
-                                                            + ctx->key.len + 1;
+    c = r->cache;
 
-    ctx->file.name.len = ctx->path->name.len + 1 + ctx->path->len + 32;
-    if (!(ctx->file.name.data = ngx_palloc(r->pool, ctx->file.name.len + 1))) {
-        return NGX_ERROR;
+    c->file.name.len = ctx->path->name.len + 1 + ctx->path->len + 32;
+    if (!(c->file.name.data = ngx_palloc(r->pool, c->file.name.len + 1))) {
+        return NGX_ABORT;
     }
 
-    ngx_memcpy(ctx->file.name.data, ctx->path->name.data, ctx->path->name.len);
-
     MD5Init(&md5);
-    MD5Update(&md5, (u_char *) ctx->key.data, ctx->key.len);
-    MD5Final(ctx->md5, &md5);
 
-    ngx_md5_text(ctx->file.name.data + ctx->path->name.len + 1 + ctx->path->len,
-                 ctx->md5);
+    key = c->key.elts;
+    for (i = 0; i < c->key.nelts; i++) {
+        MD5Update(&md5, key[i].data, key[i].len);
+    }
+
+    MD5Update(&md5, ctx->key.data, ctx->key.len);
+
+    MD5Final(c->md5, &md5);
+
+    ngx_memcpy(c->file.name.data, ctx->path->name.data, ctx->path->name.len);
+
+    ngx_md5_text(c->file.name.data + ctx->path->name.len + 1 + ctx->path->len,
+                 c->md5);
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-               "file cache uri: %s, md5: %s", ctx->key.data,
-               ctx->file.name.data + ctx->path->name.len + 1 + ctx->path->len);
+                  "file cache key: %V, md5: %s", &ctx->key,
+                  c->file.name.data + ctx->path->name.len + 1 + ctx->path->len);
 
-    ngx_create_hashed_filename(&ctx->file, ctx->path);
+    ngx_create_hashed_filename(&c->file, ctx->path);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "file cache name: %s", ctx->file.name.data);
+                   "file cache name: %s", c->file.name.data);
 
-    /* TODO: look open files cache */
-
-    return ngx_http_cache_open_file(ctx, 0);
+    return ngx_http_file_cache_open(r->cache);
 }
 
 
-int ngx_http_cache_open_file(ngx_http_cache_ctx_t *ctx, ngx_file_uniq_t uniq)
+ngx_int_t ngx_http_file_cache_open(ngx_http_cache_t *c)
 {
     ssize_t                   n;
     ngx_err_t                 err;
     ngx_http_cache_header_t  *h;
 
-    ctx->file.fd = ngx_open_file(ctx->file.name.data,
-                                 NGX_FILE_RDONLY, NGX_FILE_OPEN);
+    c->file.fd = ngx_open_file(c->file.name.data,
+                               NGX_FILE_RDONLY, NGX_FILE_OPEN);
 
-    if (ctx->file.fd == NGX_INVALID_FILE) {
+    if (c->file.fd == NGX_INVALID_FILE) {
         err = ngx_errno;
 
         if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
             return NGX_DECLINED;
         }
 
-        ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
-                      ngx_open_file_n " \"%s\" failed", ctx->file.name.data);
+        ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", c->file.name.data);
         return NGX_ERROR;
     }
 
-    if (uniq) {
-        if (ngx_fd_info(ctx->file.fd, &ctx->file.info) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
-                          ngx_fd_info_n " \"%s\" failed", ctx->file.name.data);
+    if (c->uniq) {
+        if (ngx_fd_info(c->file.fd, &c->file.info) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno,
+                          ngx_fd_info_n " \"%s\" failed", c->file.name.data);
 
             return NGX_ERROR;
         }
 
-        if (ngx_file_uniq(&ctx->file.info) == uniq) {
-            if (ngx_close_file(ctx->file.fd) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
+        if (ngx_file_uniq(&c->file.info) == c->uniq) {
+            if (ngx_close_file(c->file.fd) == NGX_FILE_ERROR) {
+                ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
                               ngx_close_file_n " \"%s\" failed",
-                              ctx->file.name.data);
+                              c->file.name.data);
             }
 
             return NGX_HTTP_CACHE_THE_SAME;
         }
     }
 
-    n = ngx_read_file(&ctx->file, ctx->buf->pos,
-                      ctx->buf->end - ctx->buf->last, 0);
+    n = ngx_read_file(&c->file, c->buf->pos, c->buf->end - c->buf->last, 0);
 
     if (n == NGX_ERROR || n == NGX_AGAIN) {
         return n;
     }
 
-    if (n <= ctx->header_size) {
-        ngx_log_error(NGX_LOG_CRIT, ctx->log, 0,
-                      "cache file \"%s\" is too small", ctx->file.name.data);
+    if (n <= c->header_size) {
+        ngx_log_error(NGX_LOG_CRIT, c->log, 0,
+                      "cache file \"%s\" is too small", c->file.name.data);
         return NGX_ERROR;
     }
 
-    h = (ngx_http_cache_header_t *) ctx->buf->pos;
-    ctx->expires = h->expires;
-    ctx->last_modified= h->last_modified;
-    ctx->date = h->date;
-    ctx->length = h->length;
+    h = (ngx_http_cache_header_t *) c->buf->pos;
+    c->expires = h->expires;
+    c->last_modified= h->last_modified;
+    c->date = h->date;
+    c->length = h->length;
 
-    if (h->key_len > (size_t) (ctx->buf->end - ctx->buf->pos)) {
-        ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
+    if (h->key_len > (size_t) (c->buf->end - c->buf->pos)) {
+        ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                       "cache file \"%s\" is probably invalid",
-                      ctx->file.name.data);
+                      c->file.name.data);
         return NGX_DECLINED;
     }
 
-    if (ctx->key.len
-        && (h->key_len != ctx->key.len
-            || ngx_strncmp(h->key, ctx->key.data, h->key_len) != 0))
-    {
+#if 0
+
+    /* TODO */
+
+    if (c->key_len && h->key_len != c->key_len)  {
+
+        ngx_strncmp(h->key, c->key_data, h->key_len) != 0))
+
         h->key[h->key_len] = '\0';
-        ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
+        ngx_log_error(NGX_LOG_ALERT, c->log, 0,
                           "md5 collision: \"%s\" and \"%s\"",
-                          h->key, ctx->key.data);
+                          h->key, c->key.data);
         return NGX_DECLINED;
     }
 
-    ctx->buf->last += n;
+#endif
 
-    if (ctx->expires < ngx_time()) {
+    c->buf->last += n;
 
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
+    if (c->expires < ngx_time()) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
                        "http file cache expired");
-
         return NGX_HTTP_CACHE_STALE;
     }
 
     /* TODO: NGX_HTTP_CACHE_AGED */
 
+    /* STUB */ return NGX_DECLINED;
+
     return NGX_OK;
 }
 
 
+#if 0
+
+
 int ngx_http_cache_update_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx,
                                ngx_str_t *temp_file)
 {
@@ -196,39 +209,45 @@
 }
 
 
-int ngx_garbage_collector_http_cache_handler(ngx_gc_t *gc, ngx_str_t *name,
-                                             ngx_dir_t *dir)
+#endif
+
+
+ngx_int_t ngx_http_cache_cleaner_handler(ngx_gc_t *gc, ngx_str_t *name,
+                                         ngx_dir_t *dir)
 {
-    int                   rc;
-    char                  data[sizeof(ngx_http_cache_header_t)];
-    ngx_hunk_t            buf;
-    ngx_http_cache_ctx_t  ctx;
+    int               rc;
+    ngx_buf_t         buf;
+    ngx_http_cache_t  c;
+    u_char            data[sizeof(ngx_http_cache_header_t)];
 
-    ctx.file.fd = NGX_INVALID_FILE;
-    ctx.file.name = *name;
-    ctx.file.log = gc->log;
+    ngx_memzero(&c, sizeof(ngx_http_cache_t));
 
-    ctx.header_size = sizeof(ngx_http_cache_header_t);
-    ctx.buf = &buf;
-    ctx.log = gc->log;
-    ctx.key.len = 0;
+    c.file.fd = NGX_INVALID_FILE;
+    c.file.name = *name;
+    c.file.log = gc->log;
 
-    buf.type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
+    c.header_size = sizeof(ngx_http_cache_header_t);
+    c.buf = &buf;
+    c.log = gc->log;
+    c.key_len = 0;
+
+    buf.memory = 1;
+    buf.temporary = 1;
     buf.pos = data;
     buf.last = data;
     buf.start = data;
     buf.end = data + sizeof(ngx_http_cache_header_t);
 
-    rc = ngx_http_cache_open_file(&ctx, 0);
+    rc = ngx_http_file_cache_open(&c);
 
     /* TODO: NGX_AGAIN */
 
-    if (rc != NGX_ERROR && rc != NGX_DECLINED && rc != NGX_HTTP_CACHE_STALE) {
+    if (rc != NGX_ERROR&& rc != NGX_DECLINED && rc != NGX_HTTP_CACHE_STALE) {
         return NGX_OK;
     }
 
     if (ngx_delete_file(name->data) == NGX_FILE_ERROR) {
-        ngx_log_error(NGX_LOG_CRIT, gc->log, ngx_errno,
+        ngx_log_error(NGX_LOG_CRIT, c.log, ngx_errno,
                       ngx_delete_file_n " \"%s\" failed", name->data);
         return NGX_ERROR;
     }
@@ -238,5 +257,3 @@
 
     return NGX_OK;
 }
-
-#endif
diff --git a/src/http/ngx_http_header_filter.c b/src/http/ngx_http_header_filter.c
index 31fa826..3610b1e 100644
--- a/src/http/ngx_http_header_filter.c
+++ b/src/http/ngx_http_header_filter.c
@@ -253,7 +253,7 @@
          */
 
         if (clcf->keepalive_header) {
-            len += sizeof("Keep-Alive: timeout=") - 1 + TIME_T_LEN + 2;
+            len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2;
         }
 
     } else {
diff --git a/src/http/ngx_http_log_handler.c b/src/http/ngx_http_log_handler.c
index 71cbb29..6702c4f 100644
--- a/src/http/ngx_http_log_handler.c
+++ b/src/http/ngx_http_log_handler.c
@@ -115,12 +115,12 @@
     { ngx_string("pipe"), 1, ngx_http_log_pipe },
     { ngx_string("time"), sizeof("28/Sep/1970:12:00:00") - 1,
                           ngx_http_log_time },
-    { ngx_string("msec"), TIME_T_LEN + 4, ngx_http_log_msec },
+    { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
     { ngx_string("request"), 0, ngx_http_log_request },
     { ngx_string("status"), 3, ngx_http_log_status },
     { ngx_string("length"), NGX_OFF_T_LEN, ngx_http_log_length },
     { ngx_string("apache_length"), NGX_OFF_T_LEN, ngx_http_log_apache_length },
-    { ngx_string("request_length"), NGX_OFF_T_LEN,
+    { ngx_string("request_length"), NGX_SIZE_T_LEN,
                                     ngx_http_log_request_length },
     { ngx_string("i"), NGX_HTTP_LOG_ARG, ngx_http_log_header_in },
     { ngx_string("o"), NGX_HTTP_LOG_ARG, ngx_http_log_header_out },
@@ -290,7 +290,7 @@
 static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
                                            uintptr_t data)
 {
-    return ngx_sprintf(buf, "%O", r->request_length);
+    return ngx_sprintf(buf, "%z", r->request_length);
 }
 
 
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index b2c3516..b1b84fe 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -20,6 +20,7 @@
 static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
                                                     ngx_uint_t request_line);
 static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r);
+static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r);
 
 static void ngx_http_set_write_handler(ngx_http_request_t *r);
 
@@ -246,7 +247,7 @@
     }
 
 #if (NGX_STAT_STUB)
-    r->stat_reading = 1;
+    (*ngx_stat_reading)--;
 #endif
 
     c->data = r;
@@ -310,7 +311,7 @@
         r->in_addr = in_addr[0].addr;
     }
 
-    r->virtual_names = &in_addr[i].names;
+    r->virtual_names = &in_addr[i];
 
     /* the default server configuration for the address:port */
     cscf = in_addr[i].core_srv_conf;
@@ -334,6 +335,8 @@
                 return;
             }
 
+            rev->event_handler = ngx_http_ssl_handshake;
+
             /*
              * The majority of browsers do not send the "close notify" alert.
              * Among them are MSIE, Mozilla, Netscape 4, Konqueror, and Links.
@@ -343,7 +346,6 @@
              */
 
             c->ssl->no_rcv_shut = 1;
-            rev->event_handler = ngx_http_ssl_handshake;
         }
 
         r->filter_need_in_memory = 1;
@@ -416,6 +418,8 @@
     r->http_state = NGX_HTTP_READING_REQUEST_STATE;
 
 #if (NGX_STAT_STUB)
+    (*ngx_stat_reading)++;
+    r->stat_reading = 1;
     (*ngx_stat_requests)++;
 #endif
 
@@ -1054,81 +1058,23 @@
 
 static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r)
 {
-    u_char                    *ua, *user_agent;
-    size_t                     len;
-    ngx_uint_t                 i;
-    ngx_http_server_name_t    *name;
-    ngx_http_core_srv_conf_t  *cscf;
-    ngx_http_core_loc_conf_t  *clcf;
+    u_char  *ua, *user_agent, ch;
+    size_t   len;
 
     if (r->headers_in.host) {
         for (len = 0; len < r->headers_in.host->value.len; len++) {
-            if (r->headers_in.host->value.data[len] == ':') {
+            ch = r->headers_in.host->value.data[len];
+
+            if (ch == ':') {
                 break;
             }
+
+            r->headers_in.host->value.data[len] = ngx_tolower(ch);
         }
         r->headers_in.host_name_len = len;
 
-        /* find the name based server configuration */
-
-        name = r->virtual_names->elts;
-        for (i = 0; i < r->virtual_names->nelts; i++) {
-
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "server name: %V", &name[i].name);
-
-            if (name[i].wildcard) {
-                if (r->headers_in.host_name_len <= name[i].name.len) {
-                    continue;
-                }
-
-                if (ngx_rstrncasecmp(r->headers_in.host->value.data,
-                                     name[i].name.data,
-                                     name[i].name.len) == 0)
-                {
-                    continue;
-                }
-
-            } else {
-                if (r->headers_in.host_name_len != name[i].name.len) {
-                    continue;
-                }
-
-                if (ngx_strncasecmp(r->headers_in.host->value.data,
-                                    name[i].name.data,
-                                    name[i].name.len) != 0)
-                {
-                    continue;
-                }
-            }
-
-            r->srv_conf = name[i].core_srv_conf->ctx->srv_conf;
-            r->loc_conf = name[i].core_srv_conf->ctx->loc_conf;
-
-            if (name[i].wildcard) {
-                r->server_name.len = r->headers_in.host_name_len;
-                r->server_name.data = r->headers_in.host->value.data;
-
-            } else {
-                r->server_name = name[i].name;
-            }
-
-            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-            r->connection->log->file = clcf->err_log->file;
-
-            if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
-                r->connection->log->log_level = clcf->err_log->log_level;
-            }
-
-            break;
-        }
-
-        if (i == r->virtual_names->nelts) {
-            cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
-
-            if (cscf->restrict_host_names != NGX_HTTP_RESTRICT_HOST_OFF) {
-                return NGX_HTTP_PARSE_INVALID_HOST;
-            }
+        if (ngx_http_find_virtual_server(r) != NGX_OK) {
+            return NGX_HTTP_PARSE_INVALID_HOST;
         }
 
     } else {
@@ -1225,11 +1171,117 @@
 }
 
 
+static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r)
+{
+    ngx_int_t                   rc;
+    ngx_uint_t                  i, n, key, found;
+    ngx_http_server_name_t     *name;
+    ngx_http_core_main_conf_t  *cmcf;
+    ngx_http_core_srv_conf_t   *cscf;
+    ngx_http_core_loc_conf_t   *clcf;
+
+    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;
+    }
+
+    found = 0;
+
+    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;
+
+            found = 1;
+            break;
+        }
+
+        if (rc < 0) {
+            /* the server names are lexicographically sorted */ 
+            break;
+        }
+    }
+
+    if (!found && 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;
+
+                found = 1;
+                break;
+            }
+        }
+    }
+
+    if (found) {
+        r->srv_conf = name[i].core_srv_conf->ctx->srv_conf;
+        r->loc_conf = name[i].core_srv_conf->ctx->loc_conf;
+
+        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+        r->connection->log->file = clcf->err_log->file;
+
+        if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
+            r->connection->log->log_level = clcf->err_log->log_level;
+        }
+
+        return NGX_OK;
+    }
+
+    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+    if (cscf->restrict_host_names != NGX_HTTP_RESTRICT_HOST_OFF) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
 void ngx_http_finalize_request(ngx_http_request_t *r, int rc)
 {
     ngx_http_core_loc_conf_t  *clcf;
 
-    /* r can be already destroyed when rc == NGX_DONE */
+    /* r may be already destroyed when rc == NGX_DONE */
 
     if (rc == NGX_DONE || r->main) {
         return;
@@ -1587,6 +1639,7 @@
                   cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *));
 
                 if (hc->free == NULL) {
+                    ngx_http_close_request(r, 0);
                     ngx_http_close_connection(c);
                     return;
                 }
@@ -1604,10 +1657,11 @@
         }
     }
 
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
     ngx_http_close_request(r, 0);
     c->data = hc;
 
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
     ngx_add_timer(rev, clcf->keepalive_timeout);
 
     if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
@@ -1877,12 +1931,14 @@
             if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_DISABLE_EVENT)
                                                                   == NGX_ERROR)
             {
+                ngx_http_close_request(r, 0);
                 ngx_http_close_connection(c);
                 return;
             }
 
         } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
             if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
+                ngx_http_close_request(r, 0);
                 ngx_http_close_connection(c);
                 return;
             }
@@ -1945,6 +2001,7 @@
     } while (rev->ready);
 
     if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
+        ngx_http_close_request(r, 0);
         ngx_http_close_connection(c);
         return;
     }
@@ -1958,8 +2015,6 @@
     }
 
     ngx_add_timer(rev, timer);
-
-    return;
 }
 
 
@@ -2093,8 +2148,6 @@
     r->request_line.len = 0;
 
     ngx_destroy_pool(r->pool);
-
-    return;
 }
 
 
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index bdc9cb2..eef9292 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -254,7 +254,7 @@
     void                    **srv_conf;
     void                    **loc_conf;
 
-    ngx_http_cache_entry_t   *cache;
+    ngx_http_cache_t         *cache;
 
     ngx_file_t                file;
 
@@ -287,7 +287,7 @@
     ngx_uint_t           port;
     ngx_str_t           *port_text;    /* ":80" */
     ngx_str_t            server_name;
-    ngx_array_t         *virtual_names;
+    ngx_http_in_addr_t  *virtual_names;
 
     ngx_uint_t           phase;
     ngx_int_t            phase_handler;
diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c
index 1af8746..5702a85 100644
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -232,15 +232,21 @@
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (r->err_ctx == NULL && clcf->error_pages) {
+
         err_page = clcf->error_pages->elts;
+
         for (i = 0; i < clcf->error_pages->nelts; i++) {
+
             if (err_page[i].status == error) {
+
                 if (err_page[i].overwrite) {
                     r->err_status = err_page[i].overwrite;
                 } else {
                     r->err_status = error;
                 }
+
                 r->err_ctx = r->ctx;
+
                 return ngx_http_internal_redirect(r, &err_page[i].uri, NULL);
             }
         }