changeset 378:820f6378fc00 NGINX_0_7_1

nginx 0.7.1 *) Change: now locations are searched in a tree. *) Change: the "optimize_server_names" directive was canceled due to the "server_name_in_redirect" directive introduction. *) Change: some long deprecated directives are not supported anymore. *) Change: the "none" parameter in the "ssl_session_cache" directive; now this is default parameter. Thanks to Rob Mueller. *) Bugfix: worker processes might not catch reconfiguration and log rotation signals. *) Bugfix: nginx could not be built on latest Fedora 9 Linux. Thanks to Roxis.
author Igor Sysoev <http://sysoev.ru>
date Mon, 26 May 2008 00:00:00 +0400
parents 5d98007adb5f
children 9d9dad60269f
files CHANGES CHANGES.ru auto/sources src/core/nginx.c src/core/nginx.h src/core/ngx_connection.c src/core/ngx_queue.c src/core/ngx_queue.h src/event/modules/ngx_kqueue_module.c src/event/ngx_event.c src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/event/ngx_event_pipe.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/perl/nginx.pm src/http/ngx_http.c src/http/ngx_http.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_header_filter_module.c src/http/ngx_http_request.c src/http/ngx_http_special_response.c src/mail/ngx_mail_ssl_module.c src/os/unix/ngx_linux_config.h src/os/unix/ngx_process_cycle.c
diffstat 29 files changed, 1589 insertions(+), 1031 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,24 @@
 
+Changes with nginx 0.7.1                                         26 May 2008
+
+    *) Change: now locations are searched in a tree.
+
+    *) Change: the "optimize_server_names" directive was canceled due to 
+       the "server_name_in_redirect" directive introduction.
+
+    *) Change: some long deprecated directives are not supported anymore.
+
+    *) Change: the "none" parameter in the "ssl_session_cache" directive; 
+       now this is default parameter.
+       Thanks to Rob Mueller.
+
+    *) Bugfix: worker processes might not catch reconfiguration and log 
+       rotation signals.
+
+    *) Bugfix: nginx could not be built on latest Fedora 9 Linux.
+       Thanks to Roxis.
+
+
 Changes with nginx 0.7.0                                         19 May 2008
 
     *) Change: now the 0x00-0x1F, '"' and '\' characters are escaped as 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,25 @@
 
+Изменения в nginx 0.7.1                                           26.05.2008
+
+    *) Изменение: теперь поиск location'а делается с помощью дерева.
+
+    *) Изменение: директива optimize_server_names упразднена в связи с 
+       появлением директивы server_name_in_redirect.
+
+    *) Изменение: некоторые давно устаревшие директивы больше не 
+       поддерживаются.
+
+    *) Изменение: параметр "none" в директиве ssl_session_cache; теперь 
+       этот параметр используется по умолчанию.
+       Спасибо Rob Mueller.
+
+    *) Исправление: рабочие процессы могли не реагировать на сигналы 
+       переконфигурации и ротации логов.
+
+    *) Исправление: nginx не собирался на последних Fedora 9 Linux.
+       Спасибо Roxis.
+
+
 Изменения в nginx 0.7.0                                           19.05.2008
 
     *) Изменение: теперь символы 0x00-0x1F, '"' и '\' в access_log 
--- a/auto/sources
+++ b/auto/sources
@@ -44,6 +44,7 @@ CORE_SRCS="src/core/nginx.c \
            src/core/ngx_list.c \
            src/core/ngx_hash.c \
            src/core/ngx_buf.c \
+           src/core/ngx_queue.c \
            src/core/ngx_output_chain.c \
            src/core/ngx_string.c \
            src/core/ngx_parse.c \
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -1078,7 +1078,7 @@ ngx_set_cpu_affinity(ngx_conf_t *cf, ngx
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid character \"%c\" in \"worker_cpu_affinity\"",
                           ch);
-            return NGX_CONF_ERROR ;
+            return NGX_CONF_ERROR;
         }
     }
 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.7.0"
+#define NGINX_VERSION      "0.7.1"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -229,7 +229,7 @@ ngx_open_listening_sockets(ngx_cycle_t *
 
     /* TODO: configurable try number */
 
-    for (tries = 5 ; tries; tries--) {
+    for (tries = 5; tries; tries--) {
         failed = 0;
 
         /* for each listening socket */
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_queue.c
@@ -0,0 +1,79 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * find the middle queue element if the queue has odd number of elements
+ * or the first element of the queue's second part otherwise
+ */
+
+ngx_queue_t *
+ngx_queue_middle(ngx_queue_t *queue)
+{
+    ngx_queue_t  *middle, *next;
+
+    middle = ngx_queue_head(queue);
+
+    if (middle == ngx_queue_last(queue)) {
+        return middle;
+    }
+
+    next = ngx_queue_head(queue);
+
+    for ( ;; ) {
+        middle = ngx_queue_next(middle);
+
+        next = ngx_queue_next(next);
+
+        if (next == ngx_queue_last(queue)) {
+            return middle;
+        }
+
+        next = ngx_queue_next(next);
+
+        if (next == ngx_queue_last(queue)) {
+            return middle;
+        }
+    }
+}
+
+
+/* the stable insertion sort */
+
+void
+ngx_queue_sort(ngx_queue_t *queue,
+    ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *))
+{
+    ngx_queue_t  *q, *prev, *next;
+
+    q = ngx_queue_head(queue);
+
+    if (q == ngx_queue_last(queue)) {
+        return;
+    }
+
+    for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) {
+
+        prev = ngx_queue_prev(q);
+        next = ngx_queue_next(q);
+
+        ngx_queue_remove(q);
+
+        do {
+            if (cmp(prev, q) <= 0) {
+                break;
+            }
+
+            prev = ngx_queue_prev(prev);
+
+        } while (prev != ngx_queue_sentinel(queue));
+
+        ngx_queue_insert_after(prev, q);
+    }
+}
--- a/src/core/ngx_queue.h
+++ b/src/core/ngx_queue.h
@@ -36,6 +36,16 @@ struct ngx_queue_s {
     (h)->next = x
 
 
+#define ngx_queue_insert_after   ngx_queue_insert_head
+
+
+#define ngx_queue_insert_tail(h, x)                                           \
+    (x)->prev = (h)->prev;                                                    \
+    (x)->prev->next = x;                                                      \
+    (x)->next = h;                                                            \
+    (h)->prev = x
+
+
 #define ngx_queue_head(h)                                                     \
     (h)->next
 
@@ -44,6 +54,18 @@ struct ngx_queue_s {
     (h)->prev
 
 
+#define ngx_queue_sentinel(h)                                                 \
+    (h)
+
+
+#define ngx_queue_next(q)                                                     \
+    (q)->next
+
+
+#define ngx_queue_prev(q)                                                     \
+    (q)->prev
+
+
 #if (NGX_DEBUG)
 
 #define ngx_queue_remove(x)                                                   \
@@ -61,8 +83,29 @@ struct ngx_queue_s {
 #endif
 
 
+#define ngx_queue_split(h, q, n)                                              \
+    (n)->prev = (h)->prev;                                                    \
+    (n)->prev->next = n;                                                      \
+    (n)->next = q;                                                            \
+    (h)->prev = (q)->prev;                                                    \
+    (h)->prev->next = h;                                                      \
+    (q)->prev = n;
+
+
+#define ngx_queue_add(h, n)                                                   \
+    (h)->prev->next = (n)->next;                                              \
+    (n)->next->prev = (h)->prev;                                              \
+    (h)->prev = (n)->prev;                                                    \
+    (h)->prev->next = h;
+
+
 #define ngx_queue_data(q, type, link)                                         \
     (type *) ((u_char *) q - offsetof(type, link))
 
 
+ngx_queue_t *ngx_queue_middle(ngx_queue_t *queue);
+void ngx_queue_sort(ngx_queue_t *queue,
+    ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *));
+
+
 #endif /* _NGX_QUEUE_H_INCLUDED_ */
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -446,7 +446,7 @@ ngx_kqueue_set_event(ngx_event_t *ev, ng
     || __FreeBSD_version >= 500018
                                  |NOTE_REVOKE
 #endif
-                                       ;
+                      ;
         kev->data = 0;
 
     } else {
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -942,7 +942,7 @@ ngx_event_connections(ngx_conf_t *cf, ng
     ngx_str_t  *value;
 
     if (ecf->connections != NGX_CONF_UNSET_UINT) {
-        return "is duplicate" ;
+        return "is duplicate";
     }
 
     if (ngx_strcmp(cmd->name.data, "connections") == 0) {
@@ -977,7 +977,7 @@ ngx_event_use(ngx_conf_t *cf, ngx_comman
     ngx_event_module_t   *module;
 
     if (ecf->use != NGX_CONF_UNSET_UINT) {
-        return "is duplicate" ;
+        return "is duplicate";
     }
 
     value = cf->args->elts;
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -1267,6 +1267,29 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng
         return NGX_OK;
     }
 
+    if (builtin_session_cache == NGX_SSL_NONE_SCACHE) {
+
+        /*
+         * If the server explicitly says that it does not support
+         * session reuse (see SSL_SESS_CACHE_OFF above), then
+         * Outlook Express fails to upload a sent email to
+         * the Sent Items folder on the IMAP server via a separate IMAP
+         * connection in the background. Therefore we have a special
+         * mode (SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL_STORE)
+         * where the server pretends that it supports session reuse,
+         * but it does not actually store any session.
+         */
+
+        SSL_CTX_set_session_cache_mode(ssl->ctx,
+                                       SSL_SESS_CACHE_SERVER
+                                       |SSL_SESS_CACHE_NO_AUTO_CLEAR
+                                       |SSL_SESS_CACHE_NO_INTERNAL_STORE);
+
+        SSL_CTX_sess_set_cache_size(ssl->ctx, 1);
+
+        return NGX_OK;
+    }
+
     cache_mode = SSL_SESS_CACHE_SERVER;
 
     if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) {
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -51,9 +51,10 @@ typedef struct {
 } ngx_ssl_connection_t;
 
 
-#define NGX_SSL_DFLT_BUILTIN_SCACHE  -2
-#define NGX_SSL_NO_BUILTIN_SCACHE    -3
-#define NGX_SSL_NO_SCACHE            -4
+#define NGX_SSL_NO_SCACHE            -2
+#define NGX_SSL_NONE_SCACHE          -3
+#define NGX_SSL_NO_BUILTIN_SCACHE    -4
+#define NGX_SSL_DFLT_BUILTIN_SCACHE  -5
 
 
 #define NGX_SSL_MAX_SESSION_SIZE  4096
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -880,7 +880,7 @@ ngx_event_pipe_free_shadow_raw_buf(ngx_c
 
     ll = free;
 
-    for (cl = *free ; cl; cl = cl->next) {
+    for (cl = *free; cl; cl = cl->next) {
         if (cl->buf == s) {
             *ll = cl->next;
             break;
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -138,14 +138,6 @@ static char *ngx_http_fastcgi_upstream_f
 static ngx_conf_post_t  ngx_http_fastcgi_lowat_post =
     { ngx_http_fastcgi_lowat_check };
 
-static ngx_conf_deprecated_t  ngx_conf_deprecated_fastcgi_header_buffer_size = {
-    ngx_conf_deprecated, "fastcgi_header_buffer_size", "fastcgi_buffer_size"
-};
-
-static ngx_conf_deprecated_t  ngx_conf_deprecated_fastcgi_redirect_errors = {
-    ngx_conf_deprecated, "fastcgi_redirect_errors", "fastcgi_intercept_errors"
-};
-
 
 static ngx_conf_bitmask_t  ngx_http_fastcgi_next_upstream_masks[] = {
     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
@@ -224,13 +216,6 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffer_size),
       NULL },
 
-    { ngx_string("fastcgi_header_buffer_size"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffer_size),
-      &ngx_conf_deprecated_fastcgi_header_buffer_size },
-
     { ngx_string("fastcgi_pass_request_headers"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -252,13 +237,6 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.intercept_errors),
       NULL },
 
-    { ngx_string("fastcgi_redirect_errors"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.intercept_errors),
-      &ngx_conf_deprecated_fastcgi_redirect_errors },
-
     { ngx_string("fastcgi_read_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -142,14 +142,6 @@ static ngx_int_t ngx_http_proxy_set_vars
 static ngx_conf_post_t  ngx_http_proxy_lowat_post =
     { ngx_http_proxy_lowat_check };
 
-static ngx_conf_deprecated_t  ngx_conf_deprecated_proxy_header_buffer_size = {
-    ngx_conf_deprecated, "proxy_header_buffer_size", "proxy_buffer_size"
-};
-
-static ngx_conf_deprecated_t  ngx_conf_deprecated_proxy_redirect_errors = {
-    ngx_conf_deprecated, "proxy_redirect_errors", "proxy_intercept_errors"
-};
-
 
 static ngx_conf_bitmask_t  ngx_http_proxy_next_upstream_masks[] = {
     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
@@ -235,13 +227,6 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
       NULL },
 
-    { ngx_string("proxy_redirect_errors"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
-      &ngx_conf_deprecated_proxy_redirect_errors },
-
     { ngx_string("proxy_set_header"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
       ngx_conf_set_keyval_slot,
@@ -298,13 +283,6 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
       NULL },
 
-    { ngx_string("proxy_header_buffer_size"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
-      &ngx_conf_deprecated_proxy_header_buffer_size },
-
     { ngx_string("proxy_read_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -1224,7 +1202,7 @@ ngx_http_proxy_process_header(ngx_http_r
 
     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
 
-    for ( ;;  ) {
+    for ( ;; ) {
 
         rc = ngx_http_parse_header_line(r, &r->upstream->buffer);
 
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -524,7 +524,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_
     ngx_conf_t                    save;
     ngx_http_module_t            *module;
     ngx_http_conf_ctx_t          *ctx, *pctx;
-    ngx_http_core_loc_conf_t     *clcf, *pclcf, **clcfp;
+    ngx_http_core_loc_conf_t     *clcf, *pclcf;
     ngx_http_script_if_code_t    *if_code;
     ngx_http_rewrite_loc_conf_t  *nlcf;
 
@@ -567,21 +567,10 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_
     clcf->name = pclcf->name;
     clcf->noname = 1;
 
-    if (pclcf->locations == NULL) {
-        pclcf->locations = ngx_array_create(cf->pool, 2, sizeof(void *));
-        if (pclcf->locations == NULL) {
-            return NGX_CONF_ERROR;
-        }
-    }
-
-    clcfp = ngx_array_push(pclcf->locations);
-    if (clcfp == NULL) {
+    if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
-    *clcfp = clcf;
-
-
     if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) {
         return NGX_CONF_ERROR;
     }
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -1637,7 +1637,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re
 
         quoted = 0;
 
-        for (i = 0 ; i < text->len; i++) {
+        for (i = 0; i < text->len; i++) {
             ch = text->data[i];
 
             if (!quoted) {
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -415,7 +415,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
     }
 
     ngx_conf_merge_value(conf->builtin_session_cache,
-                         prev->builtin_session_cache, NGX_SSL_NO_SCACHE);
+                         prev->builtin_session_cache, NGX_SSL_NONE_SCACHE);
 
     if (conf->shm_zone == NULL) {
         conf->shm_zone = prev->shm_zone;
@@ -452,6 +452,11 @@ ngx_http_ssl_session_cache(ngx_conf_t *c
             continue;
         }
 
+        if (ngx_strcmp(value[i].data, "none") == 0) {
+            sscf->builtin_session_cache = NGX_SSL_NONE_SCACHE;
+            continue;
+        }
+
         if (ngx_strcmp(value[i].data, "builtin") == 0) {
             sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
             continue;
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.7.0';
+our $VERSION = '0.7.1';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -11,22 +11,48 @@
 
 
 static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static ngx_int_t ngx_http_init_phases(ngx_conf_t *cf,
+    ngx_http_core_main_conf_t *cmcf);
+static ngx_int_t ngx_http_init_headers_in_hash(ngx_conf_t *cf,
+    ngx_http_core_main_conf_t *cmcf);
+static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf,
+    ngx_http_core_main_conf_t *cmcf);
+
+static ngx_int_t ngx_http_init_server_lists(ngx_conf_t *cf,
+    ngx_array_t *servers, ngx_array_t *in_ports);
 static ngx_int_t ngx_http_add_address(ngx_conf_t *cf,
-    ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *lscf,
-    ngx_http_core_srv_conf_t *cscf);
+    ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_port_t *in_port,
+    ngx_http_listen_t *listen);
 static ngx_int_t ngx_http_add_names(ngx_conf_t *cf,
-    ngx_http_conf_in_addr_t *in_addr, ngx_http_core_srv_conf_t *cscf);
+    ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_addr_t *in_addr);
+
 static char *ngx_http_merge_locations(ngx_conf_t *cf,
-    ngx_array_t *locations, void **loc_conf, ngx_http_module_t *module,
+    ngx_queue_t *locations, void **loc_conf, ngx_http_module_t *module,
     ngx_uint_t ctx_index);
+static ngx_int_t ngx_http_init_locations(ngx_conf_t *cf,
+    ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf);
+static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf,
+    ngx_http_core_loc_conf_t *pclcf);
+static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one,
+    const ngx_queue_t *two);
+static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf,
+    ngx_queue_t *locations);
+static void ngx_http_create_locations_list(ngx_queue_t *locations,
+    ngx_queue_t *q);
+static ngx_http_location_tree_node_t *
+    ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations,
+    size_t prefix);
+
+static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf,
+    ngx_http_core_main_conf_t *cmcf, ngx_array_t *in_ports);
 static ngx_int_t ngx_http_cmp_conf_in_addrs(const void *one, const void *two);
 static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one,
     const void *two);
 
-ngx_uint_t   ngx_http_max_module;
+static ngx_int_t ngx_http_init_listening(ngx_conf_t *cf,
+    ngx_http_conf_in_port_t *in_port);
 
-ngx_uint_t   ngx_http_total_requests;
-uint64_t     ngx_http_total_sent;
+ngx_uint_t   ngx_http_max_module;
 
 
 ngx_int_t  (*ngx_http_top_header_filter) (ngx_http_request_t *r);
@@ -73,34 +99,14 @@ static char *
 ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char                        *rv;
-    ngx_int_t                    rc, j;
-    ngx_uint_t                   mi, m, s, l, p, a, i, n;
-    ngx_uint_t                   find_config_index, use_rewrite, use_access;
-    ngx_uint_t                   last, bind_all, done;
+    ngx_uint_t                   mi, m, s;
     ngx_conf_t                   pcf;
-    ngx_array_t                  headers_in, in_ports;
-    ngx_hash_key_t              *hk;
-    ngx_hash_init_t              hash;
-    ngx_listening_t             *ls;
-    ngx_http_listen_t           *lscf;
+    ngx_array_t                  in_ports;
     ngx_http_module_t           *module;
-    ngx_http_header_t           *header;
-    ngx_http_in_port_t          *hip;
-    ngx_http_handler_pt         *h;
     ngx_http_conf_ctx_t         *ctx;
-    ngx_http_conf_in_port_t     *in_port;
-    ngx_http_conf_in_addr_t     *in_addr;
-    ngx_hash_keys_arrays_t       ha;
-    ngx_http_server_name_t      *name;
-    ngx_http_phase_handler_t    *ph;
-    ngx_http_virtual_names_t    *vn;
-    ngx_http_core_srv_conf_t   **cscfp, *cscf;
     ngx_http_core_loc_conf_t    *clcf;
-    ngx_http_phase_handler_pt    checker;
+    ngx_http_core_srv_conf_t   **cscfp;
     ngx_http_core_main_conf_t   *cmcf;
-#if (NGX_PCRE)
-    ngx_uint_t                   regex;
-#endif
 
     /* the main http context */
 
@@ -199,7 +205,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
         }
 
         module = ngx_modules[m]->ctx;
-        mi = ngx_modules[m]->ctx_index;
 
         if (module->preconfiguration) {
             if (module->preconfiguration(cf) != NGX_OK) {
@@ -215,8 +220,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     rv = ngx_conf_parse(cf, NULL);
 
     if (rv != NGX_CONF_OK) {
-        *cf = pcf;
-        return rv;
+        goto failed;
     }
 
     /*
@@ -240,8 +244,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
         if (module->init_main_conf) {
             rv = module->init_main_conf(cf, ctx->main_conf[mi]);
             if (rv != NGX_CONF_OK) {
-                *cf = pcf;
-                return rv;
+                goto failed;
             }
         }
 
@@ -250,12 +253,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
             /* merge the server{}s' srv_conf's */
 
             if (module->merge_srv_conf) {
-                rv = module->merge_srv_conf(cf,
-                                            ctx->srv_conf[mi],
+                rv = module->merge_srv_conf(cf, ctx->srv_conf[mi],
                                             cscfp[s]->ctx->srv_conf[mi]);
                 if (rv != NGX_CONF_OK) {
-                    *cf = pcf;
-                    return rv;
+                    goto failed;
                 }
             }
 
@@ -263,112 +264,48 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
 
                 /* merge the server{}'s loc_conf */
 
-                rv = module->merge_loc_conf(cf,
-                                            ctx->loc_conf[mi],
+                rv = module->merge_loc_conf(cf, ctx->loc_conf[mi],
                                             cscfp[s]->ctx->loc_conf[mi]);
                 if (rv != NGX_CONF_OK) {
-                    *cf = pcf;
-                    return rv;
+                    goto failed;
                 }
 
                 /* merge the locations{}' loc_conf's */
 
-                rv = ngx_http_merge_locations(cf, &cscfp[s]->locations,
+                clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
+
+                rv = ngx_http_merge_locations(cf, clcf->locations,
                                               cscfp[s]->ctx->loc_conf,
                                               module, mi);
                 if (rv != NGX_CONF_OK) {
-                    *cf = pcf;
-                    return rv;
+                    goto failed;
                 }
             }
         }
     }
 
 
-    /* init lists of the handlers */
-
-    if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers,
-                       cf->pool, 1, sizeof(ngx_http_handler_pt))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
+    /* create location trees */
 
+    for (s = 0; s < cmcf->servers.nelts; s++) {
 
-    if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers,
-                       cf->pool, 1, sizeof(ngx_http_handler_pt))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
+        clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
 
-    if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
-                       cf->pool, 1, sizeof(ngx_http_handler_pt))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
+        if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
 
-    if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers,
-                       cf->pool, 1, sizeof(ngx_http_handler_pt))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-
-    if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,
-                       cf->pool, 2, sizeof(ngx_http_handler_pt))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
+        if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
     }
 
 
-    if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
-                       cf->pool, 4, sizeof(ngx_http_handler_pt))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-
-    if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers,
-                       cf->pool, 1, sizeof(ngx_http_handler_pt))
-        != NGX_OK)
-    {
+    if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
-
-    if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-    for (header = ngx_http_headers_in; header->name.len; header++) {
-        hk = ngx_array_push(&headers_in);
-        if (hk == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        hk->key = header->name;
-        hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
-        hk->value = header;
-    }
-
-    hash.hash = &cmcf->headers_in_hash;
-    hash.key = ngx_hash_key_lc;
-    hash.max_size = 512;
-    hash.bucket_size = ngx_align(64, ngx_cacheline_size);
-    hash.name = "headers_in_hash";
-    hash.pool = cf->pool;
-    hash.temp_pool = NULL;
-
-    if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
+    if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
@@ -379,7 +316,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
         }
 
         module = ngx_modules[m]->ctx;
-        mi = ngx_modules[m]->ctx_index;
 
         if (module->postconfiguration) {
             if (module->postconfiguration(cf) != NGX_OK) {
@@ -400,6 +336,148 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     *cf = pcf;
 
 
+    if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+
+    /*
+     * create the lists of ports, addresses and server names
+     * to find quickly the server core module configuration at run-time
+     */
+
+    /* AF_INET only */
+
+    if (ngx_http_init_server_lists(cf, &cmcf->servers, &in_ports) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+
+    /* optimize the lists of ports, addresses and server names */
+
+    /* AF_INET only */
+
+    if (ngx_http_optimize_servers(cf, cmcf, &in_ports) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+
+failed:
+
+    *cf = pcf;
+
+    return rv;
+}
+
+
+static ngx_int_t
+ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
+{
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers,
+                       cf->pool, 1, sizeof(ngx_http_handler_pt))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers,
+                       cf->pool, 1, sizeof(ngx_http_handler_pt))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
+                       cf->pool, 1, sizeof(ngx_http_handler_pt))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers,
+                       cf->pool, 1, sizeof(ngx_http_handler_pt))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,
+                       cf->pool, 2, sizeof(ngx_http_handler_pt))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
+                       cf->pool, 4, sizeof(ngx_http_handler_pt))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers,
+                       cf->pool, 1, sizeof(ngx_http_handler_pt))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_init_headers_in_hash(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
+{
+    ngx_array_t         headers_in;
+    ngx_hash_key_t     *hk;
+    ngx_hash_init_t     hash;
+    ngx_http_header_t  *header;
+
+    if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
+        != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    for (header = ngx_http_headers_in; header->name.len; header++) {
+        hk = ngx_array_push(&headers_in);
+        if (hk == NULL) {
+            return NGX_ERROR;
+        }
+
+        hk->key = header->name;
+        hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
+        hk->value = header;
+    }
+
+    hash.hash = &cmcf->headers_in_hash;
+    hash.key = ngx_hash_key_lc;
+    hash.max_size = 512;
+    hash.bucket_size = ngx_align(64, ngx_cacheline_size);
+    hash.name = "headers_in_hash";
+    hash.pool = cf->pool;
+    hash.temp_pool = NULL;
+
+    if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
+{
+    ngx_int_t                   j;
+    ngx_uint_t                  i, n;
+    ngx_uint_t                  find_config_index, use_rewrite, use_access;
+    ngx_http_handler_pt        *h;
+    ngx_http_phase_handler_t   *ph;
+    ngx_http_phase_handler_pt   checker;
+
     cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1;
     cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1;
     find_config_index = 0;
@@ -415,7 +493,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     ph = ngx_pcalloc(cf->pool,
                      n * sizeof(ngx_http_phase_handler_t) + sizeof(void *));
     if (ph == NULL) {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     cmcf->phase_engine.handlers = ph;
@@ -493,35 +571,548 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
         }
     }
 
+    return NGX_OK;
+}
 
-    /*
-     * create the lists of ports, addresses and server names
-     * to quickly find the server core module configuration at run-time
-     */
+
+static char *
+ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations,
+    void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index)
+{
+    char                       *rv;
+    ngx_queue_t                *q;
+    ngx_http_core_loc_conf_t   *clcf;
+    ngx_http_location_queue_t  *lq;
+
+    if (locations == NULL) {
+        return NGX_CONF_OK;
+    }
+
+    for (q = ngx_queue_head(locations);
+         q != ngx_queue_sentinel(locations);
+         q = ngx_queue_next(q))
+    {
+        lq = (ngx_http_location_queue_t *) q;
+
+        clcf = lq->exact ? lq->exact : lq->inclusive;
+
+        rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
+                                    clcf->loc_conf[ctx_index]);
+        if (rv != NGX_CONF_OK) {
+            return rv;
+        }
+
+        rv = ngx_http_merge_locations(cf, clcf->locations, clcf->loc_conf,
+                                      module, ctx_index);
+        if (rv != NGX_CONF_OK) {
+            return rv;
+        }
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
+    ngx_http_core_loc_conf_t *pclcf)
+{
+    ngx_uint_t                   n;
+    ngx_queue_t                 *q, *locations, *named, tail;
+    ngx_http_core_loc_conf_t    *clcf;
+    ngx_http_location_queue_t   *lq;
+    ngx_http_core_loc_conf_t   **clcfp;
+#if (NGX_PCRE)
+    ngx_uint_t                   r;
+    ngx_queue_t                 *regex;
+#endif
+
+    locations = pclcf->locations;
+
+    if (locations == NULL) {
+        return NGX_OK;
+    }
+
+    ngx_queue_sort(locations, ngx_http_cmp_locations);
+
+    named = NULL;
+    n = 0;
+#if (NGX_PCRE)
+    regex = NULL;
+    r = 0;
+#endif
+
+    for (q = ngx_queue_head(locations);
+         q != ngx_queue_sentinel(locations);
+         q = ngx_queue_next(q))
+    {
+        lq = (ngx_http_location_queue_t *) q;
+
+        clcf = lq->exact ? lq->exact : lq->inclusive;
+
+        if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+#if (NGX_PCRE)
+
+        if (clcf->regex) {
+            r++;
+
+            if (regex == NULL) {
+                regex = q;
+            }
+
+            continue;
+        }
+
+#endif
+
+        if (clcf->named) {
+            n++;
+
+            if (named == NULL) {
+                named = q;
+            }
+
+            continue;
+        }
+
+        if (clcf->noname) {
+            break;
+        }
+    }
+
+    if (q != ngx_queue_sentinel(locations)) {
+        ngx_queue_split(locations, q, &tail);
+    }
+
+    if (named) {
+        clcfp = ngx_palloc(cf->pool,
+                           (n + 1) * sizeof(ngx_http_core_loc_conf_t **));
+        if (clcfp == NULL) {
+            return NGX_ERROR;
+        }
+
+        cscf->named_locations = clcfp;
+
+        for (q = named;
+             q != ngx_queue_sentinel(locations);
+             q = ngx_queue_next(q))
+        {
+            lq = (ngx_http_location_queue_t *) q;
+
+            *(clcfp++) = lq->exact;
+        }
+
+        *clcfp = NULL;
+
+        ngx_queue_split(locations, named, &tail);
+    }
+
+#if (NGX_PCRE)
+
+    if (regex) {
+
+        clcfp = ngx_palloc(cf->pool,
+                           (r + 1) * sizeof(ngx_http_core_loc_conf_t **));
+        if (clcfp == NULL) {
+            return NGX_ERROR;
+        }
+
+        pclcf->regex_locations = clcfp;
+
+        for (q = regex;
+             q != ngx_queue_sentinel(locations);
+             q = ngx_queue_next(q))
+        {
+            lq = (ngx_http_location_queue_t *) q;
+
+            *(clcfp++) = lq->exact;
+        }
+
+        *clcfp = NULL;
+
+        ngx_queue_split(locations, regex, &tail);
+    }
+
+#endif
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_init_static_location_trees(ngx_conf_t *cf,
+    ngx_http_core_loc_conf_t *pclcf)
+{
+    ngx_queue_t                *q, *locations;
+    ngx_http_core_loc_conf_t   *clcf;
+    ngx_http_location_queue_t  *lq;
+
+    locations = pclcf->locations;
+
+    if (locations == NULL) {
+        return NGX_OK;
+    }
+
+    if (ngx_queue_empty(locations)) {
+        return NGX_OK;
+    }
+
+    for (q = ngx_queue_head(locations);
+         q != ngx_queue_sentinel(locations);
+         q = ngx_queue_next(q))
+    {
+        lq = (ngx_http_location_queue_t *) q;
+
+        clcf = lq->exact ? lq->exact : lq->inclusive;
+
+        if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
+            return NGX_ERROR;
+        }
+    }
+
+    if (ngx_http_join_exact_locations(cf, locations) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    ngx_http_create_locations_list(locations, ngx_queue_head(locations));
+
+    pclcf->static_locations = ngx_http_create_locations_tree(cf, locations, 0);
+    if (pclcf->static_locations == NULL) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
+    ngx_http_core_loc_conf_t *clcf)
+{
+    ngx_http_location_queue_t  *lq;
+
+    if (*locations == NULL) {
+        *locations = ngx_palloc(cf->temp_pool,
+                                sizeof(ngx_http_location_queue_t));
+        if (*locations == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_queue_init(*locations);
+    }
+
+    lq = ngx_palloc(cf->temp_pool, sizeof(ngx_http_location_queue_t));
+    if (lq == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (clcf->exact_match
+#if (NGX_PCRE)
+        || clcf->regex
+#endif
+        || clcf->named || clcf->noname)
+    {
+        lq->exact = clcf;
+        lq->inclusive = NULL;
+
+    } else {
+        lq->exact = NULL;
+        lq->inclusive = clcf;
+    }
+
+    lq->name = &clcf->name;
+    lq->file_name = cf->conf_file->file.name.data;
+    lq->line = cf->conf_file->line;
+
+    ngx_queue_init(&lq->list);
+
+    ngx_queue_insert_tail(*locations, &lq->queue);
 
-    if (ngx_array_init(&in_ports, cf->temp_pool, 2,
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two)
+{
+    ngx_int_t                   rc;
+    ngx_http_core_loc_conf_t   *first, *second;
+    ngx_http_location_queue_t  *lq1, *lq2;
+
+    lq1 = (ngx_http_location_queue_t *) one;
+    lq2 = (ngx_http_location_queue_t *) two;
+
+    first = lq1->exact ? lq1->exact : lq1->inclusive;
+    second = lq2->exact ? lq2->exact : lq2->inclusive;
+
+    if (first->noname && !second->noname) {
+        /* shift no named locations to the end */
+        return 1;
+    }
+
+    if (!first->noname && second->noname) {
+        /* shift no named locations to the end */
+        return -1;
+    }
+
+    if (first->noname || second->noname) {
+        /* do not sort no named locations */
+        return 0;
+    }
+
+    if (first->named && !second->named) {
+        /* shift named locations to the end */
+        return 1;
+    }
+
+    if (!first->named && second->named) {
+        /* shift named locations to the end */
+        return -1;
+    }
+
+    if (first->named && second->named) {
+        return ngx_strcmp(first->name.data, second->name.data);
+    }
+
+#if (NGX_PCRE)
+
+    if (first->regex && !second->regex) {
+        /* shift the regex matches to the end */
+        return 1;
+    }
+
+    if (!first->regex && second->regex) {
+        /* shift the regex matches to the end */
+        return -1;
+    }
+
+    if (first->regex || second->regex) {
+        /* do not sort the regex matches */
+        return 0;
+    }
+
+#endif
+
+    rc = ngx_strcmp(first->name.data, second->name.data);
+
+    if (rc == 0 && !first->exact_match && second->exact_match) {
+        /* an exact match must be before the same inclusive one */
+        return 1;
+    }
+
+    return rc;
+}
+
+
+static ngx_int_t
+ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations)
+{
+    ngx_queue_t                *q, *x;
+    ngx_http_location_queue_t  *lq, *lx;
+
+    q = ngx_queue_head(locations);
+
+    while (q != ngx_queue_last(locations)) {
+
+        x = ngx_queue_next(q);
+
+        lq = (ngx_http_location_queue_t *) q;
+        lx = (ngx_http_location_queue_t *) x;
+
+        if (ngx_strcmp(lq->name->data, lx->name->data) == 0) {
+
+            if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) {
+                ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                              "duplicate location \"%V\" in %s:%ui",
+                              lx->name, lx->file_name, lx->line);
+
+                return NGX_ERROR;
+            }
+
+            lq->inclusive = lx->inclusive;
+
+            ngx_queue_remove(x);
+
+            continue;
+        }
+
+        q = ngx_queue_next(q);
+    }
+
+    return NGX_OK;
+}
+
+
+static void
+ngx_http_create_locations_list(ngx_queue_t *locations, ngx_queue_t *q)
+{
+    u_char                     *name;
+    size_t                      len;
+    ngx_queue_t                *x, tail;
+    ngx_http_location_queue_t  *lq, *lx;
+
+    if (q == ngx_queue_last(locations)) {
+        return;
+    }
+
+    lq = (ngx_http_location_queue_t *) q;
+
+    if (lq->inclusive == NULL) {
+        ngx_http_create_locations_list(locations, ngx_queue_next(q));
+        return;
+    }
+
+    len = lq->name->len;
+    name = lq->name->data;
+
+    for (x = ngx_queue_next(q);
+         x != ngx_queue_sentinel(locations);
+         x = ngx_queue_next(x))
+    {
+        lx = (ngx_http_location_queue_t *) x;
+
+        if (len > lx->name->len
+            || (ngx_strncmp(name, lx->name->data, len) != 0))
+        {
+            break;
+        }
+    }
+
+    q = ngx_queue_next(q);
+
+    if (q == x) {
+        ngx_http_create_locations_list(locations, x);
+        return;
+    }
+
+    ngx_queue_split(locations, q, &tail);
+    ngx_queue_add(&lq->list, &tail);
+
+    if (x == ngx_queue_sentinel(locations)) {
+        ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list));
+        return;
+    }
+
+    ngx_queue_split(&lq->list, x, &tail);
+    ngx_queue_add(locations, &tail);
+
+    ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list));
+
+    ngx_http_create_locations_list(locations, x);
+}
+
+
+/*
+ * to keep cache locality for left leaf nodes, allocate nodes in following
+ * order: node, left subtree, right subtree, inclusive subtree
+ */
+
+static ngx_http_location_tree_node_t *
+ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations,
+    size_t prefix)
+{
+    size_t                          len;
+    ngx_queue_t                    *q, tail;
+    ngx_http_location_queue_t      *lq;
+    ngx_http_location_tree_node_t  *node;
+
+    q = ngx_queue_middle(locations);
+
+    lq = (ngx_http_location_queue_t *) q;
+    len = lq->name->len - prefix;
+
+    node = ngx_pcalloc(cf->pool,
+                       offsetof(ngx_http_location_tree_node_t, name) + len);
+    if (node == NULL) {
+        return NULL;
+    }
+
+    node->exact = lq->exact;
+    node->inclusive = lq->inclusive;
+
+    node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect)
+                           || (lq->inclusive && lq->inclusive->auto_redirect));
+
+    node->len = (u_char) len;
+    ngx_memcpy(node->name, &lq->name->data[prefix], len);
+
+    ngx_queue_split(locations, q, &tail);
+
+    if (ngx_queue_empty(locations)) {
+        /*
+         * ngx_queue_split() insures that if left part is empty,
+         * then right one is empty too
+         */
+        goto inclusive;
+    }
+
+    node->left = ngx_http_create_locations_tree(cf, locations, prefix);
+    if (node->left == NULL) {
+        return NULL;
+    }
+
+    ngx_queue_remove(q);
+
+    if (ngx_queue_empty(&tail)) {
+        goto inclusive;
+    }
+
+    node->right = ngx_http_create_locations_tree(cf, &tail, prefix);
+    if (node->right == NULL) {
+        return NULL;
+    }
+
+inclusive:
+
+    if (ngx_queue_empty(&lq->list)) {
+        return node;
+    }
+
+    node->tree = ngx_http_create_locations_tree(cf, &lq->list, prefix + len);
+    if (node->tree == NULL) {
+        return NULL;
+    }
+
+    return node;
+}
+
+
+static ngx_int_t
+ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers,
+    ngx_array_t *in_ports)
+{
+    ngx_uint_t                  s, l, p, a;
+    ngx_http_listen_t          *listen;
+    ngx_http_conf_in_port_t    *in_port;
+    ngx_http_conf_in_addr_t    *in_addr;
+    ngx_http_core_srv_conf_t  **cscfp;
+
+    if (ngx_array_init(in_ports, cf->temp_pool, 2,
                        sizeof(ngx_http_conf_in_port_t))
         != NGX_OK)
     {
-        return NGX_CONF_ERROR;
+        return NGX_ERROR;
     }
 
     /* "server" directives */
 
-    cscfp = cmcf->servers.elts;
-    for (s = 0; s < cmcf->servers.nelts; s++) {
+    cscfp = servers->elts;
+    for (s = 0; s < servers->nelts; s++) {
 
         /* "listen" directives */
 
-        lscf = cscfp[s]->listen.elts;
+        listen = cscfp[s]->listen.elts;
         for (l = 0; l < cscfp[s]->listen.nelts; l++) {
 
             /* AF_INET only */
 
-            in_port = in_ports.elts;
-            for (p = 0; p < in_ports.nelts; p++) {
+            in_port = in_ports->elts;
+            for (p = 0; p < in_ports->nelts; p++) {
 
-                if (lscf[l].port != in_port[p].port) {
+                if (listen[l].port != in_port[p].port) {
                     continue;
                 }
 
@@ -530,15 +1121,15 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
                 in_addr = in_port[p].addrs.elts;
                 for (a = 0; a < in_port[p].addrs.nelts; a++) {
 
-                    if (lscf[l].addr != in_addr[a].addr) {
+                    if (listen[l].addr != in_addr[a].addr) {
                         continue;
                     }
 
                     /* the address is already in the address list */
 
-                    if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) != NGX_OK)
+                    if (ngx_http_add_names(cf, cscfp[s], &in_addr[a]) != NGX_OK)
                     {
-                        return NGX_CONF_ERROR;
+                        return NGX_ERROR;
                     }
 
                     /*
@@ -546,14 +1137,14 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
                      * for this address:port
                      */
 
-                    if (lscf[l].conf.default_server) {
+                    if (listen[l].conf.default_server) {
 
                         if (in_addr[a].default_server) {
                             ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                       "the duplicate default server in %s:%ui",
-                                       lscf[l].file_name, lscf[l].line);
+                                       listen[l].file_name, listen[l].line);
 
-                            return NGX_CONF_ERROR;
+                            return NGX_ERROR;
                         }
 
                         in_addr[a].core_srv_conf = cscfp[s];
@@ -568,10 +1159,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
                  * bound to this port
                  */
 
-                if (ngx_http_add_address(cf, &in_port[p], &lscf[l], cscfp[s])
+                if (ngx_http_add_address(cf, cscfp[s], &in_port[p], &listen[l])
                     != NGX_OK)
                 {
-                    return NGX_CONF_ERROR;
+                    return NGX_ERROR;
                 }
 
                 goto found;
@@ -579,17 +1170,18 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
 
             /* add the port to the in_port list */
 
-            in_port = ngx_array_push(&in_ports);
+            in_port = ngx_array_push(in_ports);
             if (in_port == NULL) {
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
 
-            in_port->port = lscf[l].port;
+            in_port->port = listen[l].port;
             in_port->addrs.elts = NULL;
 
-            if (ngx_http_add_address(cf, in_port, &lscf[l], cscfp[s]) != NGX_OK)
+            if (ngx_http_add_address(cf, cscfp[s], in_port, &listen[l])
+                != NGX_OK)
             {
-                return NGX_CONF_ERROR;
+                return NGX_ERROR;
             }
 
         found:
@@ -598,364 +1190,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
         }
     }
 
-
-    /* optimize the lists of ports, addresses and server names */
-
-    /* AF_INET only */
-
-    in_port = in_ports.elts;
-    for (p = 0; p < in_ports.nelts; p++) {
-
-        ngx_sort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts,
-                 sizeof(ngx_http_conf_in_addr_t), ngx_http_cmp_conf_in_addrs);
-
-        /*
-         * check whether all name-based servers have the same configuraiton
-         *     as the default server,
-         * or some servers disable optimizing the server names
-         */
-
-        in_addr = in_port[p].addrs.elts;
-        for (a = 0; a < in_port[p].addrs.nelts; a++) {
-
-            name = in_addr[a].names.elts;
-            for (s = 0; s < in_addr[a].names.nelts; s++) {
-
-                if (in_addr[a].core_srv_conf != name[s].core_srv_conf
-                    || name[s].core_srv_conf->optimize_server_names == 0)
-                {
-                    goto virtual_names;
-                }
-            }
-
-            /*
-             * if all name-based servers have the same configuration
-             *         as the default server,
-             *     and no servers disable optimizing the server names
-             * then we do not need to check them at run-time at all
-             */
-
-            in_addr[a].names.nelts = 0;
-
-            continue;
-
-        virtual_names:
-
-            ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t));
-
-            ha.temp_pool = ngx_create_pool(16384, cf->log);
-            if (ha.temp_pool == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            ha.pool = cf->pool;
-
-            if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) {
-                ngx_destroy_pool(ha.temp_pool);
-                return NGX_CONF_ERROR;
-            }
-
-#if (NGX_PCRE)
-            regex = 0;
-#endif
-
-            name = in_addr[a].names.elts;
-
-            for (s = 0; s < in_addr[a].names.nelts; s++) {
-
-#if (NGX_PCRE)
-                if (name[s].regex) {
-                    regex++;
-                    continue;
-                }
-#endif
-
-                rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf,
-                                      NGX_HASH_WILDCARD_KEY);
-
-                if (rc == NGX_ERROR) {
-                    return NGX_CONF_ERROR;
-                }
-
-                if (rc == NGX_DECLINED) {
-                    ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                                "invalid server name or wildcard \"%V\" on %s",
-                                &name[s].name, in_addr[a].listen_conf->addr);
-                    return NGX_CONF_ERROR;
-                }
-
-                if (rc == NGX_BUSY) {
-                    ngx_log_error(NGX_LOG_WARN, cf->log, 0,
-                                "conflicting server name \"%V\" on %s, ignored",
-                                &name[s].name, in_addr[a].listen_conf->addr);
-                }
-            }
-
-            hash.key = ngx_hash_key_lc;
-            hash.max_size = cmcf->server_names_hash_max_size;
-            hash.bucket_size = cmcf->server_names_hash_bucket_size;
-            hash.name = "server_names_hash";
-            hash.pool = cf->pool;
-
-            if (ha.keys.nelts) {
-                hash.hash = &in_addr[a].hash;
-                hash.temp_pool = NULL;
-
-                if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK)
-                {
-                    ngx_destroy_pool(ha.temp_pool);
-                    return NGX_CONF_ERROR;
-                }
-            }
-
-            if (ha.dns_wc_head.nelts) {
-
-                ngx_qsort(ha.dns_wc_head.elts,
-                          (size_t) ha.dns_wc_head.nelts,
-                          sizeof(ngx_hash_key_t),
-                          ngx_http_cmp_dns_wildcards);
-
-                hash.hash = NULL;
-                hash.temp_pool = ha.temp_pool;
-
-                if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts,
-                                           ha.dns_wc_head.nelts)
-                    != NGX_OK)
-                {
-                    ngx_destroy_pool(ha.temp_pool);
-                    return NGX_CONF_ERROR;
-                }
-
-                in_addr[a].wc_head = (ngx_hash_wildcard_t *) hash.hash;
-            }
-
-            if (ha.dns_wc_tail.nelts) {
-
-                ngx_qsort(ha.dns_wc_tail.elts,
-                          (size_t) ha.dns_wc_tail.nelts,
-                          sizeof(ngx_hash_key_t),
-                          ngx_http_cmp_dns_wildcards);
-
-                hash.hash = NULL;
-                hash.temp_pool = ha.temp_pool;
-
-                if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts,
-                                           ha.dns_wc_tail.nelts)
-                    != NGX_OK)
-                {
-                    ngx_destroy_pool(ha.temp_pool);
-                    return NGX_CONF_ERROR;
-                }
-
-                in_addr[a].wc_tail = (ngx_hash_wildcard_t *) hash.hash;
-            }
-
-            ngx_destroy_pool(ha.temp_pool);
-
-#if (NGX_PCRE)
-
-            if (regex == 0) {
-                continue;
-            }
-
-            in_addr[a].nregex = regex;
-            in_addr[a].regex = ngx_palloc(cf->pool,
-                                       regex * sizeof(ngx_http_server_name_t));
-
-            if (in_addr[a].regex == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            for (i = 0, s = 0; s < in_addr[a].names.nelts; s++) {
-                if (name[s].regex) {
-                    in_addr[a].regex[i++] = name[s];
-                }
-            }
-#endif
-        }
-
-        in_addr = in_port[p].addrs.elts;
-        last = in_port[p].addrs.nelts;
-
-        /*
-         * if there is the binding to the "*:port" then we need to bind()
-         * to the "*:port" only and ignore the other bindings
-         */
-
-        if (in_addr[last - 1].addr == INADDR_ANY) {
-            in_addr[last - 1].bind = 1;
-            bind_all = 0;
-
-        } else {
-            bind_all = 1;
-        }
-
-        for (a = 0; a < last; /* void */ ) {
-
-            if (!bind_all && !in_addr[a].bind) {
-                a++;
-                continue;
-            }
-
-            ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr,
-                                                  in_port[p].port);
-            if (ls == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            ls->addr_ntop = 1;
-
-            ls->handler = ngx_http_init_connection;
-
-            cscf = in_addr[a].core_srv_conf;
-            ls->pool_size = cscf->connection_pool_size;
-            ls->post_accept_timeout = cscf->client_header_timeout;
-
-            clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
-
-            ls->log = *clcf->err_log;
-            ls->log.data = &ls->addr_text;
-            ls->log.handler = ngx_accept_log_error;
-
-#if (NGX_WIN32)
-            {
-            ngx_iocp_conf_t  *iocpcf;
-
-            iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module);
-            if (iocpcf->acceptex_read) {
-                ls->post_accept_buffer_size = cscf->client_header_buffer_size;
-            }
-            }
-#endif
-
-            ls->backlog = in_addr[a].listen_conf->backlog;
-            ls->rcvbuf = in_addr[a].listen_conf->rcvbuf;
-            ls->sndbuf = in_addr[a].listen_conf->sndbuf;
-
-#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
-            ls->accept_filter = in_addr[a].listen_conf->accept_filter;
-#endif
-
-#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
-            ls->deferred_accept = in_addr[a].listen_conf->deferred_accept;
-#endif
-
-            hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t));
-            if (hip == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            hip->port = in_port[p].port;
-
-            hip->port_text.data = ngx_palloc(cf->pool, 7);
-            if (hip->port_text.data == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            ls->servers = hip;
-
-            hip->port_text.len = ngx_sprintf(hip->port_text.data, ":%d",
-                                             hip->port)
-                                 - hip->port_text.data;
-
-            in_addr = in_port[p].addrs.elts;
-
-            if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) {
-                hip->naddrs = 1;
-                done = 0;
-
-            } else if (in_port[p].addrs.nelts > 1
-                       && in_addr[last - 1].addr == INADDR_ANY)
-            {
-                hip->naddrs = last;
-                done = 1;
-
-            } else {
-                hip->naddrs = 1;
-                done = 0;
-            }
-
-#if 0
-            ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
-                          "%ui: %V %d %ui %ui",
-                          a, &ls->addr_text, in_addr[a].bind,
-                          hip->naddrs, last);
-#endif
-
-            hip->addrs = ngx_pcalloc(cf->pool,
-                                     hip->naddrs * sizeof(ngx_http_in_addr_t));
-            if (hip->addrs == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            for (i = 0; i < hip->naddrs; i++) {
-                hip->addrs[i].addr = in_addr[i].addr;
-                hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf;
-
-                if (in_addr[i].hash.buckets == NULL
-                    && (in_addr[i].wc_head == NULL
-                        || in_addr[i].wc_head->hash.buckets == NULL)
-                    && (in_addr[i].wc_head == NULL
-                        || in_addr[i].wc_head->hash.buckets == NULL))
-                {
-                    continue;
-                }
-
-                vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));
-                if (vn == NULL) {
-                    return NGX_CONF_ERROR;
-                }
-                hip->addrs[i].virtual_names = vn;
-
-                vn->names.hash = in_addr[i].hash;
-                vn->names.wc_head = in_addr[i].wc_head;
-                vn->names.wc_tail = in_addr[i].wc_tail;
-#if (NGX_PCRE)
-                vn->nregex = in_addr[i].nregex;
-                vn->regex = in_addr[i].regex;
-#endif
-            }
-
-            if (done) {
-                break;
-            }
-
-            in_addr++;
-            in_port[p].addrs.elts = in_addr;
-            last--;
-
-            a = 0;
-        }
-    }
-
-#if 0
-    {
-    u_char      address[20];
-    ngx_uint_t  p, a;
-
-    in_port = in_ports.elts;
-    for (p = 0; p < in_ports.nelts; p++) {
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-                      "port: %d %p", in_port[p].port, &in_port[p]);
-        in_addr = in_port[p].addrs.elts;
-        for (a = 0; a < in_port[p].addrs.nelts; a++) {
-            ngx_inet_ntop(AF_INET, &in_addr[a].addr, address, 20);
-            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-                           "%s:%d %p",
-                           address, in_port[p].port, in_addr[a].core_srv_conf);
-            name = in_addr[a].names.elts;
-            for (n = 0; n < in_addr[a].names.nelts; n++) {
-                 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-                                "%s:%d %V %p",
-                                address, in_port[p].port, &name[n].name,
-                                name[n].core_srv_conf);
-            }
-        }
-    }
-    }
-#endif
-
-    return NGX_CONF_OK;
+    return NGX_OK;
 }
 
 
@@ -965,8 +1200,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
  */
 
 static ngx_int_t
-ngx_http_add_address(ngx_conf_t *cf, ngx_http_conf_in_port_t *in_port,
-    ngx_http_listen_t *lscf, ngx_http_core_srv_conf_t *cscf)
+ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
+     ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *listen)
 {
     ngx_http_conf_in_addr_t  *in_addr;
 
@@ -984,7 +1219,7 @@ ngx_http_add_address(ngx_conf_t *cf, ngx
         return NGX_ERROR;
     }
 
-    in_addr->addr = lscf->addr;
+    in_addr->addr = listen->addr;
     in_addr->hash.buckets = NULL;
     in_addr->hash.size = 0;
     in_addr->wc_head = NULL;
@@ -995,9 +1230,9 @@ ngx_http_add_address(ngx_conf_t *cf, ngx
     in_addr->regex = NULL;
 #endif
     in_addr->core_srv_conf = cscf;
-    in_addr->default_server = lscf->conf.default_server;
-    in_addr->bind = lscf->conf.bind;
-    in_addr->listen_conf = &lscf->conf;
+    in_addr->default_server = listen->conf.default_server;
+    in_addr->bind = listen->conf.bind;
+    in_addr->listen_conf = &listen->conf;
 
 #if (NGX_DEBUG)
     {
@@ -1008,7 +1243,7 @@ ngx_http_add_address(ngx_conf_t *cf, ngx
     }
 #endif
 
-    return ngx_http_add_names(cf, in_addr, cscf);
+    return ngx_http_add_names(cf, cscf, in_addr);
 }
 
 
@@ -1018,8 +1253,8 @@ ngx_http_add_address(ngx_conf_t *cf, ngx
  */
 
 static ngx_int_t
-ngx_http_add_names(ngx_conf_t *cf, ngx_http_conf_in_addr_t *in_addr,
-    ngx_http_core_srv_conf_t *cscf)
+ngx_http_add_names(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
+    ngx_http_conf_in_addr_t *in_addr)
 {
     ngx_uint_t               i, n;
     ngx_http_server_name_t  *server_names, *name;
@@ -1057,35 +1292,196 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h
 }
 
 
-static char *
-ngx_http_merge_locations(ngx_conf_t *cf, ngx_array_t *locations,
-    void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index)
+static ngx_int_t
+ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
+    ngx_array_t *in_ports)
 {
-    char                       *rv;
-    ngx_uint_t                  i;
-    ngx_http_core_loc_conf_t  **clcfp;
+    ngx_int_t                  rc;
+    ngx_uint_t                 s, p, a, i;
+    ngx_hash_init_t            hash;
+    ngx_http_server_name_t    *name;
+    ngx_hash_keys_arrays_t     ha;
+    ngx_http_conf_in_port_t   *in_port;
+    ngx_http_conf_in_addr_t   *in_addr;
+#if (NGX_PCRE)
+    ngx_uint_t                 regex;
+#endif
+
+    in_port = in_ports->elts;
+    for (p = 0; p < in_ports->nelts; p++) {
+
+        ngx_sort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts,
+                 sizeof(ngx_http_conf_in_addr_t), ngx_http_cmp_conf_in_addrs);
+
+        /*
+         * check whether all name-based servers have
+         * the same configuraiton as the default server
+         */
+
+        in_addr = in_port[p].addrs.elts;
+        for (a = 0; a < in_port[p].addrs.nelts; a++) {
+
+            name = in_addr[a].names.elts;
+            for (s = 0; s < in_addr[a].names.nelts; s++) {
+
+                if (in_addr[a].core_srv_conf != name[s].core_srv_conf) {
+                    goto virtual_names;
+                }
+            }
+
+            /*
+             * if all name-based servers have the same configuration
+             * as the default server, then we do not need to check
+             * them at run-time at all
+             */
+
+            in_addr[a].names.nelts = 0;
+
+            continue;
+
+        virtual_names:
+
+            ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t));
+
+            ha.temp_pool = ngx_create_pool(16384, cf->log);
+            if (ha.temp_pool == NULL) {
+                return NGX_ERROR;
+            }
+
+            ha.pool = cf->pool;
+
+            if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) {
+                goto failed;
+            }
+
+#if (NGX_PCRE)
+            regex = 0;
+#endif
+
+            name = in_addr[a].names.elts;
+
+            for (s = 0; s < in_addr[a].names.nelts; s++) {
+
+#if (NGX_PCRE)
+                if (name[s].regex) {
+                    regex++;
+                    continue;
+                }
+#endif
+
+                rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf,
+                                      NGX_HASH_WILDCARD_KEY);
+
+                if (rc == NGX_ERROR) {
+                    return NGX_ERROR;
+                }
 
-    clcfp = locations->elts;
+                if (rc == NGX_DECLINED) {
+                    ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                                "invalid server name or wildcard \"%V\" on %s",
+                                &name[s].name, in_addr[a].listen_conf->addr);
+                    return NGX_ERROR;
+                }
+
+                if (rc == NGX_BUSY) {
+                    ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+                                "conflicting server name \"%V\" on %s, ignored",
+                                &name[s].name, in_addr[a].listen_conf->addr);
+                }
+            }
+
+            hash.key = ngx_hash_key_lc;
+            hash.max_size = cmcf->server_names_hash_max_size;
+            hash.bucket_size = cmcf->server_names_hash_bucket_size;
+            hash.name = "server_names_hash";
+            hash.pool = cf->pool;
+
+            if (ha.keys.nelts) {
+                hash.hash = &in_addr[a].hash;
+                hash.temp_pool = NULL;
+
+                if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK)
+                {
+                    goto failed;
+                }
+            }
+
+            if (ha.dns_wc_head.nelts) {
+
+                ngx_qsort(ha.dns_wc_head.elts,
+                          (size_t) ha.dns_wc_head.nelts,
+                          sizeof(ngx_hash_key_t),
+                          ngx_http_cmp_dns_wildcards);
+
+                hash.hash = NULL;
+                hash.temp_pool = ha.temp_pool;
 
-    for (i = 0; i < locations->nelts; i++) {
-        rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
-                                    clcfp[i]->loc_conf[ctx_index]);
-        if (rv != NGX_CONF_OK) {
-            return rv;
+                if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts,
+                                           ha.dns_wc_head.nelts)
+                    != NGX_OK)
+                {
+                    goto failed;
+                }
+
+                in_addr[a].wc_head = (ngx_hash_wildcard_t *) hash.hash;
+            }
+
+            if (ha.dns_wc_tail.nelts) {
+
+                ngx_qsort(ha.dns_wc_tail.elts,
+                          (size_t) ha.dns_wc_tail.nelts,
+                          sizeof(ngx_hash_key_t),
+                          ngx_http_cmp_dns_wildcards);
+
+                hash.hash = NULL;
+                hash.temp_pool = ha.temp_pool;
+
+                if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts,
+                                           ha.dns_wc_tail.nelts)
+                    != NGX_OK)
+                {
+                    goto failed;
+                }
+
+                in_addr[a].wc_tail = (ngx_hash_wildcard_t *) hash.hash;
+            }
+
+            ngx_destroy_pool(ha.temp_pool);
+
+#if (NGX_PCRE)
+
+            if (regex == 0) {
+                continue;
+            }
+
+            in_addr[a].nregex = regex;
+            in_addr[a].regex = ngx_palloc(cf->pool,
+                                       regex * sizeof(ngx_http_server_name_t));
+
+            if (in_addr[a].regex == NULL) {
+                return NGX_ERROR;
+            }
+
+            for (i = 0, s = 0; s < in_addr[a].names.nelts; s++) {
+                if (name[s].regex) {
+                    in_addr[a].regex[i++] = name[s];
+                }
+            }
+#endif
         }
 
-        if (clcfp[i]->locations == NULL) {
-            continue;
-        }
-
-        rv = ngx_http_merge_locations(cf, clcfp[i]->locations,
-                                      clcfp[i]->loc_conf, module, ctx_index);
-        if (rv != NGX_CONF_OK) {
-            return rv;
+        if (ngx_http_init_listening(cf, &in_port[p]) != NGX_OK) {
+            return NGX_ERROR;
         }
     }
 
-    return NGX_CONF_OK;
+    return NGX_OK;
+
+failed:
+
+    ngx_destroy_pool(ha.temp_pool);
+
+    return NGX_ERROR;
 }
 
 
@@ -1128,3 +1524,165 @@ ngx_http_cmp_dns_wildcards(const void *o
 
     return ngx_strcmp(first->key.data, second->key.data);
 }
+
+
+static ngx_int_t
+ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_in_port_t *in_port)
+{
+    ngx_uint_t                 i, a, last, bind_all, done;
+    ngx_listening_t           *ls;
+    ngx_http_in_port_t        *hip;
+    ngx_http_conf_in_addr_t   *in_addr;
+    ngx_http_virtual_names_t  *vn;
+    ngx_http_core_loc_conf_t  *clcf;
+    ngx_http_core_srv_conf_t  *cscf;
+
+    in_addr = in_port->addrs.elts;
+    last = in_port->addrs.nelts;
+
+    /*
+     * if there is a binding to a "*:port" then we need to bind()
+     * to the "*:port" only and ignore other bindings
+     */
+
+    if (in_addr[last - 1].addr == INADDR_ANY) {
+        in_addr[last - 1].bind = 1;
+        bind_all = 0;
+
+    } else {
+        bind_all = 1;
+    }
+
+    a = 0;
+
+    while (a < last) {
+
+        if (!bind_all && !in_addr[a].bind) {
+            a++;
+            continue;
+        }
+
+        ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr,
+                                              in_port->port);
+        if (ls == NULL) {
+            return NGX_ERROR;
+        }
+
+        ls->addr_ntop = 1;
+
+        ls->handler = ngx_http_init_connection;
+
+        cscf = in_addr[a].core_srv_conf;
+        ls->pool_size = cscf->connection_pool_size;
+        ls->post_accept_timeout = cscf->client_header_timeout;
+
+        clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
+
+        ls->log = *clcf->err_log;
+        ls->log.data = &ls->addr_text;
+        ls->log.handler = ngx_accept_log_error;
+
+#if (NGX_WIN32)
+        {
+        ngx_iocp_conf_t  *iocpcf;
+
+        iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module);
+        if (iocpcf->acceptex_read) {
+            ls->post_accept_buffer_size = cscf->client_header_buffer_size;
+        }
+        }
+#endif
+
+        ls->backlog = in_addr[a].listen_conf->backlog;
+        ls->rcvbuf = in_addr[a].listen_conf->rcvbuf;
+        ls->sndbuf = in_addr[a].listen_conf->sndbuf;
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+        ls->accept_filter = in_addr[a].listen_conf->accept_filter;
+#endif
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+        ls->deferred_accept = in_addr[a].listen_conf->deferred_accept;
+#endif
+
+        hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t));
+        if (hip == NULL) {
+            return NGX_ERROR;
+        }
+
+        hip->port = in_port->port;
+
+        hip->port_text.data = ngx_palloc(cf->pool, 7);
+        if (hip->port_text.data == NULL) {
+            return NGX_ERROR;
+        }
+
+        ls->servers = hip;
+
+        hip->port_text.len = ngx_sprintf(hip->port_text.data, ":%d", hip->port)
+                             - hip->port_text.data;
+
+        in_addr = in_port->addrs.elts;
+
+        if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) {
+            hip->naddrs = 1;
+            done = 0;
+
+        } else if (in_port->addrs.nelts > 1
+                   && in_addr[last - 1].addr == INADDR_ANY)
+        {
+            hip->naddrs = last;
+            done = 1;
+
+        } else {
+            hip->naddrs = 1;
+            done = 0;
+        }
+
+        hip->addrs = ngx_pcalloc(cf->pool,
+                                 hip->naddrs * sizeof(ngx_http_in_addr_t));
+        if (hip->addrs == NULL) {
+            return NGX_ERROR;
+        }
+
+        for (i = 0; i < hip->naddrs; i++) {
+            hip->addrs[i].addr = in_addr[i].addr;
+            hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf;
+
+            if (in_addr[i].hash.buckets == NULL
+                && (in_addr[i].wc_head == NULL
+                    || in_addr[i].wc_head->hash.buckets == NULL)
+                && (in_addr[i].wc_head == NULL
+                    || in_addr[i].wc_head->hash.buckets == NULL))
+            {
+                continue;
+            }
+
+            vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));
+            if (vn == NULL) {
+                return NGX_ERROR;
+            }
+            hip->addrs[i].virtual_names = vn;
+
+            vn->names.hash = in_addr[i].hash;
+            vn->names.wc_head = in_addr[i].wc_head;
+            vn->names.wc_tail = in_addr[i].wc_tail;
+#if (NGX_PCRE)
+            vn->nregex = in_addr[i].nregex;
+            vn->regex = in_addr[i].regex;
+#endif
+        }
+
+        if (done) {
+            return NGX_OK;
+        }
+
+        in_addr++;
+        in_port->addrs.elts = in_addr;
+        last--;
+
+        a = 0;
+    }
+
+    return NGX_OK;
+}
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -57,6 +57,10 @@ struct ngx_http_log_ctx_s {
 #define ngx_http_set_ctx(r, c, module)      r->ctx[module.ctx_index] = c;
 
 
+ngx_int_t ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
+    ngx_http_core_loc_conf_t *clcf);
+
+
 void ngx_http_init_connection(ngx_connection_t *c);
 
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
@@ -106,10 +110,6 @@ void ngx_http_block_reading(ngx_http_req
 extern ngx_module_t  ngx_http_module;
 
 
-extern ngx_uint_t  ngx_http_total_requests;
-extern uint64_t    ngx_http_total_sent;
-
-
 extern ngx_http_output_header_filter_pt  ngx_http_top_header_filter;
 extern ngx_http_output_body_filter_pt    ngx_http_top_body_filter;
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -17,19 +17,14 @@ typedef struct {
 } ngx_http_method_name_t;
 
 
-#define NGX_HTTP_LOCATION_EXACT           1
-#define NGX_HTTP_LOCATION_AUTO_REDIRECT   2
-#define NGX_HTTP_LOCATION_NOREGEX         3
-#define NGX_HTTP_LOCATION_REGEX           4
-
-
 #define NGX_HTTP_REQUEST_BODY_FILE_OFF    0
 #define NGX_HTTP_REQUEST_BODY_FILE_ON     1
 #define NGX_HTTP_REQUEST_BODY_FILE_CLEAN  2
 
 
-static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r,
-    ngx_array_t *locations, ngx_uint_t regex_start, size_t len);
+static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r);
+static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r,
+    ngx_http_location_tree_node_t *node);
 
 static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf);
 static void *ngx_http_core_create_main_conf(ngx_conf_t *cf);
@@ -45,8 +40,6 @@ static char *ngx_http_core_server(ngx_co
     void *dummy);
 static char *ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd,
     void *dummy);
-static ngx_int_t ngx_http_core_cmp_locations(const void *first,
-    const void *second);
 
 static char *ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
@@ -86,8 +79,8 @@ static ngx_conf_post_t  ngx_http_core_lo
 static ngx_conf_post_handler_pt  ngx_http_core_pool_size_p =
     ngx_http_core_pool_size;
 
-static ngx_conf_deprecated_t  ngx_conf_deprecated_optimize_host_names = {
-    ngx_conf_deprecated, "optimize_host_names", "optimize_server_names"
+static ngx_conf_deprecated_t  ngx_conf_deprecated_optimize_server_names = {
+    ngx_conf_deprecated, "optimize_server_names", "server_name_in_redirect"
 };
 
 static ngx_conf_deprecated_t  ngx_conf_deprecated_open_file_cache_retest = {
@@ -219,16 +212,9 @@ static ngx_command_t  ngx_http_core_comm
     { ngx_string("optimize_server_names"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
-      NGX_HTTP_SRV_CONF_OFFSET,
-      offsetof(ngx_http_core_srv_conf_t, optimize_server_names),
-      NULL },
-
-    { ngx_string("optimize_host_names"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_HTTP_SRV_CONF_OFFSET,
-      offsetof(ngx_http_core_srv_conf_t, optimize_server_names),
-      &ngx_conf_deprecated_optimize_host_names },
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, server_name_in_redirect),
+      &ngx_conf_deprecated_optimize_server_names },
 
     { ngx_string("ignore_invalid_headers"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
@@ -787,14 +773,11 @@ ngx_http_core_find_config_phase(ngx_http
     size_t                     len;
     ngx_int_t                  rc;
     ngx_http_core_loc_conf_t  *clcf;
-    ngx_http_core_srv_conf_t  *cscf;
 
     r->content_handler = NULL;
     r->uri_changed = 0;
 
-    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
-
-    rc = ngx_http_core_find_location(r, &cscf->locations, cscf->regex_start, 0);
+    rc = ngx_http_core_find_location(r);
 
     if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -832,8 +815,7 @@ ngx_http_core_find_config_phase(ngx_http
         return NGX_OK;
     }
 
-
-    if (rc == NGX_HTTP_LOCATION_AUTO_REDIRECT) {
+    if (rc == NGX_DONE) {
         r->headers_out.location = ngx_list_push(&r->headers_out.headers);
         if (r->headers_out.location == NULL) {
             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -1112,143 +1094,148 @@ ngx_http_update_location_config(ngx_http
 
 
 static ngx_int_t
-ngx_http_core_find_location(ngx_http_request_t *r,
-    ngx_array_t *locations, ngx_uint_t regex_start, size_t len)
+ngx_http_core_find_location(ngx_http_request_t *r)
 {
-    ngx_int_t                  n, rc;
-    ngx_uint_t                 i, found;
+    ngx_int_t                  rc;
+    ngx_http_core_loc_conf_t  *pclcf;
+
+    pclcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    rc = ngx_http_core_find_static_location(r, pclcf->static_locations);
+
+    if (rc == NGX_AGAIN) {
+        /* look up nested locations */
+        rc = ngx_http_core_find_location(r);
+    }
+
+    if (rc == NGX_OK || rc == NGX_DONE) {
+        return rc;
+    }
+
+    /* rc == NGX_DECLINED or rc == NGX_AGAIN in nested location */
+
+#if (NGX_PCRE)
+    {
+    ngx_int_t                  n;
     ngx_http_core_loc_conf_t  *clcf, **clcfp;
-#if (NGX_PCRE)
-    ngx_uint_t                 noregex;
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (clcf->noregex == 0 && pclcf->regex_locations) {
+
+        for (clcfp = pclcf->regex_locations; *clcfp; clcfp++) {
+
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "test location: ~ \"%V\"", &(*clcfp)->name);
+
+            n = ngx_regex_exec((*clcfp)->regex, &r->uri, NULL, 0);
+
+            if (n == NGX_REGEX_NO_MATCHED) {
+                continue;
+            }
+
+            if (n < 0) {
+                ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                              ngx_regex_exec_n
+                              " failed: %d on \"%V\" using \"%V\"",
+                              n, &r->uri, &(*clcfp)->name);
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            /* match */
+
+            r->loc_conf = (*clcfp)->loc_conf;
+
+            /* look up nested locations */
+
+            return ngx_http_core_find_location(r);
+        }
+    }
+    }
 #endif
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "find location for \"%V\"", &r->uri);
-
-    found = 0;
-#if (NGX_PCRE)
-    noregex = 0;
-#endif
-
-    clcfp = locations->elts;
-    for (i = 0; i < locations->nelts; i++) {
-
-        if (clcfp[i]->noname
-#if (NGX_PCRE)
-            || clcfp[i]->regex
-#endif
-            || clcfp[i]->named)
-        {
-            break;
+    return rc;
+}
+
+
+/*
+ * NGX_OK       - exact match
+ * NGX_DONE     - auto redirect
+ * NGX_AGAIN    - inclusive match
+ * NGX_DECLINED - no match
+ */
+
+static ngx_int_t
+ngx_http_core_find_static_location(ngx_http_request_t *r,
+    ngx_http_location_tree_node_t *node)
+{
+    u_char     *uri;
+    size_t      len, n;
+    ngx_int_t   rc, rv;
+
+    len = r->uri.len;
+    uri = r->uri.data;
+
+    rv = NGX_DECLINED;
+
+    for ( ;; ) {
+
+        if (node == NULL) {
+            return rv;
         }
 
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "find location: %s\"%V\"",
-                       clcfp[i]->exact_match ? "= " : "", &clcfp[i]->name);
-
-        if (clcfp[i]->auto_redirect
-            && r->uri.len == clcfp[i]->name.len - 1
-            && ngx_strncmp(r->uri.data, clcfp[i]->name.data,
-                           clcfp[i]->name.len - 1)
-                == 0)
-        {
-            /* the locations are lexicographically sorted */
-
-            r->loc_conf = clcfp[i]->loc_conf;
-
-            return NGX_HTTP_LOCATION_AUTO_REDIRECT;
-        }
-
-        if (r->uri.len < clcfp[i]->name.len) {
+                       "test location: \"%*s\"", node->len, node->name);
+
+        n = (len <= (size_t) node->len) ? len : node->len;
+
+        rc = ngx_memcmp(uri, node->name, n);
+
+        if (rc != 0) {
+            node = (rc < 0) ? node->left : node->right;
+
             continue;
         }
 
-        n = ngx_strncmp(r->uri.data, clcfp[i]->name.data, clcfp[i]->name.len);
-
-        if (n < 0) {
-            /* the locations are lexicographically sorted */
-            break;
-        }
-
-        if (n == 0) {
-            if (clcfp[i]->exact_match) {
-
-                if (r->uri.len == clcfp[i]->name.len) {
-                    r->loc_conf = clcfp[i]->loc_conf;
-                    return NGX_HTTP_LOCATION_EXACT;
-                }
+        if (len > (size_t) node->len) {
+
+            if (node->inclusive) {
+
+                r->loc_conf = node->inclusive->loc_conf;
+                rv = NGX_AGAIN;
+
+                node = node->tree;
+                uri += n;
+                len -= n;
 
                 continue;
             }
 
-            if (len > clcfp[i]->name.len) {
-                /* the previous match is longer */
-                break;
-            }
-
-            found = 1;
-
-            r->loc_conf = clcfp[i]->loc_conf;
-#if (NGX_PCRE)
-            noregex = clcfp[i]->noregex;
-#endif
-        }
-    }
-
-    if (found) {
-        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
-        if (clcf->locations) {
-            rc = ngx_http_core_find_location(r, clcf->locations,
-                                             clcf->regex_start, len);
-
-            if (rc != NGX_OK) {
-                return rc;
-            }
-        }
-    }
-
-#if (NGX_PCRE)
-
-    if (noregex) {
-        return NGX_HTTP_LOCATION_NOREGEX;
-    }
-
-    /* regex matches */
-
-    for (i = regex_start; i < locations->nelts; i++) {
-
-        if (!clcfp[i]->regex) {
-            break;
-        }
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "find location: ~ \"%V\"", &clcfp[i]->name);
-
-        n = ngx_regex_exec(clcfp[i]->regex, &r->uri, NULL, 0);
-
-        if (n == NGX_REGEX_NO_MATCHED) {
+            /* exact only */
+
+            node = node->right;
+
             continue;
         }
 
-        if (n < 0) {
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                          ngx_regex_exec_n
-                          " failed: %d on \"%V\" using \"%V\"",
-                          n, &r->uri, &clcfp[i]->name);
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        if (len == (size_t) node->len) {
+
+            r->loc_conf = (node->exact) ? node->exact->loc_conf:
+                                          node->inclusive->loc_conf;
+            return NGX_OK;
         }
 
-        /* match */
-
-        r->loc_conf = clcfp[i]->loc_conf;
-
-        return NGX_HTTP_LOCATION_REGEX;
+        /* len < node->len */
+
+        if (len + 1 == (size_t) node->len && node->auto_redirect) {
+
+            r->loc_conf = (node->exact) ? node->exact->loc_conf:
+                                          node->inclusive->loc_conf;
+            rv = NGX_DONE;
+        }
+
+        node = node->left;
     }
-
-#endif /* NGX_PCRE */
-
-    return NGX_OK;
 }
 
 
@@ -1896,29 +1883,29 @@ ngx_http_internal_redirect(ngx_http_requ
 ngx_int_t
 ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name)
 {
-    ngx_uint_t                   i;
     ngx_http_core_srv_conf_t    *cscf;
     ngx_http_core_loc_conf_t   **clcfp;
     ngx_http_core_main_conf_t   *cmcf;
 
     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
 
-    clcfp = cscf->locations.elts;
-
-    for (i = cscf->named_start; i < cscf->locations.nelts; i++) {
-
-        if (name->len != clcfp[i]->name.len
-            || ngx_strncmp(name->data, clcfp[i]->name.data, name->len) != 0)
+    for (clcfp = cscf->named_locations; *clcfp; clcfp++) {
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "test location: \"%V\"", &(*clcfp)->name);
+
+        if (name->len != (*clcfp)->name.len
+            || ngx_strncmp(name->data, (*clcfp)->name.data, name->len) != 0)
         {
             continue;
         }
 
         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "named location: %V \"%V?%V\"", name, &r->uri, &r->args);
+                       "using location: %V \"%V?%V\"", name, &r->uri, &r->args);
 
         r->internal = 1;
         r->content_handler = NULL;
-        r->loc_conf = clcfp[i]->loc_conf;
+        r->loc_conf = (*clcfp)->loc_conf;
 
         ngx_http_update_location_config(r);
 
@@ -1935,6 +1922,7 @@ ngx_http_named_location(ngx_http_request
                   "could not find named location \"%V\"", name);
 
     ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+
     return NGX_DONE;
 }
 
@@ -1983,7 +1971,6 @@ ngx_http_core_server(ngx_conf_t *cf, ngx
     ngx_http_module_t           *module;
     ngx_http_conf_ctx_t         *ctx, *http_ctx;
     ngx_http_core_srv_conf_t    *cscf, **cscfp;
-    ngx_http_core_loc_conf_t   **clcfp;
     ngx_http_core_main_conf_t   *cmcf;
 
     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
@@ -2061,37 +2048,6 @@ ngx_http_core_server(ngx_conf_t *cf, ngx
 
     *cf = pcf;
 
-    if (rv != NGX_CONF_OK) {
-        return rv;
-    }
-
-    ngx_sort(cscf->locations.elts, (size_t) cscf->locations.nelts,
-             sizeof(ngx_http_core_loc_conf_t *), ngx_http_core_cmp_locations);
-
-    clcfp = cscf->locations.elts;
-
-#if (NGX_PCRE)
-
-    cscf->regex_start = cscf->locations.nelts;
-
-    for (i = 0; i < cscf->locations.nelts; i++) {
-        if (clcfp[i]->regex) {
-            cscf->regex_start = i;
-            break;
-        }
-    }
-
-#endif
-
-    cscf->named_start = cscf->locations.nelts;
-
-    for (i = 0; i < cscf->locations.nelts; i++) {
-        if (clcfp[i]->named) {
-            cscf->named_start = i;
-            break;
-        }
-    }
-
     return rv;
 }
 
@@ -2105,8 +2061,7 @@ ngx_http_core_location(ngx_conf_t *cf, n
     ngx_conf_t                 save;
     ngx_http_module_t         *module;
     ngx_http_conf_ctx_t       *ctx, *pctx;
-    ngx_http_core_srv_conf_t  *cscf;
-    ngx_http_core_loc_conf_t  *clcf, *pclcf, **clcfp;
+    ngx_http_core_loc_conf_t  *clcf, *pclcf;
 
     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
     if (ctx == NULL) {
@@ -2201,15 +2156,10 @@ ngx_http_core_location(ngx_conf_t *cf, n
 
     pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
 
-    if (pclcf->name.len == 0) {
-        cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
-
-        clcfp = ngx_array_push(&cscf->locations);
-        if (clcfp == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-    } else {
+    if (pclcf->name.len) {
+
+        /* nested location */
+
 #if 0
         clcf->prev_location = pclcf;
 #endif
@@ -2230,6 +2180,14 @@ ngx_http_core_location(ngx_conf_t *cf, n
             return NGX_CONF_ERROR;
         }
 
+        if (clcf->named) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "named location \"%V\" must be "
+                               "on server level only",
+                               &clcf->name);
+            return NGX_CONF_ERROR;
+        }
+
 #if (NGX_PCRE)
         if (clcf->regex == NULL
             && ngx_strncmp(clcf->name.data, pclcf->name.data, pclcf->name.len)
@@ -2244,22 +2202,11 @@ ngx_http_core_location(ngx_conf_t *cf, n
                                &clcf->name, &pclcf->name);
             return NGX_CONF_ERROR;
         }
-
-        if (pclcf->locations == NULL) {
-            pclcf->locations = ngx_array_create(cf->pool, 2, sizeof(void *));
-
-            if (pclcf->locations == NULL) {
-                return NGX_CONF_ERROR;
-            }
-        }
-
-        clcfp = ngx_array_push(pclcf->locations);
-        if (clcfp == NULL) {
-            return NGX_CONF_ERROR;
-        }
     }
 
-    *clcfp = clcf;
+    if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
 
     save = *cf;
     cf->ctx = ctx;
@@ -2269,103 +2216,10 @@ ngx_http_core_location(ngx_conf_t *cf, n
 
     *cf = save;
 
-    if (rv != NGX_CONF_OK) {
-        return rv;
-    }
-
-    if (clcf->locations == NULL) {
-        return rv;
-    }
-
-    ngx_sort(clcf->locations->elts, (size_t) clcf->locations->nelts,
-             sizeof(ngx_http_core_loc_conf_t *), ngx_http_core_cmp_locations);
-
-#if (NGX_PCRE)
-
-    clcf->regex_start = clcf->locations->nelts;
-    clcfp = clcf->locations->elts;
-
-    for (i = 0; i < clcf->locations->nelts; i++) {
-        if (clcfp[i]->regex) {
-            clcf->regex_start = i;
-            break;
-        }
-    }
-
-#endif
-
     return rv;
 }
 
 
-static ngx_int_t
-ngx_http_core_cmp_locations(const void *one, const void *two)
-{
-    ngx_int_t                  rc;
-    ngx_http_core_loc_conf_t  *first, *second;
-
-    first = *(ngx_http_core_loc_conf_t **) one;
-    second = *(ngx_http_core_loc_conf_t **) two;
-
-    if (first->named && !second->named) {
-        /* shift named locations to the end */
-        return 1;
-    }
-
-    if (!first->named && second->named) {
-        /* shift named locations to the end */
-        return -1;
-    }
-
-    if (first->named && second->named) {
-        return ngx_strcmp(first->name.data, second->name.data);
-    }
-
-    if (first->noname && !second->noname) {
-        /* shift no named locations to the end */
-        return 1;
-    }
-
-    if (!first->noname && second->noname) {
-        /* shift no named locations to the end */
-        return -1;
-    }
-
-    if (first->noname || second->noname) {
-        /* do not sort no named locations */
-        return 0;
-    }
-
-#if (NGX_PCRE)
-
-    if (first->regex && !second->regex) {
-        /* shift the regex matches to the end */
-        return 1;
-    }
-
-    if (!first->regex && second->regex) {
-        /* shift the regex matches to the end */
-        return -1;
-    }
-
-    if (first->regex || second->regex) {
-        /* do not sort the regex matches */
-        return 0;
-    }
-
-#endif
-
-    rc = ngx_strcmp(first->name.data, second->name.data);
-
-    if (rc == 0 && second->exact_match) {
-        /* an exact match must be before the same inclusive one */
-        return 1;
-    }
-
-    return rc;
-}
-
-
 static char *
 ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
@@ -2541,12 +2395,6 @@ ngx_http_core_create_srv_conf(ngx_conf_t
      *     conf->client_large_buffers.num = 0;
      */
 
-    if (ngx_array_init(&cscf->locations, cf->pool, 4, sizeof(void *))
-        == NGX_ERROR)
-    {
-        return NGX_CONF_ERROR;
-    }
-
     if (ngx_array_init(&cscf->listen, cf->pool, 4, sizeof(ngx_http_listen_t))
         == NGX_ERROR)
     {
@@ -2564,7 +2412,6 @@ ngx_http_core_create_srv_conf(ngx_conf_t
     cscf->request_pool_size = NGX_CONF_UNSET_SIZE;
     cscf->client_header_timeout = NGX_CONF_UNSET_MSEC;
     cscf->client_header_buffer_size = NGX_CONF_UNSET_SIZE;
-    cscf->optimize_server_names = NGX_CONF_UNSET;
     cscf->ignore_invalid_headers = NGX_CONF_UNSET;
     cscf->merge_slashes = NGX_CONF_UNSET;
 
@@ -2640,9 +2487,6 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
-    ngx_conf_merge_value(conf->optimize_server_names,
-                              prev->optimize_server_names, 1);
-
     ngx_conf_merge_value(conf->ignore_invalid_headers,
                               prev->ignore_invalid_headers, 1);
 
@@ -3345,7 +3189,7 @@ static ngx_http_method_name_t  ngx_metho
 static char *
 ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_loc_conf_t *clcf = conf;
+    ngx_http_core_loc_conf_t *pclcf = conf;
 
     char                      *rv;
     void                      *mconf;
@@ -3355,13 +3199,13 @@ ngx_http_core_limit_except(ngx_conf_t *c
     ngx_http_module_t         *module;
     ngx_http_conf_ctx_t       *ctx, *pctx;
     ngx_http_method_name_t    *name;
-    ngx_http_core_loc_conf_t  *lcf, **clcfp;
-
-    if (clcf->limit_except) {
+    ngx_http_core_loc_conf_t  *clcf;
+
+    if (pclcf->limit_except) {
         return "duplicate";
     }
 
-    clcf->limit_except = 0xffffffff;
+    pclcf->limit_except = 0xffffffff;
 
     value = cf->args->elts;
 
@@ -3369,7 +3213,7 @@ ngx_http_core_limit_except(ngx_conf_t *c
         for (name = ngx_methods_names; name->name; name++) {
 
             if (ngx_strcasecmp(value[i].data, name->name) == 0) {
-                clcf->limit_except &= name->method;
+                pclcf->limit_except &= name->method;
                 goto next;
             }
         }
@@ -3382,8 +3226,8 @@ ngx_http_core_limit_except(ngx_conf_t *c
         continue;
     }
 
-    if (!(clcf->limit_except & NGX_HTTP_GET)) {
-        clcf->limit_except &= (uint32_t) ~NGX_HTTP_HEAD;
+    if (!(pclcf->limit_except & NGX_HTTP_GET)) {
+        pclcf->limit_except &= (uint32_t) ~NGX_HTTP_HEAD;
     }
 
     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
@@ -3419,27 +3263,16 @@ ngx_http_core_limit_except(ngx_conf_t *c
     }
 
 
-    lcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
-    clcf->limit_except_loc_conf = ctx->loc_conf;
-    lcf->loc_conf = ctx->loc_conf;
-    lcf->name = clcf->name;
-    lcf->noname = 1;
-
-    if (clcf->locations == NULL) {
-        clcf->locations = ngx_array_create(cf->pool, 2, sizeof(void *));
-        if (clcf->locations == NULL) {
-            return NGX_CONF_ERROR;
-        }
-    }
-
-    clcfp = ngx_array_push(clcf->locations);
-    if (clcfp == NULL) {
+    clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
+    pclcf->limit_except_loc_conf = ctx->loc_conf;
+    clcf->loc_conf = ctx->loc_conf;
+    clcf->name = pclcf->name;
+    clcf->noname = 1;
+
+    if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
-    *clcfp = lcf;
-
-
     save = *cf;
     cf->ctx = ctx;
     cf->cmd_type = NGX_HTTP_LMT_CONF;
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -28,6 +28,10 @@
 #define NGX_HTTP_SATISFY_ANY            1
 
 
+typedef struct ngx_http_location_tree_node_s  ngx_http_location_tree_node_t;
+typedef struct ngx_http_core_loc_conf_s  ngx_http_core_loc_conf_t;
+
+
 typedef struct {
     unsigned                   default_server:1;
     unsigned                   bind:1;
@@ -127,37 +131,29 @@ typedef struct {
 
 
 typedef struct {
-    /*
-     * array of the ngx_http_core_loc_conf_t *,
-     * used in the ngx_http_core_find_location() and in the merge phase
-     */
-    ngx_array_t                locations;
-
-    unsigned                   regex_start:15;
-    unsigned                   named_start:15;
-
     /* array of the ngx_http_listen_t, "listen" directive */
-    ngx_array_t                listen;
+    ngx_array_t                 listen;
 
     /* array of the ngx_http_server_name_t, "server_name" directive */
-    ngx_array_t                server_names;
+    ngx_array_t                 server_names;
 
     /* server ctx */
-    ngx_http_conf_ctx_t       *ctx;
+    ngx_http_conf_ctx_t        *ctx;
 
-    ngx_str_t                  server_name;
+    ngx_str_t                   server_name;
 
-    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                 client_header_timeout;
+    ngx_msec_t                  client_header_timeout;
 
-    ngx_flag_t                 optimize_server_names;
-    ngx_flag_t                 ignore_invalid_headers;
-    ngx_flag_t                 merge_slashes;
+    ngx_flag_t                  ignore_invalid_headers;
+    ngx_flag_t                  merge_slashes;
+
+    ngx_http_core_loc_conf_t  **named_locations;
 } ngx_http_core_srv_conf_t;
 
 
@@ -231,8 +227,6 @@ typedef struct {
 } ngx_http_err_page_t;
 
 
-typedef struct ngx_http_core_loc_conf_s  ngx_http_core_loc_conf_t;
-
 struct ngx_http_core_loc_conf_s {
     ngx_str_t     name;          /* location name */
 
@@ -240,8 +234,6 @@ struct ngx_http_core_loc_conf_s {
     ngx_regex_t  *regex;
 #endif
 
-    unsigned      regex_start:15;
-
     unsigned      noname:1;   /* "if () {}" block or limit_except */
     unsigned      named:1;
 
@@ -251,14 +243,14 @@ struct ngx_http_core_loc_conf_s {
     unsigned      auto_redirect:1;
     unsigned      alias:1;
 
-    /* array of inclusive ngx_http_core_loc_conf_t */
-    ngx_array_t  *locations;
+    ngx_http_location_tree_node_t   *static_locations;
+    ngx_http_core_loc_conf_t       **regex_locations;
 
     /* pointer to the modules' loc_conf */
-    void        **loc_conf ;
+    void        **loc_conf;
 
     uint32_t      limit_except;
-    void        **limit_except_loc_conf ;
+    void        **limit_except_loc_conf;
 
     ngx_http_handler_pt  handler;
 
@@ -333,12 +325,39 @@ struct ngx_http_core_loc_conf_s {
     ngx_uint_t    types_hash_max_size;
     ngx_uint_t    types_hash_bucket_size;
 
+    ngx_queue_t  *locations;
+
 #if 0
     ngx_http_core_loc_conf_t  *prev_location;
 #endif
 };
 
 
+typedef struct {
+    ngx_queue_t                      queue;
+    ngx_http_core_loc_conf_t        *exact;
+    ngx_http_core_loc_conf_t        *inclusive;
+    ngx_str_t                       *name;
+    u_char                          *file_name;
+    ngx_uint_t                       line;
+    ngx_queue_t                      list;
+} ngx_http_location_queue_t;
+
+
+struct ngx_http_location_tree_node_s {
+    ngx_http_location_tree_node_t   *left;
+    ngx_http_location_tree_node_t   *right;
+    ngx_http_location_tree_node_t   *tree;
+
+    ngx_http_core_loc_conf_t        *exact;
+    ngx_http_core_loc_conf_t        *inclusive;
+
+    u_char                           auto_redirect;
+    u_char                           len;
+    u_char                           name[1];
+};
+
+
 void ngx_http_core_run_phases(ngx_http_request_t *r);
 ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r,
     ngx_http_phase_handler_t *ph);
@@ -401,7 +420,7 @@ extern ngx_uint_t ngx_http_max_module;
                                                                               \
     r->allow_ranges = 0;                                                      \
     if (r->headers_out.accept_ranges) {                                       \
-        r->headers_out.accept_ranges->hash = 0 ;                              \
+        r->headers_out.accept_ranges->hash = 0;                               \
         r->headers_out.accept_ranges = NULL;                                  \
     }
 
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -536,7 +536,7 @@ ngx_http_header_filter(ngx_http_request_
         }
 
         b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
-        *b->last++ = ':' ; *b->last++ = ' ' ;
+        *b->last++ = ':'; *b->last++ = ' ';
 
         b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
         *b->last++ = CR; *b->last++ = LF;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1836,7 +1836,7 @@ ngx_http_finalize_request(ngx_http_reque
 
     if (!ngx_terminate
          && !ngx_exiting
-         && r->keepalive != 0
+         && r->keepalive
          && clcf->keepalive_timeout > 0)
     {
         ngx_http_set_keepalive(r);
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -343,7 +343,7 @@ ngx_http_special_response_handler(ngx_ht
 
     r->err_status = error;
 
-    if (r->keepalive != 0) {
+    if (r->keepalive) {
         switch (error) {
             case NGX_HTTP_BAD_REQUEST:
             case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE:
@@ -619,7 +619,7 @@ ngx_http_send_special_response(ngx_http_
     b->last = tail + len;
 
     out[1].buf = b;
-    out[1].next = NULL;;
+    out[1].next = NULL;
 
     if (msie_padding) {
         b = ngx_calloc_buf(r->pool);
@@ -633,7 +633,7 @@ ngx_http_send_special_response(ngx_http_
 
         out[1].next = &out[2];
         out[2].buf = b;
-        out[2].next = NULL;;
+        out[2].next = NULL;
     }
 
     if (r == r->main) {
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -261,7 +261,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
     }
 
     ngx_conf_merge_value(conf->builtin_session_cache,
-                         prev->builtin_session_cache, NGX_SSL_NO_SCACHE);
+                         prev->builtin_session_cache, NGX_SSL_NONE_SCACHE);
 
     if (conf->shm_zone == NULL) {
         conf->shm_zone = prev->shm_zone;
@@ -298,6 +298,11 @@ ngx_mail_ssl_session_cache(ngx_conf_t *c
             continue;
         }
 
+        if (ngx_strcmp(value[i].data, "none") == 0) {
+            scf->builtin_session_cache = NGX_SSL_NONE_SCACHE;
+            continue;
+        }
+
         if (ngx_strcmp(value[i].data, "builtin") == 0) {
             scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
             continue;
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -47,6 +47,7 @@
 
 #include <time.h>               /* tzset() */
 #include <malloc.h>             /* memalign() */
+#include <limits.h>             /* IOV_MAX */
 #include <sys/ioctl.h>
 #include <sys/sysctl.h>
 #include <crypt.h>
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -1054,70 +1054,74 @@ ngx_channel_handler(ngx_event_t *ev)
 
     ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler");
 
-    n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log);
+    for ( ;; ) {
 
-    ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);
+        n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log);
+
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);
 
-    if (n == NGX_ERROR) {
+        if (n == NGX_ERROR) {
 
-        if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
-            ngx_del_conn(c, 0);
+            if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+                ngx_del_conn(c, 0);
+            }
+
+            ngx_close_connection(c);
+            return;
         }
 
-        ngx_close_connection(c);
-        return;
-    }
+        if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) {
+            if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
+                return;
+            }
+        }
 
-    if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) {
-        if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
+        if (n == NGX_AGAIN) {
             return;
         }
-    }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
+                       "channel command: %d", ch.command);
 
-    if (n == NGX_AGAIN) {
-        return;
-    }
+        switch (ch.command) {
 
-    ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
-                   "channel command: %d", ch.command);
-
-    switch (ch.command) {
+        case NGX_CMD_QUIT:
+            ngx_quit = 1;
+            break;
 
-    case NGX_CMD_QUIT:
-        ngx_quit = 1;
-        break;
+        case NGX_CMD_TERMINATE:
+            ngx_terminate = 1;
+            break;
 
-    case NGX_CMD_TERMINATE:
-        ngx_terminate = 1;
-        break;
+        case NGX_CMD_REOPEN:
+            ngx_reopen = 1;
+            break;
 
-    case NGX_CMD_REOPEN:
-        ngx_reopen = 1;
-        break;
+        case NGX_CMD_OPEN_CHANNEL:
 
-    case NGX_CMD_OPEN_CHANNEL:
-
-        ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0,
-                       "get channel s:%i pid:%P fd:%d", ch.slot, ch.pid, ch.fd);
+            ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0,
+                           "get channel s:%i pid:%P fd:%d",
+                           ch.slot, ch.pid, ch.fd);
 
-        ngx_processes[ch.slot].pid = ch.pid;
-        ngx_processes[ch.slot].channel[0] = ch.fd;
-        break;
+            ngx_processes[ch.slot].pid = ch.pid;
+            ngx_processes[ch.slot].channel[0] = ch.fd;
+            break;
 
-    case NGX_CMD_CLOSE_CHANNEL:
+        case NGX_CMD_CLOSE_CHANNEL:
 
-        ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0,
-                       "close channel s:%i pid:%P our:%P fd:%d",
-                       ch.slot, ch.pid, ngx_processes[ch.slot].pid,
-                       ngx_processes[ch.slot].channel[0]);
+            ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0,
+                           "close channel s:%i pid:%P our:%P fd:%d",
+                           ch.slot, ch.pid, ngx_processes[ch.slot].pid,
+                           ngx_processes[ch.slot].channel[0]);
 
-        if (close(ngx_processes[ch.slot].channel[0]) == -1) {
-            ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
-                          "close() channel failed");
+            if (close(ngx_processes[ch.slot].channel[0]) == -1) {
+                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+                              "close() channel failed");
+            }
+
+            ngx_processes[ch.slot].channel[0] = -1;
+            break;
         }
-
-        ngx_processes[ch.slot].channel[0] = -1;
-        break;
     }
 }