changeset 366:babd3d9efb62 NGINX_0_6_27

nginx 0.6.27 *) Change: now by default the rtsig method is not built on Linux 2.6.18+. *) Change: now a request method is not changed while redirection to a named location via an "error_page" directive. *) Feature: the "resolver" and "resolver_timeout" directives in SMTP proxy. *) Feature: the "post_action" directive supports named locations. *) Bugfix: a segmentation fault occurred in worker process, if a request was redirected from proxy, FastCGI, or memcached location to static named locations. *) Bugfix: browsers did not repeat SSL handshake if there is no valid client certificate in first handshake. Thanks to Alexander V. Inyukhin. *) Bugfix: if response code 495-497 was redirected via an "error_page" directive without code change, then nginx tried to allocate too many memory. *) Bugfix: memory leak in long-lived non buffered connections. *) Bugfix: memory leak in resolver. *) Bugfix: a segmentation fault occurred in worker process, if a request was redirected from proxy, FastCGI, or memcached location to static named locations. *) Bugfix: in the $proxy_host and $proxy_port variables caching. Thanks to Sergey Bochenkov. *) Bugfix: a "proxy_pass" directive with variables used incorrectly the same port as in another "proxy_pass" directive with the same host name and without variables. Thanks to Sergey Bochenkov. *) Bugfix: an alert "sendmsg() failed (9: Bad file descriptor)" on some 64-bit platforms while reconfiguration. *) Bugfix: a segmentation fault occurred in worker process, if empty stub block was used second time in SSI. *) Bugfix: in copying URI part contained escaped symbols into arguments.
author Igor Sysoev <http://sysoev.ru>
date Wed, 12 Mar 2008 00:00:00 +0300
parents 9b0140fa1132
children 579b892330d8
files CHANGES CHANGES.ru auto/os/linux conf/nginx.conf src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_connection.c src/core/ngx_file.c src/core/ngx_file.h src/core/ngx_resolver.c src/core/ngx_resolver.h src/event/ngx_event.h src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/nginx.xs src/http/modules/perl/ngx_http_perl_module.c src/http/modules/perl/ngx_http_perl_module.h src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/http/ngx_http_script.c src/http/ngx_http_script.h src/http/ngx_http_special_response.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h src/mail/ngx_mail.h src/mail/ngx_mail_core_module.c src/mail/ngx_mail_proxy_module.c src/mail/ngx_mail_smtp_handler.c src/os/unix/ngx_channel.c src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_linux_init.c src/os/unix/ngx_posix_config.h src/os/unix/ngx_process_cycle.c
diffstat 39 files changed, 689 insertions(+), 107 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,54 @@
 
+Changes with nginx 0.6.27                                        12 Mar 2008
+
+    *) Change: now by default the rtsig method is not built on 
+       Linux 2.6.18+.
+
+    *) Change: now a request method is not changed while redirection to a 
+       named location via an "error_page" directive.
+
+    *) Feature: the "resolver" and "resolver_timeout" directives in SMTP 
+       proxy.
+
+    *) Feature: the "post_action" directive supports named locations.
+
+    *) Bugfix: a segmentation fault occurred in worker process, if a 
+       request was redirected from proxy, FastCGI, or memcached location to 
+       static named locations.
+
+    *) Bugfix: browsers did not repeat SSL handshake if there is no valid 
+       client certificate in first handshake. 
+       Thanks to Alexander V. Inyukhin.
+
+    *) Bugfix: if response code 495-497 was redirected via an "error_page" 
+       directive without code change, then nginx tried to allocate too many 
+       memory.
+
+    *) Bugfix: memory leak in long-lived non buffered connections.
+
+    *) Bugfix: memory leak in resolver.
+
+    *) Bugfix: a segmentation fault occurred in worker process, if a 
+       request was redirected from proxy, FastCGI, or memcached location to 
+       static named locations.
+
+    *) Bugfix: in the $proxy_host and $proxy_port variables caching.
+       Thanks to Sergey Bochenkov.
+
+    *) Bugfix: a "proxy_pass" directive with variables used incorrectly the 
+       same port as in another "proxy_pass" directive with the same host 
+       name and without variables.
+       Thanks to Sergey Bochenkov.
+
+    *) Bugfix: an alert "sendmsg() failed (9: Bad file descriptor)" on some 
+       64-bit platforms while reconfiguration.
+
+    *) Bugfix: a segmentation fault occurred in worker process, if empty 
+       stub block was used second time in SSI.
+
+    *) Bugfix: in copying URI part contained escaped symbols into arguments.
+
+
 Changes with nginx 0.6.26                                        11 Feb 2008
 
     *) Bugfix: the "proxy_store" and "fastcgi_store" directives did not 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,60 @@
 
+Изменения в nginx 0.6.27                                          12.03.2008
+
+    *) Изменение: теперь на Linux 2.6.18+ по умолчанию не собирается метод 
+       rtsig.
+
+    *) Изменение: теперь при перенаправлении запроса в именованный location 
+       с помощью директивы error_page метод запроса не изменяется.
+
+    *) Добавление: директивы resolver и resolver_timeout в SMTP 
+       прокси-сервере.
+
+    *) Добавление: директива post_action поддерживает именованные 
+       location'ы.
+
+    *) Исправление: при перенаправлении запроса из location'а c 
+       обработчиком proxy, FastCGI или memcached в именованный location со 
+       статическим обработчиком в рабочем процессе происходил segmentation 
+       fault.
+
+    *) Исправление: браузеры не повторяли SSL handshake, если при первом 
+       handshake не оказалось правильного клиентского сертификата. 
+       Спасибо Александру Инюхину.
+
+    *) Исправление: при перенаправлении ошибок 495-497 с помощью директивы 
+       error_page без изменения кода ошибки nginx пытался выделить очень 
+       много памяти.
+
+    *) Исправление: утечки памяти в долгоживущих небуфферизированных 
+       соединениях.
+
+    *) Исправление: утечки памяти в resolver'е.
+
+    *) Исправление: при перенаправлении запроса из location'а c 
+       обработчиком proxy в другой location с обработчиком proxy в рабочем 
+       процессе происходил segmentation fault.
+
+    *) Исправление: ошибки в кэшировании переменных $proxy_host и 
+       $proxy_port.
+       Спасибо Сергею Боченкову.
+
+    *) Исправление: директива proxy_pass с переменными использовала порт, 
+       описанной в другой директиве proxy_pass без переменных, но с таким 
+       же именем хоста.
+       Спасибо Сергею Боченкову.
+
+    *) Исправление: во время переконфигурации на некоторых 64-битном 
+       платформах в лог записывался alert "sendmsg() failed (9: Bad file 
+       descriptor)".
+
+    *) Исправление: при повторном использовании в SSI пустого block'а в 
+       качестве заглушки в рабочем процессе происходил segmentation fault.
+
+    *) Исправление: ошибки при копировании части URI, содержащего 
+       экранированные символы, в аргументы.
+
+
 Изменения в nginx 0.6.26                                          11.02.2008
 
     *) Исправление: директивы proxy_store и fastcgi_store не проверяли 
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -16,18 +16,18 @@ CC_AUX_FLAGS="$CC_AUX_FLAGS -D_GNU_SOURC
 
 # Linux kernel version
 
-version=`grep "#define LINUX_VERSION_CODE" /usr/include/linux/version.h \
-         | sed -e 's/^.* \(.*\)$/\1/'`
+version=$((`uname -r \
+         | sed 's/^\([^.]*\)\.\([^.]*\)\.\([^.-]*\).*/\1*256*256+\2*256+\3/'`))
 
 version=${version:-0}
 
 
-# enable the rt signals on Linux 2.2.19 and onward
+# enable the rt signals on Linux between 2.2.19 and 2.6.17
 
-if [ $version -ge 131609 -o $EVENT_RTSIG = YES ]; then
+if [ \( $version -ge 131603 -a $version -lt 132626 \) -o $EVENT_RTSIG = YES ]
+then
     echo " + rt signals found"
     have=NGX_HAVE_RTSIG . auto/have
-    have=NGX_HAVE_POLL . auto/have
     EVENT_MODULES="$EVENT_MODULES $RTSIG_MODULE"
     CORE_SRCS="$CORE_SRCS $RTSIG_SRCS"
     EVENT_FOUND=YES
--- a/conf/nginx.conf
+++ b/conf/nginx.conf
@@ -63,6 +63,7 @@ http {
         # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
         #
         #location ~ \.php$ {
+        #    root           html;
         #    fastcgi_pass   127.0.0.1:9000;
         #    fastcgi_index  index.php;
         #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.6.26"
+#define NGINX_VERSION      "0.6.27"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -633,7 +633,7 @@ ngx_conf_include(ngx_conf_t *cf, ngx_com
 {
     char        *rv;
     ngx_int_t    n;
-    ngx_str_t   *value, file;
+    ngx_str_t   *value, file, name;
     ngx_glob_t   gl;
 
     value = cf->args->elts;
@@ -659,12 +659,15 @@ ngx_conf_include(ngx_conf_t *cf, ngx_com
     rv = NGX_CONF_OK;
 
     for ( ;; ) {
-        n = ngx_read_glob(&gl, &file);
+        n = ngx_read_glob(&gl, &name);
 
         if (n != NGX_OK) {
             break;
         }
 
+        file.len = name.len++;
+        file.data = ngx_pstrdup(cf->pool, &name);
+
         ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
 
         rv = ngx_conf_parse(cf, &file);
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -661,6 +661,8 @@ ngx_free_connection(ngx_connection_t *c)
 void
 ngx_close_connection(ngx_connection_t *c)
 {
+    ngx_err_t     err;
+    ngx_uint_t    log_error, level;
     ngx_socket_t  fd;
 
     if (c->fd == -1) {
@@ -733,6 +735,8 @@ ngx_close_connection(ngx_connection_t *c
 
 #endif
 
+    log_error = c->log_error;
+
     ngx_free_connection(c);
 
     fd = c->fd;
@@ -740,9 +744,31 @@ ngx_close_connection(ngx_connection_t *c
 
     if (ngx_close_socket(fd) == -1) {
 
+        err = ngx_socket_errno;
+
+        if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) {
+
+            switch (log_error) {
+
+            case NGX_ERROR_INFO:
+                level = NGX_LOG_INFO;
+                break;
+
+            case NGX_ERROR_ERR:
+                level = NGX_LOG_ERR;
+                break;
+
+            default:
+                level = NGX_LOG_CRIT;
+            }
+
+        } else {
+            level = NGX_LOG_CRIT;
+        }
+
         /* we use ngx_cycle->log because c->log was in c->pool */
 
-        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+        ngx_log_error(level, ngx_cycle->log, err,
                       ngx_close_socket_n " %d failed", fd);
     }
 }
@@ -784,11 +810,11 @@ ngx_connection_error(ngx_connection_t *c
             break;
 
         default:
-            level = NGX_LOG_CRIT;
+            level = NGX_LOG_ALERT;
         }
 
     } else {
-        level = NGX_LOG_CRIT;
+        level = NGX_LOG_ALERT;
     }
 
     ngx_log_error(level, c->log, err, text);
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -554,7 +554,7 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_
 
 failed:
 
-    if (ext->delete) {
+    if (ext->delete_file) {
         if (ngx_delete_file(src->data) == NGX_FILE_ERROR) {
             ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno,
                           ngx_delete_file_n " \"%s\" failed", src->data);
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -63,7 +63,7 @@ typedef struct {
     ngx_fd_t            fd;
 
     unsigned            create_path:1;
-    unsigned            delete:1;
+    unsigned            delete_file:1;
 
     ngx_log_t          *log;
 } ngx_ext_rename_file_t;
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -50,6 +50,8 @@ typedef struct {
 ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc);
 
 
+static void ngx_resolver_cleanup(void *data);
+static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
     ngx_resolver_ctx_t *ctx);
 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
@@ -81,6 +83,7 @@ static ngx_int_t ngx_resolver_copy(ngx_r
 static void ngx_resolver_timeout_handler(ngx_event_t *ev);
 static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
 static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
+static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
 static void ngx_resolver_free(ngx_resolver_t *r, void *p);
 static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
 static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
@@ -89,17 +92,27 @@ static void *ngx_resolver_dup(ngx_resolv
 /* STUB: ngx_peer_addr_t * */
 
 ngx_resolver_t *
-ngx_resolver_create(ngx_peer_addr_t *addr, ngx_log_t *log)
+ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr)
 {
     ngx_resolver_t        *r;
+    ngx_pool_cleanup_t    *cln;
     ngx_udp_connection_t  *uc;
 
-    r = ngx_calloc(sizeof(ngx_resolver_t), log);
+    cln = ngx_pool_cleanup_add(cf->pool, 0);
+    if (cln == NULL) {
+        return NULL;
+    }
+
+    cln->handler = ngx_resolver_cleanup;
+
+    r = ngx_calloc(sizeof(ngx_resolver_t), cf->log);
     if (r == NULL) {
         return NULL;
     }
 
-    r->event = ngx_calloc(sizeof(ngx_event_t), log);
+    cln->data = r;
+
+    r->event = ngx_calloc(sizeof(ngx_event_t), cf->log);
     if (r->event == NULL) {
         return NULL;
     }
@@ -118,18 +131,18 @@ ngx_resolver_create(ngx_peer_addr_t *add
 
     r->event->handler = ngx_resolver_resend_handler;
     r->event->data = r;
-    r->event->log = log;
+    r->event->log = cf->cycle->new_log;
     r->ident = -1;
 
     r->resend_timeout = 5;
     r->expire = 30;
     r->valid = 300;
 
-    r->log = log;
+    r->log = cf->cycle->new_log;
     r->log_level = NGX_LOG_ALERT;
 
     if (addr) {
-        uc = ngx_calloc(sizeof(ngx_udp_connection_t), log);
+        uc = ngx_calloc(sizeof(ngx_udp_connection_t), cf->log);
         if (uc == NULL) {
             return NULL;
         }
@@ -139,13 +152,72 @@ ngx_resolver_create(ngx_peer_addr_t *add
         uc->sockaddr = addr->sockaddr;
         uc->socklen = addr->socklen;
         uc->server = addr->name;
-        uc->log = log;
+        uc->log = cf->cycle->new_log;
     }
 
     return r;
 }
 
 
+static void
+ngx_resolver_cleanup(void *data)
+{
+    ngx_resolver_t  *r = data;
+
+    if (r) {
+        ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+                       "cleanup resolver");
+
+        ngx_resolver_cleanup_tree(r, &r->name_rbtree);
+
+        ngx_resolver_cleanup_tree(r, &r->addr_rbtree);
+
+        if (r->event) {
+            ngx_free(r->event);
+        }
+
+        if (r->udp_connection) {
+            if (r->udp_connection->connection) {
+                ngx_close_connection(r->udp_connection->connection);
+            }
+
+            ngx_free(r->udp_connection);
+        }
+
+        ngx_free(r);
+    }
+}
+
+
+static void
+ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree)
+{
+    ngx_resolver_ctx_t   *ctx, *next;
+    ngx_resolver_node_t  *rn;
+
+    while (tree->root != tree->sentinel) {
+
+        rn = (ngx_resolver_node_t *) ngx_rbtree_min(tree->root, tree->sentinel);
+
+        ngx_queue_remove(&rn->queue);
+
+        for (ctx = rn->waiting; ctx; ctx = next) {
+            next = ctx->next; 
+
+            if (ctx->event) {
+                ngx_resolver_free(r, ctx->event);
+            }
+
+            ngx_resolver_free(r, ctx);
+        }
+
+        ngx_rbtree_delete(tree, &rn->node);
+
+        ngx_resolver_free_node(r, rn);
+    }
+}
+
+
 ngx_resolver_ctx_t *
 ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
 {
@@ -211,14 +283,13 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx
         return NGX_OK;
     }
 
-    /* lock alloc mutex */
+    /* NGX_ERROR */
 
     if (ctx->event) {
-        ngx_resolver_free_locked(r, ctx->event);
-        ctx->event = NULL;
+        ngx_resolver_free(r, ctx->event);
     }
 
-    /* unlock alloc mutex */
+    ngx_resolver_free(r, ctx);
 
     return NGX_ERROR;
 }
@@ -279,7 +350,15 @@ done:
 
     /* unlock name mutex */
 
-    ngx_resolver_free(r, ctx);
+    /* lock alloc mutex */
+
+    if (ctx->event) {
+        ngx_resolver_free_locked(r, ctx->event);
+    }
+
+    ngx_resolver_free_locked(r, ctx);
+
+    /* unlock alloc mutex */
 }
 
 
@@ -572,15 +651,11 @@ failed:
 
     /* unlock addr mutex */
 
-    /* lock alloc mutex */
-
     if (ctx->event) {
-        ngx_resolver_free_locked(r, ctx->event);
+        ngx_resolver_free(r, ctx->event);
     }
 
-    ngx_resolver_free_locked(r, ctx);
-
-    /* unlock alloc mutex */
+    ngx_resolver_free(r, ctx);
 
     return NGX_ERROR;
 }
@@ -639,7 +714,15 @@ done:
 
     /* unlock addr mutex */
 
-    ngx_resolver_free(r, ctx);
+    /* lock alloc mutex */
+
+    if (ctx->event) {
+        ngx_resolver_free_locked(r, ctx->event);
+    }
+
+    ngx_resolver_free_locked(r, ctx);
+
+    /* unlock alloc mutex */
 }
 
 
@@ -695,6 +778,7 @@ ngx_resolver_send_query(ngx_resolver_t *
 
         uc->connection->data = r;
         uc->connection->read->handler = ngx_resolver_read_response;
+        uc->connection->read->resolver = 1;
     }
 
     n = ngx_send(uc->connection, rn->query, rn->qlen);
@@ -1813,7 +1897,7 @@ ngx_resolver_alloc(ngx_resolver_t *r, si
 }
 
 
-void *
+static void *
 ngx_resolver_calloc(ngx_resolver_t *r, size_t size)
 {
     u_char  *p;
--- a/src/core/ngx_resolver.h
+++ b/src/core/ngx_resolver.h
@@ -131,14 +131,13 @@ struct ngx_resolver_ctx_s {
 };
 
 
-ngx_resolver_t *ngx_resolver_create(ngx_peer_addr_t *addr, ngx_log_t *log);
+ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr);
 ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r,
     ngx_resolver_ctx_t *temp);
 ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx);
 void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx);
 ngx_int_t ngx_resolve_addr(ngx_resolver_ctx_t *ctx);
 void ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx);
-void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
 char *ngx_resolver_strerror(ngx_int_t err);
 
 
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -136,6 +136,7 @@ struct ngx_event_s {
 
     /* to test on worker exit */
     unsigned         channel:1;
+    unsigned         resolver:1;
 
 #if (NGX_THREADS)
 
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -1552,6 +1552,15 @@ done:
 }
 
 
+void
+ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
+{
+     SSL_CTX_remove_session(ssl, sess);
+
+     ngx_ssl_remove_session(ssl, sess);
+}
+
+
 static void
 ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
 {
@@ -1567,6 +1576,10 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx
 
     shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index);
 
+    if (shm_zone == NULL) {
+        return;
+    }
+
     cache = shm_zone->data;
 
     id = sess->session_id;
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -105,6 +105,7 @@ ngx_int_t ngx_ssl_session_cache(ngx_ssl_
 ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c,
     ngx_uint_t flags);
 
+void ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);
 ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session);
 #define ngx_ssl_get_session(c)      SSL_get1_session(c->ssl->connection)
 #define ngx_ssl_free_session        SSL_SESSION_free
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -248,7 +248,7 @@ ngx_http_dav_put_handler(ngx_http_reques
     ext.access = dlcf->access;
     ext.time = -1;
     ext.create_path = dlcf->create_full_put_path;
-    ext.delete = 1;
+    ext.delete_file = 1;
     ext.log = r->connection->log;
 
     if (r->headers_in.date) {
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -461,6 +461,7 @@ ngx_http_memcached_filter(void *data, ss
     cl->buf->pos = last;
     b->last += bytes;
     cl->buf->last = b->last;
+    cl->buf->tag = u->output.tag;
 
     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0,
                    "memcached filter bytes:%z size:%z length:%z rest:%z",
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -444,10 +444,10 @@ static ngx_str_t  ngx_http_proxy_hide_he
 static ngx_http_variable_t  ngx_http_proxy_vars[] = {
 
     { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
-      NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+      NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
 
     { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
-      NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+      NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
 
     { ngx_string("proxy_add_x_forwarded_for"), NULL,
       ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
@@ -611,6 +611,7 @@ ngx_http_proxy_eval(ngx_http_request_t *
     r->upstream->resolved->host = u.host;
     r->upstream->resolved->port = (in_port_t) (u.no_port ? u.default_port:
                                                            u.port);
+    r->upstream->resolved->default_port = u.default_port;
 
     return NGX_OK;
 }
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -1983,6 +1983,7 @@ ngx_http_ssi_include(ngx_http_request_t 
 
         if (bl[i].count++) {
 
+            out = NULL;
             ll = &out;
 
             for (tl = bl[i].bufs; tl; tl = tl->next) {
--- 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.6.26';
+our $VERSION = '0.6.27';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -933,19 +933,24 @@ void
 sleep(r, sleep, next)
     CODE:
 
-    dXSTARG;
     ngx_http_request_t   *r;
+    ngx_msec_t            sleep;
     ngx_http_perl_ctx_t  *ctx;
 
     ngx_http_perl_set_request(r);
 
+    sleep = (ngx_msec_t) SvIV(ST(1));
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "perl sleep: %M", sleep);
+
     ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
 
-    ctx->sleep = SvIV(ST(1));
     ctx->next = SvRV(ST(2));
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "perl sleep: %d", ctx->sleep);
+    ngx_add_timer(r->connection->write, sleep);
+
+    r->write_event_handler = ngx_http_perl_sleep_handler;
 
 
 void
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -41,7 +41,6 @@ static ngx_int_t ngx_http_perl_ssi(ngx_h
     ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params);
 #endif
 
-static void ngx_http_perl_sleep_handler(ngx_http_request_t *r);
 static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf,
     ngx_http_perl_main_conf_t *pmcf);
 static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf,
@@ -49,7 +48,7 @@ static PerlInterpreter *ngx_http_perl_cr
 static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires,
     ngx_log_t *log);
 static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
-    HV *nginx, SV *sub, ngx_str_t **args, ngx_str_t *handler, ngx_str_t *rv);
+    HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv);
 static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv);
 
 static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf);
@@ -252,12 +251,6 @@ ngx_http_perl_handle_request(ngx_http_re
     ctx->filename.data = NULL;
     ctx->redirect_uri.len = 0;
 
-    if (ctx->sleep) {
-        ngx_add_timer(r->connection->write, (ngx_msec_t) ctx->sleep);
-        r->write_event_handler = ngx_http_perl_sleep_handler;
-        ctx->sleep = 0;
-    }
-
     if (ctx->done || ctx->next) {
         return;
     }
@@ -276,7 +269,7 @@ ngx_http_perl_handle_request(ngx_http_re
 }
 
 
-static void
+void
 ngx_http_perl_sleep_handler(ngx_http_request_t *r)
 {
     ngx_event_t  *wev;
@@ -364,9 +357,10 @@ static ngx_int_t
 ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx,
     ngx_str_t **params)
 {
-    SV                         *sv;
+    SV                         *sv, **asv;
     ngx_int_t                   rc;
-    ngx_str_t                  *handler;
+    ngx_str_t                  *handler, **args;
+    ngx_uint_t                  i;
     ngx_http_perl_ctx_t        *ctx;
     ngx_http_perl_main_conf_t  *pmcf;
 
@@ -416,9 +410,31 @@ ngx_http_perl_ssi(ngx_http_request_t *r,
 
     sv = newSVpvn((char *) handler->data, handler->len);
 
-    rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv,
-                                    &params[NGX_HTTP_PERL_SSI_ARG],
-                                    handler, NULL);
+    args = &params[NGX_HTTP_PERL_SSI_ARG];
+
+    if (args) {
+
+        for (i = 0; args[i]; i++) { /* void */ }
+
+        asv = ngx_pcalloc(r->pool, (i + 1) * sizeof(SV *));
+
+        if (asv == NULL) {
+            SvREFCNT_dec(sv);
+            return NGX_ERROR;
+        }
+
+        asv[0] = (SV *) i;
+
+        for (i = 0; args[i]; i++) {
+            asv[i + 1] = newSVpvn((char *) args[i]->data, args[i]->len);
+        }
+
+    } else {
+        asv = NULL;
+    }
+
+    rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler,
+                                    NULL);
 
     SvREFCNT_dec(sv);
 
@@ -629,7 +645,7 @@ ngx_http_perl_run_requires(pTHX_ ngx_arr
 
 static ngx_int_t
 ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
-    ngx_str_t **args, ngx_str_t *handler, ngx_str_t *rv)
+    SV **args, ngx_str_t *handler, ngx_str_t *rv)
 {
     SV                *sv;
     int                n, status;
@@ -652,12 +668,10 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt
     XPUSHs(sv);
 
     if (args) {
-        for (i = 0; args[i]; i++) { /* void */ }
+        EXTEND(sp, (int) args[0]);
 
-        EXTEND(sp, (int) i);
-
-        for (i = 0; args[i]; i++) {
-            PUSHs(sv_2mortal(newSVpvn((char *) args[i]->data, args[i]->len)));
+        for (i = 1; i <= (ngx_uint_t) args[0]; i++) {
+            PUSHs(sv_2mortal(args[i]));
         }
     }
 
--- a/src/http/modules/perl/ngx_http_perl_module.h
+++ b/src/http/modules/perl/ngx_http_perl_module.h
@@ -25,9 +25,8 @@ typedef struct {
     ngx_str_t                 redirect_args;
 
     SV                       *next;
-    int                       sleep;
 
-    ngx_uint_t                done;   /* unsigned  done:1; */
+    ngx_uint_t                done;       /* unsigned  done:1; */
 
     ngx_array_t              *variables;  /* array of ngx_http_perl_var_t */
 
@@ -61,6 +60,7 @@ extern void boot_DynaLoader(pTHX_ CV* cv
 
 
 void ngx_http_perl_handle_request(ngx_http_request_t *r);
+void ngx_http_perl_sleep_handler(ngx_http_request_t *r);
 
 
 #endif /* _NGX_HTTP_PERL_MODULE_H_INCLUDED_ */
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -551,7 +551,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
                         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);
+                                       lscf[l].file_name, lscf[l].line);
 
                             return NGX_CONF_ERROR;
                         }
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1916,7 +1916,7 @@ ngx_http_named_location(ngx_http_request
                        "named location: %V \"%V?%V\"", name, &r->uri, &r->args);
 
         r->internal = 1;
-
+        r->content_handler = NULL;
         r->loc_conf = clcfp[i]->loc_conf;
 
         ngx_http_update_location_config(r);
@@ -1924,6 +1924,7 @@ ngx_http_named_location(ngx_http_request
         cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
 
         r->phase_handler = cmcf->phase_engine.location_rewrite_index;
+
         ngx_http_core_run_phases(r);
 
         return NGX_DONE;
@@ -2907,14 +2908,21 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
                               prev->resolver_timeout, 30000);
 
     if (conf->resolver == NULL) {
-        conf->resolver = prev->resolver;
-
-        if (conf->resolver == NULL) {
-            conf->resolver = ngx_resolver_create(NULL, cf->cycle->new_log);
-            if (conf->resolver == NULL) {
+
+        if (prev->resolver == NULL) {
+
+            /*
+             * create dummy resolver in http {} context
+             * to inherit it in all servers
+             */
+
+            prev->resolver = ngx_resolver_create(cf, NULL);
+            if (prev->resolver == NULL) {
                 return NGX_CONF_ERROR;
             }
         }
+ 
+        conf->resolver = prev->resolver;
     }
 
     ngx_conf_merge_path_value(conf->client_body_temp_path,
@@ -3551,7 +3559,22 @@ ngx_http_core_error_page(ngx_conf_t *cf,
             return NGX_CONF_ERROR;
         }
 
-        err->overwrite = (overwrite >= 0) ? overwrite : err->status;
+        if (overwrite >= 0) {
+            err->overwrite = overwrite;
+
+        } else {
+            switch (err->status) {
+                case NGX_HTTP_TO_HTTPS:
+                case NGX_HTTPS_CERT_ERROR:
+                case NGX_HTTPS_NO_CERT:
+                    err->overwrite = NGX_HTTP_BAD_REQUEST;
+                    break;
+
+                default:
+                    err->overwrite = err->status;
+                    break;
+            }
+        }
 
         err->uri = uri;
         err->uri_lengths = uri_lengths;
@@ -3716,6 +3739,10 @@ ngx_http_core_resolver(ngx_conf_t *cf, n
     ngx_url_t   u;
     ngx_str_t  *value;
 
+    if (clcf->resolver) {
+        return "is duplicate";
+    }
+
     value = cf->args->elts;
 
     ngx_memzero(&u, sizeof(ngx_url_t));
@@ -3728,7 +3755,7 @@ ngx_http_core_resolver(ngx_conf_t *cf, n
         return NGX_CONF_ERROR;
     }
 
-    clcf->resolver = ngx_resolver_create(&u.addrs[0], cf->cycle->new_log);
+    clcf->resolver = ngx_resolver_create(cf, &u.addrs[0]);
     if (clcf->resolver == NULL) {
         return NGX_OK;
     }
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1430,6 +1430,10 @@ ngx_http_process_request(ngx_http_reques
                 ngx_log_error(NGX_LOG_INFO, c->log, 0,
                               "client SSL certificate verify error: (%l:%s)",
                               rc, X509_verify_cert_error_string(rc));
+
+                ngx_ssl_remove_cached_session(sscf->ssl.ctx,
+                                       (SSL_get0_session(c->ssl->connection)));
+
                 ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR);
                 return;
             }
@@ -1439,6 +1443,10 @@ ngx_http_process_request(ngx_http_reques
             {
                 ngx_log_error(NGX_LOG_INFO, c->log, 0,
                               "client sent no required SSL certificate");
+
+                ngx_ssl_remove_cached_session(sscf->ssl.ctx,
+                                       (SSL_get0_session(c->ssl->connection)));
+
                 ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT);
                 return;
             }
@@ -2448,7 +2456,12 @@ ngx_http_post_action(ngx_http_request_t 
 
     r->read_event_handler = ngx_http_block_reading;
 
-    ngx_http_internal_redirect(r, &clcf->post_action, NULL);
+    if (clcf->post_action.data[0] == '/') {
+        ngx_http_internal_redirect(r, &clcf->post_action, NULL);
+
+    } else {
+        ngx_http_named_location(r, &clcf->post_action);
+    }
 
     return NGX_OK;
 }
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -221,6 +221,14 @@ ngx_http_script_compile(ngx_http_script_
             sc->args = 1;
             sc->compile_args = 0;
 
+            code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t),
+                                            NULL);
+            if (code == NULL) {
+                return NGX_ERROR;
+            }
+
+            *code = (uintptr_t) ngx_http_script_mark_args_code;
+
             code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t),
                                             &sc->main);
             if (code == NULL) {
@@ -504,7 +512,7 @@ ngx_http_script_copy_capture_len_code(ng
     e->ip += sizeof(ngx_http_script_copy_capture_code_t);
 
     if (code->n < e->ncaptures) {
-        if ((e->args || e->quote)
+        if ((e->is_args || e->quote)
             && (e->request->quoted_uri || e->request->plus_in_uri))
         {
             return e->captures[code->n + 1] - e->captures[code->n]
@@ -531,7 +539,7 @@ ngx_http_script_copy_capture_code(ngx_ht
     e->ip += sizeof(ngx_http_script_copy_capture_code_t);
 
     if (code->n < e->ncaptures) {
-        if ((e->args || e->quote)
+        if ((e->is_args || e->quote)
             && (e->request->quoted_uri || e->request->plus_in_uri))
         {
             e->pos = (u_char *) ngx_escape_uri(e->pos,
@@ -550,6 +558,16 @@ ngx_http_script_copy_capture_code(ngx_ht
 }
 
 
+size_t
+ngx_http_script_mark_args_code(ngx_http_script_engine_t *e)
+{
+    e->is_args = 1;
+    e->ip += sizeof(uintptr_t);
+
+    return 1;
+}
+
+
 void
 ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
 {
@@ -700,7 +718,7 @@ ngx_http_script_regex_start_code(ngx_htt
         le.ncaptures = e->ncaptures;
         le.quote = code->redirect;
 
-        len = 1;  /* reserve 1 byte for possible "?" */
+        len = 0;
 
         while (*(uintptr_t *) le.ip) {
             lcode = *(ngx_http_script_len_code_pt *) le.ip;
@@ -708,6 +726,7 @@ ngx_http_script_regex_start_code(ngx_htt
         }
 
         e->buf.len = len;
+        e->is_args = le.is_args;
     }
 
     if (code->add_args && r->args.len) {
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -27,6 +27,7 @@ typedef struct {
     unsigned                    flushed:1;
     unsigned                    skip:1;
     unsigned                    quote:1;
+    unsigned                    is_args:1;
     unsigned                    log:1;
 
     int                        *captures;
@@ -194,6 +195,7 @@ size_t ngx_http_script_copy_var_len_code
 void ngx_http_script_copy_var_code(ngx_http_script_engine_t *e);
 size_t ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e);
 void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e);
+size_t ngx_http_script_mark_args_code(ngx_http_script_engine_t *e);
 void ngx_http_script_start_args_code(ngx_http_script_engine_t *e);
 #if (NGX_PCRE)
 void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e);
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -439,9 +439,6 @@ ngx_http_send_error_page(ngx_http_reques
 
     r->err_status = err_page->overwrite;
 
-    r->method = NGX_HTTP_GET;
-    r->method_name = ngx_http_get_name;
-
     r->zero_in_uri = 0;
 
     args = NULL;
@@ -494,6 +491,10 @@ ngx_http_send_error_page(ngx_http_reques
     }
 
     if (uri->data[0] == '/') {
+
+        r->method = NGX_HTTP_GET;
+        r->method_name = ngx_http_get_name;
+
         return ngx_http_internal_redirect(r, uri, args);
     }
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -392,6 +392,8 @@ ngx_http_upstream_init(ngx_http_request_
             uscf = uscfp[i];
 
             if (uscf->host.len == host->len
+                && ((uscf->port == 0 && u->resolved->default_port)
+                     || uscf->port == u->resolved->port)
                 && ngx_memcmp(uscf->host.data, host->data, host->len) == 0)
             {
                 goto found;
@@ -420,13 +422,13 @@ ngx_http_upstream_init(ngx_http_request_
         ctx->data = r;
         ctx->timeout = clcf->resolver_timeout;
 
-        u->resolved->ctx = ctx;
-
         if (ngx_resolve_name(ctx) != NGX_OK) {
             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
             return;
         }
 
+        u->resolved->ctx = ctx;
+
         return;
     }
 
@@ -1936,6 +1938,7 @@ ngx_http_upstream_non_buffered_filter(vo
     cl->buf->pos = b->last;
     b->last += bytes;
     cl->buf->last = b->last;
+    cl->buf->tag = u->output.tag;
 
     if (u->length == NGX_MAX_SIZE_T_VALUE) {
         return NGX_OK;
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -201,6 +201,7 @@ typedef struct {
 typedef struct {
     ngx_str_t                       host;
     in_port_t                       port;
+    ngx_uint_t                      default_port; /* unsigned  default_port:1 */
     ngx_uint_t                      naddrs;
     in_addr_t                      *addrs;
     ngx_resolver_ctx_t             *ctx;
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -81,6 +81,7 @@ typedef struct {
     ngx_mail_protocol_t    *protocol;
 
     ngx_msec_t              timeout;
+    ngx_msec_t              resolver_timeout;
 
     ngx_flag_t              so_keepalive;
 
@@ -89,6 +90,8 @@ typedef struct {
     u_char                 *file_name;
     ngx_int_t               line;
 
+    ngx_resolver_t         *resolver;
+
     /* server ctx */
     ngx_mail_conf_ctx_t    *ctx;
 } ngx_mail_core_srv_conf_t;
@@ -147,6 +150,8 @@ typedef struct {
     void                  **main_conf;
     void                  **srv_conf;
 
+    ngx_resolver_ctx_t     *resolver_ctx;
+
     ngx_mail_proxy_ctx_t   *proxy;
 
     ngx_uint_t              mail_state;
@@ -171,6 +176,7 @@ typedef struct {
     ngx_str_t               text;
 
     ngx_str_t              *addr_text;
+    ngx_str_t               host;
     ngx_str_t               smtp_helo;
 
     ngx_uint_t              command;
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_core_module.c
@@ -20,6 +20,8 @@ static char *ngx_mail_core_listen(ngx_co
     void *conf);
 static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 
 
 static ngx_command_t  ngx_mail_core_commands[] = {
@@ -66,6 +68,20 @@ static ngx_command_t  ngx_mail_core_comm
       offsetof(ngx_mail_core_srv_conf_t, server_name),
       NULL },
 
+    { ngx_string("resolver"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_mail_core_resolver,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("resolver_timeout"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_core_srv_conf_t, resolver_timeout),
+      NULL },
+
       ngx_null_command
 };
 
@@ -141,8 +157,14 @@ ngx_mail_core_create_srv_conf(ngx_conf_t
      */
 
     cscf->timeout = NGX_CONF_UNSET_MSEC;
+    cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
     cscf->so_keepalive = NGX_CONF_UNSET;
 
+    cscf->resolver = NGX_CONF_UNSET_PTR;
+
+    cscf->file_name = cf->conf_file->file.name.data;
+    cscf->line = cf->conf_file->line;
+
     return cscf;
 }
 
@@ -154,6 +176,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
     ngx_mail_core_srv_conf_t *conf = child;
 
     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
+    ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout,
+                              30000);
 
     ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0);
 
@@ -184,6 +208,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
+    ngx_conf_merge_ptr_value(conf->resolver, prev->resolver, NULL);
+
     return NGX_CONF_OK;
 }
 
@@ -237,9 +263,6 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx
     cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
     cscf->ctx = ctx;
 
-    cscf->file_name = cf->conf_file->file.name.data;
-    cscf->line = cf->conf_file->line;
-
     cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
 
     cscfp = ngx_array_push(&cmcf->servers);
@@ -389,6 +412,44 @@ ngx_mail_core_protocol(ngx_conf_t *cf, n
 }
 
 
+static char *
+ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_mail_core_srv_conf_t  *cscf = conf;
+
+    ngx_url_t   u;
+    ngx_str_t  *value;
+
+    value = cf->args->elts;
+
+    if (cscf->resolver != NGX_CONF_UNSET_PTR) {
+        return "is duplicate";
+    }
+
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        cscf->resolver = NULL;
+        return NGX_CONF_OK;
+    }
+
+    ngx_memzero(&u, sizeof(ngx_url_t));
+
+    u.host = value[1];
+    u.port = 53;
+
+    if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err);
+        return NGX_CONF_ERROR;
+    }
+
+    cscf->resolver = ngx_resolver_create(cf, &u.addrs[0]);
+    if (cscf->resolver == NULL) {
+        return NGX_CONF_OK;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
 char *
 ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -528,10 +528,10 @@ ngx_mail_proxy_smtp_handler(ngx_event_t 
 
         s->connection->log->action = "sending XCLIENT to upstream";
 
-        line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= "
-                          "NAME=[UNAVAILABLE]" CRLF) - 1
+        line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= NAME="
+                          CRLF) - 1
                    + s->esmtp + s->smtp_helo.len
-                   + s->connection->addr_text.len + s->login.len;
+                   + s->connection->addr_text.len + s->login.len + s->host.len;
 
         line.data = ngx_palloc(c->pool, line.len);
         if (line.data == NULL) {
@@ -542,15 +542,14 @@ ngx_mail_proxy_smtp_handler(ngx_event_t 
         if (s->smtp_helo.len) {
             line.len = ngx_sprintf(line.data,
                            "XCLIENT PROTO=%sSMTP HELO=%V ADDR=%V LOGIN=%V "
-                           "NAME=[UNAVAILABLE]" CRLF,
+                           "NAME=%V" CRLF,
                            (s->esmtp ? "E" : ""), &s->smtp_helo,
-                           &s->connection->addr_text, &s->login)
+                           &s->connection->addr_text, &s->login, &s->host)
                        - line.data;
         } else {
             line.len = ngx_sprintf(line.data,
-                           "XCLIENT PROTO=SMTP ADDR=%V LOGIN=%V "
-                           "NAME=[UNAVAILABLE]" CRLF,
-                           &s->connection->addr_text, &s->login)
+                           "XCLIENT PROTO=SMTP ADDR=%V LOGIN=%V NAME=%V" CRLF,
+                           &s->connection->addr_text, &s->login, &s->host)
                        - line.data;
         }
 
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -11,6 +11,9 @@
 #include <ngx_mail_smtp_module.h>
 
 
+static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx);
+static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx);
+static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c);
 static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
 static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s,
     ngx_connection_t *c);
@@ -40,13 +43,182 @@ static u_char  smtp_invalid_argument[] =
 static u_char  smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF;
 
 
+static ngx_str_t  smtp_unavailable = ngx_string("[UNAVAILABLE]");
+static ngx_str_t  smtp_tempunavail = ngx_string("[TEMPUNAVAIL]");
+
+
 void
 ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
 {
+    struct sockaddr_in        *sin;
+    ngx_resolver_ctx_t        *ctx;
+    ngx_mail_core_srv_conf_t  *cscf;
+
+    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+    if (cscf->resolver == NULL) {
+        s->host = smtp_unavailable;
+        ngx_mail_smtp_greeting(s, c);
+        return;
+    }
+
+    c->log->action = "in resolving client address";
+
+    ctx = ngx_resolve_start(cscf->resolver, NULL);
+    if (ctx == NULL) {
+        ngx_mail_close_connection(c);
+        return;
+    }
+
+    /* AF_INET only */
+
+    sin = (struct sockaddr_in *) c->sockaddr;
+
+    ctx->addr = sin->sin_addr.s_addr;
+    ctx->handler = ngx_mail_smtp_resolve_addr_handler;
+    ctx->data = s;
+    ctx->timeout = cscf->resolver_timeout;
+
+    if (ngx_resolve_addr(ctx) != NGX_OK) {
+        ngx_mail_close_connection(c);
+    }
+}
+
+
+static void
+ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx)
+{
+    ngx_connection_t          *c;
+    ngx_mail_session_t        *s;
+    ngx_mail_core_srv_conf_t  *cscf;
+
+    s = ctx->data;
+    c = s->connection;
+
+    if (ctx->state) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                      "%V could not be resolved (%i: %s)",
+                      &c->addr_text, ctx->state,
+                      ngx_resolver_strerror(ctx->state));
+
+        if (ctx->state == NGX_RESOLVE_NXDOMAIN) {
+            s->host = smtp_unavailable;
+
+        } else {
+            s->host = smtp_tempunavail;
+        }
+
+        ngx_resolve_addr_done(ctx);
+
+        ngx_mail_smtp_greeting(s, s->connection);
+
+        return;
+    }
+
+    c->log->action = "in resolving client hostname";
+
+    s->host.data = ngx_pstrdup(c->pool, &ctx->name);
+    if (s->host.data == NULL) {
+        ngx_resolve_addr_done(ctx);
+        ngx_mail_close_connection(c);
+        return;
+    }
+
+    s->host.len = ctx->name.len;
+
+    ngx_resolve_addr_done(ctx);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+                   "address resolved: %V", &s->host);
+
+    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+    ctx = ngx_resolve_start(cscf->resolver, NULL);
+    if (ctx == NULL) {
+        ngx_mail_close_connection(c);
+        return;
+    }
+
+    ctx->name = s->host;
+    ctx->type = NGX_RESOLVE_A;
+    ctx->handler = ngx_mail_smtp_resolve_name_handler;
+    ctx->data = s;
+    ctx->timeout = cscf->resolver_timeout;
+
+    if (ngx_resolve_name(ctx) != NGX_OK) {
+        ngx_mail_close_connection(c);
+    }
+}
+
+
+static void
+ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx)
+{
+    in_addr_t            addr;
+    ngx_uint_t           i;
+    ngx_connection_t    *c;
+    struct sockaddr_in  *sin;
+    ngx_mail_session_t  *s;
+
+    s = ctx->data;
+    c = s->connection;
+
+    if (ctx->state) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                      "%V could not be resolved (%i: %s)",
+                      &ctx->name, ctx->state,
+                      ngx_resolver_strerror(ctx->state));
+
+        if (ctx->state == NGX_RESOLVE_NXDOMAIN) {
+            s->host = smtp_unavailable;
+
+        } else {
+            s->host = smtp_tempunavail;
+        }
+
+    } else {
+
+        /* AF_INET only */
+
+        sin = (struct sockaddr_in *) c->sockaddr;
+
+        for (i = 0; i < ctx->naddrs; i++) {
+
+            addr = ctx->addrs[i];
+
+            ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0,
+                           "name was resolved to %ud.%ud.%ud.%ud",
+                           (ntohl(addr) >> 24) & 0xff,
+                           (ntohl(addr) >> 16) & 0xff,
+                           (ntohl(addr) >> 8) & 0xff,
+                           ntohl(addr) & 0xff);
+
+            if (addr == sin->sin_addr.s_addr) {
+                goto found;
+            }
+        }
+
+        s->host = smtp_unavailable;
+    }
+
+found:
+
+    ngx_resolve_name_done(ctx);
+
+    ngx_mail_smtp_greeting(s, c);
+}
+
+
+static void
+ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c)
+{
     ngx_msec_t                 timeout;
     ngx_mail_core_srv_conf_t  *cscf;
     ngx_mail_smtp_srv_conf_t  *sscf;
 
+    ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+                   "smtp greeting for \"%V\"", &s->host);
+
     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
 
--- a/src/os/unix/ngx_channel.c
+++ b/src/os/unix/ngx_channel.c
@@ -33,7 +33,7 @@ ngx_write_channel(ngx_socket_t s, ngx_ch
         msg.msg_control = (caddr_t) &cmsg;
         msg.msg_controllen = sizeof(cmsg);
 
-        cmsg.cm.cmsg_len = sizeof(cmsg);
+        cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int));
         cmsg.cm.cmsg_level = SOL_SOCKET;
         cmsg.cm.cmsg_type = SCM_RIGHTS;
         *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;
@@ -138,7 +138,7 @@ ngx_read_channel(ngx_socket_t s, ngx_cha
 
     if (ch->command == NGX_CMD_OPEN_CHANNEL) {
 
-        if (cmsg.cm.cmsg_len < (socklen_t) sizeof(cmsg)) {
+        if (cmsg.cm.cmsg_len < (socklen_t) CMSG_LEN(sizeof(int))) {
             ngx_log_error(NGX_LOG_ALERT, log, 0,
                           "recvmsg() returned too small ancillary data");
             return NGX_ERROR;
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -48,11 +48,16 @@
 
 #if __FreeBSD_version < 400017
 
-/* FreeBSD 3.x has no CMSG_SPACE() at all and has the broken CMSG_DATA() */
+/*
+ * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA()
+ */
 
 #undef  CMSG_SPACE
 #define CMSG_SPACE(l)       (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l))
 
+#undef  CMSG_LEN
+#define CMSG_LEN(l)         (ALIGN(sizeof(struct cmsghdr)) + (l))
+
 #undef  CMSG_DATA
 #define CMSG_DATA(cmsg)     ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr)))
 
--- a/src/os/unix/ngx_linux_init.c
+++ b/src/os/unix/ngx_linux_init.c
@@ -11,7 +11,7 @@
 u_char  ngx_linux_kern_ostype[50];
 u_char  ngx_linux_kern_osrelease[50];
 
-int   ngx_linux_rtsig_max;
+int     ngx_linux_rtsig_max;
 
 
 static ngx_os_io_t ngx_linux_io = {
@@ -32,9 +32,6 @@ static ngx_os_io_t ngx_linux_io = {
 ngx_int_t
 ngx_os_specific_init(ngx_log_t *log)
 {
-    int             name[2];
-    size_t          len;
-    ngx_err_t       err;
     struct utsname  u;
 
     if (uname(&u) == -1) {
@@ -48,6 +45,12 @@ ngx_os_specific_init(ngx_log_t *log)
     (void) ngx_cpystrn(ngx_linux_kern_osrelease, (u_char *) u.release,
                        sizeof(ngx_linux_kern_osrelease));
 
+#if (NGX_HAVE_RTSIG)
+    {
+    int        name[2];
+    size_t     len;
+    ngx_err_t  err;
+
     name[0] = CTL_KERN;
     name[1] = KERN_RTSIGMAX;
     len = sizeof(ngx_linux_rtsig_max);
@@ -65,6 +68,8 @@ ngx_os_specific_init(ngx_log_t *log)
         ngx_linux_rtsig_max = 0;
     }
 
+    }
+#endif
 
     ngx_os_io = ngx_linux_io;
 
@@ -78,6 +83,8 @@ ngx_os_specific_status(ngx_log_t *log)
     ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s",
                   ngx_linux_kern_ostype, ngx_linux_kern_osrelease);
 
+#if (NGX_HAVE_RTSIG)
     ngx_log_error(NGX_LOG_NOTICE, log, 0, "sysctl(KERN_RTSIGMAX): %d",
                   ngx_linux_rtsig_max);
+#endif
 }
--- a/src/os/unix/ngx_posix_config.h
+++ b/src/os/unix/ngx_posix_config.h
@@ -110,11 +110,16 @@
 
 #include <sys/param.h>          /* ALIGN() */
 
-/* FreeBSD 3.x has no CMSG_SPACE() at all and has the broken CMSG_DATA() */
+/* 
+ * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA()
+ */
 
 #undef  CMSG_SPACE
 #define CMSG_SPACE(l)       (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l))
 
+#undef  CMSG_LEN
+#define CMSG_LEN(l)         (ALIGN(sizeof(struct cmsghdr)) + (l))
+
 #undef  CMSG_DATA
 #define CMSG_DATA(cmsg)     ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr)))
 
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -994,18 +994,18 @@ ngx_worker_process_exit(ngx_cycle_t *cyc
         }
     }
 
-    if (ngx_quit) {
+    if (ngx_exiting) {
         c = cycle->connections;
         for (i = 0; i < cycle->connection_n; i++) {
             if (c[i].fd != -1
                 && c[i].read
                 && !c[i].read->accept
-                && !c[i].read->channel)
+                && !c[i].read->channel
+                && !c[i].read->resolver)
             {
                 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
-                              "open socket #%d left in %ui connection, "
-                              "aborting",
-                              c[i].fd, i);
+                              "open socket #%d left in %ui connection %s",
+                              c[i].fd, i, ngx_debug_quit ? ", aborting" : "");
                 ngx_debug_point();
             }
         }
@@ -1059,6 +1059,11 @@ ngx_channel_handler(ngx_event_t *ev)
     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);
 
     if (n == NGX_ERROR) {
+
+        if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+            ngx_del_conn(c, 0);
+        }
+
         ngx_close_connection(c);
         return;
     }