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.
diff --git a/src/core/nginx.h b/src/core/nginx.h
index c6c562f..511a7c9 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.17"
+#define NGINX_VER          "nginx/0.3.18"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index 377cad5..589eb0e 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -78,7 +78,8 @@
         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 @@
         *buf = '\0';
     }
 
+    if (cf->conf_file == NULL) {
+        ngx_log_error(level, cf->log, 0, "%s", errstr);
+        return;
+    }
+
     ngx_log_error(level, cf->log, 0, "%s in %s:%ui",
                   errstr, cf->conf_file->file.name.data, cf->conf_file->line);
 }
diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h
index e1859f8..62f3655 100644
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -167,6 +167,7 @@
 
     ngx_cycle_t          *cycle;
     ngx_pool_t           *pool;
+    ngx_pool_t           *temp_pool;
     ngx_conf_file_t      *conf_file;
     ngx_log_t            *log;
 
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 0820fed..93b43c4 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -295,6 +295,9 @@
                 }
             }
 
+            ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+                           "bind() %V #%d ", &ls[i].addr_text, s);
+
             if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
                 err = ngx_socket_errno;
 
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index da43036..e13bcd8 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -162,6 +162,12 @@
         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 @@
 #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 @@
 
         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 @@
         }
 
         if (ngx_test_config) {
+            ngx_destroy_pool(conf.temp_pool);
             ngx_destroy_pool(pool);
             return NULL;
         }
@@ -438,6 +447,7 @@
             }
         }
 
+        ngx_destroy_pool(conf.temp_pool);
         ngx_destroy_pool(pool);
         return NULL;
     }
@@ -521,6 +531,8 @@
         }
     }
 
+    ngx_destroy_pool(conf.temp_pool);
+
     if (old_cycle->connections == NULL) {
         /* an old cycle is an init cycle */
         ngx_destroy_pool(old_cycle->pool);
diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c
index dab1935..f43d675 100644
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -158,7 +158,7 @@
         }
     }
 
-    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 @@
 
     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_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 @@
 
 #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 @@
                 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 @@
         }
 
         if (next_names.nelts) {
+
             h = *hinit;
             h.hash = NULL;
 
@@ -459,8 +469,8 @@
             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 @@
 
     return NGX_OK;
 }
+
+
+ngx_int_t
+ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type)
+{
+    ngx_uint_t  asize;
+
+    if (type == NGX_HASH_SMALL) {
+        asize = 4;
+        ha->hsize = 107;
+
+    } else {
+        asize = NGX_HASH_LARGE_ASIZE;
+        ha->hsize = NGX_HASH_LARGE_HSIZE;
+    }
+
+    if (ngx_array_init(&ha->keys, ha->temp_pool, asize, sizeof(ngx_hash_key_t))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    if (ngx_array_init(&ha->dns_wildcards, ha->temp_pool, asize,
+                       sizeof(ngx_hash_key_t))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    ha->keys_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize);
+    if (ha->keys_hash == NULL) {
+        return NGX_ERROR;
+    }
+
+    ha->dns_wildcards_hash = ngx_pcalloc(ha->temp_pool,
+                                         sizeof(ngx_array_t) * ha->hsize);
+    if (ha->dns_wildcards_hash == NULL) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, void *value,
+    ngx_uint_t flags)
+{
+    size_t           len;
+    ngx_str_t       *name;
+    ngx_uint_t       i, k, n, skip;
+    ngx_hash_key_t  *hk;
+    u_char           buf[2048];
+
+    if (!(flags & NGX_HASH_WILDCARD_KEY)) {
+
+        /* exact hash */
+
+        k = 0;
+
+        for (i = 0; i < key->len; i++) {
+            key->data[i] = ngx_tolower(key->data[i]);
+            k = ngx_hash(k, key->data[i]);
+        }
+
+        k %= ha->hsize;
+
+        /* check conflicts in exact hash */
+
+        name = ha->keys_hash[k].elts;
+
+        if (name) {
+            for (i = 0; i < ha->keys_hash[k].nelts; i++) {
+                if (key->len != name[i].len) {
+                    continue;
+                }
+
+                if (ngx_strncmp(key->data, name[i].data, key->len) == 0) {
+                    return NGX_BUSY;
+                }
+            }
+
+        } else {
+            if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
+                               sizeof(ngx_str_t))
+                != NGX_OK)
+            {
+                return NGX_ERROR;
+            }
+        }
+
+        name = ngx_array_push(&ha->keys_hash[k]);
+        if (name == NULL) {
+            return NGX_ERROR;
+        }
+
+        *name = *key;
+
+        hk = ngx_array_push(&ha->keys);
+        if (hk == NULL) {
+            return NGX_ERROR;
+        }
+
+        hk->key = *key;
+        hk->key_hash = ngx_hash_key(key->data, key->len);
+        hk->value = value;
+
+    } else {
+
+        /* wildcard hash */
+
+        skip = (key->data[0] == '*') ? 2 : 1;
+        k = 0;
+
+        for (i = skip; i < key->len; i++) {
+            key->data[i] = ngx_tolower(key->data[i]);
+            k = ngx_hash(k, key->data[i]);
+        }
+
+        k %= ha->hsize;
+
+        if (skip == 1) {
+
+            /* check conflicts in exact hash for ".example.com" */
+
+            name = ha->keys_hash[k].elts;
+
+            if (name) {
+                len = key->len - skip;
+
+                for (i = 0; i < ha->keys_hash[k].nelts; i++) {
+                    if (len != name[i].len) {
+                        continue;
+                    }
+
+                    if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) {
+                        return NGX_BUSY;
+                    }
+                }
+
+            } else {
+                if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
+                                   sizeof(ngx_str_t))
+                    != NGX_OK)
+                {
+                    return NGX_ERROR;
+                }
+            }
+
+            name = ngx_array_push(&ha->keys_hash[k]);
+            if (name == NULL) {
+                return NGX_ERROR;
+            }
+
+            name->len = key->len - 1;
+            name->data = ngx_palloc(ha->temp_pool, name->len);
+            if (name->data == NULL) {
+                return NGX_ERROR;
+            }
+
+            ngx_memcpy(name->data, &key->data[1], name->len);
+        }
+
+
+        /*
+         * convert "*.example.com" to "com.example.\0"
+         *      and ".example.com" to "com.example\0"
+         */
+
+        len = 0;
+        n = 0;
+
+        for (i = key->len - 1; i; i--) {
+            if (key->data[i] == '.') {
+                ngx_memcpy(&buf[n], &key->data[i + 1], len);
+                n += len;
+                buf[n++] = '.';
+                len = 0;
+                continue;
+            }
+
+            len++;
+        }
+
+        if (len) {
+            ngx_memcpy(&buf[n], &key->data[1], len);
+            n += len;
+        }
+
+        buf[n] = '\0';
+
+
+        /* check conflicts in wildcard hash */
+
+        name = ha->dns_wildcards_hash[k].elts;
+
+        if (name) {
+            len = key->len - skip;
+
+            for (i = 0; i < ha->dns_wildcards_hash[k].nelts; i++) {
+                if (len != name[i].len) {
+                    continue;
+                }
+
+                if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) {
+                    return NGX_BUSY;
+                }
+            }
+
+        } else {
+            if (ngx_array_init(&ha->dns_wildcards_hash[k], ha->temp_pool, 4,
+                               sizeof(ngx_str_t))
+                != NGX_OK)
+            {
+                return NGX_ERROR;
+            }
+        }
+
+        name = ngx_array_push(&ha->dns_wildcards_hash[k]);
+        if (name == NULL) {
+            return NGX_ERROR;
+        }
+
+        name->len = key->len - skip;
+        name->data = ngx_palloc(ha->temp_pool, name->len);
+        if (name->data == NULL) {
+            return NGX_ERROR;
+        }
+        ngx_memcpy(name->data, key->data + skip, name->len);
+
+
+        ngx_memcpy(key->data, buf, key->len);
+        key->len--;
+
+        hk = ngx_array_push(&ha->dns_wildcards);
+        if (hk == NULL) {
+            return NGX_ERROR;
+        }
+
+        hk->key = *key;
+        hk->key_hash = 0;
+        hk->value = value;
+    }
+
+    return NGX_OK;
+}
diff --git a/src/core/ngx_hash.h b/src/core/ngx_hash.h
index 7449d05..855dde7 100644
--- a/src/core/ngx_hash.h
+++ b/src/core/ngx_hash.h
@@ -54,6 +54,29 @@
 } 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_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);