nginx-0.3.27-RELEASE import

    *) Change: the "variables_hash_max_size" and
       "variables_hash_bucket_size" directives.

    *) Feature: the $body_bytes_sent variable can be used not only in the
       "log_format" directive.

    *) Feature: the $ssl_protocol and $ssl_cipher variables.

    *) Feature: the cache line size detection for widespread CPUs at start
       time.

    *) Feature: now the "accept_mutex" directive is supported using
       fcntl(2) on platforms different from i386, amd64, sparc64, and ppc.

    *) Feature: the "lock_file" directive and the --with-lock-path=PATH
       autoconfiguration directive.

    *) Bugfix: if the HTTPS protocol was used in the "proxy_pass" directive
       then the requests with the body was not transferred.
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 579da94..e66b48b 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -741,6 +741,8 @@
             body = body->next;
         }
 
+        b->flush = 1;
+
     } else {
         u->request_bufs = cl;
     }
diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c
index 17a3427..4eac263 100644
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -271,6 +271,8 @@
         conf->blocked_referer = 0;
     }
 
+    conf->keys = NULL;
+
     return NGX_CONF_OK;
 }
 
diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c
index 4ec6749..1b528f7 100644
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -29,6 +29,7 @@
 
 typedef struct {
     ngx_str_t     name;
+    ngx_uint_t    key;
     ngx_str_t     value;
 } ngx_http_ssi_var_t;
 
@@ -62,7 +63,7 @@
 static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx);
 static ngx_str_t *ngx_http_ssi_get_variable(ngx_http_request_t *r,
-    ngx_str_t *name);
+    ngx_str_t *name, ngx_uint_t key);
 static ngx_int_t ngx_http_ssi_evaluate_string(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx, ngx_str_t *text, ngx_uint_t flags);
 
@@ -1335,7 +1336,8 @@
 
 
 static ngx_str_t *
-ngx_http_ssi_get_variable(ngx_http_request_t *r, ngx_str_t *name)
+ngx_http_ssi_get_variable(ngx_http_request_t *r, ngx_str_t *name,
+    ngx_uint_t key)
 {
     ngx_uint_t           i;
     ngx_http_ssi_var_t  *var;
@@ -1349,7 +1351,11 @@
             continue;
         }
 
-        if (ngx_strncasecmp(name->data, var[i].name.data, name->len) == 0) {
+        if (key != var[i].key) {
+            continue;
+        }
+
+        if (ngx_strncmp(name->data, var[i].name.data, name->len) == 0) {
             return &var[i].value;
         }
     }
@@ -1365,6 +1371,7 @@
     u_char                      ch, *p, **value, *data, *part_data;
     size_t                     *size, len, prefix, part_len;
     ngx_str_t                   var, *val;
+    ngx_int_t                   key;
     ngx_uint_t                  i, j, n, bracket;
     ngx_array_t                 lengths, values;
     ngx_http_variable_value_t  *vv;
@@ -1469,14 +1476,17 @@
                 goto invalid_variable;
             }
 
+            key = 0;
+
             for (j = 0; j < var.len; j++) {
                 var.data[j] = ngx_tolower(var.data[j]);
+                key = ngx_hash(key, var.data[j]);
             }
 
-            val = ngx_http_ssi_get_variable(r, &var);
+            val = ngx_http_ssi_get_variable(r, &var, key);
 
             if (val == NULL) {
-                vv = ngx_http_get_variable(r, &var);
+                vv = ngx_http_get_variable(r, &var, key);
 
                 if (vv == NULL) {
                     return NGX_ERROR;
@@ -1636,6 +1646,7 @@
 ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
     ngx_str_t **params)
 {
+    ngx_int_t                   key;
     ngx_uint_t                  i;
     ngx_buf_t                  *b;
     ngx_str_t                  *var, *value, text;
@@ -1644,14 +1655,17 @@
 
     var = params[NGX_HTTP_SSI_ECHO_VAR];
 
-    value = ngx_http_ssi_get_variable(r, var);
+    key = 0;
+
+    for (i = 0; i < var->len; i++) {
+        var->data[i] = ngx_tolower(var->data[i]);
+        key = ngx_hash(key, var->data[i]);
+    }
+
+    value = ngx_http_ssi_get_variable(r, var, key);
 
     if (value == NULL) {
-        for (i = 0; i < var->len; i++) {
-            var->data[i] = ngx_tolower(var->data[i]);
-        }
-
-        vv = ngx_http_get_variable(r, var);
+        vv = ngx_http_get_variable(r, var, key);
 
         if (vv == NULL) {
             return NGX_HTTP_SSI_ERROR;
@@ -1735,6 +1749,8 @@
 ngx_http_ssi_set(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
     ngx_str_t **params)
 {
+    ngx_int_t            key;
+    ngx_uint_t           i;
     ngx_str_t           *name, *value, *vv;
     ngx_http_ssi_var_t  *var;
     ngx_http_ssi_ctx_t  *mctx;
@@ -1756,7 +1772,14 @@
         return NGX_HTTP_SSI_ERROR;
     }
 
-    vv = ngx_http_ssi_get_variable(r, name);
+    key = 0;
+
+    for (i = 0; i < name->len; i++) {
+        name->data[i] = ngx_tolower(name->data[i]);
+        key = ngx_hash(key, name->data[i]);
+    }
+
+    vv = ngx_http_ssi_get_variable(r, name, key);
 
     if (vv) {
         *vv = *value;
@@ -1769,6 +1792,7 @@
     }
 
     var->name = *name;
+    var->key = key;
     var->value = *value;
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index 55f7b48..a70c7f2 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -9,11 +9,18 @@
 #include <ngx_http.h>
 
 
+typedef u_char *(*ngx_ssl_variable_handler_pt)(ngx_connection_t *);
+
+
 #define NGX_DEFLAUT_CERTIFICATE      "cert.pem"
 #define NGX_DEFLAUT_CERTIFICATE_KEY  "cert.pem"
 #define NGX_DEFLAUT_CIPHERS  "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
 
 
+static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
+
+static ngx_int_t ngx_http_ssl_add_variables(ngx_conf_t *cf);
 static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf);
 static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
     void *parent, void *child);
@@ -97,7 +104,7 @@
 
 
 static ngx_http_module_t  ngx_http_ssl_module_ctx = {
-    NULL,                                  /* preconfiguration */
+    ngx_http_ssl_add_variables,            /* preconfiguration */
     NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
@@ -127,9 +134,70 @@
 };
 
 
+static ngx_http_variable_t  ngx_http_ssl_vars[] = {
+
+    { ngx_string("ssl_protocol"), ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_protocol, NGX_HTTP_VAR_CHANGABLE, 0 },
+
+    { ngx_string("ssl_cipher"), ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGABLE, 0 },
+
+    { ngx_null_string, NULL, 0, 0, 0 }
+};
+
+
 static u_char ngx_http_session_id_ctx[] = "HTTP";
 
 
+static ngx_int_t
+ngx_http_ssl_variable(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data;
+
+    size_t   len;
+    u_char  *name;
+
+    if (r->connection->ssl) {
+
+        name = handler(r->connection);
+
+        for (len = 0; name[len]; len++) { /* void */ }
+
+        v->len = len;
+        v->valid = 1;
+        v->no_cachable = 0;
+        v->not_found = 0;
+        v->data = name;
+
+        return NGX_OK;
+    }
+
+    v->not_found = 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_ssl_add_variables(ngx_conf_t *cf)
+{
+    ngx_http_variable_t  *var, *v;
+
+    for (v = ngx_http_ssl_vars; v->name.len; v++) {
+        var = ngx_http_add_variable(cf, &v->name, v->flags);
+        if (var == NULL) {
+            return NGX_ERROR;
+        }
+
+        var->handler = v->handler;
+        var->data = v->data;
+    }
+
+    return NGX_OK;
+}
+
+
 static void *
 ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
 {
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 89f846c..1bc43de 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -77,6 +77,20 @@
 
 static ngx_command_t  ngx_http_core_commands[] = {
 
+    { ngx_string("variables_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, variables_hash_max_size),
+      NULL },
+
+    { ngx_string("variables_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, variables_hash_bucket_size),
+      NULL },
+
     { ngx_string("server_names_hash_max_size"),
       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_num_slot,
@@ -1787,6 +1801,9 @@
     cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT;
     cmcf->server_names_hash_bucket_size = NGX_CONF_UNSET_UINT;
 
+    cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT;
+    cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT;
+
     return cmcf;
 }
 
@@ -1807,6 +1824,18 @@
     cmcf->server_names_hash_bucket_size =
             ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size);
 
+
+    if (cmcf->variables_hash_max_size == NGX_CONF_UNSET_UINT) {
+        cmcf->variables_hash_max_size = 512;
+    }
+
+    if (cmcf->variables_hash_bucket_size == NGX_CONF_UNSET_UINT) {
+        cmcf->variables_hash_bucket_size = 64;
+    }
+
+    cmcf->variables_hash_bucket_size =
+               ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);
+
     return NGX_CONF_OK;
 }
 
@@ -2224,7 +2253,7 @@
 
     ls->family = AF_INET;
     ls->port = (in_port_t) (inet_upstream.default_port ?
-                                                      80 : inet_upstream.port);
+                            80 : inet_upstream.port);
     ls->file_name = cf->conf_file->file.name;
     ls->line = cf->conf_file->line;
     ls->conf.backlog = -1;
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index 4382289..6d815a7 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -71,13 +71,18 @@
     ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1];
 
     ngx_hash0_t                headers_in_hash;
-    ngx_hash0_t                variables_hash;
+
+    ngx_hash_t                 variables_hash;
+
+    ngx_array_t                variables;       /* ngx_http_variable_t */
 
     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 */
+    ngx_uint_t                 variables_hash_max_size;
+    ngx_uint_t                 variables_hash_bucket_size;
+
+    ngx_hash_keys_arrays_t    *variables_keys;
 } ngx_http_core_main_conf_t;
 
 
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 9ef5a80..aa2b85f 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -174,7 +174,7 @@
     if (rev->ready) {
         /* the deferred accept(), rtsig, aio, iocp */
 
-        if (ngx_accept_mutex) {
+        if (ngx_use_accept_mutex) {
             ngx_post_event(rev, &ngx_posted_events);
             return;
         }
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 3c3a9e6..9afa4d5 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1457,11 +1457,10 @@
     if (ev->timedout) {
         if (ev->write) {
             c->timedout = 1;
-            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                          "client timed out");
+            ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
+
         } else {
-            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                          "upstream timed out");
+            ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
         }
     }
 
@@ -1681,14 +1680,12 @@
             } else {
                 p->downstream_error = 1;
                 c->timedout = 1;
-                ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                              "client timed out");
+                ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
             }
 
         } else {
             p->upstream_error = 1;
-            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                          "upstream timed out");
+            ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
         }
 
     } else {
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 93080ab..1370162 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -42,6 +42,8 @@
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_remote_user(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 
 
 /*
@@ -130,6 +132,9 @@
 
     { ngx_string("remote_user"), ngx_http_variable_remote_user, 0, 0, 0 },
 
+    { ngx_string("body_bytes_sent"), ngx_http_variable_body_bytes_sent,
+      0, 0, 0 },
+
     { ngx_null_string, NULL, 0, 0, 0 }
 };
 
@@ -143,30 +148,34 @@
 ngx_http_variable_t *
 ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
 {
+    ngx_int_t                   rc;
     ngx_uint_t                  i;
+    ngx_hash_key_t             *key;
     ngx_http_variable_t        *v;
     ngx_http_core_main_conf_t  *cmcf;
 
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
-    v = cmcf->all_variables.elts;
-    for (i = 0; i < cmcf->all_variables.nelts; i++) {
-        if (name->len != v[i].name.len
-            || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
+    key = cmcf->variables_keys->keys.elts;
+    for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
+        if (name->len != key[i].key.len
+            || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
         {
             continue;
         }
 
-        if (!(v[i].flags & NGX_HTTP_VAR_CHANGABLE)) {
+        v = key[i].value;
+
+        if (!(v->flags & NGX_HTTP_VAR_CHANGABLE)) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "the duplicate \"%V\" variable", name);
             return NULL;
         }
 
-        return &v[i];
+        return v;
     }
 
-    v = ngx_array_push(&cmcf->all_variables);
+    v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
     if (v == NULL) {
         return NULL;
     }
@@ -186,6 +195,18 @@
     v->flags = flags;
     v->index = 0;
 
+    rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
+
+    if (rc == NGX_ERROR) {
+        return NULL;
+    }
+
+    if (rc == NGX_BUSY) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "conflicting variable name \"%V\"", name);
+        return NULL;
+    }
+
     return v;
 }
 
@@ -298,34 +319,25 @@
 
 
 ngx_http_variable_value_t *
-ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name)
+ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
 {
-    ngx_uint_t                  i, key;
     ngx_http_variable_t        *v;
     ngx_http_variable_value_t  *vv;
     ngx_http_core_main_conf_t  *cmcf;
 
     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
 
-    key = 0;
-    for (i = 0; i < name->len; i++) {
-        key += name->data[i];
-    }
+    v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
 
-    key %= cmcf->variables_hash.hash_size;
-    v = (ngx_http_variable_t *) cmcf->variables_hash.buckets;
-
-    if (v[key].name.len == name->len
-        && ngx_strncmp(v[key].name.data, name->data, name->len) == 0)
-    {
-        if (v[key].flags & NGX_HTTP_VAR_INDEXED) {
-            return ngx_http_get_indexed_variable(r, v[key].index);
+    if (v) {
+        if (v->flags & NGX_HTTP_VAR_INDEXED) {
+            return ngx_http_get_indexed_variable(r, v->index);
 
         } else {
 
             vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
 
-            if (vv && v[key].handler(r, vv, v[key].data) == NGX_OK) {
+            if (vv && v->handler(r, vv, v->data) == NGX_OK) {
                 return vv;
             }
 
@@ -758,28 +770,72 @@
 }
 
 
+static ngx_int_t
+ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    off_t    sent;
+    u_char  *p;
+
+    sent = r->connection->sent - r->header_size;
+
+    if (sent < 0) {
+        sent = 0;
+    }
+
+    p = ngx_palloc(r->pool, NGX_OFF_T_LEN);
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    v->len = ngx_sprintf(p, "%O", sent) - p;
+    v->valid = 1;
+    v->no_cachable = 0;
+    v->not_found = 0;
+    v->data = p;
+
+    return NGX_OK;
+}
+
+
 ngx_int_t
 ngx_http_variables_add_core_vars(ngx_conf_t *cf)
 {
-    ngx_http_variable_t        *v, *cv;
+    ngx_int_t                   rc;
+    ngx_http_variable_t        *v;
     ngx_http_core_main_conf_t  *cmcf;
 
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
-    if (ngx_array_init(&cmcf->all_variables, cf->pool, 32,
-                       sizeof(ngx_http_variable_t))
-        == NGX_ERROR)
+    cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
+                                       sizeof(ngx_hash_keys_arrays_t));
+    if (cmcf->variables_keys == NULL) {
+        return NGX_ERROR;
+    }
+
+    cmcf->variables_keys->pool = cf->pool;
+    cmcf->variables_keys->temp_pool = cf->pool;
+
+    if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
+        != NGX_OK)
     {
         return NGX_ERROR;
     }
 
-    for (cv = ngx_http_core_variables; cv->name.len; cv++) {
-        v = ngx_array_push(&cmcf->all_variables);
-        if (v == NULL) {
-            return NGX_ERROR;
+    for (v = ngx_http_core_variables; v->name.len; v++) {
+        rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v,
+                              NGX_HASH_READONLY_KEY);
+
+        if (rc == NGX_OK) {
+            continue;
         }
 
-        *v = *cv;
+        if (rc == NGX_BUSY) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "conflicting variable name \"%V\"", &v->name);
+        }
+
+        return NGX_ERROR;
     }
 
     return NGX_OK;
@@ -790,6 +846,8 @@
 ngx_http_variables_init_vars(ngx_conf_t *cf)
 {
     ngx_uint_t                  i, n;
+    ngx_hash_key_t             *key;
+    ngx_hash_init_t             hash;
     ngx_http_variable_t        *v, *av;
     ngx_http_core_main_conf_t  *cmcf;
 
@@ -798,23 +856,25 @@
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
     v = cmcf->variables.elts;
-    av = cmcf->all_variables.elts;
+    key = cmcf->variables_keys->keys.elts;
 
     for (i = 0; i < cmcf->variables.nelts; i++) {
 
-        for (n = 0; n < cmcf->all_variables.nelts; n++) {
+        for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
 
-            if (v[i].name.len == av[n].name.len
-                && ngx_strncmp(v[i].name.data, av[n].name.data, v[i].name.len)
+            if (v[i].name.len == key[n].key.len
+                && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
                    == 0)
             {
-                v[i].handler = av[n].handler;
-                v[i].data = av[n].data;
+                av = key[n].value;
 
-                av[n].flags |= NGX_HTTP_VAR_INDEXED;
-                v[i].flags = av[n].flags;
+                v[i].handler = av->handler;
+                v[i].data = av->data;
 
-                av[n].index = i;
+                av->flags |= NGX_HTTP_VAR_INDEXED;
+                v[i].flags = av->flags;
+
+                av->index = i;
 
                 goto next;
             }
@@ -843,36 +903,32 @@
         continue;
     }
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-                   "http variables: %ui", cmcf->variables.nelts);
 
+    for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
+        av = key[n].value;
 
-    for (n = 0; n < cmcf->all_variables.nelts; n++) {
-        if (av[n].flags & NGX_HTTP_VAR_NOHASH) {
-            av[n].name.data = NULL;
+        if (av->flags & NGX_HTTP_VAR_NOHASH) {
+            key[n].key.data = NULL;
         }
     }
 
 
-    /* init the all http variables hash */
+    hash.hash = &cmcf->variables_hash;
+    hash.key = ngx_hash_key;
+    hash.max_size = cmcf->variables_hash_max_size;
+    hash.bucket_size = cmcf->variables_hash_bucket_size;
+    hash.name = "variables_hash";
+    hash.pool = cf->pool;
+    hash.temp_pool = NULL;
 
-    cmcf->variables_hash.max_size = 500;
-    cmcf->variables_hash.bucket_limit = 1;
-    cmcf->variables_hash.bucket_size = sizeof(ngx_http_variable_t);
-    cmcf->variables_hash.name = "http variables";
-
-    if (ngx_hash0_init(&cmcf->variables_hash, cf->pool,
-                      cmcf->all_variables.elts, cmcf->all_variables.nelts)
+    if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
+                      cmcf->variables_keys->keys.nelts)
         != NGX_OK)
     {
         return NGX_ERROR;
     }
 
-    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-                   "http variables hash size: %ui for %ui values, "
-                   "max buckets per entry: %ui",
-                   cmcf->variables_hash.hash_size, cmcf->all_variables.nelts,
-                   cmcf->variables_hash.min_buckets);
+    cmcf->variables_keys = NULL;
 
     return NGX_OK;
 }
diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h
index 480b4a5..f3f1fe8 100644
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -56,7 +56,7 @@
     ngx_uint_t index);
 
 ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
-    ngx_str_t *name);
+    ngx_str_t *name, ngx_uint_t key);
 
 #define ngx_http_clear_variable(r, index) r->variables0[index].text.data = NULL;