nginx-0.3.46-RELEASE import

    *) Feature: the "proxy_hide_header", "proxy_pass_header",
       "fastcgi_hide_header", and "fastcgi_pass_header" directives.

    *) Change: the "proxy_pass_x_powered_by", "fastcgi_x_powered_by", and
       "proxy_pass_server" directives were canceled.

    *) Feature: the "X-Accel-Buffering" response header line is supported
       in proxy mode.

    *) Bugfix: the reconfiguration bug and memory leaks in the
       ngx_http_perl_module.
diff --git a/src/core/nginx.h b/src/core/nginx.h
index e49b91c..ece57f5 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.45"
+#define NGINX_VER          "nginx/0.3.46"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index b895910..94dfe62 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -900,38 +900,73 @@
 
 
 char *
-ngx_conf_set_table_elt_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char  *p = conf;
 
-    ngx_str_t         *value;
+    ngx_str_t         *value, *s;
     ngx_array_t      **a;
-    ngx_table_elt_t   *elt;
     ngx_conf_post_t   *post;
 
     a = (ngx_array_t **) (p + cmd->offset);
 
     if (*a == NULL) {
-        *a = ngx_array_create(cf->pool, 4, sizeof(ngx_table_elt_t));
+        *a = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
         if (*a == NULL) {
             return NGX_CONF_ERROR;
         }
     }
 
-    elt = ngx_array_push(*a);
-    if (elt == NULL) {
+    s = ngx_array_push(*a);
+    if (s == NULL) {
         return NGX_CONF_ERROR;
     }
 
     value = cf->args->elts;
 
-    elt->hash = 0;
-    elt->key = value[1];
-    elt->value = value[2];
+    *s = value[1];
 
     if (cmd->post) {
         post = cmd->post;
-        return post->post_handler(cf, post, elt);
+        return post->post_handler(cf, post, s);
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char  *p = conf;
+
+    ngx_str_t         *value;
+    ngx_array_t      **a;
+    ngx_keyval_t      *kv;
+    ngx_conf_post_t   *post;
+
+    a = (ngx_array_t **) (p + cmd->offset);
+
+    if (*a == NULL) {
+        *a = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t));
+        if (*a == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    kv = ngx_array_push(*a);
+    if (kv == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    kv->key = value[1];
+    kv->value = value[2];
+
+    if (cmd->post) {
+        post = cmd->post;
+        return post->post_handler(cf, post, kv);
     }
 
     return NGX_CONF_OK;
diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h
index 37d36d6..8f84e36 100644
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -323,8 +323,9 @@
 
 char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-char *ngx_conf_set_table_elt_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+char *ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+char *ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c
index 0ee5e77..0e9bc2c 100644
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -525,180 +525,6 @@
 
 
 ngx_int_t
-ngx_hash0_init(ngx_hash0_t *hash, ngx_pool_t *pool, void *names,
-    ngx_uint_t nelts)
-{
-    u_char      *p;
-    ngx_str_t   *name, *bucket;
-    ngx_uint_t   i, n, key, size, best, *test, buckets, min_buckets;
-
-    if (nelts == 0) {
-        for (name = (ngx_str_t *) names;
-             name->len;
-             name = (ngx_str_t *) ((char *) name + hash->bucket_size))
-        {
-            nelts++;
-        }
-    }
-
-    test = ngx_alloc(hash->max_size * sizeof(ngx_uint_t), pool->log);
-    if (test == NULL) {
-        return NGX_ERROR;
-    }
-
-    min_buckets = hash->bucket_limit + 1;
-
-#if (NGX_SUPPRESS_WARN)
-    best = 0;
-#endif
-
-    for (size = 1; size < hash->max_size; size++) {
-
-        buckets = 0;
-
-        for (i = 0; i < size; i++) {
-            test[i] = 0;
-        }
-
-        for (n = 0, name = (ngx_str_t *) names;
-             n < nelts;
-             n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
-        {
-            if (name->data == NULL) {
-                continue;
-            }
-
-            key = 0;
-
-            for (i = 0; i < name->len; i++) {
-                key += ngx_tolower(name->data[i]);
-            }
-
-            key %= size;
-
-            if (test[key] == hash->bucket_limit) {
-                break;
-            }
-
-            test[key]++;
-
-            if (buckets < test[key]) {
-                buckets = test[key];
-            }
-        }
-
-        if (n == nelts) {
-            if (min_buckets > buckets) {
-                min_buckets = buckets;
-                best = size;
-            }
-
-            if (hash->bucket_limit == 1) {
-                break;
-            }
-        }
-    }
-
-    if (min_buckets == hash->bucket_limit + 1) {
-        ngx_log_error(NGX_LOG_EMERG, pool->log, 0,
-                      "could not build the %s hash, you should increase "
-                      "either %s_size: %i or %s_bucket_limit: %i",
-                      hash->name, hash->name, hash->max_size,
-                      hash->name, hash->bucket_limit);
-        ngx_free(test);
-        return NGX_ERROR;
-    }
-
-    hash->buckets = ngx_pcalloc(pool, best * hash->bucket_size);
-    if (hash->buckets == NULL) {
-        ngx_free(test);
-        return NGX_ERROR;
-    }
-
-    if (hash->bucket_limit != 1) {
-
-        for (i = 0; i < best; i++) {
-            test[i] = 0;
-        }
-
-        for (n = 0, name = (ngx_str_t *) names;
-             n < nelts;
-             n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
-        {
-            if (name->data == NULL) {
-                continue;
-            }
-
-            key = 0;
-
-            for (i = 0; i < name->len; i++) {
-                key += ngx_tolower(name->data[i]);
-            }
-
-            key %= best;
-
-            test[key]++;
-        }
-
-        for (i = 0; i < best; i++) {
-            if (test[i] == 0) {
-                continue;
-            }
-
-            bucket = ngx_palloc(pool, test[i] * hash->bucket_size);
-            if (bucket == NULL) {
-                ngx_free(test);
-                return NGX_ERROR;
-            }
-
-            hash->buckets[i] = bucket;
-            bucket->len = 0;
-        }
-    }
-
-    for (n = 0, name = (ngx_str_t *) names;
-         n < nelts;
-         n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
-    {
-        if (name->data == NULL) {
-            continue;
-        }
-
-        key = 0;
-
-        for (i = 0; i < name->len; i++) {
-            key += ngx_tolower(name->data[i]);
-        }
-
-        key %= best;
-
-        if (hash->bucket_limit == 1) {
-            p = (u_char *) hash->buckets + key * hash->bucket_size;
-            ngx_memcpy(p, name, hash->bucket_size);
-            continue;
-        }
-
-        for (bucket = hash->buckets[key];
-             bucket->len;
-             bucket = (ngx_str_t *) ((char *) bucket + hash->bucket_size))
-        {
-            bucket->len &= 0x7fffffff;
-        }
-
-        ngx_memcpy(bucket, name, hash->bucket_size);
-        bucket->len |= 0x80000000;
-    }
-
-    ngx_free(test);
-
-    hash->hash_size = best;
-    hash->min_buckets = min_buckets;
-
-    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;
diff --git a/src/core/ngx_hash.h b/src/core/ngx_hash.h
index ad73438..da8b7e0 100644
--- a/src/core/ngx_hash.h
+++ b/src/core/ngx_hash.h
@@ -94,6 +94,7 @@
     ngx_uint_t        hash;
     ngx_str_t         key;
     ngx_str_t         value;
+    u_char           *lowcase_key;
 } ngx_table_elt_t;
 
 
@@ -106,7 +107,7 @@
 ngx_int_t ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
     ngx_uint_t nelts);
 
-#define ngx_hash(key, c)   key * 31 + c
+#define ngx_hash(key, c)   ((ngx_uint_t) key * 31 + c)
 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);
 
@@ -115,9 +116,4 @@
     void *value, ngx_uint_t flags);
 
 
-#define ngx_hash0(key, c)   key + c
-ngx_int_t ngx_hash0_init(ngx_hash0_t *hash, ngx_pool_t *pool, void *names,
-    ngx_uint_t nelts);
-
-
 #endif /* _NGX_HASH_H_INCLUDED_ */
diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h
index d76a0f5..818a290 100644
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -13,11 +13,17 @@
 
 
 typedef struct {
-    size_t    len;
-    u_char   *data;
+    size_t     len;
+    u_char    *data;
 } ngx_str_t;
 
 
+typedef struct {
+    ngx_str_t  key;
+    ngx_str_t  value;
+} ngx_keyval_t;
+
+
 #define ngx_string(str)  { sizeof(str) - 1, (u_char *) str }
 #define ngx_null_string  { 0, NULL }