nginx-0.3.13-RELEASE import

    *) Feature: the IMAP/POP3 proxy supports STARTTLS and STLS.

    *) Bugfix: the IMAP/POP3 proxy did not work with the select, poll, and
       /dev/poll methods.

    *) Bugfix: in SSI handling.

    *) Bugfix: now Solaris sendfilev() is not used to transfer the client
       request body to FastCGI-server via the unix domain socket.

    *) Bugfix: the "auth_basic" directive did not disable the
       authorization; the bug had appeared in 0.3.11.
diff --git a/auto/cc/gcc b/auto/cc/gcc
index 0597072..9e0e52d 100644
--- a/auto/cc/gcc
+++ b/auto/cc/gcc
@@ -36,7 +36,7 @@
 
 case "$NGX_MACHINE" in
 
-    sun4u | sparc )
+    sun4u | sparc | sparc64 )
         # "-mcpu=v9" enables the "casa" assembler instruction
         CFLAGS="$CFLAGS -mcpu=v9"
     ;;
diff --git a/auto/cc/msvc b/auto/cc/msvc
index 29c40c7..a890234 100644
--- a/auto/cc/msvc
+++ b/auto/cc/msvc
@@ -49,6 +49,8 @@
     ;;
 esac
 
+# __cdecl, use with OpenSSL
+#CPU_OPT="$CPU_OPT -Gd"
 # __stdcall
 #CPU_OPT="$CPU_OPT -Gz"
 # __fastcall
diff --git a/auto/cc/owc b/auto/cc/owc
index c8088d2..8688600 100644
--- a/auto/cc/owc
+++ b/auto/cc/owc
@@ -2,7 +2,7 @@
 # Copyright (C) Igor Sysoev
 
 
-# Open Watcom C 1.0, 1.2
+# Open Watcom C 1.0, 1.2, 1.3
 
 # optimizations
 
@@ -60,7 +60,7 @@
 CFLAGS="$CFLAGS -zq"
 
 # Open Watcom C 1.2
-#have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have
+have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have
 
 
 # the precompiled headers
diff --git a/auto/endianess b/auto/endianess
index db6420d..0f16bc5 100644
--- a/auto/endianess
+++ b/auto/endianess
@@ -20,7 +20,7 @@
 
 END
 
-ngx_test="$CC $CC_TEST_FLAGS $CC_WARN $CC_AUX_FLAGS \
+ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \
           -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs"
 
 eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
diff --git a/auto/feature b/auto/feature
index 0fbbe84..5a40c69 100644
--- a/auto/feature
+++ b/auto/feature
@@ -31,7 +31,7 @@
 END
 
 
-ngx_test="$CC $CC_TEST_FLAGS $CC_WARN $CC_AUX_FLAGS \
+ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \
           -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs"
 
 eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
diff --git a/auto/fmt/fmt b/auto/fmt/fmt
deleted file mode 100644
index a316d9b..0000000
--- a/auto/fmt/fmt
+++ /dev/null
@@ -1,98 +0,0 @@
-
-# Copyright (C) Igor Sysoev
-
-
-echo $ngx_n "checking for $ngx_type printf() format ...$ngx_c"
-
-cat << END >> $NGX_AUTOCONF_ERR
-
-----------------------------------------
-checking for $ngx_type printf() format
-
-END
-
-
-ngx_format=no
-ngx_comma=
-
-
-for ngx_fmt in $ngx_formats
-do
-
-    cat << END > $NGX_AUTOTEST.c
-
-#include <sys/types.h>
-#include <sys/time.h>
-#include <stdio.h>
-#include <sys/resource.h>
-$NGX_INCLUDE_INTTYPES_H
-$NGX_INCLUDE_AUTO_CONFIG_H
-
-int main() {
-    printf("$ngx_fmt", ($ngx_type) $ngx_max_value);
-    return 0;
-}
-
-END
-
-    ngx_test="$CC $CC_TEST_FLAGS $CC_WARN $CC_AUX_FLAGS \
-              -o $NGX_AUTOTEST $NGX_AUTOTEST.c"
-    eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
-
-    ngx_max_val=`echo $ngx_max_value | sed -e "s/L*\$//"`
-
-    if [ -x $NGX_AUTOTEST ]; then
-
-        if [ "`$NGX_AUTOTEST`" = $ngx_max_val ]; then
-
-            if [ $ngx_fmt_collect = yes ]; then
-                echo $ngx_n "$ngx_comma \"${ngx_fmt}\" is appropriate$ngx_c"
-            else
-                echo $ngx_n "$ngx_comma \"${ngx_fmt}\" used$ngx_c"
-            fi
-
-            ngx_format=$ngx_fmt
-        fi
-    fi
-
-    rm -f $NGX_AUTOTEST
-
-    if [ $ngx_format != no ]; then
-        if [ $ngx_fmt_collect = yes ]; then
-            eval "ngx_${ngx_size}_fmt=\"\${ngx_${ngx_size}_fmt} \$ngx_format\""
-            ngx_comma=","
-            continue
-        else
-            break
-        fi
-    fi
-
-    echo $ngx_n "$ngx_comma \"${ngx_fmt}\" is not appropriate$ngx_c"
-    ngx_comma=","
-
-    echo "----------"    >> $NGX_AUTOCONF_ERR
-    cat $NGX_AUTOTEST.c  >> $NGX_AUTOCONF_ERR
-    echo "----------"    >> $NGX_AUTOCONF_ERR
-    echo $ngx_test       >> $NGX_AUTOCONF_ERR
-    echo "----------"    >> $NGX_AUTOCONF_ERR
-done
-
-echo
-
-if [ $ngx_format = no ]; then
-    echo "$0: error: printf() $ngx_type format not found"
-
-    exit 1
-fi
-
-
-if [ $ngx_fmt_collect = no ]; then
-    cat << END >> $NGX_AUTO_CONFIG_H
-
-#ifndef $ngx_fmt_name
-#define $ngx_fmt_name  "$ngx_format"
-#endif
-
-END
-
-fi
diff --git a/auto/fmt/ptrfmt b/auto/fmt/ptrfmt
deleted file mode 100644
index 32ba8a4..0000000
--- a/auto/fmt/ptrfmt
+++ /dev/null
@@ -1,86 +0,0 @@
-
-# Copyright (C) Igor Sysoev
-
-
-echo $ngx_n "checking for $ngx_type printf() format ...$ngx_c"
-
-cat << END >> $NGX_AUTOCONF_ERR
-
-----------------------------------------
-checking for $ngx_type printf() format
-
-END
-
-
-ngx_format=no
-ngx_comma=
-ngx_fmt_x=
-
-for ngx_fmt in $ngx_formats
-do
-
-    cat << END > $NGX_AUTOTEST.c
-
-int main() {
-    printf("$ngx_fmt", ($ngx_type) $ngx_max_value);
-    return 0;
-}
-
-END
-
-    ngx_test="$CC $CC_TEST_FLAGS $CC_WARN $CC_AUX_FLAGS \
-              -o $NGX_AUTOTEST $NGX_AUTOTEST.c"
-    eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
-
-    ngx_max_val=`echo $ngx_max_value | sed -e "s/L*\$//"`
-
-    if [ -x $NGX_AUTOTEST ]; then
-        if [ "`$NGX_AUTOTEST`" = $ngx_max_val ]; then
-            ngx_format=$ngx_fmt
-        fi
-    fi
-
-    rm $NGX_AUTOTEST
-
-    if [ $ngx_format != no ]; then
-        break
-    fi
-
-    ngx_fmt_x=`echo $ngx_fmt | sed -e "s/d/X/"`
-
-    echo $ngx_n "$ngx_comma \"${ngx_fmt_x}\" is not appropriate$ngx_c"
-    ngx_comma=","
-
-    echo "----------"    >> $NGX_AUTOCONF_ERR
-    cat $NGX_AUTOTEST.c  >> $NGX_AUTOCONF_ERR
-    echo "----------"    >> $NGX_AUTOCONF_ERR
-    echo $ngx_test       >> $NGX_AUTOCONF_ERR
-    echo "----------"    >> $NGX_AUTOCONF_ERR
-done
-
-
-if [ $ngx_format = no ]; then
-    echo "$0: error: printf() $ngx_type format not found"
-
-    exit 1
-fi
-
-
-if [ $ngx_ptr_size = 4 ]; then
-    ngx_fmt_x="%0`expr 2 \* $ngx_ptr_size`"
-else
-    ngx_fmt_x="%"
-fi
-
-ngx_format=`echo $ngx_format | sed -e "s/d/X/" -e "s/^%/$ngx_fmt_x/"`
-
-echo "$ngx_comma \"${ngx_format}\" used"
-
-
-cat << END >> $NGX_AUTO_CONFIG_H
-
-#ifndef $ngx_fmt_name
-#define $ngx_fmt_name  "$ngx_format"
-#endif
-
-END
diff --git a/auto/fmt/xfmt b/auto/fmt/xfmt
deleted file mode 100644
index 957e590..0000000
--- a/auto/fmt/xfmt
+++ /dev/null
@@ -1,11 +0,0 @@
-
-# Copyright (C) Igor Sysoev
-
-
-cat << END | sed -e 's/d"$/x"/' >> $NGX_AUTO_CONFIG_H
-
-#ifndef $ngx_fmt_name
-#define $ngx_fmt_name  "$ngx_fmt"
-#endif
-
-END
diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf
index 3356689..32f82ca 100644
--- a/auto/lib/openssl/conf
+++ b/auto/lib/openssl/conf
@@ -23,29 +23,47 @@
 
 else
 
-    if [ "$NGX_PLATFORM" != win32 ]; then
-        OPENSSL=NO
+    case "$NGX_PLATFORM" in
 
-        ngx_feature="OpenSSL library"
-        ngx_feature_name="NGX_OPENSSL"
-        ngx_feature_run=no
-        ngx_feature_incs="#include <openssl/ssl.h>"
-        ngx_feature_libs="-lssl -lcrypto"
-        ngx_feature_test="SSL_library_init()"
-        . auto/feature
-
-        if [ $ngx_found = yes ]; then
+        win32)
+            have=NGX_OPENSSL . auto/have
             have=NGX_SSL . auto/have
-            CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
             OPENSSL=YES
 
-            case "$NGX_SYSTEM" in
-                SunOS)
-                    CORE_LIBS="$CORE_LIBS -ldl"
-                ;;
-            esac
-        fi
+            CORE_INCS="$CORE_INCS c:/openssl/include"
+            CORE_LIBS="$CORE_LIBS c:/openssl/ssleay32.lib"
+            CORE_LIBS="$CORE_LIBS c:/openssl/libeay32.lib"
 
-    fi
+            # libeay32.lib requires gdi32.lib
+            CORE_LIBS="$CORE_LIBS gdi32.lib"
+            # OpenSSL 0.8's libeay32.lib requires advapi32.lib
+            CORE_LIBS="$CORE_LIBS advapi32.lib"
+        ;;
+
+        *)
+            OPENSSL=NO
+
+            ngx_feature="OpenSSL library"
+            ngx_feature_name="NGX_OPENSSL"
+            ngx_feature_run=no
+            ngx_feature_incs="#include <openssl/ssl.h>"
+            ngx_feature_libs="-lssl -lcrypto"
+            ngx_feature_test="SSL_library_init()"
+            . auto/feature
+
+            if [ $ngx_found = yes ]; then
+                have=NGX_SSL . auto/have
+                CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+                OPENSSL=YES
+
+                case "$NGX_SYSTEM" in
+                    SunOS)
+                        CORE_LIBS="$CORE_LIBS -ldl"
+                    ;;
+                esac
+            fi
+        ;;
+
+    esac
 
 fi
diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make
index ff05a38..31e15dc 100644
--- a/auto/lib/openssl/make
+++ b/auto/lib/openssl/make
@@ -1,6 +1,7 @@
 
 # Copyright (C) Igor Sysoev
 
+
 if test -n "$OPENSSL_OPT"; then
     NGX_OPENSSL_CONFIG="./Configure \"$OPENSSL_OPT\""
 else
diff --git a/auto/os/conf b/auto/os/conf
index 4ad72d8..f4ba388 100644
--- a/auto/os/conf
+++ b/auto/os/conf
@@ -63,7 +63,7 @@
         have=NGX_HAVE_NONALIGNED . auto/have
     ;;
 
-    sun4u | ia64 )
+    sun4u | sparc | sparc64 | ia64 )
         have=NGX_ALIGNMENT value=16 . auto/define
     ;;
 
diff --git a/auto/os/linux b/auto/os/linux
index 6354bed..39027b3 100644
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -110,5 +110,5 @@
 ngx_feature_incs="#include <sched.h>"
 ngx_feature_libs=
 ngx_feature_test="long mask = 0;
-                  sched_setaffinity(0, 32, &mask)"
+                  sched_setaffinity(0, 32, (cpu_set_t *) &mask)"
 . auto/feature
diff --git a/auto/types/sizeof b/auto/types/sizeof
index 796aed1..2cd1fb8 100644
--- a/auto/types/sizeof
+++ b/auto/types/sizeof
@@ -31,7 +31,7 @@
 END
 
 
-ngx_test="$CC $CC_TEST_FLAGS $CC_WARN $CC_AUX_FLAGS \
+ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \
           -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs"
 
 eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
diff --git a/auto/types/typedef b/auto/types/typedef
index 4b89643..884ef25 100644
--- a/auto/types/typedef
+++ b/auto/types/typedef
@@ -33,7 +33,9 @@
 
 END
 
-    ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS -o $NGX_AUTOTEST $NGX_AUTOTEST.c"
+    ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \
+              -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs"
+
     eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1"
 
     if [ -x $NGX_AUTOTEST ]; then
diff --git a/auto/unix b/auto/unix
index 6295ec2..0fe2974 100755
--- a/auto/unix
+++ b/auto/unix
@@ -4,10 +4,7 @@
 
 have=NGX_HAVE_UNIX_DOMAIN . auto/have
 
-
-# STUB
-CC_WARN=
-ngx_fmt_collect=yes
+ngx_feature_libs=
 
 
 # C types
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 7f686ef..999f11f 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -9,6 +9,60 @@
 <title lang="en">nginx changelog</title>
 
 
+<changes ver="0.3.13" date="05.12.2005">
+
+<change type="feature">
+<para lang="ru">
+IMAP/POP3 ÐÒÏËÓÉ ÐÏÄÄÅÒÖÉ×ÁÅÔ STARTTLS É STLS.
+</para>
+<para lang="en">
+the IMAP/POP3 proxy supports STARTTLS and STLS.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+IMAP/POP3 ÐÒÏËÓÉ ÎÅ ÒÁÂÏÔÁÌÁ Ó ÍÅÔÏÄÁÍÉ select, poll É /dev/poll.
+</para>
+<para lang="en">
+the IMAP/POP3 proxy did not work with the select, poll, and /dev/poll methods.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÏÛÉÂËÉ × ÏÂÒÁÂÏÔËÅ SSI.
+</para>
+<para lang="en">
+in SSI handling.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+sendfilev() × Solaris ÔÅÐÅÒØ ÎÅ ÉÓÐÏÌØÚÕÅÔÓÑ ÐÒÉ ÐÅÒÅÄÁÞÅ ÔÅÌÁ ÚÁÐÒÏÓÁ
+FastCGI-ÓÅÒ×ÅÒÕ ÞÅÒÅÚ unix domain ÓÏËÅÔ.
+</para>
+<para lang="en">
+now Solaris sendfilev() is not used to transfer the client request body
+to FastCGI-server via the unix domain socket.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á auth_basic ÎÅ ÚÁÐÒÅÝÁÌÁ ÁÕÔÅÎÔÉÆÉËÁÃÉÀ;
+ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.3.11.
+</para>
+<para lang="en">
+the "auth_basic" directive did not disable the authorization;
+bug appeared in 0.3.11.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="0.3.12" date="26.11.2005">
 
 <change type="security">
@@ -75,7 +129,7 @@
 
 <change type="bugfix">
 <para lang="ru">
-ÅÓÌÉ ËÌÉÅÎÔ ÐÅÒÅÄÁÌ ÓÔÒÏËÕ "Transfer-Encoding: chunked" × ÚÁÇÏÌÏÏ×ËÅ
+ÅÓÌÉ ËÌÉÅÎÔ ÐÅÒÅÄÁÌ ÓÔÒÏËÕ "Transfer-Encoding: chunked" × ÚÁÇÏÌÏ×ËÅ
 ÚÁÐÒÏÓÁ, ÔÏ nginx ÔÅÐÅÒØ ×ÙÄÁ£Ô ÏÛÉÂËÕ 411.
 </para>
 <para lang="en">
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 44b15f9..9505aee 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.12"
+#define NGINX_VER          "nginx/0.3.13"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index d89fa7f..377cad5 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -182,6 +182,8 @@
 
 
     if (filename) {
+        ngx_pfree(cf->pool, cf->conf_file->buffer->start);
+
         cf->conf_file = prev;
 
         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
index 279efb6..38a59bc 100644
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -140,7 +140,8 @@
     unsigned            single_connection:1;
     unsigned            unexpected_eof:1;
     unsigned            timedout:1;
-    unsigned            closed:1;
+    unsigned            error:1;
+    unsigned            destroyed:1;
 
     unsigned            sendfile:1;
     unsigned            sndlowat:1;
diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c
index 6b75fa5..9d41df6 100644
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -47,6 +47,10 @@
              n < nelts;
              n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
         {
+            if (name->data == NULL) {
+                continue;
+            }
+
             key = 0;
 
             for (i = 0; i < name->len; i++) {
@@ -104,6 +108,10 @@
              n < nelts;
              n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
         {
+            if (name->data == NULL) {
+                continue;
+            }
+
             key = 0;
 
             for (i = 0; i < name->len; i++) {
@@ -135,6 +143,10 @@
          n < nelts;
          n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
     {
+        if (name->data == NULL) {
+            continue;
+        }
+
         key = 0;
 
         for (i = 0; i < name->len; i++) {
diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c
index a1f9d59..3bb0b35 100644
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -102,7 +102,7 @@
             }
 
             if ((size_t) (p->end - m) < NGX_ALIGNMENT) {
-                p->current = p->next;
+                pool->current = p->next;
             }
 
             if (p->next == NULL) {
@@ -117,8 +117,8 @@
             return NULL;
         }
 
-        if (p->current == NULL) {
-            p->current = n;
+        if (pool->current == NULL) {
+            pool->current = n;
         }
 
         p->next = n;
diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h
index 1b1322d..a57ec77 100644
--- a/src/core/ngx_rbtree.h
+++ b/src/core/ngx_rbtree.h
@@ -29,7 +29,7 @@
 
 typedef struct ngx_rbtree_s  ngx_rbtree_t;
 
-typedef ngx_rbtree_t *(*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
+typedef ngx_rbtree_node_t *(*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
 
 struct ngx_rbtree_s {
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
new file mode 100644
index 0000000..cf47cd8
--- /dev/null
+++ b/src/core/ngx_resolver.c
@@ -0,0 +1,183 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+typedef struct {
+    ngx_connection_t      *connection;
+
+    struct sockaddr       *sockaddr;
+    socklen_t              socklen;
+
+    ngx_str_r              server;
+    ngx_str_r              name;
+
+    ngx_event_handler_pt   handler;
+
+    ngx_log_t             *pool;
+    ngx_log_t             *log;
+} ngx_resolver_t;
+
+
+ngx_int_t
+ngx_gethostbyname(ngx_resolver_t *r)
+{
+    ngx_socket_t  s;
+
+    if (r->connection) {
+        return NGX_OK;
+    }
+
+    s = ngx_socket(AF_INET, SOCK_DGRAM, 0);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, r->log, 0, "socket %d", s);
+
+    if (s == -1) {
+        ngx_log_error(NGX_LOG_ALERT, r->log, ngx_socket_errno,
+                      ngx_socket_n " failed");
+        return NGX_ERROR;
+    }
+
+    c = ngx_get_connection(s, r->log);
+
+    if (c == NULL) {
+        if (ngx_close_socket(s) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, r->log, ngx_socket_errno,
+                          ngx_close_socket_n "failed");
+        }
+
+        return NGX_ERROR;
+    }
+
+    rev = c->read;
+    wev = c->write;
+
+    rev->log = pc->log;
+    wev->log = pc->log;
+
+    r->connection = c;
+
+    /*
+     * TODO: MT: - ngx_atomic_fetch_add()
+     *             or protection by critical section or mutex
+     *
+     * TODO: MP: - allocated in a shared memory
+     *           - ngx_atomic_fetch_add()
+     *             or protection by critical section or mutex
+     */
+
+    c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
+
+#if (NGX_THREADS)
+    rev->lock = pc->lock;
+    wev->lock = pc->lock;
+    rev->own_lock = &c->lock;
+    wev->own_lock = &c->lock;
+#endif
+
+    ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
+                   "connect to %V, fd:%d #%d", &r->server, s, c->number);
+
+    rc = connect(s, r->sockaddr, r->socklen);
+
+    if (rc == -1) {
+        ngx_log_error(level, r->log, ngx_socket_errno,
+                      "connect() to %V failed", &r->server);
+
+        return NGX_ERROR;
+    }
+
+
+
+
+
+
+
+    if (ngx_add_conn) {
+        if (ngx_add_conn(c) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+    }
+
+
+    if (ngx_add_conn) {
+        if (rc == -1) {
+
+            /* NGX_EINPROGRESS */
+
+            return NGX_AGAIN;
+        }
+
+        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
+
+        wev->ready = 1;
+
+        return NGX_OK;
+    }
+
+    if (ngx_event_flags & NGX_USE_AIO_EVENT) {
+
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno,
+                       "connect(): %d", rc);
+
+        /* aio, iocp */
+
+        if (ngx_blocking(s) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
+                          ngx_blocking_n " failed");
+            return NGX_ERROR;
+        }
+
+        /*
+         * FreeBSD's aio allows to post an operation on non-connected socket.
+         * NT does not support it.
+         *
+         * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
+         */
+
+        rev->ready = 1;
+        wev->ready = 1;
+
+        return NGX_OK;
+    }
+
+    if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
+
+        /* kqueue */
+
+        event = NGX_CLEAR_EVENT;
+
+    } else {
+
+        /* select, poll, /dev/poll */
+
+        event = NGX_LEVEL_EVENT;
+    }
+
+    if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    if (rc == -1) {
+
+        /* NGX_EINPROGRESS */
+
+        if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        return NGX_AGAIN;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
+
+    wev->ready = 1;
+
+    return NGX_OK;
+}
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index fc37382..f042d7c 100644
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1036,3 +1036,19 @@
     *dst = d;
     *src = s;
 }
+
+
+#if (NGX_MEMCPY_LIMIT)
+
+void *
+ngx_memcpy(void *dst, void *src, size_t n)
+{
+    if (n > NGX_MEMCPY_LIMIT) {
+        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);
+        ngx_debug_point();
+    }
+
+    return memcpy(dst, src, n);
+}
+
+#endif
diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h
index 0bee98b..0192a30 100644
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -63,6 +63,13 @@
 #define ngx_memset(buf, c, n)     (void) memset(buf, c, n)
 
 
+#if (NGX_MEMCPY_LIMIT)
+
+void *ngx_memcpy(void *dst, void *src, size_t n);
+#define ngx_cpymem(dst, src, n)   ((u_char *) ngx_memcpy(dst, src, n)) + (n)
+
+#else
+
 /*
  * gcc3, msvc, and icc7 compile memcpy() to the inline "rep movs".
  * gcc3 compiles memcpy(d, s, 4) to the inline "mov"es.
@@ -71,6 +78,8 @@
 #define ngx_memcpy(dst, src, n)   (void) memcpy(dst, src, n)
 #define ngx_cpymem(dst, src, n)   ((u_char *) memcpy(dst, src, n)) + (n)
 
+#endif
+
 
 #if ( __INTEL_COMPILER >= 800 )
 
diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c
index 839afb5..88b5b3f 100644
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -276,8 +276,10 @@
 ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags)
 {
     ngx_int_t          rc;
+#if 0
     ngx_event_t       *e;
     ngx_connection_t  *c;
+#endif
 
     ev->active = 1;
     ev->disabled = 0;
@@ -285,12 +287,11 @@
 
     ngx_mutex_lock(list_mutex);
 
-#if 1
+#if 0
 
-    if (nchanges > 0
-        && ev->index < (u_int) nchanges
+    if (ev->index < (u_int) nchanges
         && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
-                                                             == (uintptr_t) ev)
+            == (uintptr_t) ev)
     {
         if (change_list[ev->index].flags == EV_DISABLE) {
 
@@ -346,12 +347,9 @@
 
     ngx_mutex_lock(list_mutex);
 
-#if 1
-
-    if (nchanges > 0
-        && ev->index < (u_int) nchanges
+    if (ev->index < (u_int) nchanges
         && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
-                                                             == (uintptr_t) ev)
+            == (uintptr_t) ev)
     {
         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                        "kevent deleted: %d: ft:%d",
@@ -359,7 +357,9 @@
 
         /* if the event is still not passed to a kernel we will not pass it */
 
-        if (ev->index < (u_int) --nchanges) {
+        nchanges--;
+
+        if (ev->index < (u_int) nchanges) {
             e = (ngx_event_t *)
                     ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
             change_list[ev->index] = change_list[nchanges];
@@ -371,8 +371,6 @@
         return NGX_OK;
     }
 
-#endif
-
     /*
      * when the file descriptor is closed the kqueue automatically deletes
      * its filters so we do not need to delete explicity the event
@@ -551,7 +549,9 @@
 
         if (event_list[i].flags & EV_ERROR) {
             ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
-                          "kevent() error on %d", event_list[i].ident);
+                          "kevent() error on %d filter:%d flags:%04Xd",
+                          event_list[i].ident, event_list[i].filter,
+                          event_list[i].flags);
             continue;
         }
 
diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c
index 34ee252..e4ca238 100644
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -181,6 +181,11 @@
     if (peer->sockaddr->sa_family != AF_INET) {
         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
     }
 
     rev = c->read;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 7efb713..441472e 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -301,12 +301,12 @@
 
             *d = '\0';
 
-            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
                            "SSL: %s, cipher: \"%s\"",
                            SSL_get_version(c->ssl->connection), &buf[1]);
 
             if (SSL_session_reused(c->ssl->connection)) {
-                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
                                "SSL reused session");
             }
 
@@ -630,7 +630,7 @@
     for ( ;; ) {
 
         while (in && buf->last < buf->end) {
-            if (in->buf->last_buf) {
+            if (in->buf->last_buf || in->buf->flush) {
                 flush = 1;
             }
 
@@ -645,11 +645,6 @@
                 size = buf->end - buf->last;
             }
 
-            /*
-             * TODO: the taking in->buf->flush into account can be
-             *       implemented using the limit on the higher level
-             */
-
             if (send + size > limit) {
                 size = (ssize_t) (limit - send);
                 flush = 1;
@@ -943,7 +938,7 @@
 }
 
 
-void
+void ngx_cdecl
 ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...)
 {
     u_long   n;
@@ -958,7 +953,13 @@
 
     p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
 
-    while (p < last && (n = ERR_get_error())) {
+    while (p < last) {
+
+        n = ERR_get_error();
+
+        if (n == 0) {
+            break;
+        }
 
         *p++ = ' ';
 
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 63cb333..66edc52 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -79,7 +79,7 @@
 ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in,
     off_t limit);
 ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c);
-void ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
+void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
     char *fmt, ...);
 void ngx_ssl_cleanup_ctx(void *data);
 
diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c
index 779ec18..0c499a8 100644
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -407,12 +407,15 @@
 static ngx_int_t
 ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
 {
-    size_t        bsize;
-    ngx_uint_t    flush;
-    ngx_chain_t  *out, **ll, *cl;
+    size_t             bsize;
+    ngx_uint_t         flush;
+    ngx_chain_t       *out, **ll, *cl;
+    ngx_connection_t  *downstream;
+
+    downstream = p->downstream;
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
-                   "pipe write downstream: %d", p->downstream->write->ready);
+                   "pipe write downstream: %d", downstream->write->ready);
 
     for ( ;; ) {
         if (p->downstream_error) {
@@ -452,6 +455,11 @@
                 }
 
                 if (p->output_filter(p->output_ctx, p->in) == NGX_ERROR) {
+
+                    if (downstream->destroyed) {
+                        return NGX_ABORT;
+                    }
+
                     p->downstream_error = 1;
                     return ngx_event_pipe_drain_chains(p);
                 }
@@ -468,9 +476,9 @@
             break;
         }
 
-        if (p->downstream->data != p->output_ctx
-            || !p->downstream->write->ready
-            || p->downstream->write->delayed)
+        if (downstream->data != p->output_ctx
+            || !downstream->write->ready
+            || downstream->write->delayed)
         {
             break;
         }
diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c
index cf85557..48192ca 100644
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -379,6 +379,8 @@
     if (ngx_strcmp(realm->data, "off") == 0) {
         realm->len = 0;
         realm->data = (u_char *) "";
+
+        return NGX_CONF_OK;
     }
 
     len = sizeof("Basic realm=\"") - 1 + realm->len + 1;
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 125b8e0..45b6e73 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -1419,7 +1419,8 @@
 {
     ngx_http_variable_t  *var;
 
-    var = ngx_http_add_variable(cf, &ngx_http_fastcgi_script_name, 0);
+    var = ngx_http_add_variable(cf, &ngx_http_fastcgi_script_name,
+                                NGX_HTTP_VAR_NOHASH);
     if (var == NULL) {
         return NGX_ERROR;
     }
diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c
index 8231de1..bf7b925 100644
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -130,18 +130,14 @@
     var->handler = ngx_http_geo_variable;
     var->data = (uintptr_t) tree;
 
-    /*
-     * create the temporary pool of a huge initial size
-     * to process quickly a large number of geo lines
-     */
-
-    pool = ngx_create_pool(512 * 1024, cf->log);
+    pool = ngx_create_pool(16384, cf->log);
     if (pool == NULL) {
         return NGX_CONF_ERROR;
     }
 
     if (ngx_array_init(&geo.values, pool, 512,
-                       sizeof(ngx_http_variable_value_t *)) == NGX_ERROR)
+                       sizeof(ngx_http_variable_value_t *))
+        == NGX_ERROR)
     {
         ngx_destroy_pool(pool);
         return NGX_CONF_ERROR;
diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c
index 66d5935..e819759 100644
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -961,7 +961,7 @@
     ngx_http_variable_t     *var;
     ngx_http_log_op_name_t  *op;
 
-    var = ngx_http_add_variable(cf, &ngx_http_gzip_ratio, 0);
+    var = ngx_http_add_variable(cf, &ngx_http_gzip_ratio, NGX_HTTP_VAR_NOHASH);
     if (var == NULL) {
         return NGX_ERROR;
     }
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 8278d34..afadc18 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -359,20 +359,20 @@
 static ngx_http_variable_t  ngx_http_proxy_vars[] = {
 
     { ngx_string("proxy_host"), ngx_http_proxy_host_variable, 0,
-      NGX_HTTP_VAR_CHANGABLE, 0 },
+      NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH, 0 },
 
     { ngx_string("proxy_port"), ngx_http_proxy_port_variable, 0,
-      NGX_HTTP_VAR_CHANGABLE, 0 },
+      NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH, 0 },
 
     { ngx_string("proxy_add_x_forwarded_for"),
-      ngx_http_proxy_add_x_forwarded_for_variable, 0, 0, 0 },
+      ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
 
 #if 0
-    { ngx_string("proxy_add_via"), NULL, 0, 0, 0 },
+    { ngx_string("proxy_add_via"), NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
 #endif
 
     { ngx_string("proxy_internal_body_length"),
-      ngx_http_proxy_internal_body_length_variable, 0, 0, 0 },
+      ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
 
     { ngx_null_string, NULL, 0, 0, 0 }
 };
diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c
index a3d3d46..cd8be78 100644
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -217,7 +217,8 @@
     name.len = sizeof("invalid_referer") - 1;
     name.data = (u_char *) "invalid_referer";
 
-    var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGABLE);
+    var = ngx_http_add_variable(cf, &name,
+                                NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH);
     if (var == NULL) {
         return NGX_CONF_ERROR;
     }
diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c
index 6f4ac45..dd0e92f 100644
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -648,13 +648,17 @@
 
                 rc = cmd->handler(r, ctx, params);
 
-                if (c->closed) {
+                if (c->destroyed) {
                     return NGX_DONE;
                 }
 
                 if (rc == NGX_OK) {
                     continue;
                 }
+
+                if (rc == NGX_ERROR) {
+                    return NGX_ERROR;
+                }
             }
 
 
diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c
index 808d945..1504f24 100644
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -244,6 +244,12 @@
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    r->allow_ranges = 1;
+
+    if (r->header_only || (r->main != r && ngx_file_size(&fi) == 0)) {
+        return ngx_http_send_header(r);
+    }
+
     /* we need to allocate all before the header would be sent */
 
     b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
@@ -256,11 +262,9 @@
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    r->allow_ranges = 1;
-
     rc = ngx_http_send_header(r);
 
-    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+    if (rc == NGX_ERROR || rc > NGX_OK) {
         return rc;
     }
 
diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c
index c77dca2..159bd34 100644
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -554,7 +554,7 @@
     ngx_http_variable_t     *var;
     ngx_http_log_op_name_t  *op;
 
-    var = ngx_http_add_variable(cf, &ngx_http_userid_got, 0);
+    var = ngx_http_add_variable(cf, &ngx_http_userid_got, NGX_HTTP_VAR_NOHASH);
     if (var == NULL) {
         return NGX_ERROR;
     }
@@ -562,7 +562,7 @@
     var->handler = ngx_http_userid_variable;
     var->data = offsetof(ngx_http_userid_ctx_t, uid_got);
 
-    var = ngx_http_add_variable(cf, &ngx_http_userid_set, 0);
+    var = ngx_http_add_variable(cf, &ngx_http_userid_set, NGX_HTTP_VAR_NOHASH);
     if (var == NULL) {
         return NGX_ERROR;
     }
diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c
index c251273..bba3f5d 100644
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -70,11 +70,15 @@
 static ngx_int_t
 ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
+    ngx_int_t                     rc;
+    ngx_connection_t             *c;
     ngx_output_chain_ctx_t       *ctx;
     ngx_http_copy_filter_conf_t  *conf;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "copy filter: \"%V\"", &r->uri);
+    c = r->connection;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "copy filter: \"%V?%V\"", &r->uri, &r->args);
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module);
 
@@ -88,7 +92,7 @@
 
         ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module);
 
-        ctx->sendfile = r->connection->sendfile;
+        ctx->sendfile = c->sendfile;
         ctx->need_in_memory = r->main_filter_need_in_memory
                               || r->filter_need_in_memory;
         ctx->need_in_temp = r->filter_need_temporary;
@@ -102,9 +106,16 @@
 
     }
 
-    /* the request pool may be already destroyed after ngx_output_chain()*/
+    rc = ngx_output_chain(ctx, in);
 
-    return ngx_output_chain(ctx, in);
+#if (NGX_DEBUG)
+    if (!c->destroyed) {
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);
+    }
+#endif
+
+    return rc;
 }
 
 
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 4743389..c100bee 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -966,14 +966,14 @@
 {
     ngx_int_t  rc;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http output filter \"%V\"", &r->uri);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http output filter \"%V?%V\"", &r->uri, &r->args);
 
     rc = ngx_http_top_body_filter(r, in);
 
     if (rc == NGX_ERROR) {
         /* NGX_ERROR may be returned by any filter */
-        r->connection->closed = 1;
+        r->connection->error = 1;
     }
 
     return rc;
@@ -1080,6 +1080,7 @@
 ngx_http_subrequest(ngx_http_request_t *r,
     ngx_str_t *uri, ngx_str_t *args, ngx_uint_t flags)
 {
+    ngx_connection_t              *c;
     ngx_http_request_t            *sr;
     ngx_http_core_srv_conf_t      *cscf;
     ngx_http_postponed_request_t  *pr, *p;
@@ -1090,7 +1091,9 @@
     }
 
     sr->signature = NGX_HTTP_MODULE;
-    sr->connection = r->connection;
+
+    c = r->connection;
+    sr->connection = c;
 
     sr->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
     if (sr->ctx == NULL) {
@@ -1128,16 +1131,13 @@
     sr->request_line = r->request_line;
     sr->uri = *uri;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http subrequest \"%V\"", uri);
-
     if (args) {
         sr->args = *args;
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http subrequest args \"%V\"", args);
     }
 
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http subrequest \"%V?%V\"", uri, &sr->args);
+
     if (flags & NGX_HTTP_ZERO_IN_URI) {
         sr->zero_in_uri = 1;
     }
@@ -1155,8 +1155,8 @@
     sr->read_event_handler = ngx_http_request_empty_handler;
     sr->write_event_handler = ngx_http_request_empty_handler;
 
-    if (r->connection->data == r) {
-        sr->connection->data = sr;
+    if (c->data == r) {
+        c->data = sr;
     }
 
     sr->in_addr = r->in_addr;
@@ -1192,7 +1192,12 @@
 
     ngx_http_handler(sr);
 
-    /* the request pool may be already destroyed */
+#if (NGX_LOG_DEBUG)
+    if (!c->destroyed) {
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                       "http subrequest done \"%V?%V\"", uri, &sr->args);
+    }
+#endif
 
     return NGX_OK;
 }
@@ -1204,22 +1209,19 @@
 {
     ngx_http_core_srv_conf_t  *cscf;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "internal redirect: \"%V\"", uri);
-
     r->uri = *uri;
 
     if (args) {
         r->args = *args;
 
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "internal redirect args: \"%V\"", args);
-
     } else {
         r->args.len = 0;
         r->args.data = NULL;
     }
 
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "internal redirect: \"%V?%V\"", uri, &r->args);
+
     if (ngx_http_set_exten(r) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
diff --git a/src/http/ngx_http_postpone_filter_module.c b/src/http/ngx_http_postpone_filter_module.c
index 9c56f46..478393c 100644
--- a/src/http/ngx_http_postpone_filter_module.c
+++ b/src/http/ngx_http_postpone_filter_module.c
@@ -9,6 +9,8 @@
 #include <ngx_http.h>
 
 
+static ngx_int_t
+    ngx_http_postpone_filter_output_postponed_request(ngx_http_request_t *r);
 static ngx_int_t ngx_http_postpone_filter_init(ngx_cycle_t *cycle);
 
 
@@ -53,8 +55,8 @@
     ngx_chain_t                   *out;
     ngx_http_postponed_request_t  *pr, **ppr;
 
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http postpone filter \"%V\" %p", &r->uri, in);
+    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http postpone filter \"%V?%V\" %p", &r->uri, &r->args, in);
 
     if (r != r->connection->data || (r->postponed && in)) {
 
@@ -104,14 +106,25 @@
         return NGX_OK;
     }
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http postpone filter out \"%V\"", &r->uri);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http postpone filter out \"%V?%V\"", &r->uri, &r->args);
 
     rc = ngx_http_next_filter(r->main, out);
 
     if (rc == NGX_ERROR) {
         /* NGX_ERROR may be returned by any filter */
-        r->connection->closed = 1;
+        r->connection->error = 1;
+    }
+
+    if (r->postponed == NULL) {
+        return rc;
+    }
+
+    rc = ngx_http_postpone_filter_output_postponed_request(r);
+
+    if (rc == NGX_ERROR) {
+        /* NGX_ERROR may be returned by any filter */
+        r->connection->error = 1;
     }
 
     return rc;
@@ -119,6 +132,55 @@
 
 
 static ngx_int_t
+ngx_http_postpone_filter_output_postponed_request(ngx_http_request_t *r)
+{
+    ngx_int_t                      rc;
+    ngx_http_postponed_request_t  *pr;
+
+    for ( ;; ) {
+        pr = r->postponed;
+
+        if (pr == NULL) {
+            return NGX_OK;
+        }
+
+        if (pr->request) {
+
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http postpone filter handle \"%V?%V\"",
+                           &pr->request->uri, &pr->request->args);
+
+            if (!pr->request->done) {
+                r->connection->data = pr->request;
+                return NGX_AGAIN;
+            }
+
+            rc = ngx_http_postpone_filter_output_postponed_request(pr->request);
+
+            if (rc == NGX_AGAIN || rc == NGX_ERROR) {
+                return rc;
+            }
+
+            r->postponed = r->postponed->next;
+            pr = r->postponed;
+        }
+
+        if (pr->out) {
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http postpone filter out postponed \"%V?%V\"",
+                           &r->uri, &r->args);
+
+            if (ngx_http_next_filter(r->main, pr->out) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+        }
+
+        r->postponed = r->postponed->next;
+    }
+}
+
+
+static ngx_int_t
 ngx_http_postpone_filter_init(ngx_cycle_t *cycle)
 {
     ngx_http_next_filter = ngx_http_top_body_filter;
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index f695056..569f62e 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -30,7 +30,6 @@
 static void ngx_http_request_handler(ngx_event_t *ev);
 static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r);
 static void ngx_http_writer(ngx_http_request_t *r);
-static ngx_int_t ngx_http_postponed_handler(ngx_http_request_t *r);
 
 static void ngx_http_block_read(ngx_http_request_t *r);
 static void ngx_http_read_discarded_body_handler(ngx_http_request_t *r);
@@ -404,6 +403,8 @@
     }
 
     c->single_connection = 1;
+    c->destroyed = 0;
+
     r->connection = c;
 
     r->main = r;
@@ -455,7 +456,7 @@
         return;
     }
 
-    n = recv(c->fd, buf, 1, MSG_PEEK);
+    n = recv(c->fd, (char *) buf, 1, MSG_PEEK);
 
     if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
         return;
@@ -1448,10 +1449,11 @@
         return;
     }
 
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http finalize request: %d, \"%V\"", rc, &r->uri);
+    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http finalize request: %d, \"%V?%V\"",
+                   rc, &r->uri, &r->args);
 
-    if (rc == NGX_ERROR || r->connection->closed) {
+    if (rc == NGX_ERROR || r->connection->error) {
         ngx_http_close_request(r, 0);
         return;
     }
@@ -1482,8 +1484,9 @@
     r->done = 1;
 
     if (r != r->connection->data) {
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http finalize non-active request: \"%V\"", &r->uri);
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http finalize non-active request: \"%V?%V\"",
+                       &r->uri, &r->args);
         return;
     }
 
@@ -1491,8 +1494,8 @@
 
         pr = r->parent;
 
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http parent request: \"%V\"", &pr->uri);
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http parent request: \"%V?%V\"", &pr->uri, &pr->args);
 
         if (rc != NGX_AGAIN) {
             pr->connection->data = pr;
@@ -1500,8 +1503,9 @@
 
         if (pr->postponed) {
 
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "http request: \"%V\" has postponed", &pr->uri);
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http request: \"%V?%V\" has postponed",
+                           &pr->uri, &pr->args);
 
             if (rc != NGX_AGAIN && pr->postponed->request == r) {
                 pr->postponed = pr->postponed->next;
@@ -1511,13 +1515,14 @@
                 }
             }
 
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "http request: \"%V\" still has postponed",
-                           &pr->uri);
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http request: \"%V?%V\" still has postponed",
+                           &pr->uri, &pr->args);
 
-            if (pr->done) {
-                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                               "http wake parent request: \"%V\"", &pr->uri);
+            if (pr->done || pr->postponed->out) {
+                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                               "http wake parent request: \"%V?%V\"",
+                               &pr->uri, &pr->args);
 
                 pr->write_event_handler(pr);
             }
@@ -1619,8 +1624,8 @@
     c = r->connection;
     wev = c->write;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, wev->log, 0,
-                   "http writer handler: \"%V\"", &r->uri);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0,
+                   "http writer handler: \"%V?%V\"", &r->uri, &r->args);
 
     if (wev->timedout) {
         if (!wev->delayed) {
@@ -1661,21 +1666,15 @@
         }
     }
 
-    if (r->postponed) {
-        rc = ngx_http_postponed_handler(r);
+    rc = ngx_http_output_filter(r, NULL);
 
-        if (rc == NGX_DONE) {
-            /* the request pool may be already destroyed */
-            return;
-        }
-
-    } else {
-        rc = ngx_http_output_filter(r, NULL);
-
+    if (c->destroyed) {
+        return;
     }
 
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http writer output filter: %d, \"%V\"", rc, &r->uri);
+    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http writer output filter: %d, \"%V?%V\"",
+                   rc, &r->uri, &r->args);
 
     if (rc == NGX_AGAIN) {
         clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module);
@@ -1690,67 +1689,13 @@
         return;
     }
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, wev->log, 0,
-                   "http writer done: \"%V\"", &r->uri);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0,
+                   "http writer done: \"%V?%V\"", &r->uri, &r->args);
 
     ngx_http_finalize_request(r, rc);
 }
 
 
-static ngx_int_t
-ngx_http_postponed_handler(ngx_http_request_t *r)
-{
-    ngx_int_t                      rc;
-    ngx_http_postponed_request_t  *pr;
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http postpone handler \"%V\"", &r->uri);
-
-    pr = r->postponed;
-
-    if (pr->request == NULL) {
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http postponed data \"%V\" %p", &r->uri, pr->out);
-
-        rc = ngx_http_output_filter(r, NULL);
-
-        if (rc == NGX_DONE) {
-            /* the request pool is already destroyed */
-            return NGX_DONE;
-        }
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http postponed output filter: %d", rc);
-
-        if (rc == NGX_ERROR) {
-            ngx_http_close_request(r, 0);
-            return NGX_DONE;
-        }
-
-        pr = r->postponed;
-
-        if (pr == NULL) {
-
-            if (rc == NGX_AGAIN) {
-                return NGX_AGAIN;
-            }
-
-            return NGX_OK;
-        }
-    }
-
-    r = pr->request;
-    r->connection->data = r;
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http wake child request \"%V\"", &r->uri);
-
-    r->write_event_handler(r);
-
-    return NGX_DONE;
-}
-
-
 static void
 ngx_http_block_read(ngx_http_request_t *r)
 {
@@ -1862,7 +1807,7 @@
 
     if (n == NGX_ERROR) {
 
-        r->connection->closed = 1;
+        r->connection->error = 1;
 
         /*
          * if a client request body is discarded then we already set
@@ -2029,20 +1974,10 @@
 
     rev->handler = ngx_http_keepalive_handler;
 
-    if (wev->active) {
-        if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
-            if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_DISABLE_EVENT)
-                                                                  == NGX_ERROR)
-            {
-                ngx_http_close_connection(c);
-                return;
-            }
-
-        } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
-            if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
-                ngx_http_close_connection(c);
-                return;
-            }
+    if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
+        if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
+            ngx_http_close_connection(c);
+            return;
         }
     }
 
@@ -2224,20 +2159,10 @@
     wev = c->write;
     wev->handler = ngx_http_empty_handler;
 
-    if (wev->active) {
-        if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
-            if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_DISABLE_EVENT)
-                                                                  == NGX_ERROR)
-            {
-                ngx_http_close_request(r, 0);
-                return;
-            }
-
-        } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
-            if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
-                ngx_http_close_request(r, 0);
-                return;
-            }
+    if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
+        if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
+            ngx_http_close_request(r, 0);
+            return;
         }
     }
 
@@ -2324,7 +2249,7 @@
 ngx_http_request_empty_handler(ngx_http_request_t *r)
 {
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http requets empty handler");
+                   "http request empty handler");
 
     return;
 }
@@ -2442,6 +2367,8 @@
 
     r->request_line.len = 0;
 
+    r->connection->destroyed = 1;
+
     ngx_destroy_pool(r->pool);
 }
 
@@ -2469,6 +2396,8 @@
     ngx_atomic_fetch_add(ngx_stat_active, -1);
 #endif
 
+    c->destroyed = 1;
+
     pool = c->pool;
 
     ngx_close_connection(c);
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index 779edf9..48aff74 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -230,7 +230,7 @@
         }
 
         if (n == 0 || n == NGX_ERROR) {
-            c->closed = 1;
+            c->error = 1;
             return NGX_HTTP_BAD_REQUEST;
         }
 
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 37e979a..cfaca6e 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -234,7 +234,7 @@
 };
 
 
-static ngx_http_log_op_name_t ngx_http_upstream_log_fmt_ops[] = {
+static ngx_http_log_op_name_t  ngx_http_upstream_log_fmt_ops[] = {
     { ngx_string("upstream_status"), 0, NULL,
                                     ngx_http_upstream_log_status_getlen,
                                     ngx_http_upstream_log_status },
@@ -248,10 +248,10 @@
 static ngx_http_variable_t  ngx_http_upstream_vars[] = {
 
     { ngx_string("upstream_status"),
-      ngx_http_upstream_status_variable, 0, 0, 0 },
+      ngx_http_upstream_status_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
 
     { ngx_string("upstream_response_time"),
-      ngx_http_upstream_response_time_variable, 0, 0, 0 },
+      ngx_http_upstream_response_time_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
 
     { ngx_null_string, NULL, 0, 0, 0 }
 };
@@ -387,7 +387,7 @@
     c = r->connection;
     u = r->upstream;
 
-    if (c->closed) {
+    if (c->error) {
         ngx_http_upstream_finalize_request(r, u,
                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
         return;
@@ -406,7 +406,7 @@
         }
 
         ev->eof = 1;
-        c->closed = 1;
+        c->error = 1;
 
         if (ev->kq_errno) {
             ev->error = 1;
@@ -473,7 +473,7 @@
     }
 
     ev->eof = 1;
-    c->closed = 1;
+    c->error = 1;
 
     if (!u->cachable && u->peer.connection) {
         ngx_log_error(NGX_LOG_INFO, ev->log, err,
@@ -1125,12 +1125,14 @@
 static void
 ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
 {
+    int                             tcp_nodelay;
     ssize_t                         size;
     ngx_int_t                       rc;
     ngx_uint_t                      i, key;
     ngx_list_part_t                *part;
     ngx_table_elt_t                *h;
     ngx_event_pipe_t               *p;
+    ngx_connection_t               *c;
     ngx_pool_cleanup_t             *cl;
     ngx_pool_cleanup_file_t        *clf;
     ngx_http_core_loc_conf_t       *clcf;
@@ -1209,6 +1211,8 @@
         }
     }
 
+    c = r->connection;
+
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (u->pipe == NULL) {
@@ -1231,6 +1235,23 @@
             return;
         }
 
+        if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
+
+            tcp_nodelay = 1;
+
+            if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
+                               (const void *) &tcp_nodelay, sizeof(int)) == -1)
+            {
+                ngx_connection_error(c, ngx_socket_errno,
+                                     "setsockopt(TCP_NODELAY) failed");
+                ngx_http_upstream_finalize_request(r, u, 0);
+                return;
+            }
+
+            c->tcp_nodelay = NGX_TCP_NODELAY_SET;
+        }
+
         size = u->buffer.last - u->buffer.pos;
 
         if (size) {
@@ -1241,7 +1262,7 @@
                 return;
             }
 
-            ngx_http_upstream_process_non_buffered_body(r->connection->write);
+            ngx_http_upstream_process_non_buffered_body(c->write);
 
         } else {
             u->buffer.pos = u->buffer.start;
@@ -1262,7 +1283,7 @@
 
     if (u->cache && u->cache->ctx.file.fd != NGX_INVALID_FILE) {
         if (ngx_close_file(u->cache->ctx.file.fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+            ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
                           ngx_close_file_n " \"%s\" failed",
                           u->cache->ctx.file.name.data);
         }
@@ -1292,9 +1313,9 @@
     p->bufs = u->conf->bufs;
     p->busy_size = u->conf->busy_buffers_size;
     p->upstream = u->peer.connection;
-    p->downstream = r->connection;
+    p->downstream = c;
     p->pool = r->pool;
-    p->log = r->connection->log;
+    p->log = c->log;
 
     p->cachable = u->cachable;
 
@@ -1305,7 +1326,7 @@
     }
 
     p->temp_file->file.fd = NGX_INVALID_FILE;
-    p->temp_file->file.log = r->connection->log;
+    p->temp_file->file.log = c->log;
     p->temp_file->path = u->conf->temp_path;
     p->temp_file->pool = r->pool;
 
@@ -1364,7 +1385,7 @@
          */
 
         p->cyclic_temp_file = 1;
-        r->connection->sendfile = 0;
+        c->sendfile = 0;
 
     } else {
         p->cyclic_temp_file = 0;
@@ -1394,8 +1415,9 @@
     size_t                     size;
     ssize_t                    n;
     ngx_buf_t                 *b;
+    ngx_int_t                  rc;
     ngx_uint_t                 do_write;
-    ngx_connection_t          *c;
+    ngx_connection_t          *c, *client;
     ngx_http_request_t        *r;
     ngx_http_upstream_t       *u;
     ngx_http_core_loc_conf_t  *clcf;
@@ -1426,6 +1448,7 @@
 
     r = c->data;
     u = r->upstream;
+    client = r->connection;
 
     b = &u->buffer;
 
@@ -1438,7 +1461,13 @@
         if (do_write) {
 
             if (u->out_bufs || u->busy_bufs) {
-                if (ngx_http_output_filter(r, u->out_bufs) == NGX_ERROR) {
+                rc = ngx_http_output_filter(r, u->out_bufs);
+
+                if (client->destroyed) {
+                    return;
+                }
+
+                if (rc == NGX_ERROR) {
                     ngx_http_upstream_finalize_request(r, u, 0);
                     return;
                 }
@@ -1490,18 +1519,20 @@
         break;
     }
 
-    if (ngx_handle_write_event(r->connection->write, clcf->send_lowat)
-        == NGX_ERROR)
-    {
-        ngx_http_upstream_finalize_request(r, u, 0);
-        return;
+    if (client->data == r) {
+        if (ngx_handle_write_event(client->write, clcf->send_lowat)
+            == NGX_ERROR)
+        {
+            ngx_http_upstream_finalize_request(r, u, 0);
+            return;
+        }
     }
 
-    if (r->connection->write->active) {
-        ngx_add_timer(r->connection->write, clcf->send_timeout);
+    if (client->write->active) {
+        ngx_add_timer(client->write, clcf->send_timeout);
 
-    } else if (r->connection->write->timer_set) {
-        ngx_del_timer(r->connection->write);
+    } else if (client->write->timer_set) {
+        ngx_del_timer(client->write);
     }
 
     if (ngx_handle_read_event(u->peer.connection->read, 0) == NGX_ERROR) {
@@ -1512,8 +1543,8 @@
     if (u->peer.connection->read->active) {
         ngx_add_timer(u->peer.connection->read, u->conf->read_timeout);
 
-    } else if (r->connection->read->timer_set) {
-        ngx_del_timer(r->connection->read);
+    } else if (u->peer.connection->read->timer_set) {
+        ngx_del_timer(u->peer.connection->read);
     }
 }
 
@@ -1577,13 +1608,14 @@
 ngx_http_upstream_process_body(ngx_event_t *ev)
 {
     ngx_event_pipe_t     *p;
-    ngx_connection_t     *c;
+    ngx_connection_t     *c, *downstream;
     ngx_http_request_t   *r;
     ngx_http_upstream_t  *u;
 
     c = ev->data;
     r = c->data;
     u = r->upstream;
+    downstream = r->connection;
 
     if (ev->write) {
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
@@ -1618,6 +1650,11 @@
                 }
 
                 if (ngx_event_pipe(p, ev->write) == NGX_ABORT) {
+
+                    if (downstream->destroyed) {
+                        return;
+                    }
+
                     ngx_http_upstream_finalize_request(r, u, 0);
                     return;
                 }
@@ -1648,6 +1685,11 @@
         }
 
         if (ngx_event_pipe(p, ev->write) == NGX_ABORT) {
+
+            if (downstream->destroyed) {
+                return;
+            }
+
             ngx_http_upstream_finalize_request(r, u, 0);
             return;
         }
@@ -1761,7 +1803,7 @@
         }
     }
 
-    if (r->connection->closed) {
+    if (r->connection->error) {
         ngx_http_upstream_finalize_request(r, u,
                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
         return;
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 3969d7e..6e831b5 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -843,6 +843,13 @@
                    "http variables: %ui", cmcf->variables.nelts);
 
 
+    for (n = 0; n < cmcf->all_variables.nelts; n++) {
+        if (av[n].flags & NGX_HTTP_VAR_NOHASH) {
+            av[n].name.data = NULL;
+        }
+    }
+
+
     /* init the all http variables hash */
 
     cmcf->variables_hash.max_size = 500;
diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h
index d1b23e8..480b4a5 100644
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -35,6 +35,7 @@
 #define NGX_HTTP_VAR_CHANGABLE   1
 #define NGX_HTTP_VAR_NOCACHABLE  2
 #define NGX_HTTP_VAR_INDEXED     4
+#define NGX_HTTP_VAR_NOHASH      8
 
 
 struct ngx_http_variable_s {
diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c
index f3b3622..c4d0a0e 100644
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -55,7 +55,7 @@
 
     c = r->connection;
 
-    if (c->closed) {
+    if (c->error) {
         return NGX_ERROR;
     }
 
@@ -220,7 +220,7 @@
     }
 
     if (chain == NGX_CHAIN_ERROR) {
-        c->closed = 1;
+        c->error = 1;
         return NGX_ERROR;
     }
 
diff --git a/src/imap/ngx_imap.h b/src/imap/ngx_imap.h
index fed6852..1f3c12e 100644
--- a/src/imap/ngx_imap.h
+++ b/src/imap/ngx_imap.h
@@ -20,13 +20,13 @@
 
 
 typedef struct {
-    void   **main_conf;
-    void   **srv_conf;
+    void                  **main_conf;
+    void                  **srv_conf;
 } ngx_imap_conf_ctx_t;
 
 
 typedef struct {
-    ngx_array_t           servers;         /* ngx_imap_core_srv_conf_t */
+    ngx_array_t             servers;         /* ngx_imap_core_srv_conf_t */
 } ngx_imap_core_main_conf_t;
 
 
@@ -34,17 +34,20 @@
 #define NGX_IMAP_IMAP_PROTOCOL  1
 
 typedef struct {
-    ngx_msec_t            timeout;
+    ngx_msec_t              timeout;
 
-    size_t                imap_client_buffer_size;
+    size_t                  imap_client_buffer_size;
 
-    ngx_uint_t            protocol;
+    ngx_uint_t              protocol;
 
-    ngx_buf_t            *pop3_capability;
-    ngx_buf_t            *imap_capability;
+    ngx_str_t               pop3_capability;
+    ngx_str_t               pop3_starttls_capability;
+    ngx_str_t               imap_capability;
+    ngx_str_t               imap_starttls_capability;
+    ngx_str_t               imap_starttls_only_capability;
 
-    ngx_array_t           pop3_capabilities;
-    ngx_array_t           imap_capabilities;
+    ngx_array_t             pop3_capabilities;
+    ngx_array_t             imap_capabilities;
 
     /* server ctx */
     ngx_imap_conf_ctx_t  *ctx;
@@ -52,11 +55,12 @@
 
 
 typedef struct {
-    void       *(*create_main_conf)(ngx_conf_t *cf);
-    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);
+    void                 *(*create_main_conf)(ngx_conf_t *cf);
+    char                 *(*init_main_conf)(ngx_conf_t *cf, void *conf);
 
-    void       *(*create_srv_conf)(ngx_conf_t *cf);
-    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
+    void                 *(*create_srv_conf)(ngx_conf_t *cf);
+    char                 *(*merge_srv_conf)(ngx_conf_t *cf, void *prev,
+                                void *conf);
 } ngx_imap_module_t;
 
 
@@ -126,8 +130,8 @@
 
 
 typedef struct {
-    ngx_str_t           *client;
-    ngx_imap_session_t  *session;
+    ngx_str_t              *client;
+    ngx_imap_session_t     *session;
 } ngx_imap_log_ctx_t;
 
 
@@ -136,22 +140,24 @@
 #define NGX_POP3_CAPA       3
 #define NGX_POP3_QUIT       4
 #define NGX_POP3_NOOP       5
-#define NGX_POP3_APOP       6
-#define NGX_POP3_STAT       7
-#define NGX_POP3_LIST       8
-#define NGX_POP3_RETR       9
-#define NGX_POP3_DELE       10
-#define NGX_POP3_RSET       11
-#define NGX_POP3_TOP        12
-#define NGX_POP3_UIDL       13
+#define NGX_POP3_STLS       6
+#define NGX_POP3_APOP       7
+#define NGX_POP3_STAT       8
+#define NGX_POP3_LIST       9
+#define NGX_POP3_RETR       10
+#define NGX_POP3_DELE       11
+#define NGX_POP3_RSET       12
+#define NGX_POP3_TOP        13
+#define NGX_POP3_UIDL       14
 
 
 #define NGX_IMAP_LOGIN      1
 #define NGX_IMAP_LOGOUT     2
 #define NGX_IMAP_CAPABILITY 3
 #define NGX_IMAP_NOOP       4
+#define NGX_IMAP_STARTTLS   5
 
-#define NGX_IMAP_NEXT       5
+#define NGX_IMAP_NEXT       6
 
 
 #define NGX_IMAP_PARSE_INVALID_COMMAND  20
diff --git a/src/imap/ngx_imap_auth_http_module.c b/src/imap/ngx_imap_auth_http_module.c
index 75350d5..cedb0d8 100644
--- a/src/imap/ngx_imap_auth_http_module.c
+++ b/src/imap/ngx_imap_auth_http_module.c
@@ -727,7 +727,7 @@
 
         ngx_imap_send(s->connection->write);
 
-        if (c->closed) {
+        if (c->destroyed) {
             return;
         }
 
@@ -1181,6 +1181,8 @@
             return NGX_CONF_ERROR;
         }
 
+        ahcf->peers->number = 1;
+
         ahcf->host_header = inet_upstream.host_header;
         ahcf->uri = inet_upstream.uri;
     }
diff --git a/src/imap/ngx_imap_core_module.c b/src/imap/ngx_imap_core_module.c
index 6408e54..e805a81 100644
--- a/src/imap/ngx_imap_core_module.c
+++ b/src/imap/ngx_imap_core_module.c
@@ -181,8 +181,8 @@
     ngx_imap_core_srv_conf_t *prev = parent;
     ngx_imap_core_srv_conf_t *conf = child;
 
+    u_char      *p;
     size_t       size;
-    ngx_buf_t   *b;
     ngx_str_t   *c, *d;
     ngx_uint_t   i;
 
@@ -218,22 +218,40 @@
         size += c[i].len + sizeof(CRLF) - 1;
     }
 
-    b = ngx_create_temp_buf(cf->pool, size);
-    if (b == NULL) {
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    b->last = ngx_cpymem(b->last, "+OK Capability list follows" CRLF,
-                         sizeof("+OK Capability list follows" CRLF) - 1);
+    conf->pop3_capability.len = size;
+    conf->pop3_capability.data = p;
+
+    p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
+                   sizeof("+OK Capability list follows" CRLF) - 1);
 
     for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
-        b->last = ngx_cpymem(b->last, c[i].data, c[i].len);
-        *b->last++ = CR; *b->last++ = LF;
+        p = ngx_cpymem(p, c[i].data, c[i].len);
+        *p++ = CR; *p++ = LF;
     }
 
-    *b->last++ = '.'; *b->last++ = CR; *b->last++ = LF;
+    *p++ = '.'; *p++ = CR; *p = LF;
 
-    conf->pop3_capability = b;
+
+    size += sizeof("STLS" CRLF) - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->pop3_starttls_capability.len = size;
+    conf->pop3_starttls_capability.data = p;
+
+    p = ngx_cpymem(p, conf->pop3_capability.data,
+                   conf->pop3_capability.len - (sizeof("." CRLF) - 1));
+
+    p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
+    *p++ = '.'; *p++ = CR; *p = LF;
 
 
     if (conf->imap_capabilities.nelts == 0) {
@@ -259,21 +277,55 @@
         size += 1 + c[i].len;
     }
 
-    b = ngx_create_temp_buf(cf->pool, size);
-    if (b == NULL) {
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    b->last = ngx_cpymem(b->last, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
+    conf->imap_capability.len = size;
+    conf->imap_capability.data = p;
+
+    p = ngx_cpymem(p, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
 
     for (i = 0; i < conf->imap_capabilities.nelts; i++) {
-        *b->last++ = ' ';
-        b->last = ngx_cpymem(b->last, c[i].data, c[i].len);
+        *p++ = ' ';
+        p = ngx_cpymem(p, c[i].data, c[i].len);
     }
 
-    *b->last++ = CR; *b->last++ = LF;
+    *p++ = CR; *p = LF;
 
-    conf->imap_capability = b;
+
+    size += sizeof(" STARTTLS") - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->imap_starttls_capability.len = size;
+    conf->imap_starttls_capability.data = p;
+
+    p = ngx_cpymem(p, conf->imap_capability.data,
+                   conf->imap_capability.len - (sizeof(CRLF) - 1));
+    p = ngx_cpymem(p, " STARTTLS", sizeof(" STARTTLS") - 1);
+    *p++ = CR; *p = LF;
+
+
+    size += sizeof(" LOGINDISABLED") - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->imap_starttls_only_capability.len = size;
+    conf->imap_starttls_only_capability.data = p;
+
+    p = ngx_cpymem(p, conf->imap_starttls_capability.data,
+                   conf->imap_starttls_capability.len - (sizeof(CRLF) - 1));
+    p = ngx_cpymem(p, " LOGINDISABLED", sizeof(" LOGINDISABLED") - 1);
+    *p++ = CR; *p = LF;
+
 
     return NGX_CONF_OK;
 }
diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c
index ddff96a..f90b968 100644
--- a/src/imap/ngx_imap_handler.c
+++ b/src/imap/ngx_imap_handler.c
@@ -16,6 +16,7 @@
 static u_char *ngx_imap_log_error(ngx_log_t *log, u_char *buf, size_t len);
 
 #if (NGX_IMAP_SSL)
+static void ngx_imap_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c);
 static void ngx_imap_ssl_handshake_handler(ngx_connection_t *c);
 #endif
 
@@ -43,11 +44,10 @@
 void
 ngx_imap_init_connection(ngx_connection_t *c)
 {
-    ngx_imap_log_ctx_t        *lctx;
+    ngx_imap_log_ctx_t   *lctx;
 #if (NGX_IMAP_SSL)
-    ngx_imap_conf_ctx_t       *ctx;
-    ngx_imap_ssl_conf_t       *sslcf;
-    ngx_imap_core_srv_conf_t  *cscf;
+    ngx_imap_conf_ctx_t  *ctx;
+    ngx_imap_ssl_conf_t  *sslcf;
 #endif
 
     ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V",
@@ -75,23 +75,7 @@
     sslcf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_ssl_module);
 
     if (sslcf->enable) {
-        if (ngx_ssl_create_connection(&sslcf->ssl, c, 0) == NGX_ERROR) {
-            ngx_imap_close_connection(c);
-            return;
-        }
-
-        if (ngx_ssl_handshake(c) == NGX_AGAIN) {
-
-            cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module);
-
-            ngx_add_timer(c->read, cscf->timeout);
-
-            c->ssl->handler = ngx_imap_ssl_handshake_handler;
-
-            return;
-        }
-
-        ngx_imap_ssl_handshake_handler(c);
+        ngx_imap_ssl_init_connection(&sslcf->ssl, c);
         return;
     }
 
@@ -104,15 +88,69 @@
 #if (NGX_IMAP_SSL)
 
 static void
+ngx_imap_starttls_handler(ngx_event_t *rev)
+{
+    ngx_connection_t     *c;
+    ngx_imap_session_t   *s;
+    ngx_imap_ssl_conf_t  *sslcf;
+
+    c = rev->data;
+    s = c->data;
+
+    c->log->action = "in starttls state";
+
+    sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module);
+
+    ngx_imap_ssl_init_connection(&sslcf->ssl, c);
+}
+
+
+static void
+ngx_imap_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c)
+{
+    ngx_imap_conf_ctx_t       *ctx;
+    ngx_imap_core_srv_conf_t  *cscf;
+
+    if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) {
+        ngx_imap_close_connection(c);
+        return;
+    }
+
+    if (ngx_ssl_handshake(c) == NGX_AGAIN) {
+
+        ctx = c->ctx;
+        cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module);
+
+        ngx_add_timer(c->read, cscf->timeout);
+
+        c->ssl->handler = ngx_imap_ssl_handshake_handler;
+
+        return;
+    }
+
+    ngx_imap_ssl_handshake_handler(c);
+}
+
+
+static void
 ngx_imap_ssl_handshake_handler(ngx_connection_t *c)
 {
     if (c->ssl->handshaked) {
+
+        if (c->data) {
+            c->read->handler = ngx_imap_init_protocol;
+            c->write->handler = ngx_imap_send;
+
+            ngx_imap_init_protocol(c->read);
+
+            return;
+        }
+
         ngx_imap_init_session(c);
         return;
     }
 
     ngx_imap_close_connection(c);
-    return;
 }
 
 #endif
@@ -253,11 +291,6 @@
 
     s = c->data;
 
-    if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) {
-        ngx_imap_session_internal_server_error(s);
-        return;
-    }
-
     if (s->protocol == NGX_IMAP_POP3_PROTOCOL) {
         size = 128;
         s->imap_state = ngx_pop3_start;
@@ -270,10 +303,19 @@
         c->read->handler = ngx_imap_auth_state;
     }
 
-    s->buffer = ngx_create_temp_buf(c->pool, size);
     if (s->buffer == NULL) {
-        ngx_imap_session_internal_server_error(s);
-        return;
+        if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t))
+            == NGX_ERROR)
+        {
+            ngx_imap_session_internal_server_error(s);
+            return;
+        }
+
+        s->buffer = ngx_create_temp_buf(c->pool, size);
+        if (s->buffer == NULL) {
+            ngx_imap_session_internal_server_error(s);
+            return;
+        }
     }
 
     c->read->handler(rev);
@@ -291,6 +333,9 @@
     ngx_connection_t          *c;
     ngx_imap_session_t        *s;
     ngx_imap_core_srv_conf_t  *cscf;
+#if (NGX_IMAP_SSL)
+    ngx_imap_ssl_conf_t       *sslcf;
+#endif
 
     c = rev->data;
     s = c->data;
@@ -357,6 +402,19 @@
         switch (s->command) {
 
         case NGX_IMAP_LOGIN:
+
+#if (NGX_IMAP_SSL)
+
+            if (c->ssl == NULL) {
+                sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module);
+
+                if (sslcf->starttls == NGX_IMAP_STARTTLS_ONLY) {
+                    rc = NGX_IMAP_PARSE_INVALID_COMMAND;
+                    break;
+                }
+            }
+#endif
+
             arg = s->args.elts;
 
             if (s->args.nelts == 2 && arg[0].len) {
@@ -410,8 +468,28 @@
 
         case NGX_IMAP_CAPABILITY:
             cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
-            text = cscf->imap_capability->pos;
-            text_len = cscf->imap_capability->last - cscf->imap_capability->pos;
+
+#if (NGX_IMAP_SSL)
+
+            if (c->ssl == NULL) {
+                sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module);
+
+                if (sslcf->starttls == NGX_IMAP_STARTTLS_ON) {
+                    text_len = cscf->imap_starttls_capability.len;
+                    text = cscf->imap_starttls_capability.data;
+                    break;
+                }
+
+                if (sslcf->starttls == NGX_IMAP_STARTTLS_ONLY) {
+                    text_len = cscf->imap_starttls_only_capability.len;
+                    text = cscf->imap_starttls_only_capability.data;
+                    break;
+                }
+            }
+#endif
+
+            text_len = cscf->imap_capability.len;
+            text = cscf->imap_capability.data;
             break;
 
         case NGX_IMAP_LOGOUT:
@@ -423,6 +501,21 @@
         case NGX_IMAP_NOOP:
             break;
 
+#if (NGX_IMAP_SSL)
+
+        case NGX_IMAP_STARTTLS:
+            if (c->ssl == NULL) {
+                sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module);
+                if (sslcf->starttls) {
+                    c->read->handler = ngx_imap_starttls_handler;
+                    break;
+                }
+            }
+
+            rc = NGX_IMAP_PARSE_INVALID_COMMAND;
+            break;
+#endif
+
         default:
             rc = NGX_IMAP_PARSE_INVALID_COMMAND;
             break;
@@ -492,6 +585,9 @@
     ngx_connection_t          *c;
     ngx_imap_session_t        *s;
     ngx_imap_core_srv_conf_t  *cscf;
+#if (NGX_IMAP_SSL)
+    ngx_imap_ssl_conf_t       *sslcf;
+#endif
 
     c = rev->data;
     s = c->data;
@@ -554,8 +650,22 @@
 
             case NGX_POP3_CAPA:
                 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
-                text = cscf->pop3_capability->pos;
-                size = cscf->pop3_capability->last - cscf->pop3_capability->pos;
+
+#if (NGX_IMAP_SSL)
+
+                if (c->ssl == NULL) {
+                    sslcf = ngx_imap_get_module_srv_conf(s,
+                                                         ngx_imap_ssl_module);
+                    if (sslcf->starttls) {
+                        size = cscf->pop3_starttls_capability.len;
+                        text = cscf->pop3_starttls_capability.data;
+                        break;
+                    }
+                }
+#endif
+
+                size = cscf->pop3_capability.len;
+                text = cscf->pop3_capability.data;
                 break;
 
             case NGX_POP3_QUIT:
@@ -565,6 +675,22 @@
             case NGX_POP3_NOOP:
                 break;
 
+#if (NGX_IMAP_SSL)
+
+            case NGX_POP3_STLS:
+                if (c->ssl == NULL) {
+                    sslcf = ngx_imap_get_module_srv_conf(s,
+                                                         ngx_imap_ssl_module);
+                    if (sslcf->starttls) {
+                        c->read->handler = ngx_imap_starttls_handler;
+                        break;
+                    }
+                }
+
+                rc = NGX_IMAP_PARSE_INVALID_COMMAND;
+                break;
+#endif
+
             default:
                 s->imap_state = ngx_pop3_start;
                 rc = NGX_IMAP_PARSE_INVALID_COMMAND;
@@ -616,8 +742,8 @@
 
             case NGX_POP3_CAPA:
                 cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module);
-                text = cscf->pop3_capability->pos;
-                size = cscf->pop3_capability->last - cscf->pop3_capability->pos;
+                size = cscf->pop3_capability.len;
+                text = cscf->pop3_capability.data;
                 break;
 
             case NGX_POP3_QUIT:
@@ -735,7 +861,7 @@
 
 #endif
 
-    c->closed = 1;
+    c->destroyed = 1;
 
     pool = c->pool;
 
diff --git a/src/imap/ngx_imap_parse.c b/src/imap/ngx_imap_parse.c
index d8c436b..eea4550 100644
--- a/src/imap/ngx_imap_parse.c
+++ b/src/imap/ngx_imap_parse.c
@@ -119,6 +119,25 @@
                     }
                     break;
 
+#if (NGX_IMAP_SSL)
+                case 8:
+                    if ((c[0] == 'S'|| c[0] == 's')
+                        && (c[1] == 'T'|| c[1] == 't')
+                        && (c[2] == 'A'|| c[2] == 'a')
+                        && (c[3] == 'R'|| c[3] == 'r')
+                        && (c[4] == 'T'|| c[4] == 't')
+                        && (c[5] == 'T'|| c[5] == 't')
+                        && (c[6] == 'L'|| c[6] == 'l')
+                        && (c[7] == 'S'|| c[7] == 's'))
+                    {
+                        s->command = NGX_IMAP_STARTTLS;
+
+                    } else {
+                        goto invalid;
+                    }
+                    break;
+#endif
+
                 case 10:
                     if ((c[0] == 'C'|| c[0] == 'c')
                         && (c[1] == 'A'|| c[1] == 'a')
@@ -421,7 +440,11 @@
                     } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P')
                     {
                         s->command = NGX_POP3_NOOP;
-
+#if (NGX_IMAP_SSL)
+                    } else if (c0 == 'S' && c1 == 'T' && c2 == 'L' && c3 == 'S')
+                    {
+                        s->command = NGX_POP3_STLS;
+#endif
                     } else {
                         goto invalid;
                     }
diff --git a/src/imap/ngx_imap_proxy_module.c b/src/imap/ngx_imap_proxy_module.c
index 6232960..bdce364 100644
--- a/src/imap/ngx_imap_proxy_module.c
+++ b/src/imap/ngx_imap_proxy_module.c
@@ -286,8 +286,6 @@
 
         c->log->action = NULL;
         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
-
-        c->log->action = "proxying";
     }
 }
 
@@ -405,16 +403,24 @@
 
         c->log->action = NULL;
         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
-
-        c->log->action = "proxying";
     }
 }
 
 
 static void
-ngx_imap_proxy_dummy_handler(ngx_event_t *ev)
+ngx_imap_proxy_dummy_handler(ngx_event_t *wev)
 {
-    ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, "imap proxy dummy handler");
+    ngx_connection_t    *c;
+    ngx_imap_session_t  *s;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_IMAP, wev->log, 0, "imap proxy dummy handler");
+
+    if (ngx_handle_write_event(wev, 0) == NGX_ERROR) {
+        c = wev->data;
+        s = c->data;
+
+        ngx_imap_proxy_close_session(s);
+    }
 }
 
 
@@ -487,11 +493,11 @@
 static void
 ngx_imap_proxy_handler(ngx_event_t *ev)
 {
-    char                   *action;
+    char                   *action, *recv_action, *send_action;
     size_t                  size;
     ssize_t                 n;
     ngx_buf_t              *b;
-    ngx_uint_t              again, do_write;
+    ngx_uint_t              do_write;
     ngx_connection_t       *c, *src, *dst;
     ngx_imap_session_t     *s;
     ngx_imap_proxy_conf_t  *pcf;
@@ -500,6 +506,8 @@
     s = c->data;
 
     if (ev->timedout) {
+        c->log->action = "proxying";
+
         if (c == s->connection) {
             ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
                           "client timed out");
@@ -516,11 +524,15 @@
 
     if (c == s->connection) {
         if (ev->write) {
+            recv_action = "proxying and reading from upstream";
+            send_action = "proxying and sending to client";
             src = s->proxy->upstream.connection;
             dst = c;
             b = s->proxy->buffer;
 
         } else {
+            recv_action = "proxying and reading from client";
+            send_action = "proxying and sending to upstream";
             src = c;
             dst = s->proxy->upstream.connection;
             b = s->buffer;
@@ -528,11 +540,15 @@
 
     } else {
         if (ev->write) {
+            recv_action = "proxying and reading from upstream";
+            send_action = "proxying and sending to client";
             src = s->connection;
             dst = c;
             b = s->buffer;
 
         } else {
+            recv_action = "proxying and reading from client";
+            send_action = "proxying and sending to upstream";
             src = c;
             dst = s->connection;
             b = s->proxy->buffer;
@@ -545,14 +561,15 @@
                    "imap proxy handler: %d, #%d > #%d",
                    do_write, src->fd, dst->fd);
 
-    do {
-        again = 0;
+    for ( ;; ) {
 
-        if (do_write == 1) {
+        if (do_write) {
 
             size = b->last - b->pos;
 
             if (size && dst->write->ready) {
+                c->log->action = send_action;
+
                 n = dst->send(dst, b->pos, size);
 
                 if (n == NGX_ERROR) {
@@ -561,7 +578,6 @@
                 }
 
                 if (n > 0) {
-                    again = 1;
                     b->pos += n;
 
                     if (b->pos == b->last) {
@@ -569,58 +585,74 @@
                         b->last = b->start;
                     }
                 }
-
-                if (n == NGX_AGAIN || n < (ssize_t) size) {
-                    if (ngx_handle_write_event(dst->write, /* TODO: LOWAT */ 0)
-                        == NGX_ERROR)
-                    {
-                        ngx_imap_proxy_close_session(s);
-                        return;
-                    }
-                }
             }
         }
 
         size = b->end - b->last;
 
         if (size && src->read->ready) {
+            c->log->action = recv_action;
+
             n = src->recv(src, b->last, size);
 
-            if (n == NGX_ERROR) {
-                ngx_imap_proxy_close_session(s);
-                return;
-            }
-
-            if (n == 0) {
-                action = c->log->action;
-                c->log->action = NULL;
-                ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxied session done");
-                c->log->action = action;
-
-                ngx_imap_proxy_close_session(s);
-                return;
+            if (n == NGX_AGAIN || n == 0) {
+                break;
             }
 
             if (n > 0) {
-                again = 1;
                 do_write = 1;
                 b->last += n;
+
+                continue;
             }
 
-            if (n == NGX_AGAIN || n < (ssize_t) size) {
-                if (ngx_handle_read_event(src->read, 0) == NGX_ERROR) {
-                    ngx_imap_proxy_close_session(s);
-                    return;
-                }
-            }
-
-            if (c == s->connection) {
-                pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module);
-                ngx_add_timer(c->read, pcf->timeout);
+            if (n == NGX_ERROR) {
+                src->read->eof = 1;
             }
         }
 
-    } while (again);
+        break;
+    }
+
+    c->log->action = "proxying";
+
+    if ((s->connection->read->eof || s->proxy->upstream.connection->read->eof)
+        && s->buffer->pos == s->buffer->last
+        && s->proxy->buffer->pos == s->proxy->buffer->last)
+    {
+        action = c->log->action;
+        c->log->action = NULL;
+        ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxied session done");
+        c->log->action = action;
+
+        ngx_imap_proxy_close_session(s);
+        return;
+    }
+
+    if (ngx_handle_write_event(dst->write, 0) == NGX_ERROR) {
+        ngx_imap_proxy_close_session(s);
+        return;
+    }
+
+    if (ngx_handle_read_event(dst->read, 0) == NGX_ERROR) {
+        ngx_imap_proxy_close_session(s);
+        return;
+    }
+
+    if (ngx_handle_write_event(src->write, 0) == NGX_ERROR) {
+        ngx_imap_proxy_close_session(s);
+        return;
+    }
+
+    if (ngx_handle_read_event(src->read, 0) == NGX_ERROR) {
+        ngx_imap_proxy_close_session(s);
+        return;
+    }
+
+    if (c == s->connection) {
+        pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module);
+        ngx_add_timer(c->read, pcf->timeout);
+    }
 }
 
 
diff --git a/src/imap/ngx_imap_ssl_module.c b/src/imap/ngx_imap_ssl_module.c
index cbbbb68..cb2b8ca 100644
--- a/src/imap/ngx_imap_ssl_module.c
+++ b/src/imap/ngx_imap_ssl_module.c
@@ -27,6 +27,15 @@
 #endif
 
 
+static ngx_conf_enum_t  ngx_http_starttls_state[] = {
+    { ngx_string("off"), NGX_IMAP_STARTTLS_OFF },
+    { ngx_string("on"), NGX_IMAP_STARTTLS_ON },
+    { ngx_string("only"), NGX_IMAP_STARTTLS_ONLY },
+    { ngx_null_string, 0 }
+};
+
+
+
 static ngx_conf_bitmask_t  ngx_imap_ssl_protocols[] = {
     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
     { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
@@ -44,6 +53,13 @@
       offsetof(ngx_imap_ssl_conf_t, enable),
       NULL },
 
+    { ngx_string("starttls"),
+      NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_IMAP_SRV_CONF_OFFSET,
+      offsetof(ngx_imap_ssl_conf_t, starttls),
+      ngx_http_starttls_state },
+
     { ngx_string("ssl_certificate"),
       NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
@@ -146,6 +162,7 @@
      */
 
     scf->enable = NGX_CONF_UNSET;
+    scf->starttls = NGX_CONF_UNSET;
     scf->session_timeout = NGX_CONF_UNSET;
     scf->prefer_server_ciphers = NGX_CONF_UNSET;
 
@@ -162,8 +179,9 @@
     ngx_pool_cleanup_t  *cln;
 
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
+    ngx_conf_merge_value(conf->starttls, prev->starttls, NGX_IMAP_STARTTLS_OFF);
 
-    if (conf->enable == 0) {
+    if (conf->enable == 0 && conf->starttls == NGX_IMAP_STARTTLS_OFF) {
         return NGX_CONF_OK;
     }
 
diff --git a/src/imap/ngx_imap_ssl_module.h b/src/imap/ngx_imap_ssl_module.h
index 2ac9f11..7b05bce 100644
--- a/src/imap/ngx_imap_ssl_module.h
+++ b/src/imap/ngx_imap_ssl_module.h
@@ -13,12 +13,18 @@
 #include <ngx_imap.h>
 
 
+#define NGX_IMAP_STARTTLS_OFF   0
+#define NGX_IMAP_STARTTLS_ON    1
+#define NGX_IMAP_STARTTLS_ONLY  2
+
+
 typedef struct {
     ngx_flag_t      enable;
 
     ngx_ssl_t       ssl;
 
     ngx_flag_t      prefer_server_ciphers;
+    ngx_flag_t      starttls;
 
     ngx_uint_t      protocols;
 
diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c
index 6f01ab3..a906430 100644
--- a/src/os/unix/ngx_recv.c
+++ b/src/os/unix/ngx_recv.c
@@ -60,7 +60,7 @@
                 rev->available -= n;
 
                 /*
-                 * rev->available can be negative here because some additional
+                 * rev->available may be negative here because some additional
                  * bytes can be received between kevent() and recv()
                  */