changeset 550:1dcf6adad484 NGINX_0_8_21

nginx 0.8.21 *) Feature: now the "-V" switch shows TLS SNI support. *) Feature: the "listen" directive of the HTTP module supports unix domain sockets. Thanks to Hongli Lai. *) Feature: the "default_server" parameter of the "listen" directive. *) Feature: now a "default" parameter is not required to set listen socket options. *) Bugfix: nginx did not support dates in 2038 year on 32-bit platforms; *) Bugfix: socket leak; the bug had appeared in 0.8.11.
author Igor Sysoev <http://sysoev.ru>
date Mon, 26 Oct 2009 00:00:00 +0300
parents 3ca2e495d9de
children c88014f74832
files CHANGES CHANGES.ru src/core/nginx.c src/core/nginx.h src/core/ngx_connection.c src/core/ngx_cycle.c src/core/ngx_inet.c src/core/ngx_inet.h src/event/ngx_event_accept.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_parse_time.c src/http/ngx_http_request.c src/http/ngx_http_request_body.c src/os/unix/ngx_process_cycle.c
diffstat 19 files changed, 443 insertions(+), 383 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,22 @@
 
+Changes with nginx 0.8.21                                        26 Oct 2009
+
+    *) Feature: now the "-V" switch shows TLS SNI support.
+
+    *) Feature: the "listen" directive of the HTTP module supports unix 
+       domain sockets.
+       Thanks to Hongli Lai.
+
+    *) Feature: the "default_server" parameter of the "listen" directive.
+
+    *) Feature: now a "default" parameter is not required to set listen 
+       socket options.
+
+    *) Bugfix: nginx did not support dates in 2038 year on 32-bit platforms;
+
+    *) Bugfix: socket leak; the bug had appeared in 0.8.11.
+
+
 Changes with nginx 0.8.20                                        14 Oct 2009
 
     *) Change: now default SSL ciphers are "HIGH:!ADH:!MD5".
@@ -13,7 +31,7 @@ Changes with nginx 0.8.20               
        "Cache-Control" backend response header line.
 
     *) Bugfix: nginx/Windows might not create temporary file, a cache file, 
-       or "proxy/fastcgi_store"d file if a worker has no enough access 
+       or "proxy/fastcgi_store"d file if a worker had no enough access 
        rights for top level directories.
 
     *) Bugfix: the "Set-Cookie" and "P3P" FastCGI response header lines 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,23 @@
 
+Изменения в nginx 0.8.21                                          26.10.2009
+
+    *) Добавление: теперь ключ -V показывает статус поддержки TLS SNI.
+
+    *) Добавление: директива listen модуля HTTP поддерживает unix domain 
+       сокеты.
+       Спасибо Hongli Lai.
+
+    *) Добавление: параметр "default_server" в директиве listen.
+
+    *) Добавление: теперь параметр "default" не обязателен для установки 
+       параметров listen-сокета.
+
+    *) Исправление: nginx не поддерживал даты в 2038 году на 32-битных 
+       платформах;
+
+    *) Исправление: утечки сокетов; ошибка появилась в 0.8.11.
+
+
 Изменения в nginx 0.8.20                                          14.10.2009
 
     *) Изменение: теперь по умолчанию используются следующие шифры SSL: 
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -239,6 +239,13 @@ main(int argc, char *const *argv)
 #ifdef NGX_COMPILER
             ngx_log_stderr(0, "built by " NGX_COMPILER);
 #endif
+#if (NGX_SSL)
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+            ngx_log_stderr(0, "TLS SNI support enabled");
+#else
+            ngx_log_stderr(0, "TLS SNI support disabled");
+#endif
+#endif
             ngx_log_stderr(0, "configure arguments:" NGX_CONFIGURE);
         }
 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8020
-#define NGINX_VERSION      "0.8.20"
+#define nginx_version         8021
+#define NGINX_VERSION      "0.8.21"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -15,6 +15,7 @@ ngx_os_io_t  ngx_io;
 ngx_listening_t *
 ngx_create_listening(ngx_conf_t *cf, void *sockaddr, socklen_t socklen)
 {
+    size_t            len;
     ngx_listening_t  *ls;
     struct sockaddr  *sa;
     u_char            text[NGX_SOCKADDR_STRLEN];
@@ -36,17 +37,8 @@ ngx_create_listening(ngx_conf_t *cf, voi
     ls->sockaddr = sa;
     ls->socklen = socklen;
 
-    ls->addr_text.len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1);
-
-    ls->addr_text.data = ngx_pnalloc(cf->pool, ls->addr_text.len);
-    if (ls->addr_text.data == NULL) {
-        return NULL;
-    }
-
-    ngx_memcpy(ls->addr_text.data, text, ls->addr_text.len);
-
-    ls->fd = (ngx_socket_t) -1;
-    ls->type = SOCK_STREAM;
+    len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1);
+    ls->addr_text.len = len;
 
     switch (ls->sockaddr->sa_family) {
 #if (NGX_HAVE_INET6)
@@ -54,6 +46,12 @@ ngx_create_listening(ngx_conf_t *cf, voi
          ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN;
          break;
 #endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+    case AF_UNIX:
+         ls->addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
+         len++;
+         break;
+#endif
     case AF_INET:
          ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
          break;
@@ -62,6 +60,16 @@ ngx_create_listening(ngx_conf_t *cf, voi
          break;
     }
 
+    ls->addr_text.data = ngx_pnalloc(cf->pool, len);
+    if (ls->addr_text.data == NULL) {
+        return NULL;
+    }
+
+    ngx_memcpy(ls->addr_text.data, text, len);
+
+    ls->fd = (ngx_socket_t) -1;
+    ls->type = SOCK_STREAM;
+
     ls->backlog = NGX_LISTEN_BACKLOG;
     ls->rcvbuf = -1;
     ls->sndbuf = -1;
@@ -604,6 +612,21 @@ ngx_close_listening_sockets(ngx_cycle_t 
                           ngx_close_socket_n " %V failed", &ls[i].addr_text);
         }
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+        if (ls[i].sockaddr->sa_family == AF_UNIX
+            && ngx_process != NGX_PROCESS_WORKER)
+        {
+            u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1;
+
+            if (ngx_delete_file(name) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+                              ngx_delete_file_n " %s failed", name);
+            }
+        }
+
+#endif
+
         ls[i].fd = (ngx_socket_t) -1;
     }
 }
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -204,7 +204,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         return NULL;
     }
 
-    ngx_memcpy(cycle->hostname.data, hostname, cycle->hostname.len);
+    ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);
 
 
     for (i = 0; ngx_modules[i]; i++) {
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -68,6 +68,9 @@ ngx_sock_ntop(struct sockaddr *sa, u_cha
     size_t                n;
     struct sockaddr_in6  *sin6;
 #endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+    struct sockaddr_un   *saun;
+#endif
 
     switch (sa->sa_family) {
 
@@ -108,6 +111,17 @@ ngx_sock_ntop(struct sockaddr *sa, u_cha
         return n;
 #endif
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+    case AF_UNIX:
+        saun = (struct sockaddr_un *) sa;
+
+        /* we do not include trailing zero in address length */
+
+        return ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path) - text - 1;
+
+#endif
+
     default:
         return 0;
     }
--- a/src/core/ngx_inet.h
+++ b/src/core/ngx_inet.h
@@ -12,21 +12,26 @@
 #include <ngx_core.h>
 
 
-#define NGX_INET_ADDRSTRLEN   (sizeof("255.255.255.255") - 1)
-#define NGX_INET6_ADDRSTRLEN                                                 \
-    (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1)
-
-#define NGX_SOCKADDR_STRLEN   (NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1)
-
-
 /*
- * TODO: autoconfigure NGX_SOCKADDRLEN as
+ * TODO: autoconfigure NGX_SOCKADDRLEN and NGX_SOCKADDR_STRLEN as
  *       sizeof(struct sockaddr_storage)
  *       sizeof(struct sockaddr_un)
  *       sizeof(struct sockaddr_in6)
  *       sizeof(struct sockaddr_in)
  */
 
+#define NGX_INET_ADDRSTRLEN   (sizeof("255.255.255.255") - 1)
+#define NGX_INET6_ADDRSTRLEN                                                 \
+    (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1)
+#define NGX_UNIX_ADDRSTRLEN                                                  \
+    (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path))
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+#define NGX_SOCKADDR_STRLEN   (sizeof("unix:") - 1 + NGX_UNIX_ADDRSTRLEN)
+#else
+#define NGX_SOCKADDR_STRLEN   (NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1)
+#endif
+
 #if (NGX_HAVE_UNIX_DOMAIN)
 #define NGX_SOCKADDRLEN       sizeof(struct sockaddr_un)
 #else
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -156,6 +156,17 @@ ngx_event_accept(ngx_event_t *ev)
 
         c->unexpected_eof = 1;
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+        if (c->sockaddr->sa_family == AF_UNIX) {
+            c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
+            c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
+#if (NGX_SOLARIS)
+            /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */
+            c->sendfile = 0;
+#endif
+        }
+#endif
+
         rev = c->read;
         wev = c->write;
 
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -409,7 +409,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
         == 0)
     {
         ngx_log_error(NGX_LOG_WARN, cf->log, 0,
-            "nginx was build with SNI support, however, now it is linked "
+            "nginx was built with SNI support, however, now it is linked "
             "dynamically to an OpenSSL library which has no tlsext support, "
             "therefore SNI is not available");
     }
--- 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.8.20';
+our $VERSION = '0.8.21';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -17,18 +17,13 @@ static ngx_int_t ngx_http_init_headers_i
 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 *ports);
-static ngx_int_t ngx_http_add_ports(ngx_conf_t *cf,
-    ngx_http_core_srv_conf_t *cscf, ngx_array_t *ports,
-    ngx_http_listen_t *listen);
 static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf,
     ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port,
-    ngx_http_listen_t *listen);
+    ngx_http_listen_opt_t *lsopt);
 static ngx_int_t ngx_http_add_address(ngx_conf_t *cf,
     ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port,
-    ngx_http_listen_t *listen);
-static ngx_int_t ngx_http_add_names(ngx_conf_t *cf,
+    ngx_http_listen_opt_t *lsopt);
+static ngx_int_t ngx_http_add_server(ngx_conf_t *cf,
     ngx_http_core_srv_conf_t *cscf, ngx_http_conf_addr_t *addr);
 
 static char *ngx_http_merge_locations(ngx_conf_t *cf,
@@ -122,7 +117,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     char                        *rv;
     ngx_uint_t                   mi, m, s;
     ngx_conf_t                   pcf;
-    ngx_array_t                  ports;
     ngx_http_module_t           *module;
     ngx_http_conf_ctx_t         *ctx;
     ngx_http_core_loc_conf_t    *clcf;
@@ -362,19 +356,9 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     }
 
 
-    /*
-     * create the lists of ports, addresses and server names
-     * to find quickly the server core module configuration at run-time
-     */
-
-    if (ngx_http_init_server_lists(cf, &cmcf->servers, &ports) != NGX_OK) {
-        return NGX_CONF_ERROR;
-    }
-
-
     /* optimize the lists of ports, addresses and server names */
 
-    if (ngx_http_optimize_servers(cf, cmcf, &ports) != NGX_OK) {
+    if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
@@ -1109,54 +1093,31 @@ inclusive:
 }
 
 
-static ngx_int_t
-ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers,
-    ngx_array_t *ports)
+ngx_int_t
+ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
+    ngx_http_listen_opt_t *lsopt)
 {
-    ngx_uint_t                  s, i;
-    ngx_http_listen_t          *listen;
-    ngx_http_core_srv_conf_t  **cscfp;
-
-    if (ngx_array_init(ports, cf->temp_pool, 2, sizeof(ngx_http_conf_port_t))
-        != NGX_OK)
-    {
-        return NGX_ERROR;
-    }
+    in_port_t                   p;
+    ngx_uint_t                  i;
+    struct sockaddr            *sa;
+    struct sockaddr_in         *sin;
+    ngx_http_conf_port_t       *port;
+    ngx_http_core_main_conf_t  *cmcf;
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6        *sin6;
+#endif
 
-    /* "server" directives */
-
-    cscfp = servers->elts;
-    for (s = 0; s < servers->nelts; s++) {
-
-        /* "listen" directives */
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
-        listen = cscfp[s]->listen.elts;
-        for (i = 0; i < cscfp[s]->listen.nelts; i++) {
-
-            if (ngx_http_add_ports(cf, cscfp[s], ports, &listen[i]) != NGX_OK) {
-                return NGX_ERROR;
-            }
+    if (cmcf->ports == NULL) {
+        cmcf->ports = ngx_array_create(cf->temp_pool, 2,
+                                       sizeof(ngx_http_conf_port_t));
+        if (cmcf->ports == NULL) {
+            return NGX_ERROR;
         }
     }
 
-    return NGX_OK;
-}
-
-
-static ngx_int_t
-ngx_http_add_ports(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
-    ngx_array_t *ports, ngx_http_listen_t *listen)
-{
-    in_port_t                 p;
-    ngx_uint_t                i;
-    struct sockaddr          *sa;
-    struct sockaddr_in       *sin;
-    ngx_http_conf_port_t     *port;
-#if (NGX_HAVE_INET6)
-    struct sockaddr_in6      *sin6;
-#endif
-
-    sa = (struct sockaddr *) &listen->sockaddr;
+    sa = (struct sockaddr *) &lsopt->sockaddr;
 
     switch (sa->sa_family) {
 
@@ -1167,14 +1128,20 @@ ngx_http_add_ports(ngx_conf_t *cf, ngx_h
         break;
 #endif
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+    case AF_UNIX:
+        p = 0;
+        break;
+#endif
+
     default: /* AF_INET */
         sin = (struct sockaddr_in *) sa;
         p = sin->sin_port;
         break;
     }
 
-    port = ports->elts;
-    for (i = 0; i < ports->nelts; i++) {
+    port = cmcf->ports->elts;
+    for (i = 0; i < cmcf->ports->nelts; i++) {
 
         if (p != port[i].port || sa->sa_family != port[i].family) {
             continue;
@@ -1182,12 +1149,12 @@ ngx_http_add_ports(ngx_conf_t *cf, ngx_h
 
         /* a port is already in the port list */
 
-        return ngx_http_add_addresses(cf, cscf, &port[i], listen);
+        return ngx_http_add_addresses(cf, cscf, &port[i], lsopt);
     }
 
     /* add a port to the port list */
 
-    port = ngx_array_push(ports);
+    port = ngx_array_push(cmcf->ports);
     if (port == NULL) {
         return NGX_ERROR;
     }
@@ -1196,26 +1163,29 @@ ngx_http_add_ports(ngx_conf_t *cf, ngx_h
     port->port = p;
     port->addrs.elts = NULL;
 
-    return ngx_http_add_address(cf, cscf, port, listen);
+    return ngx_http_add_address(cf, cscf, port, lsopt);
 }
 
 
 static ngx_int_t
 ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
-    ngx_http_conf_port_t *port, ngx_http_listen_t *listen)
+    ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
 {
     u_char                *p;
     size_t                 len, off;
-    ngx_uint_t             i;
+    ngx_uint_t             i, default_server;
     struct sockaddr       *sa;
     ngx_http_conf_addr_t  *addr;
+#if (NGX_HAVE_UNIX_DOMAIN)
+    struct sockaddr_un    *saun;
+#endif
 
     /*
      * we can not compare whole sockaddr struct's as kernel
      * may fill some fields in inherited sockaddr struct's
      */
 
-    sa = (struct sockaddr *) &listen->sockaddr;
+    sa = (struct sockaddr *) &lsopt->sockaddr;
 
     switch (sa->sa_family) {
 
@@ -1226,54 +1196,71 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
         break;
 #endif
 
+#if (NGX_HAVE_UNIX_DOMAIN)
+    case AF_UNIX:
+        off = offsetof(struct sockaddr_un, sun_path);
+        len = sizeof(saun->sun_path);
+        break;
+#endif
+
     default: /* AF_INET */
         off = offsetof(struct sockaddr_in, sin_addr);
         len = 4;
         break;
     }
 
-    p = listen->sockaddr + off;
+    p = lsopt->sockaddr + off;
 
     addr = port->addrs.elts;
 
     for (i = 0; i < port->addrs.nelts; i++) {
 
-        if (ngx_memcmp(p, (u_char *) addr[i].sockaddr + off, len) != 0) {
+        if (ngx_memcmp(p, (u_char *) addr[i].opt.sockaddr + off, len) != 0) {
             continue;
         }
 
         /* the address is already in the address list */
 
-        if (ngx_http_add_names(cf, cscf, &addr[i]) != NGX_OK) {
+        if (ngx_http_add_server(cf, cscf, &addr[i]) != NGX_OK) {
             return NGX_ERROR;
         }
 
+        /* preserve default_server bit during listen options overwriting */
+        default_server = addr[i].opt.default_server;
+
+        if (lsopt->set) {
+
+            if (addr[i].opt.set) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                        "a duplicate listen options for %s", addr[i].opt.addr);
+                return NGX_ERROR;
+            }
+
+            addr[i].opt = *lsopt;
+        }
+
         /* check the duplicate "default" server for this address:port */
 
-        if (listen->conf.default_server) {
+        if (lsopt->default_server) {
 
-            if (addr[i].default_server) {
-                ngx_log_error(NGX_LOG_ERR, cf->log, 0,
-                              "the duplicate default server in %s:%ui",
-                               listen->file_name, listen->line);
-
+            if (default_server) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                        "a duplicate default server for %s", addr[i].opt.addr);
                 return NGX_ERROR;
             }
 
-            addr[i].core_srv_conf = cscf;
-            addr[i].default_server = 1;
-#if (NGX_HTTP_SSL)
-            addr[i].ssl = listen->conf.ssl;
-#endif
-            addr[i].listen_conf = &listen->conf;
+            default_server = 1;
+            addr[i].default_server = cscf;
         }
 
+        addr[i].opt.default_server = default_server;
+
         return NGX_OK;
     }
 
     /* add the address to the addresses list that bound to this port */
 
-    return ngx_http_add_address(cf, cscf, port, listen);
+    return ngx_http_add_address(cf, cscf, port, lsopt);
 }
 
 
@@ -1284,7 +1271,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
 
 static ngx_int_t
 ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
-    ngx_http_conf_port_t *port, ngx_http_listen_t *listen)
+    ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
 {
     ngx_http_conf_addr_t  *addr;
 
@@ -1302,68 +1289,56 @@ ngx_http_add_address(ngx_conf_t *cf, ngx
         return NGX_ERROR;
     }
 
-    addr->sockaddr = (struct sockaddr *) &listen->sockaddr;
-    addr->socklen = listen->socklen;
+    addr->opt = *lsopt;
     addr->hash.buckets = NULL;
     addr->hash.size = 0;
     addr->wc_head = NULL;
     addr->wc_tail = NULL;
-    addr->names.elts = NULL;
 #if (NGX_PCRE)
     addr->nregex = 0;
     addr->regex = NULL;
 #endif
-    addr->core_srv_conf = cscf;
-    addr->default_server = listen->conf.default_server;
-    addr->bind = listen->conf.bind;
-    addr->wildcard = listen->conf.wildcard;
-#if (NGX_HTTP_SSL)
-    addr->ssl = listen->conf.ssl;
-#endif
-    addr->listen_conf = &listen->conf;
+    addr->default_server = cscf;
+    addr->servers.elts = NULL;
 
-    return ngx_http_add_names(cf, cscf, addr);
+    return ngx_http_add_server(cf, cscf, addr);
 }
 
 
-/*
- * add the server names and the server core module
- * configurations to the address:port
- */
+/* add the server core module configuration to the address:port */
 
 static ngx_int_t
-ngx_http_add_names(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
+ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
     ngx_http_conf_addr_t *addr)
 {
-    ngx_uint_t               i;
-    ngx_http_server_name_t  *server_names, *name;
+    ngx_uint_t                  i;
+    ngx_http_core_srv_conf_t  **server;
 
-    if (addr->names.elts == NULL) {
-        if (ngx_array_init(&addr->names, cf->temp_pool, 4,
-                           sizeof(ngx_http_server_name_t))
+    if (addr->servers.elts == NULL) {
+        if (ngx_array_init(&addr->servers, cf->temp_pool, 4,
+                           sizeof(ngx_http_core_srv_conf_t *))
             != NGX_OK)
         {
             return NGX_ERROR;
         }
+
+    } else {
+        server = addr->servers.elts;
+        for (i = 0; i < addr->servers.nelts; i++) {
+            if (server[i] == cscf) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "a duplicate listen %s", addr->opt.addr);
+                return NGX_ERROR;
+            }
+        }
     }
 
-    server_names = cscf->server_names.elts;
-
-    for (i = 0; i < cscf->server_names.nelts; i++) {
-
-        ngx_strlow(server_names[i].name.data, server_names[i].name.data,
-                   server_names[i].name.len);
+    server = ngx_array_push(&addr->servers);
+    if (server == NULL) {
+        return NGX_ERROR;
+    }
 
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-                       "name: %V", &server_names[i].name);
-
-        name = ngx_array_push(&addr->names);
-        if (name == NULL) {
-            return NGX_ERROR;
-        }
-
-        *name = server_names[i];
-    }
+    *server = cscf;
 
     return NGX_OK;
 }
@@ -1373,10 +1348,9 @@ static ngx_int_t
 ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
     ngx_array_t *ports)
 {
-    ngx_uint_t               s, p, a;
-    ngx_http_conf_port_t    *port;
-    ngx_http_conf_addr_t    *addr;
-    ngx_http_server_name_t  *name;
+    ngx_uint_t               p, a;
+    ngx_http_conf_port_t  *port;
+    ngx_http_conf_addr_t  *addr;
 
     port = ports->elts;
     for (p = 0; p < ports->nelts; p++) {
@@ -1392,23 +1366,15 @@ ngx_http_optimize_servers(ngx_conf_t *cf
         addr = port[p].addrs.elts;
         for (a = 0; a < port[p].addrs.nelts; a++) {
 
-            name = addr[a].names.elts;
-            for (s = 0; s < addr[a].names.nelts; s++) {
-
-                if (addr[a].core_srv_conf == name[s].core_srv_conf
+            if (addr[a].servers.nelts > 1
 #if (NGX_PCRE)
-                    && name[s].captures == 0
+                || addr[a].default_server->captures
 #endif
-                    )
-                {
-                    continue;
-                }
-
+               )
+            {
                 if (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) {
                     return NGX_ERROR;
                 }
-
-                break;
             }
         }
 
@@ -1425,13 +1391,14 @@ static ngx_int_t
 ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
     ngx_http_conf_addr_t *addr)
 {
-    ngx_int_t                rc;
-    ngx_uint_t               s;
-    ngx_hash_init_t          hash;
-    ngx_hash_keys_arrays_t   ha;
-    ngx_http_server_name_t  *name;
+    ngx_int_t                   rc;
+    ngx_uint_t                  n, s;
+    ngx_hash_init_t             hash;
+    ngx_hash_keys_arrays_t      ha;
+    ngx_http_server_name_t     *name;
+    ngx_http_core_srv_conf_t  **cscfp;
 #if (NGX_PCRE)
-    ngx_uint_t               regex, i;
+    ngx_uint_t                  regex, i;
 
     regex = 0;
 #endif
@@ -1449,35 +1416,40 @@ ngx_http_server_names(ngx_conf_t *cf, ng
         goto failed;
     }
 
-    name = addr->names.elts;
+    cscfp = addr->servers.elts;
+
+    for (s = 0; s < addr->servers.nelts; s++) {
 
-    for (s = 0; s < addr->names.nelts; s++) {
+        name = cscfp[s]->server_names.elts;
+
+        for (n = 0; n < cscfp[s]->server_names.nelts; n++) {
 
 #if (NGX_PCRE)
-        if (name[s].regex) {
-            regex++;
-            continue;
-        }
+            if (name[n].regex) {
+                regex++;
+                continue;
+            }
 #endif
 
-        rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf,
-                              NGX_HASH_WILDCARD_KEY);
+            rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server,
+                                  NGX_HASH_WILDCARD_KEY);
 
-        if (rc == NGX_ERROR) {
-            return NGX_ERROR;
-        }
+            if (rc == NGX_ERROR) {
+                return NGX_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, addr->listen_conf->addr);
-            return NGX_ERROR;
-        }
+            if (rc == NGX_DECLINED) {
+                ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                              "invalid server name or wildcard \"%V\" on %s",
+                              &name[n].name, addr->opt.addr);
+                return NGX_ERROR;
+            }
 
-        if (rc == NGX_BUSY) {
+            if (rc == NGX_BUSY) {
             ngx_log_error(NGX_LOG_WARN, cf->log, 0,
-                          "conflicting server name \"%V\" on %s, ignored",
-                          &name[s].name, addr->listen_conf->addr);
+                              "conflicting server name \"%V\" on %s, ignored",
+                              &name[n].name, addr->opt.addr);
+            }
         }
     }
 
@@ -1546,9 +1518,16 @@ ngx_http_server_names(ngx_conf_t *cf, ng
         return NGX_ERROR;
     }
 
-    for (i = 0, s = 0; s < addr->names.nelts; s++) {
-        if (name[s].regex) {
-            addr->regex[i++] = name[s];
+    i = 0;
+
+    for (s = 0; s < addr->servers.nelts; s++) {
+
+        name = cscfp[s]->server_names.elts;
+
+        for (n = 0; n < cscfp[s]->server_names.nelts; n++) {
+            if (name[n].regex) {
+                addr->regex[i++] = name[n];
+            }
         }
     }
 
@@ -1572,17 +1551,17 @@ ngx_http_cmp_conf_addrs(const void *one,
     first = (ngx_http_conf_addr_t *) one;
     second = (ngx_http_conf_addr_t *) two;
 
-    if (first->wildcard) {
+    if (first->opt.wildcard) {
         /* a wildcard address must be the last resort, shift it to the end */
         return 1;
     }
 
-    if (first->bind && !second->bind) {
+    if (first->opt.bind && !second->opt.bind) {
         /* shift explicit bind()ed addresses to the start */
         return -1;
     }
 
-    if (!first->bind && second->bind) {
+    if (!first->opt.bind && second->opt.bind) {
         /* shift explicit bind()ed addresses to the start */
         return 1;
     }
@@ -1623,8 +1602,8 @@ ngx_http_init_listening(ngx_conf_t *cf, 
      * implicit bindings go, and wildcard binding is in the end.
      */
 
-    if (addr[last - 1].wildcard) {
-        addr[last - 1].bind = 1;
+    if (addr[last - 1].opt.wildcard) {
+        addr[last - 1].opt.bind = 1;
         bind_wildcard = 1;
 
     } else {
@@ -1635,7 +1614,7 @@ ngx_http_init_listening(ngx_conf_t *cf, 
 
     while (i < last) {
 
-        if (bind_wildcard && !addr[i].bind) {
+        if (bind_wildcard && !addr[i].opt.bind) {
             i++;
             continue;
         }
@@ -1691,7 +1670,7 @@ ngx_http_add_listening(ngx_conf_t *cf, n
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
 
-    ls = ngx_create_listening(cf, addr->sockaddr, addr->socklen);
+    ls = ngx_create_listening(cf, addr->opt.sockaddr, addr->opt.socklen);
     if (ls == NULL) {
         return NULL;
     }
@@ -1700,7 +1679,7 @@ ngx_http_add_listening(ngx_conf_t *cf, n
 
     ls->handler = ngx_http_init_connection;
 
-    cscf = addr->core_srv_conf;
+    cscf = addr->default_server;
     ls->pool_size = cscf->connection_pool_size;
     ls->post_accept_timeout = cscf->client_header_timeout;
 
@@ -1721,20 +1700,20 @@ ngx_http_add_listening(ngx_conf_t *cf, n
     }
 #endif
 
-    ls->backlog = addr->listen_conf->backlog;
-    ls->rcvbuf = addr->listen_conf->rcvbuf;
-    ls->sndbuf = addr->listen_conf->sndbuf;
+    ls->backlog = addr->opt.backlog;
+    ls->rcvbuf = addr->opt.rcvbuf;
+    ls->sndbuf = addr->opt.sndbuf;
 
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
-    ls->accept_filter = addr->listen_conf->accept_filter;
+    ls->accept_filter = addr->opt.accept_filter;
 #endif
 
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
-    ls->deferred_accept = addr->listen_conf->deferred_accept;
+    ls->deferred_accept = addr->opt.deferred_accept;
 #endif
 
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
-    ls->ipv6only = addr->listen_conf->ipv6only;
+    ls->ipv6only = addr->opt.ipv6only;
 #endif
 
     return ls;
@@ -1760,11 +1739,11 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h
 
     for (i = 0; i < hport->naddrs; i++) {
 
-        sin = (struct sockaddr_in *) addr[i].sockaddr;
+        sin = (struct sockaddr_in *) addr[i].opt.sockaddr;
         addrs[i].addr = sin->sin_addr.s_addr;
-        addrs[i].conf.core_srv_conf = addr[i].core_srv_conf;
+        addrs[i].conf.default_server = addr[i].default_server;
 #if (NGX_HTTP_SSL)
-        addrs[i].conf.ssl = addr[i].ssl;
+        addrs[i].conf.ssl = addr[i].opt.ssl;
 #endif
 
         if (addr[i].hash.buckets == NULL
@@ -1821,11 +1800,11 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_
 
     for (i = 0; i < hport->naddrs; i++) {
 
-        sin6 = (struct sockaddr_in6 *) addr[i].sockaddr;
+        sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr;
         addrs6[i].addr6 = sin6->sin6_addr;
-        addrs6[i].conf.core_srv_conf = addr[i].core_srv_conf;
+        addrs6[i].conf.default_server = addr[i].default_server;
 #if (NGX_HTTP_SSL)
-        addrs6[i].conf.ssl = addr[i].ssl;
+        addrs6[i].conf.ssl = addr[i].opt.ssl;
 #endif
 
         if (addr[i].hash.buckets == NULL
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -57,6 +57,8 @@ struct ngx_http_log_ctx_s {
 
 ngx_int_t ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
     ngx_http_core_loc_conf_t *clcf);
+ngx_int_t ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
+    ngx_http_listen_opt_t *lsopt);
 
 
 void ngx_http_init_connection(ngx_connection_t *c);
@@ -118,6 +120,7 @@ size_t ngx_http_get_time(char *buf, time
 
 
 ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r);
+void ngx_http_discarded_request_body_handler(ngx_http_request_t *r);
 void ngx_http_block_reading(ngx_http_request_t *r);
 void ngx_http_test_reading(ngx_http_request_t *r);
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -2807,13 +2807,6 @@ ngx_http_core_create_srv_conf(ngx_conf_t
      *     conf->client_large_buffers.num = 0;
      */
 
-    if (ngx_array_init(&cscf->listen, cf->temp_pool, 4,
-                       sizeof(ngx_http_listen_t))
-        != NGX_OK)
-    {
-        return NULL;
-    }
-
     if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4,
                        sizeof(ngx_http_server_name_t))
         != NGX_OK)
@@ -2839,21 +2832,16 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
     ngx_http_core_srv_conf_t *prev = parent;
     ngx_http_core_srv_conf_t *conf = child;
 
-    ngx_http_listen_t       *ls;
     struct sockaddr_in      *sin;
+    ngx_http_listen_opt_t    lsopt;
     ngx_http_server_name_t  *sn;
 
     /* TODO: it does not merge, it inits only */
 
-    if (conf->listen.nelts == 0) {
-        ls = ngx_array_push(&conf->listen);
-        if (ls == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        ngx_memzero(ls, sizeof(ngx_http_listen_t));
-
-        sin = (struct sockaddr_in *) &ls->sockaddr;
+    if (!conf->listen) {
+        ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));
+
+        sin = (struct sockaddr_in *) &lsopt.sockaddr;
 
         sin->sin_family = AF_INET;
 #if (NGX_WIN32)
@@ -2863,15 +2851,19 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
 #endif
         sin->sin_addr.s_addr = INADDR_ANY;
 
-        ls->socklen = sizeof(struct sockaddr_in);
-
-        ls->conf.backlog = NGX_LISTEN_BACKLOG;
-        ls->conf.rcvbuf = -1;
-        ls->conf.sndbuf = -1;
-        ls->conf.wildcard = 1;
-
-        (void) ngx_sock_ntop((struct sockaddr *) &ls->sockaddr, ls->conf.addr,
+        lsopt.socklen = sizeof(struct sockaddr_in);
+
+        lsopt.backlog = NGX_LISTEN_BACKLOG;
+        lsopt.rcvbuf = -1;
+        lsopt.sndbuf = -1;
+        lsopt.wildcard = 1;
+
+        (void) ngx_sock_ntop((struct sockaddr *) &lsopt.sockaddr, lsopt.addr,
                              NGX_SOCKADDR_STRLEN, 1);
+
+        if (ngx_http_add_listen(cf, conf, &lsopt) == NGX_OK) {
+            return NGX_CONF_OK;
+        }
     }
 
     if (conf->server_name.data == NULL) {
@@ -2884,9 +2876,8 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
 
 #if (NGX_PCRE)
         sn->regex = NULL;
-        sn->captures = 0;
 #endif
-        sn->core_srv_conf = conf;
+        sn->server = conf;
         sn->name.len = conf->server_name.len;
         sn->name.data = conf->server_name.data;
     }
@@ -3273,17 +3264,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
 static char *
 ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_core_srv_conf_t *scf = conf;
-
-    ngx_str_t          *value, size;
-    ngx_url_t           u;
-    ngx_uint_t          n;
-    ngx_http_listen_t  *ls;
-
-    /*
-     * TODO: check duplicate 'listen' directives,
-     *       add resolved name to server names ???
-     */
+    ngx_http_core_srv_conf_t *cscf = conf;
+
+    ngx_str_t              *value, size;
+    ngx_url_t               u;
+    ngx_uint_t              n;
+    ngx_http_listen_opt_t   lsopt;
+
+    cscf->listen = 1;
 
     value = cf->args->elts;
 
@@ -3303,58 +3291,40 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    ls = ngx_array_push(&scf->listen);
-    if (ls == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    ngx_memzero(ls, sizeof(ngx_http_listen_t));
-
-    ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen);
-
-    ls->socklen = u.socklen;
-    ls->file_name = cf->conf_file->file.name.data;
-    ls->line = cf->conf_file->line;
-    ls->conf.backlog = NGX_LISTEN_BACKLOG;
-    ls->conf.rcvbuf = -1;
-    ls->conf.sndbuf = -1;
-    ls->conf.wildcard = u.wildcard;
-
-    (void) ngx_sock_ntop((struct sockaddr *) &ls->sockaddr, ls->conf.addr,
+    ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));
+
+    ngx_memcpy(lsopt.sockaddr, u.sockaddr, u.socklen);
+
+    lsopt.socklen = u.socklen;
+    lsopt.backlog = NGX_LISTEN_BACKLOG;
+    lsopt.rcvbuf = -1;
+    lsopt.sndbuf = -1;
+    lsopt.wildcard = u.wildcard;
+
+    (void) ngx_sock_ntop((struct sockaddr *) &lsopt.sockaddr, lsopt.addr,
                          NGX_SOCKADDR_STRLEN, 1);
 
-    if (cf->args->nelts == 2) {
-        return NGX_CONF_OK;
-    }
-
-    if (ngx_strcmp(value[2].data, "default") == 0) {
-        ls->conf.default_server = 1;
-        n = 3;
-
-    } else {
-        n = 2;
-    }
-
-    for ( /* void */ ; n < cf->args->nelts; n++) {
-
-        if (ls->conf.default_server == 0) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "\"%V\" parameter can be specified for "
-                               "the default \"listen\" directive only",
-                               &value[n]);
-            return NGX_CONF_ERROR;
+    for (n = 2; n < cf->args->nelts; n++) {
+
+        if (ngx_strcmp(value[n].data, "default_server") == 0
+            || ngx_strcmp(value[n].data, "default") == 0)
+        {
+            lsopt.default_server = 1;
+            continue;
         }
 
         if (ngx_strcmp(value[n].data, "bind") == 0) {
-            ls->conf.bind = 1;
+            lsopt.set = 1;
+            lsopt.bind = 1;
             continue;
         }
 
         if (ngx_strncmp(value[n].data, "backlog=", 8) == 0) {
-            ls->conf.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);
-            ls->conf.bind = 1;
-
-            if (ls->conf.backlog == NGX_ERROR || ls->conf.backlog == 0) {
+            lsopt.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);
+            lsopt.set = 1;
+            lsopt.bind = 1;
+
+            if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                    "invalid backlog \"%V\"", &value[n]);
                 return NGX_CONF_ERROR;
@@ -3367,10 +3337,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
             size.len = value[n].len - 7;
             size.data = value[n].data + 7;
 
-            ls->conf.rcvbuf = ngx_parse_size(&size);
-            ls->conf.bind = 1;
-
-            if (ls->conf.rcvbuf == NGX_ERROR) {
+            lsopt.rcvbuf = ngx_parse_size(&size);
+            lsopt.set = 1;
+            lsopt.bind = 1;
+
+            if (lsopt.rcvbuf == NGX_ERROR) {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                    "invalid rcvbuf \"%V\"", &value[n]);
                 return NGX_CONF_ERROR;
@@ -3383,10 +3354,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
             size.len = value[n].len - 7;
             size.data = value[n].data + 7;
 
-            ls->conf.sndbuf = ngx_parse_size(&size);
-            ls->conf.bind = 1;
-
-            if (ls->conf.sndbuf == NGX_ERROR) {
+            lsopt.sndbuf = ngx_parse_size(&size);
+            lsopt.set = 1;
+            lsopt.bind = 1;
+
+            if (lsopt.sndbuf == NGX_ERROR) {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                    "invalid sndbuf \"%V\"", &value[n]);
                 return NGX_CONF_ERROR;
@@ -3397,8 +3369,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
         if (ngx_strncmp(value[n].data, "accept_filter=", 14) == 0) {
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
-            ls->conf.accept_filter = (char *) &value[n].data[14];
-            ls->conf.bind = 1;
+            lsopt.accept_filter = (char *) &value[n].data[14];
+            lsopt.set = 1;
+            lsopt.bind = 1;
 #else
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "accept filters \"%V\" are not supported "
@@ -3410,8 +3383,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
         if (ngx_strcmp(value[n].data, "deferred") == 0) {
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
-            ls->conf.deferred_accept = 1;
-            ls->conf.bind = 1;
+            lsopt.deferred_accept = 1;
+            lsopt.set = 1;
+            lsopt.bind = 1;
 #else
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "the deferred accept is not supported "
@@ -3424,15 +3398,15 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
             struct sockaddr  *sa;
 
-            sa = (struct sockaddr *) ls->sockaddr;
+            sa = (struct sockaddr *) lsopt.sockaddr;
 
             if (sa->sa_family == AF_INET6) {
 
                 if (ngx_strcmp(&value[n].data[10], "n") == 0) {
-                    ls->conf.ipv6only = 1;
+                    lsopt.ipv6only = 1;
 
                 } else if (ngx_strcmp(&value[n].data[10], "ff") == 0) {
-                    ls->conf.ipv6only = 2;
+                    lsopt.ipv6only = 2;
 
                 } else {
                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3441,13 +3415,13 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
                     return NGX_CONF_ERROR;
                 }
 
-                ls->conf.bind = 1;
+                lsopt.set = 1;
+                lsopt.bind = 1;
 
             } else {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                    "ipv6only is not supported "
-                                   "on addr \"%s\", ignored",
-                                   ls->conf.addr);
+                                   "on addr \"%s\", ignored", lsopt.addr);
             }
 
             continue;
@@ -3461,7 +3435,8 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
         if (ngx_strcmp(value[n].data, "ssl") == 0) {
 #if (NGX_HTTP_SSL)
-            ls->conf.ssl = 1;
+            lsopt.set = 1;
+            lsopt.ssl = 1;
             continue;
 #else
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -3476,7 +3451,11 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    return NGX_CONF_OK;
+    if (ngx_http_add_listen(cf, cscf, &lsopt) == NGX_OK) {
+        return NGX_CONF_OK;
+    }
+
+    return NGX_CONF_ERROR;
 }
 
 
@@ -3548,11 +3527,12 @@ ngx_http_core_server_name(ngx_conf_t *cf
 
 #if (NGX_PCRE)
         sn->regex = NULL;
-        sn->captures = 0;
 #endif
-        sn->core_srv_conf = cscf;
+        sn->server = cscf;
         sn->name = value[i];
 
+        ngx_strlow(sn->name.data, sn->name.data, sn->name.len);
+
         if (value[i].data[0] != '~') {
             continue;
         }
@@ -3581,8 +3561,8 @@ ngx_http_core_server_name(ngx_conf_t *cf
             return NGX_CONF_ERROR;
         }
 
-        sn->captures = (ngx_regex_capture_count(sn->regex) > 0);
         sn->name = value[i];
+        cscf->captures = (ngx_regex_capture_count(sn->regex) > 0);
         }
 #else
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -43,6 +43,10 @@ typedef struct ngx_http_core_loc_conf_s 
 
 
 typedef struct {
+    u_char                     sockaddr[NGX_SOCKADDRLEN];
+    socklen_t                  socklen;
+
+    unsigned                   set:1;
     unsigned                   default_server:1;
     unsigned                   bind:1;
     unsigned                   wildcard:1;
@@ -65,18 +69,7 @@ typedef struct {
 #endif
 
     u_char                     addr[NGX_SOCKADDR_STRLEN + 1];
-} ngx_http_listen_conf_t;
-
-
-typedef struct {
-    u_char                     sockaddr[NGX_SOCKADDRLEN];
-    socklen_t                  socklen;
-
-    u_char                    *file_name;
-    ngx_uint_t                 line;
-
-    ngx_http_listen_conf_t     conf;
-} ngx_http_listen_t;
+} ngx_http_listen_opt_t;
 
 
 typedef enum {
@@ -142,6 +135,8 @@ typedef struct {
 
     ngx_hash_keys_arrays_t    *variables_keys;
 
+    ngx_array_t               *ports;
+
     ngx_uint_t                 try_files;       /* unsigned  try_files:1 */
 
     ngx_http_phase_t           phases[NGX_HTTP_LOG_PHASE + 1];
@@ -149,9 +144,6 @@ typedef struct {
 
 
 typedef struct {
-    /* array of the ngx_http_listen_t, "listen" directive */
-    ngx_array_t                 listen;
-
     /* array of the ngx_http_server_name_t, "server_name" directive */
     ngx_array_t                 server_names;
 
@@ -172,6 +164,11 @@ typedef struct {
     ngx_flag_t                  merge_slashes;
     ngx_flag_t                  underscores_in_headers;
 
+    unsigned                    listen:1;
+#if (NGX_PCRE)
+    unsigned                    captures:1;
+#endif
+
     ngx_http_core_loc_conf_t  **named_locations;
 } ngx_http_core_srv_conf_t;
 
@@ -181,7 +178,7 @@ typedef struct {
 
 typedef struct {
     /* the default server configuration for this address:port */
-    ngx_http_core_srv_conf_t  *core_srv_conf;
+    ngx_http_core_srv_conf_t  *default_server;
 
     ngx_http_virtual_names_t  *virtual_names;
 
@@ -222,40 +219,28 @@ typedef struct {
 
 
 typedef struct {
-    struct sockaddr           *sockaddr;
-    socklen_t                  socklen;
+    ngx_http_listen_opt_t      opt;
 
     ngx_hash_t                 hash;
     ngx_hash_wildcard_t       *wc_head;
     ngx_hash_wildcard_t       *wc_tail;
 
-    ngx_array_t                names;      /* array of ngx_http_server_name_t */
-
 #if (NGX_PCRE)
     ngx_uint_t                 nregex;
     ngx_http_server_name_t    *regex;
 #endif
 
     /* the default server configuration for this address:port */
-    ngx_http_core_srv_conf_t  *core_srv_conf;
-
-    unsigned                   default_server:1;
-    unsigned                   bind:1;
-    unsigned                   wildcard:1;
-#if (NGX_HTTP_SSL)
-    unsigned                   ssl:1;
-#endif
-
-    ngx_http_listen_conf_t    *listen_conf;
+    ngx_http_core_srv_conf_t  *default_server;
+    ngx_array_t                servers;  /* array of ngx_http_core_srv_conf_t */
 } ngx_http_conf_addr_t;
 
 
 struct ngx_http_server_name_s {
 #if (NGX_PCRE)
     ngx_regex_t               *regex;
-    ngx_uint_t                 captures;      /* unsigned  captures:1; */
 #endif
-    ngx_http_core_srv_conf_t  *core_srv_conf; /* virtual name server conf */
+    ngx_http_core_srv_conf_t  *server;   /* virtual name server conf */
     ngx_str_t                  name;
 };
 
--- a/src/http/ngx_http_parse_time.c
+++ b/src/http/ngx_http_parse_time.c
@@ -8,13 +8,15 @@
 #include <ngx_core.h>
 
 
-static int mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+static ngx_uint_t  mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
 
 time_t
 ngx_http_parse_time(u_char *value, size_t len)
 {
-    u_char  *p, *end;
-    int      day, month, year, hour, min, sec;
+    u_char      *p, *end;
+    ngx_int_t    month;
+    ngx_uint_t   day, year, hour, min, sec;
+    uint64_t     time;
     enum {
         no = 0,
         rfc822,   /* Tue, 10 Nov 2002 23:50:13   */
@@ -229,14 +231,6 @@ ngx_http_parse_time(u_char *value, size_
         return NGX_ERROR;
     }
 
-#if (NGX_TIME_T_SIZE <= 4)
-
-    if (year >= 2038) {
-        return NGX_ERROR;
-    }
-
-#endif
-
     /*
      * shift new year to March 1 and start months from 1 (not 0),
      * it is needed for Gauss' formula
@@ -249,7 +243,7 @@ ngx_http_parse_time(u_char *value, size_
 
     /* Gauss' formula for Grigorian days since March 1, 1 BC */
 
-    return (
+    time = (uint64_t) (
             /* days in years including leap years since March 1, 1 BC */
 
             365 * year + year / 4 - year / 100 + year / 400
@@ -268,4 +262,14 @@ ngx_http_parse_time(u_char *value, size_
              */
 
             - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;
+
+#if (NGX_TIME_T_SIZE <= 4)
+
+    if (time > 0x7fffffff) {
+        return NGX_ERROR;
+    }
+
+#endif
+
+    return (time_t) time;
 }
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -381,7 +381,7 @@ ngx_http_init_request(ngx_event_t *rev)
     r->virtual_names = addr_conf->virtual_names;
 
     /* the default server configuration for the address:port */
-    cscf = addr_conf->core_srv_conf;
+    cscf = addr_conf->default_server;
 
     r->main_conf = cscf->ctx->main_conf;
     r->srv_conf = cscf->ctx->srv_conf;
@@ -1688,7 +1688,7 @@ ngx_http_find_virtual_server(ngx_http_re
 
 #if (NGX_PCRE)
 
-    if (r->virtual_names->nregex) {
+    if (len && r->virtual_names->nregex) {
         size_t                   ncaptures;
         ngx_int_t                n;
         ngx_uint_t               i;
@@ -1704,7 +1704,7 @@ ngx_http_find_virtual_server(ngx_http_re
 
         for (i = 0; i < r->virtual_names->nregex; i++) {
 
-            if (sn[i].captures && r->captures == NULL) {
+            if (sn[i].server->captures && r->captures == NULL) {
 
                 ncaptures = (NGX_HTTP_MAX_CAPTURES + 1) * 3;
 
@@ -1730,7 +1730,7 @@ ngx_http_find_virtual_server(ngx_http_re
 
             /* match */
 
-            cscf = sn[i].core_srv_conf;
+            cscf = sn[i].server;
 
             r->ncaptures = ncaptures;
             r->captures_data = host;
@@ -2101,13 +2101,24 @@ ngx_http_finalize_connection(ngx_http_re
 {
     ngx_http_core_loc_conf_t  *clcf;
 
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
     if (r->main->count != 1) {
+
+        if (r->discard_body) {
+            r->read_event_handler = ngx_http_discarded_request_body_handler;
+
+            if (r->lingering_time == 0) {
+                r->lingering_time = ngx_time()
+                                      + (time_t) (clcf->lingering_time / 1000);
+                ngx_add_timer(r->connection->read, clcf->lingering_timeout);
+            }
+        }
+
         ngx_http_close_request(r, 0);
         return;
     }
 
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
     if (!ngx_terminate
          && !ngx_exiting
          && r->keepalive
@@ -2133,7 +2144,9 @@ ngx_http_set_write_handler(ngx_http_requ
 
     r->http_state = NGX_HTTP_WRITING_REQUEST_STATE;
 
-    r->read_event_handler = ngx_http_test_reading;
+    r->read_event_handler = r->discard_body ?
+                                ngx_http_discarded_request_body_handler:
+                                ngx_http_test_reading;
     r->write_event_handler = ngx_http_writer;
 
     wev = r->connection->write;
@@ -2235,6 +2248,8 @@ ngx_http_writer(ngx_http_request_t *r)
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0,
                    "http writer done: \"%V?%V\"", &r->uri, &r->args);
 
+    r->write_event_handler = ngx_http_request_empty_handler;
+
     ngx_http_finalize_request(r, rc);
 }
 
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -13,7 +13,6 @@ static void ngx_http_read_client_request
 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r,
     ngx_chain_t *body);
-static void ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r);
 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
 
@@ -460,6 +459,7 @@ ngx_http_discard_request_body(ngx_http_r
 
     if (size) {
         if (r->headers_in.content_length_n > size) {
+            r->header_in->pos += size;
             r->headers_in.content_length_n -= size;
 
         } else {
@@ -469,7 +469,7 @@ ngx_http_discard_request_body(ngx_http_r
         }
     }
 
-    r->read_event_handler = ngx_http_read_discarded_request_body_handler;
+    r->read_event_handler = ngx_http_discarded_request_body_handler;
 
     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -487,8 +487,8 @@ ngx_http_discard_request_body(ngx_http_r
 }
 
 
-static void
-ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r)
+void
+ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
 {
     ngx_int_t                  rc;
     ngx_msec_t                 timer;
@@ -502,7 +502,7 @@ ngx_http_read_discarded_request_body_han
     if (rev->timedout) {
         c->timedout = 1;
         c->error = 1;
-        ngx_http_finalize_request(r, 0);
+        ngx_http_finalize_request(r, NGX_ERROR);
         return;
     }
 
@@ -512,7 +512,7 @@ ngx_http_read_discarded_request_body_han
         if (timer <= 0) {
             r->discard_body = 0;
             r->lingering_close = 0;
-            ngx_http_finalize_request(r, 0);
+            ngx_http_finalize_request(r, NGX_ERROR);
             return;
         }
 
@@ -523,14 +523,9 @@ ngx_http_read_discarded_request_body_han
     rc = ngx_http_read_discarded_request_body(r);
 
     if (rc == NGX_OK) {
-
         r->discard_body = 0;
         r->lingering_close = 0;
-
-        if (r->done) {
-            ngx_http_finalize_request(r, 0);
-        }
-
+        ngx_http_finalize_request(r, NGX_DONE);
         return;
     }
 
@@ -538,7 +533,7 @@ ngx_http_read_discarded_request_body_han
 
     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
         c->error = 1;
-        ngx_http_finalize_request(r, rc);
+        ngx_http_finalize_request(r, NGX_ERROR);
         return;
     }
 
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -675,6 +675,8 @@ ngx_master_process_exit(ngx_cycle_t *cyc
         }
     }
 
+    ngx_close_listening_sockets(cycle);
+
     /*
      * Copy ngx_cycle->log related data to the special static exit cycle,
      * log, and log file structures enough to allow a signal handler to log.