changeset 96:ca4f70b3ccc6 NGINX_0_2_2

nginx 0.2.2 *) Feature: the "config errmsg" command of the ngx_http_ssi_module. *) Change: the ngx_http_geo_module variables can be overridden by the "set" directive. *) Feature: the "ssl_protocols" and "ssl_prefer_server_ciphers" directives of the ngx_http_ssl_module and ngx_imap_ssl_module. *) Bugfix: the ngx_http_autoindex_module did not show correctly the long file names; *) Bugfix: the ngx_http_autoindex_module now do not show the files starting by dot. *) Bugfix: if the SSL handshake failed then another connection may be closed too. Thanks to Rob Mueller. *) Bugfix: the export versions of MSIE 5.x could not connect via HTTPS.
author Igor Sysoev <http://sysoev.ru>
date Fri, 30 Sep 2005 00:00:00 +0400
parents 2f95911bc4b4
children 701eee3df18f
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_connection.h src/core/ngx_core.h src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/http/modules/ngx_http_autoindex_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_geo_module.c src/http/modules/ngx_http_gzip_filter_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/ngx_http_ssl_module.h src/http/ngx_http_request.c src/imap/ngx_imap_auth_http_module.c src/imap/ngx_imap_handler.c src/imap/ngx_imap_proxy_module.c src/imap/ngx_imap_ssl_module.c src/imap/ngx_imap_ssl_module.h src/os/unix/ngx_atomic.h src/os/unix/ngx_freebsd_init.c
diffstat 23 files changed, 723 insertions(+), 488 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,25 @@
+
+Changes with nginx 0.2.2                                         30 Sep 2005
+
+    *) Feature: the "config errmsg" command of the ngx_http_ssi_module.
+
+    *) Change: the ngx_http_geo_module variables can be overridden by the 
+       "set" directive.
+
+    *) Feature: the "ssl_protocols" and "ssl_prefer_server_ciphers" 
+       directives of the ngx_http_ssl_module and ngx_imap_ssl_module.
+
+    *) Bugfix: the ngx_http_autoindex_module did not show correctly the 
+       long file names;
+
+    *) Bugfix: the ngx_http_autoindex_module now do not show the files 
+       starting by dot.
+
+    *) Bugfix: if the SSL handshake failed then another connection may be 
+       closed too. Thanks to Rob Mueller.
+
+    *) Bugfix: the export versions of MSIE 5.x could not connect via HTTPS.
+
 
 Changes with nginx 0.2.1                                         23 Sep 2005
 
@@ -33,7 +55,7 @@ Changes with nginx 0.2.0                
     *) Bugfix: if all backend using in load-balancing failed after one 
        error, then nginx did not try do connect to them during 60 seconds.
 
-    *) Bugfix: in IMAP/POP3 command argument parsing.
+    *) Bugfix: in IMAP/POP3 command argument parsing. Thanks to Rob Mueller.
 
     *) Bugfix: errors while using SSL in IMAP/POP3 proxy.
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,3 +1,26 @@
+
+Изменения в nginx 0.2.2                                           30.09.2005
+
+    *) Добавление: команда config errmsg в модуле ngx_http_ssi_module.
+
+    *) Изменение: переменные модуля ngx_http_geo_module можно 
+       переопределять директивой set.
+
+    *) Добавление: директивы ssl_protocols и ssl_prefer_server_ciphers 
+       модулей ngx_http_ssl_module и ngx_imap_ssl_module.
+
+    *) Исправление: ошибка в модуле ngx_http_autoindex_module при показе 
+       длинных имён файлов;
+
+    *) Исправление: модуль ngx_http_autoindex_module теперь не показывает 
+       файлы, начинающиеся на точку.
+
+    *) Исправление: если SSL handshake завершался с ошибкой, то это могло 
+       привести также в закрытию другого соединения. Спасибо Rob Mueller.
+
+    *) Исправление: экспортные версии MSIE 5.x не могли соединиться по 
+       HTTPS.
+
 
 Изменения в nginx 0.2.1                                           23.09.2005
 
@@ -15,8 +38,8 @@
        обычный pid-файл без суффикса ".newbin". Если новый основной процесс 
        выходит, то старый процесс переименовывает свой pid-файл c суффиксом 
        ".oldbin" в pid-файл без суффикса. При обновлении с версии 0.1.х до 
-       0.2.0 нужно учитывать, что старый процесс 0.1.x и новый процесс 
-       0.2.0 оба используют pid-файл без суффиксов.
+       0.2.0 нужно учитывать, что оба процесса - старый 0.1.x и новый 
+       0.2.0 - используют pid-файл без суффиксов.
 
     *) Изменение: директива worker_connections, новое название директивы 
        connections; директива теперь задаёт максимальное число соединений, 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.2.1"
+#define NGINX_VER          "nginx/0.2.2"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -28,7 +28,7 @@ struct ngx_listening_s {
     int                 backlog;
 
     /* handler of accepted connection */
-    void              (*handler)(ngx_connection_t *c);
+    ngx_connection_handler_pt   handler;
 
     void               *ctx;      /* ngx_http_conf_ctx_t, for example */
     void               *servers;  /* array of ngx_http_in_addr_t, for example */
@@ -118,7 +118,7 @@ struct ngx_connection_s {
     ngx_str_t           addr_text;
 
 #if (NGX_OPENSSL)
-    ngx_ssl_t          *ssl;
+    ngx_ssl_connection_t  *ssl;
 #endif
 
 #if (NGX_HAVE_IOCP)
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -23,7 +23,7 @@ typedef struct ngx_peers_s       ngx_pee
 typedef struct ngx_connection_s  ngx_connection_t;
 
 typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
-
+typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
 
 
 #define  NGX_OK          0
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -14,9 +14,12 @@ typedef struct {
 } ngx_openssl_conf_t;
 
 
+static void ngx_ssl_handshake_handler(ngx_event_t *ev);
 static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);
 static void ngx_ssl_write_handler(ngx_event_t *wev);
 static void ngx_ssl_read_handler(ngx_event_t *rev);
+static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
+    ngx_err_t err, char *text);
 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
 static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf);
 
@@ -63,7 +66,19 @@ ngx_module_t  ngx_openssl_module = {
     NULL,                                  /* exit process */
     NULL,                                  /* exit master */
     NGX_MODULE_V1_PADDING
-};  
+};
+
+
+static long  ngx_ssl_protocols[] = {
+    SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1,
+    SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1,
+    SSL_OP_NO_SSLv2|SSL_OP_NO_TLSv1,
+    SSL_OP_NO_TLSv1,
+    SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3,
+    SSL_OP_NO_SSLv3,
+    SSL_OP_NO_SSLv2,
+    0,
+};
 
 
 ngx_int_t
@@ -81,45 +96,241 @@ ngx_ssl_init(ngx_log_t *log)
 
 
 ngx_int_t
-ngx_ssl_create_connection(ngx_ssl_ctx_t *ssl_ctx, ngx_connection_t *c,
-    ngx_uint_t flags)
+ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols)
+{
+    ssl->ctx = SSL_CTX_new(SSLv23_server_method());
+
+    if (ssl->ctx == NULL) {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_new() failed");
+        return NGX_ERROR;
+    }
+
+    SSL_CTX_set_options(ssl->ctx, SSL_OP_ALL);
+
+    if (ngx_ssl_protocols[protocols >> 1] != 0) {
+        SSL_CTX_set_options(ssl->ctx, ngx_ssl_protocols[protocols >> 1]);
+    }
+
+    SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+    SSL_CTX_set_read_ahead(ssl->ctx, 1);
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_ssl_certificate(ngx_ssl_t *ssl, u_char *cert, u_char *key)
+{
+    if (SSL_CTX_use_certificate_chain_file(ssl->ctx, (char *) cert) == 0) {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "SSL_CTX_use_certificate_chain_file(\"%s\") failed",
+                      cert);
+        return NGX_ERROR;
+    }
+
+    if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key, SSL_FILETYPE_PEM)
+        == 0)
+    {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key);
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl)
+{
+    ssl->rsa512_key = RSA_generate_key(512, RSA_F4, NULL, NULL);
+
+    if (ssl->rsa512_key) {
+        SSL_CTX_set_tmp_rsa(ssl->ctx, ssl->rsa512_key);
+        return NGX_OK;
+    }
+
+    ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "RSA_generate_key(512) failed");
+
+    return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
 {   
-    ngx_ssl_t  *ssl;
+    ngx_ssl_connection_t  *sc;
 
-    ssl = ngx_pcalloc(c->pool, sizeof(ngx_ssl_t));
-    if (ssl == NULL) {
+    sc = ngx_pcalloc(c->pool, sizeof(ngx_ssl_connection_t));
+    if (sc == NULL) {
         return NGX_ERROR;
     }
 
     if (flags & NGX_SSL_BUFFER) {
-        ssl->buffer = 1;
+        sc->buffer = 1;
 
-        ssl->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE);
-        if (ssl->buf == NULL) {
+        sc->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE);
+        if (sc->buf == NULL) {
             return NGX_ERROR;
         }
     }
 
-    ssl->connection = SSL_new(ssl_ctx);
+    sc->connection = SSL_new(ssl->ctx);
 
-    if (ssl->connection == NULL) {
+    if (sc->connection == NULL) {
         ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed");
         return NGX_ERROR;
     }
 
-    if (SSL_set_fd(ssl->connection, c->fd) == 0) {
+    if (SSL_set_fd(sc->connection, c->fd) == 0) {
         ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed");
         return NGX_ERROR;
     }
 
-    SSL_set_accept_state(ssl->connection);
+    SSL_set_accept_state(sc->connection);
 
-    c->ssl = ssl;
+    c->ssl = sc;
 
     return NGX_OK;
 }
 
 
+ngx_int_t
+ngx_ssl_handshake(ngx_connection_t *c)
+{
+    int        n, sslerr;
+    ngx_err_t  err;
+
+    n = SSL_do_handshake(c->ssl->connection);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); 
+
+    if (n == 1) {
+
+        if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+#if (NGX_DEBUG)
+        {
+        char         buf[129], *s, *d;
+        SSL_CIPHER  *cipher;
+
+        cipher = SSL_get_current_cipher(c->ssl->connection);
+
+        if (cipher) {
+            SSL_CIPHER_description(cipher, &buf[1], 128);
+
+            for (s = &buf[1], d = buf; *s; s++) {
+                if (*s == ' ' && *d == ' ') {
+                    continue;
+                }
+
+                if (*s == LF || *s == CR) {
+                    continue;
+                }
+
+                *++d = *s;
+            }
+
+            if (*d != ' ') {
+                d++;
+            }
+
+            *d = '\0';
+
+            ngx_log_debug1(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,
+                               "SSL reused session");
+            }
+
+        } else {
+            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                           "SSL no shared ciphers"); 
+        }
+        }
+#endif
+
+        c->ssl->handshaked = 1;
+
+        c->recv = ngx_ssl_recv;
+        c->send = ngx_ssl_write;
+        c->send_chain = ngx_ssl_send_chain; 
+
+        return NGX_OK;
+    }
+
+    sslerr = SSL_get_error(c->ssl->connection, n);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
+
+    if (sslerr == SSL_ERROR_WANT_READ) {
+        c->read->ready = 0;
+        c->read->handler = ngx_ssl_handshake_handler;
+
+        if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        return NGX_AGAIN;
+    }
+
+    if (sslerr == SSL_ERROR_WANT_WRITE) {
+        c->write->ready = 0;
+        c->write->handler = ngx_ssl_handshake_handler;
+
+        if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        return NGX_AGAIN;
+    }
+
+    err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
+
+    c->ssl->no_wait_shutdown = 1;
+    c->ssl->no_send_shutdown = 1;
+
+    if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
+        ngx_log_error(NGX_LOG_INFO, c->log, err,
+                      "client closed connection in SSL handshake");
+
+        return NGX_ERROR;
+    }
+
+    ngx_ssl_connection_error(c, sslerr, err, "SSL_do_handshake() failed");
+
+    return NGX_ERROR;
+}
+
+
+static void
+ngx_ssl_handshake_handler(ngx_event_t *ev)
+{
+    ngx_connection_t  *c;
+
+    c = ev->data;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                   "ssl handshake handler: %d", ev->write);
+
+    if (ngx_ssl_handshake(c) == NGX_AGAIN) {
+        return;
+    }
+
+    c->ssl->handler(c);
+}
+
+
 ssize_t
 ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size)
 {
@@ -143,56 +354,7 @@ ngx_ssl_recv(ngx_connection_t *c, u_char
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n); 
 
         if (n > 0) {
-
             bytes += n;
-
-#if (NGX_DEBUG)
-
-            if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->connection))
-            {
-                char         buf[129], *s, *d;
-                SSL_CIPHER  *cipher;
-
-                c->ssl->handshaked = 1;
-
-                cipher = SSL_get_current_cipher(c->ssl->connection);
-
-                if (cipher) {
-                    SSL_CIPHER_description(cipher, &buf[1], 128);
-
-                    for (s = &buf[1], d = buf; *s; s++) {
-                        if (*s == ' ' && *d == ' ') {
-                            continue;
-                        }
-
-                        if (*s == LF || *s == CR) {
-                            continue;
-                        }
-
-                        *++d = *s;
-                    }
-
-                    if (*d != ' ') {
-                        d++;
-                    }
-
-                    *d = '\0';
-
-                    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                                   "SSL cipher: \"%s\"", &buf[1]); 
-
-                    if (SSL_session_reused(c->ssl->connection)) {
-                        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                                       "SSL reused session");
-                    }
-
-                } else {
-                    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                                   "SSL no shared ciphers"); 
-                }
-            }
-#endif
-
         }
 
         c->ssl->last = ngx_ssl_handle_recv(c, n);
@@ -221,10 +383,8 @@ ngx_ssl_recv(ngx_connection_t *c, u_char
 static ngx_int_t
 ngx_ssl_handle_recv(ngx_connection_t *c, int n)
 {
-    int          sslerr;
-    char        *handshake;
-    ngx_err_t    err;
-    ngx_uint_t   level;
+    int        sslerr;
+    ngx_err_t  err;
 
     if (n > 0) {
 
@@ -250,13 +410,6 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
         return NGX_OK;
     }
 
-    if (!SSL_is_init_finished(c->ssl->connection)) {
-        handshake = " in SSL handshake";
-
-    } else {
-        handshake = "";
-    }
-
     sslerr = SSL_get_error(c->ssl->connection, n);
 
     err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
@@ -270,9 +423,8 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
 
     if (sslerr == SSL_ERROR_WANT_WRITE) {
 
-        ngx_log_error(NGX_LOG_INFO, c->log, err,
-                      "client does SSL %shandshake",
-                      SSL_is_init_finished(c->ssl->connection) ? "re" : "");
+        ngx_log_error(NGX_LOG_INFO, c->log, 0,
+                      "client started SSL renegotiation");
 
         c->write->ready = 0;
 
@@ -292,44 +444,16 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
         return NGX_AGAIN;
     }
 
-    c->ssl->no_rcv_shut = 1;
-    c->ssl->no_send_shut = 1;
+    c->ssl->no_wait_shutdown = 1;
+    c->ssl->no_send_shutdown = 1;
 
     if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
-        ngx_log_error(NGX_LOG_INFO, c->log, err,
-                      "client closed connection%s", handshake);
+        ngx_log_error(NGX_LOG_INFO, c->log, err, "client closed connection");
 
         return NGX_ERROR;
     }
 
-    level = NGX_LOG_CRIT;
-
-    if (sslerr == SSL_ERROR_SYSCALL) {
-
-        if (err == NGX_ECONNRESET
-            || err == NGX_EPIPE
-            || err == NGX_ENOTCONN
-            || err == NGX_ECONNREFUSED
-            || err == NGX_EHOSTUNREACH)
-        {
-            switch (c->log_error) {
-
-            case NGX_ERROR_IGNORE_ECONNRESET:
-            case NGX_ERROR_INFO:
-                level = NGX_LOG_INFO;
-                break;
-
-            case NGX_ERROR_ERR:
-                level = NGX_LOG_ERR;
-                break;
-
-            default:
-                break;
-            }
-        }
-    }
-
-    ngx_ssl_error(level, c->log, err, "SSL_read() failed%s", handshake);
+    ngx_ssl_connection_error(c, sslerr, err, "SSL_read() failed");
 
     return NGX_ERROR;
 }
@@ -341,6 +465,7 @@ ngx_ssl_write_handler(ngx_event_t *wev)
     ngx_connection_t  *c;
 
     c = wev->data;
+
     c->read->handler(c->read);
 }
 
@@ -482,9 +607,8 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
 ssize_t
 ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size)
 {
-    int         n, sslerr;
-    ngx_err_t   err;
-    ngx_uint_t  level;
+    int        n, sslerr;
+    ngx_err_t  err;
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size);
 
@@ -494,52 +618,6 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
 
     if (n > 0) {
 
-#if (NGX_DEBUG)
-
-        if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->connection)) {
-            char         buf[129], *s, *d;
-            SSL_CIPHER  *cipher;
-
-            c->ssl->handshaked = 1;
-
-            cipher = SSL_get_current_cipher(c->ssl->connection);
-
-            if (cipher) {
-                SSL_CIPHER_description(cipher, &buf[1], 128);
-
-                for (s = &buf[1], d = buf; *s; s++) {
-                    if (*s == ' ' && *d == ' ') {
-                        continue;
-                    }
-
-                    if (*s == LF || *s == CR) {
-                        continue;
-                    }
-
-                    *++d = *s;
-                }
-
-                if (*d != ' ') {
-                    d++;
-                }
-
-                *d = '\0';
-
-                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                               "SSL cipher: \"%s\"", &buf[1]); 
-
-                if (SSL_session_reused(c->ssl->connection)) {
-                    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                                   "SSL reused session");
-                }
-
-            } else {
-                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                               "SSL no shared ciphers"); 
-            }
-        }
-#endif
-
         if (c->ssl->saved_read_handler) {
 
             c->read->handler = c->ssl->saved_read_handler;
@@ -575,9 +653,8 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
 
     if (sslerr == SSL_ERROR_WANT_READ) {
 
-        ngx_log_error(NGX_LOG_INFO, c->log, err,
-                      "client does SSL %shandshake",
-                      SSL_is_init_finished(c->ssl->connection) ? "re" : "");
+        ngx_log_error(NGX_LOG_INFO, c->log, 0,
+                      "client started SSL renegotiation");
 
         c->read->ready = 0;
 
@@ -598,37 +675,10 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
         return NGX_AGAIN;
     }
 
-    c->ssl->no_rcv_shut = 1;
-    c->ssl->no_send_shut = 1;
-
-    level = NGX_LOG_CRIT;
-
-    if (sslerr == SSL_ERROR_SYSCALL) {
-
-        if (err == NGX_ECONNRESET
-            || err == NGX_EPIPE
-            || err == NGX_ENOTCONN
-            || err == NGX_ECONNREFUSED
-            || err == NGX_EHOSTUNREACH)
-        {
-            switch (c->log_error) {
+    c->ssl->no_wait_shutdown = 1;
+    c->ssl->no_send_shutdown = 1;
 
-            case NGX_ERROR_IGNORE_ECONNRESET:
-            case NGX_ERROR_INFO:
-                level = NGX_LOG_INFO;
-                break;
-
-            case NGX_ERROR_ERR:
-                level = NGX_LOG_ERR;
-                break;
-
-            default:
-                break;
-            }
-        }
-    }
-
-    ngx_ssl_error(level, c->log, err, "SSL_write() failed");
+    ngx_ssl_connection_error(c, sslerr, err, "SSL_write() failed");
 
     return NGX_ERROR;
 }
@@ -640,6 +690,7 @@ ngx_ssl_read_handler(ngx_event_t *rev)
     ngx_connection_t  *c;
 
     c = rev->data;
+
     c->write->handler(c->write);
 }
 
@@ -650,31 +701,23 @@ ngx_ssl_shutdown(ngx_connection_t *c)
     int         n, sslerr, mode;
     ngx_uint_t  again;
 
-    if (!c->ssl->shutdown_set) {
-
-        /* it seems that SSL_set_shutdown() could be called once only */
-
-        if (c->read->timedout) {
-            mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
+    if (c->read->timedout) {
+        mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
 
-        } else {
-            mode = 0;
+    } else {
+        mode = SSL_get_shutdown(c->ssl->connection);
 
-            if (c->ssl->no_rcv_shut) {
-                mode = SSL_RECEIVED_SHUTDOWN;
-            }
-
-            if (c->ssl->no_send_shut) {
-                mode |= SSL_SENT_SHUTDOWN;
-            }
+        if (c->ssl->no_wait_shutdown) {
+            mode |= SSL_RECEIVED_SHUTDOWN;
         }
 
-        if (mode) {
-            SSL_set_shutdown(c->ssl->connection, mode);
-            c->ssl->shutdown_set = 1;
+        if (c->ssl->no_send_shutdown) {
+            mode |= SSL_SENT_SHUTDOWN;
         }
     }
 
+    SSL_set_shutdown(c->ssl->connection, mode);
+
     again = 0;
 #if (NGX_SUPPRESS_WARN)
     sslerr = 0;
@@ -736,11 +779,49 @@ ngx_ssl_shutdown(ngx_connection_t *c)
 }
 
 
+static void
+ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
+    char *text)
+{
+    ngx_uint_t  level;
+
+    level = NGX_LOG_CRIT;
+
+    if (sslerr == SSL_ERROR_SYSCALL) {
+
+        if (err == NGX_ECONNRESET
+            || err == NGX_EPIPE
+            || err == NGX_ENOTCONN
+            || err == NGX_ECONNREFUSED
+            || err == NGX_EHOSTUNREACH)
+        {
+            switch (c->log_error) {
+
+            case NGX_ERROR_IGNORE_ECONNRESET:
+            case NGX_ERROR_INFO:
+                level = NGX_LOG_INFO;
+                break;
+
+            case NGX_ERROR_ERR:
+                level = NGX_LOG_ERR;
+                break;
+
+            default:
+                break;
+            }
+        }
+    }
+
+    ngx_ssl_error(level, c->log, err, text);
+}
+
+
 void
 ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...)
 {   
+    u_long   n;
+    va_list  args;
     u_char   errstr[NGX_MAX_CONF_ERRSTR], *p, *last;
-    va_list  args;
 
     last = errstr + NGX_MAX_CONF_ERRSTR;
 
@@ -748,9 +829,18 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_
     p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args);
     va_end(args);
 
-    p = ngx_cpystrn(p, (u_char *) " (SSL: ", last - p);
+    p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
+
+    while (p < last && (n = ERR_get_error())) {
+
+        *p++ = ' ';
 
-    ERR_error_string_n(ERR_get_error(), (char *) p, last - p);
+        ERR_error_string_n(n, (char *) p, last - p);
+
+        while (p < last && *p) {
+            p++;
+        }
+    }
 
     ngx_log_error(level, log, err, "%s)", errstr);
 }
@@ -759,9 +849,10 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_
 void
 ngx_ssl_cleanup_ctx(void *data)
 {
-   SSL_CTX  *ctx = data;
+   ngx_ssl_t  *ssl = data;
 
-   SSL_CTX_free(ctx);
+   RSA_free(ssl->rsa512_key);
+   SSL_CTX_free(ssl->ctx);
 }
 
 
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -16,44 +16,53 @@
 
 #if OPENSSL_VERSION_NUMBER >= 0x00907000
 #include <openssl/engine.h>
-#define NGX_SSL_ENGINE     1
+#define NGX_SSL_ENGINE   1
 #endif
 
-#define NGX_SSL_NAME       "OpenSSL"
+#define NGX_SSL_NAME     "OpenSSL"
+
+
+typedef struct {
+    SSL_CTX                    *ctx;
+    RSA                        *rsa512_key;
+    ngx_log_t                  *log;
+} ngx_ssl_t;
 
 
 typedef struct {
-    SSL                   *connection;
-    ngx_int_t              last;
-    ngx_buf_t             *buf;
-    ngx_event_handler_pt   saved_read_handler;
-    ngx_event_handler_pt   saved_write_handler;
+    SSL                        *connection;
+    ngx_int_t                   last;
+    ngx_buf_t                  *buf;
+
+    ngx_connection_handler_pt   handler;
 
-    unsigned               buffer:1;
-    unsigned               no_rcv_shut:1;
-    unsigned               no_send_shut:1;
-    unsigned               shutdown_set:1;
+    ngx_event_handler_pt        saved_read_handler;
+    ngx_event_handler_pt        saved_write_handler;
 
-#if (NGX_DEBUG)
-    unsigned               handshaked:1;
-#endif
-} ngx_ssl_t;
+    unsigned                    handshaked:1;
+    unsigned                    buffer:1;
+    unsigned                    no_wait_shutdown:1;
+    unsigned                    no_send_shutdown:1;
+} ngx_ssl_connection_t;
 
 
-typedef SSL_CTX  ngx_ssl_ctx_t;
+#define NGX_SSL_SSLv2    2
+#define NGX_SSL_SSLv3    4
+#define NGX_SSL_TLSv1    8
 
 
-#define NGX_SSL_BUFFER       1
+#define NGX_SSL_BUFFER   1
 
-#define NGX_SSL_BUFSIZE      16384
+#define NGX_SSL_BUFSIZE  16384
 
 
 ngx_int_t ngx_ssl_init(ngx_log_t *log);
-ngx_int_t ngx_ssl_create_connection(ngx_ssl_ctx_t *ctx, ngx_connection_t *c,
+ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols);
+ngx_int_t ngx_ssl_certificate(ngx_ssl_t *ssl, u_char *cert, u_char *key);
+ngx_int_t ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl);
+ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c,
     ngx_uint_t flags);
-
-#define ngx_ssl_handshake(c)     NGX_OK
-
+ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
 ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size);
 ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size);
 ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in,
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -271,21 +271,14 @@ ngx_http_autoindex_handler(ngx_http_requ
 
         len = ngx_de_namelen(&dir);
 
-        if (len == 1 && ngx_de_name(&dir)[0] == '.') {
-            continue;
-        }
-
-        if (len == 2
-            && ngx_de_name(&dir)[0] == '.'
-            && ngx_de_name(&dir)[1] == '.')
-        {
+        if (ngx_de_name(&dir)[0] == '.') {
             continue;
         }
 
         if (!dir.valid_info) {
 
-            if (dname.len + 1 + len > fname.len) {
-                fname.len = dname.len + 1 + len + 32;
+            if (dname.len + 1 + len + 1 > fname.len) {
+                fname.len = dname.len + 1 + len + 1 + 32;
 
                 fname.data = ngx_palloc(pool, fname.len);
                 if (fname.data == NULL) {
@@ -468,7 +461,8 @@ ngx_http_autoindex_handler(ngx_http_requ
 
         } else {
             if (entry[i].dir) {
-                b->last = ngx_cpymem(b->last,  "     -", sizeof("     -") - 1);
+                b->last = ngx_cpymem(b->last,  "      -",
+                                     sizeof("      -") - 1);
 
             } else {
                 length = entry[i].size;
@@ -498,13 +492,14 @@ ngx_http_autoindex_handler(ngx_http_requ
 
                 } else {
                     size = (ngx_int_t) length;
-                    scale = ' ';
+                    scale = '\0';
                 }
 
-                b->last = ngx_sprintf(b->last, "%6i", size);
+                if (scale) {
+                    b->last = ngx_sprintf(b->last, "%6i%c", size, scale);
 
-                if (scale != ' ') {
-                    *b->last++ = scale;
+                } else {
+                    b->last = ngx_sprintf(b->last, " %6i", size);
                 }
             }
         }
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -293,7 +293,7 @@ static ngx_command_t  ngx_http_fastcgi_c
       NULL },
 
     { ngx_string("fastcgi_next_upstream"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_conf_set_bitmask_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -117,7 +117,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
         name.data++;
     }
 
-    var = ngx_http_add_variable(cf, &name, 0);
+    var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGABLE);
     if (var == NULL) {
         return NGX_CONF_ERROR;
     }
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -181,7 +181,7 @@ static ngx_command_t  ngx_http_gzip_filt
       &ngx_http_gzip_http_version },
 
     { ngx_string("gzip_proxied"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_conf_set_bitmask_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_gzip_conf_t, proxied),
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -244,7 +244,7 @@ static ngx_command_t  ngx_http_proxy_com
       NULL },
 
     { ngx_string("proxy_next_upstream"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_conf_set_bitmask_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -59,6 +59,7 @@ typedef struct {
     ngx_uint_t         output;        /* unsigned  output:1; */
 
     ngx_str_t          timefmt;
+    ngx_str_t          errmsg;
 } ngx_http_ssi_ctx_t;
 
 
@@ -217,8 +218,6 @@ static ngx_int_t (*ngx_http_next_body_fi
 
 
 static u_char ngx_http_ssi_string[] = "<!--";
-static u_char ngx_http_ssi_error_string[] =
-    "[an error occurred while processing the directive]";
 
 static ngx_str_t ngx_http_ssi_none = ngx_string("(none)");
 
@@ -226,7 +225,8 @@ static ngx_str_t ngx_http_ssi_none = ngx
 #define  NGX_HTTP_SSI_ECHO_VAR         0
 #define  NGX_HTTP_SSI_ECHO_DEFAULT     1
 
-#define  NGX_HTTP_SSI_CONFIG_TIMEFMT   0
+#define  NGX_HTTP_SSI_CONFIG_ERRMSG    0
+#define  NGX_HTTP_SSI_CONFIG_TIMEFMT   1
 
 #define  NGX_HTTP_SSI_INCLUDE_VIRTUAL  0
 #define  NGX_HTTP_SSI_INCLUDE_FILE     1
@@ -250,6 +250,7 @@ static ngx_http_ssi_param_t  ngx_http_ss
 
 
 static ngx_http_ssi_param_t  ngx_http_ssi_config_params[] = {
+    { ngx_string("errmsg"), NGX_HTTP_SSI_CONFIG_ERRMSG, 0 },
     { ngx_string("timefmt"), NGX_HTTP_SSI_CONFIG_TIMEFMT, 0 },
     { ngx_null_string, 0, 0 }
 };
@@ -347,6 +348,11 @@ found:
     ctx->timefmt.len = sizeof("%A, %d-%b-%Y %H:%M:%S %Z") - 1;
     ctx->timefmt.data = (u_char *) "%A, %d-%b-%Y %H:%M:%S %Z";
 
+    ctx->errmsg.len =
+              sizeof("[an error occurred while processing the directive]") - 1;
+    ctx->errmsg.data = (u_char *)
+                     "[an error occurred while processing the directive]";
+
     r->filter_need_in_memory = 1;
 
     if (r->main == NULL) {
@@ -653,9 +659,8 @@ ngx_http_ssi_body_filter(ngx_http_reques
             }
 
             b->memory = 1;
-            b->pos = ngx_http_ssi_error_string;
-            b->last = ngx_http_ssi_error_string
-                      + sizeof(ngx_http_ssi_error_string) - 1;
+            b->pos = ctx->errmsg.data;
+            b->last = ctx->errmsg.data + ctx->errmsg.len;
 
             cl->next = NULL;
             *ctx->last_out = cl;
@@ -1371,6 +1376,12 @@ ngx_http_ssi_config(ngx_http_request_t *
         ctx->timefmt = *value;
     }
 
+    value = params[NGX_HTTP_SSI_CONFIG_ERRMSG];
+
+    if (value) {
+        ctx->errmsg = *value;
+    }
+
     return NGX_OK;
 }
 
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -8,9 +8,9 @@
 #include <ngx_core.h>
 #include <ngx_http.h>
 
-
 #define NGX_DEFLAUT_CERTIFICATE      "cert.pem"
 #define NGX_DEFLAUT_CERTIFICATE_KEY  "cert.pem"
+#define NGX_DEFLAUT_CIPHERS  "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
 
 
 static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf);
@@ -18,6 +18,14 @@ static char *ngx_http_ssl_merge_srv_conf
     void *parent, void *child);
 
 
+static ngx_conf_bitmask_t  ngx_http_ssl_protocols[] = {
+    { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
+    { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
+    { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_command_t  ngx_http_ssl_commands[] = {
 
     { ngx_string("ssl"),
@@ -41,13 +49,27 @@ static ngx_command_t  ngx_http_ssl_comma
       offsetof(ngx_http_ssl_srv_conf_t, certificate_key),
       NULL },
 
+    { ngx_string("ssl_protocols"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_bitmask_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_ssl_srv_conf_t, protocols),
+      &ngx_http_ssl_protocols },
+
     { ngx_string("ssl_ciphers"),
-      NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
       ngx_conf_set_str_slot,
       NGX_HTTP_SRV_CONF_OFFSET,
       offsetof(ngx_http_ssl_srv_conf_t, ciphers),
       NULL },
 
+    { ngx_string("ssl_prefer_server_ciphers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_ssl_srv_conf_t, prefer_server_ciphers),
+      NULL },
+
       ngx_null_command
 };
 
@@ -99,6 +121,8 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t 
     /*
      * set by ngx_pcalloc():
      *
+     *     scf->protocols = 0;
+
      *     scf->certificate.len = 0;
      *     scf->certificate.data = NULL;
      *     scf->certificate_key.len = 0;
@@ -108,6 +132,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t 
      */
 
     scf->enable = NGX_CONF_UNSET;
+    scf->prefer_server_ciphers = NGX_CONF_UNSET;
 
     return scf;
 }
@@ -125,101 +150,60 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
         return NGX_CONF_OK;
     }
 
+    ngx_conf_merge_value(conf->prefer_server_ciphers,
+                         prev->prefer_server_ciphers, 0);
+
+    ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
+                         (NGX_CONF_BITMASK_SET
+                          |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1));
+
     ngx_conf_merge_str_value(conf->certificate, prev->certificate,
-                             NGX_DEFLAUT_CERTIFICATE);
+                         NGX_DEFLAUT_CERTIFICATE);
 
     ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
-                             NGX_DEFLAUT_CERTIFICATE_KEY);
+                         NGX_DEFLAUT_CERTIFICATE_KEY);
 
-    ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, "");
+    ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFLAUT_CIPHERS);
 
 
-    /* TODO: configure methods */
+    conf->ssl.log = cf->log;
 
-    conf->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
-
-    if (conf->ssl_ctx == NULL) {
-        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, "SSL_CTX_new() failed");
+    if (ngx_ssl_create(&conf->ssl, conf->protocols) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
-    if (ngx_pool_cleanup_add(cf->pool, ngx_ssl_cleanup_ctx, conf->ssl_ctx)
-        == NULL)
+    if (ngx_pool_cleanup_add(cf->pool, ngx_ssl_cleanup_ctx, &conf->ssl) == NULL)
     {
         return NGX_CONF_ERROR;
     }
 
-
-    if (conf->ciphers.len) {
-        if (SSL_CTX_set_cipher_list(conf->ssl_ctx,
-                                   (const char *) conf->ciphers.data) == 0)
-        {
-            ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
-                          "SSL_CTX_set_cipher_list(\"%V\") failed",
-                          &conf->ciphers);
-        }
-    }
-
-    if (SSL_CTX_use_certificate_chain_file(conf->ssl_ctx,
-                                         (char *) conf->certificate.data) == 0)
+    if (ngx_ssl_certificate(&conf->ssl, conf->certificate.data,
+                            conf->certificate_key.data) != NGX_OK)
     {
-        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
-                      "SSL_CTX_use_certificate_chain_file(\"%s\") failed",
-                      conf->certificate.data);
         return NGX_CONF_ERROR;
     }
 
-    if (SSL_CTX_use_PrivateKey_file(conf->ssl_ctx,
-                                    (char *) conf->certificate_key.data,
-                                    SSL_FILETYPE_PEM) == 0)
+    if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
+                                (const char *) conf->ciphers.data) == 0)
     {
         ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
-                      "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
-                      conf->certificate_key.data);
+                      "SSL_CTX_set_cipher_list(\"%V\") failed",
+                      &conf->ciphers);
+    }
+
+    if (conf->prefer_server_ciphers) {
+        SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
+    }
+
+    /* a temporary 512-bit RSA key is required for export versions of MSIE */
+    if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
-    SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL);
-
-    SSL_CTX_set_mode(conf->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+    SSL_CTX_set_session_cache_mode(conf->ssl.ctx, SSL_SESS_CACHE_SERVER);
 
-    SSL_CTX_set_read_ahead(conf->ssl_ctx, 1);
-
-    SSL_CTX_set_session_cache_mode(conf->ssl_ctx, SSL_SESS_CACHE_SERVER);
-
-    SSL_CTX_set_session_id_context(conf->ssl_ctx, ngx_http_session_id_ctx,
+    SSL_CTX_set_session_id_context(conf->ssl.ctx, ngx_http_session_id_ctx,
                                    sizeof(ngx_http_session_id_ctx) - 1);
 
     return NGX_CONF_OK;
 }
-
-
-#if 0
-
-/* how to enumrate server' configs */
-
-static ngx_int_t
-ngx_http_ssl_init_process(ngx_cycle_t *cycle)
-{
-    ngx_uint_t                   i;
-    ngx_http_ssl_srv_conf_t     *sscf;
-    ngx_http_core_srv_conf_t   **cscfp;
-    ngx_http_core_main_conf_t   *cmcf;
-
-    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
-
-    cscfp = cmcf->servers.elts;
-
-    for (i = 0; i < cmcf->servers.nelts; i++) {
-        sscf = cscfp[i]->ctx->srv_conf[ngx_http_ssl_module.ctx_index];
-
-        if (sscf->enable) {
-            cscfp[i]->recv = ngx_ssl_recv;
-            cscfp[i]->send_chain = ngx_ssl_send_chain;
-        }
-    }
-
-    return NGX_OK;
-}
-
-#endif
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -15,12 +15,17 @@
 
 typedef struct {
     ngx_flag_t      enable;
+
+    ngx_ssl_t       ssl;
+
+    ngx_flag_t      prefer_server_ciphers;
+
+    ngx_uint_t      protocols;
+
     ngx_str_t       certificate;
     ngx_str_t       certificate_key;
 
     ngx_str_t       ciphers;
-
-    ngx_ssl_ctx_t  *ssl_ctx;
 } ngx_http_ssl_srv_conf_t;
 
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -49,6 +49,7 @@ static u_char *ngx_http_log_error_handle
 
 #if (NGX_HTTP_SSL)
 static void ngx_http_ssl_handshake(ngx_event_t *rev);
+static void ngx_http_ssl_handshake_handler(ngx_connection_t *c);
 static void ngx_http_ssl_close_handler(ngx_event_t *ev);
 #endif
 
@@ -359,7 +360,7 @@ void ngx_http_init_request(ngx_event_t *
     if (sscf->enable) {
 
         if (c->ssl == NULL) {
-            if (ngx_ssl_create_connection(sscf->ssl_ctx, c, NGX_SSL_BUFFER)
+            if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER)
                 == NGX_ERROR)
             {
                 ngx_http_close_connection(c);
@@ -367,16 +368,6 @@ void ngx_http_init_request(ngx_event_t *
             }
 
             rev->handler = ngx_http_ssl_handshake;
-
-            /*
-             * The majority of browsers do not send the "close notify" alert.
-             * Among them are MSIE, Mozilla, Netscape 4, Konqueror, and Links.
-             * And what is more, MSIE ignores the server's alert.
-             *
-             * Opera always sends the alert.
-             */
-
-            c->ssl->no_rcv_shut = 1;
         }
 
         r->main_filter_need_in_memory = 1;
@@ -491,21 +482,16 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
                            "https ssl handshake: 0x%02Xd", buf[0]);
 
-            c->recv = ngx_ssl_recv;
-            c->send = ngx_ssl_write;
-            c->send_chain = ngx_ssl_send_chain;
-
             rc = ngx_ssl_handshake(c);
 
-            if (rc == NGX_ERROR) {
-                ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
-                ngx_http_close_connection(r->connection);
+            if (rc == NGX_AGAIN) {
+                c->ssl->handler = ngx_http_ssl_handshake_handler;
                 return;
             }
 
-            if (rc != NGX_OK) {
-                return;
-            }
+            ngx_http_ssl_handshake_handler(c);
+
+            return;
 
         } else {
             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
@@ -519,6 +505,41 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
     ngx_http_process_request_line(rev);
 }
 
+
+static void
+ngx_http_ssl_handshake_handler(ngx_connection_t *c)
+{
+    ngx_http_request_t  *r;
+
+    if (c->ssl->handshaked) {
+
+        /*
+         * The majority of browsers do not send the "close notify" alert.
+         * Among them are MSIE, old Mozilla, Netscape 4, Konqueror,
+         * and Links.  And what is more, MSIE ignores the server's alert.
+         *
+         * Opera and recent Mozilla send the alert.
+         */
+
+        c->ssl->no_wait_shutdown = 1;
+
+        c->read->handler = ngx_http_process_request_line;
+        /* STUB: epoll edge */ c->write->handler = ngx_http_empty_handler;
+
+        ngx_http_process_request_line(c->read);
+
+        return;
+    }
+
+    r = c->data;
+
+    ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
+    ngx_http_close_connection(r->connection);
+
+    return;
+}
+
+
 #endif
 
 
@@ -1290,7 +1311,7 @@ ngx_http_process_request_header(ngx_http
 #if 0
             /* MSIE ignores the SSL "close notify" alert */
             if (c->ssl) {
-                r->connection->ssl->no_send_shut = 1;
+                c->ssl->no_send_shutdown = 1;
             }
 #endif
         }
@@ -2126,7 +2147,7 @@ ngx_http_keepalive_handler(ngx_event_t *
                           "keepalive connection", &c->addr_text);
 #if (NGX_HTTP_SSL)
             if (c->ssl) {
-                c->ssl->no_send_shut = 1;
+                c->ssl->no_send_shutdown = 1;
             }
 #endif
             ngx_http_close_connection(c);
--- a/src/imap/ngx_imap_auth_http_module.c
+++ b/src/imap/ngx_imap_auth_http_module.c
@@ -45,9 +45,9 @@ struct ngx_imap_auth_http_ctx_s {
     ngx_str_t                       port;
     ngx_str_t                       err;
 
-    ngx_msec_t                      sleep;
+    time_t                          sleep;
 
-    ngx_peers_t                    *peers;
+    ngx_pool_t                     *pool;
 };
 
 
@@ -63,7 +63,7 @@ static ngx_int_t ngx_imap_auth_http_pars
 static void ngx_imap_auth_http_block_read(ngx_event_t *rev);
 static void ngx_imap_auth_http_dummy_handler(ngx_event_t *ev);
 static ngx_buf_t *ngx_imap_auth_http_create_request(ngx_imap_session_t *s,
-    ngx_imap_auth_http_conf_t *ahcf);
+    ngx_pool_t *pool, ngx_imap_auth_http_conf_t *ahcf);
 
 static void *ngx_imap_auth_http_create_conf(ngx_conf_t *cf);
 static char *ngx_imap_auth_http_merge_conf(ngx_conf_t *cf, void *parent,
@@ -123,21 +123,32 @@ void
 ngx_imap_auth_http_init(ngx_imap_session_t *s)
 {
     ngx_int_t                   rc;
+    ngx_pool_t                 *pool;
     ngx_imap_auth_http_ctx_t   *ctx;
     ngx_imap_auth_http_conf_t  *ahcf;
 
     s->connection->log->action = "in http auth state";
 
-    ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_auth_http_ctx_t));
-    if (ctx == NULL) {
+    pool = ngx_create_pool(2048, s->connection->log);
+    if (pool == NULL) {
         ngx_imap_session_internal_server_error(s);
         return;
     }
 
+    ctx = ngx_pcalloc(pool, sizeof(ngx_imap_auth_http_ctx_t));
+    if (ctx == NULL) {
+        ngx_destroy_pool(pool);
+        ngx_imap_session_internal_server_error(s);
+        return;
+    }
+
+    ctx->pool = pool;
+
     ahcf = ngx_imap_get_module_srv_conf(s, ngx_imap_auth_http_module);
 
-    ctx->request = ngx_imap_auth_http_create_request(s, ahcf);
+    ctx->request = ngx_imap_auth_http_create_request(s, pool, ahcf);
     if (ctx->request == NULL) {
+        ngx_destroy_pool(ctx->pool);
         ngx_imap_session_internal_server_error(s);
         return;
     }
@@ -152,6 +163,7 @@ ngx_imap_auth_http_init(ngx_imap_session
 
     if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
         ngx_close_connection(ctx->peer.connection);
+        ngx_destroy_pool(ctx->pool);
         ngx_imap_session_internal_server_error(s);
         return;
     }
@@ -197,6 +209,7 @@ ngx_imap_auth_http_write_handler(ngx_eve
                       "auth http server %V timed out",
                       &ctx->peer.peers->peer[0].name);
         ngx_close_connection(ctx->peer.connection);
+        ngx_destroy_pool(ctx->pool);
         ngx_imap_session_internal_server_error(s);
         return;
     }
@@ -207,6 +220,7 @@ ngx_imap_auth_http_write_handler(ngx_eve
 
     if (n == NGX_ERROR) {
         ngx_close_connection(ctx->peer.connection);
+        ngx_destroy_pool(ctx->pool);
         ngx_imap_session_internal_server_error(s);
         return;
     }
@@ -253,14 +267,16 @@ ngx_imap_auth_http_read_handler(ngx_even
                       "auth http server %V timed out",
                       &ctx->peer.peers->peer[0].name);
         ngx_close_connection(ctx->peer.connection);
+        ngx_destroy_pool(ctx->pool);
         ngx_imap_session_internal_server_error(s);
         return;
     }
 
     if (ctx->response == NULL) {
-        ctx->response = ngx_create_temp_buf(s->connection->pool, 1024);
+        ctx->response = ngx_create_temp_buf(ctx->pool, 1024);
         if (ctx->response == NULL) {
             ngx_close_connection(ctx->peer.connection);
+            ngx_destroy_pool(ctx->pool);
             ngx_imap_session_internal_server_error(s);
             return;
         }
@@ -282,6 +298,7 @@ ngx_imap_auth_http_read_handler(ngx_even
     }
 
     ngx_close_connection(ctx->peer.connection);
+    ngx_destroy_pool(ctx->pool);
     ngx_imap_session_internal_server_error(s);
 }
 
@@ -369,6 +386,7 @@ ngx_imap_auth_http_ignore_status_line(ng
                           "auth http server &V sent invalid response",
                           &ctx->peer.peers->peer[0].name);
             ngx_close_connection(ctx->peer.connection);
+            ngx_destroy_pool(ctx->pool);
             ngx_imap_session_internal_server_error(s);
             return;
         }
@@ -397,8 +415,10 @@ ngx_imap_auth_http_process_headers(ngx_i
     ngx_imap_auth_http_ctx_t *ctx)
 {
     u_char              *p;
+    time_t               timer;
     size_t               len, size;
     ngx_int_t            rc, port, n;
+    ngx_peers_t         *peers;
     struct sockaddr_in  *sin;
 
     ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
@@ -450,6 +470,7 @@ ngx_imap_auth_http_process_headers(ngx_i
                 p = ngx_pcalloc(s->connection->pool, size);
                 if (p == NULL) {
                     ngx_close_connection(ctx->peer.connection);
+                    ngx_destroy_pool(ctx->pool);
                     ngx_imap_session_internal_server_error(s);
                     return;
                 }
@@ -530,16 +551,20 @@ ngx_imap_auth_http_process_headers(ngx_i
 
             if (ctx->err.len) {
                 s->out = ctx->err;
+                timer = ctx->sleep;
 
-                if (ctx->sleep == 0) {
+                ngx_destroy_pool(ctx->pool);
+
+                ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
+                              "client login failed");
+
+                if (timer == 0) {
                     s->quit = 1;
-
                     ngx_imap_send(s->connection->write);
-
                     return;
                 }
 
-                ngx_add_timer(s->connection->read, ctx->sleep * 1000);
+                ngx_add_timer(s->connection->read, timer * 1000);
 
                 s->connection->read->handler = ngx_imap_auth_sleep_handler;
 
@@ -550,18 +575,21 @@ ngx_imap_auth_http_process_headers(ngx_i
                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                               "auth http server %V did not send server or port",
                               &ctx->peer.peers->peer[0].name);
+                ngx_destroy_pool(ctx->pool);
                 ngx_imap_session_internal_server_error(s);
                 return;
             }
 
-            ctx->peers = ngx_pcalloc(s->connection->pool, sizeof(ngx_peers_t));
-            if (ctx->peers == NULL) {
+            peers = ngx_pcalloc(s->connection->pool, sizeof(ngx_peers_t));
+            if (peers == NULL) {
+                ngx_destroy_pool(ctx->pool);
                 ngx_imap_session_internal_server_error(s);
                 return;
             }
 
             sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in));
             if (sin == NULL) {
+                ngx_destroy_pool(ctx->pool);
                 ngx_imap_session_internal_server_error(s);
                 return;
             }
@@ -574,6 +602,7 @@ ngx_imap_auth_http_process_headers(ngx_i
                               "auth http server %V sent invalid server "
                               "port:\"%V\"",
                               &ctx->peer.peers->peer[0].name, &ctx->port);
+                ngx_destroy_pool(ctx->pool);
                 ngx_imap_session_internal_server_error(s);
                 return;
             }
@@ -587,38 +616,40 @@ ngx_imap_auth_http_process_headers(ngx_i
                               "auth http server %V sent invalid server "
                               "address:\"%V\"",
                               &ctx->peer.peers->peer[0].name, &ctx->addr);
+                ngx_destroy_pool(ctx->pool);
                 ngx_imap_session_internal_server_error(s);
                 return;
             }
 
-            ctx->peers->number = 1;
+            peers->number = 1;
 
-            ctx->peers->peer[0].sockaddr = (struct sockaddr *) sin;
-            ctx->peers->peer[0].socklen = sizeof(struct sockaddr_in);
+            peers->peer[0].sockaddr = (struct sockaddr *) sin;
+            peers->peer[0].socklen = sizeof(struct sockaddr_in);
 
             len = ctx->addr.len + 1 + ctx->port.len;
 
-            ctx->peers->peer[0].name.len = len;
+            peers->peer[0].name.len = len;
 
-            ctx->peers->peer[0].name.data = ngx_palloc(s->connection->pool,
-                                                       len);
-            if (ctx->peers->peer[0].name.data == NULL) {
+            peers->peer[0].name.data = ngx_palloc(s->connection->pool, len);
+            if (peers->peer[0].name.data == NULL) {
+                ngx_destroy_pool(ctx->pool);
                 ngx_imap_session_internal_server_error(s);
                 return;
             }
 
             len = ctx->addr.len;
 
-            ngx_memcpy(ctx->peers->peer[0].name.data, ctx->addr.data, len);
+            ngx_memcpy(peers->peer[0].name.data, ctx->addr.data, len);
 
-            ctx->peers->peer[0].name.data[len++] = ':';
+            peers->peer[0].name.data[len++] = ':';
 
-            ngx_memcpy(ctx->peers->peer[0].name.data + len,
+            ngx_memcpy(peers->peer[0].name.data + len,
                        ctx->port.data, ctx->port.len);
 
-            ctx->peers->peer[0].uri_separator = "";
+            peers->peer[0].uri_separator = "";
 
-            ngx_imap_proxy_init(s, ctx->peers);
+            ngx_destroy_pool(ctx->pool);
+            ngx_imap_proxy_init(s, peers);
 
             return;
         }
@@ -633,6 +664,7 @@ ngx_imap_auth_http_process_headers(ngx_i
                       "auth http server %V sent invalid header in response",
                       &ctx->peer.peers->peer[0].name);
         ngx_close_connection(ctx->peer.connection);
+        ngx_destroy_pool(ctx->pool);
         ngx_imap_session_internal_server_error(s);
 
         return;
@@ -906,6 +938,7 @@ ngx_imap_auth_http_block_read(ngx_event_
         ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module);
 
         ngx_close_connection(ctx->peer.connection);
+        ngx_destroy_pool(ctx->pool);
         ngx_imap_session_internal_server_error(s);
     }
 }
@@ -920,7 +953,7 @@ ngx_imap_auth_http_dummy_handler(ngx_eve
 
 
 static ngx_buf_t *
-ngx_imap_auth_http_create_request(ngx_imap_session_t *s,
+ngx_imap_auth_http_create_request(ngx_imap_session_t *s, ngx_pool_t *pool,
     ngx_imap_auth_http_conf_t *ahcf)
 {
     size_t      len;
@@ -938,7 +971,7 @@ ngx_imap_auth_http_create_request(ngx_im
                 + sizeof(CRLF) - 1
           + sizeof(CRLF) - 1;
 
-    b = ngx_create_temp_buf(s->connection->pool, len);
+    b = ngx_create_temp_buf(pool, len);
     if (b == NULL) {
         return NULL;
     }
@@ -981,7 +1014,7 @@ ngx_imap_auth_http_create_request(ngx_im
     /* add "\r\n" at the header end */
     *b->last++ = CR; *b->last++ = LF;
 
-#if (NGX_DEBUG)
+#if (NGX_DEBUG_IMAP_PASSWD)
     {
     ngx_str_t  l;
 
--- a/src/imap/ngx_imap_handler.c
+++ b/src/imap/ngx_imap_handler.c
@@ -10,12 +10,13 @@
 #include <ngx_imap.h>
 
 
-static void ngx_imap_init_session(ngx_event_t *rev);
+static void ngx_imap_init_session(ngx_connection_t *c);
 static void ngx_imap_init_protocol(ngx_event_t *rev);
 static ngx_int_t ngx_imap_read_command(ngx_imap_session_t *s);
 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_handshake_handler(ngx_connection_t *c);
 static void ngx_imap_ssl_close_handler(ngx_event_t *ev);
 #endif
 
@@ -43,13 +44,15 @@ static u_char  imap_invalid_command[] = 
 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_conf_ctx_t       *ctx;
+    ngx_imap_ssl_conf_t       *sslcf;
+    ngx_imap_core_srv_conf_t  *cscf;
 #endif
 
-    ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap init connection");
+    ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V",
+                  c->number, &c->addr_text, &c->listening->addr_text);
 
     lctx = ngx_palloc(c->pool, sizeof(ngx_imap_log_ctx_t));
     if (lctx == NULL) {
@@ -73,63 +76,59 @@ ngx_imap_init_connection(ngx_connection_
     sslcf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_ssl_module);
 
     if (sslcf->enable) {
-        if (ngx_ssl_create_connection(sslcf->ssl_ctx, c, 0) == NGX_ERROR) {
+        if (ngx_ssl_create_connection(&sslcf->ssl, c, 0) == NGX_ERROR) {
             ngx_imap_close_connection(c);
             return;
         }
 
-        c->recv = ngx_ssl_recv;
-        c->send = ngx_ssl_write;
-        c->send_chain = ngx_ssl_send_chain;
+        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);
+        return;
     }
 
 #endif
 
-    ngx_imap_init_session(c->read);
+    ngx_imap_init_session(c);
 }
 
 
+#if (NGX_IMAP_SSL)
+
 static void
-ngx_imap_init_session(ngx_event_t *rev)
+ngx_imap_ssl_handshake_handler(ngx_connection_t *c)
+{   
+    if (c->ssl->handshaked) {
+        ngx_imap_init_session(c);
+        return;
+    }
+
+    ngx_imap_close_connection(c);
+    return;
+}
+
+#endif
+
+
+static void
+ngx_imap_init_session(ngx_connection_t *c)
 {
-    ngx_connection_t          *c;
     ngx_imap_session_t        *s;
     ngx_imap_log_ctx_t        *lctx;
     ngx_imap_conf_ctx_t       *ctx;
     ngx_imap_core_srv_conf_t  *cscf;
-#if (NGX_IMAP_SSL)
-    ngx_int_t                  rc;
-#endif
 
-    c = rev->data;
-    ctx = c->ctx;
-    cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module);
-
-#if (NGX_IMAP_SSL)
-
-    if (c->ssl) {
-
-        rc = ngx_ssl_handshake(c);
-
-        if (rc == NGX_ERROR) {
-            ngx_imap_close_connection(c);
-            return;
-        }
-
-        if (rc == NGX_AGAIN) {
-            ngx_add_timer(rev, cscf->timeout);
-            c->read->handler = ngx_imap_init_session;
-
-            if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
-                ngx_imap_close_connection(c);
-            }
-
-            return;
-        }
-
-    }
-
-#endif
+    c->read->handler = ngx_imap_init_protocol;
+    c->write->handler = ngx_imap_send;
 
     s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t));
     if (s == NULL) {
@@ -137,6 +136,9 @@ ngx_imap_init_session(ngx_event_t *rev)
         return;
     }
 
+    ctx = c->ctx;
+    cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module);
+
     c->data = s;
     s->connection = c;
 
@@ -156,12 +158,9 @@ ngx_imap_init_session(ngx_event_t *rev)
     lctx = c->log->data;
     lctx->session = s;
 
-    c->read->handler = ngx_imap_init_protocol;
-    c->write->handler = ngx_imap_send;
+    ngx_add_timer(c->read, cscf->timeout);
 
-    ngx_add_timer(rev, cscf->timeout);
-
-    if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
+    if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
         ngx_imap_close_connection(c);
     }
 
@@ -378,9 +377,14 @@ ngx_imap_auth_state(ngx_event_t *rev)
 
                 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
 
+#if (NGX_DEBUG_IMAP_PASSWD)
                 ngx_log_debug2(NGX_LOG_DEBUG_IMAP, c->log, 0,
                                "imap login:\"%V\" passwd:\"%V\"",
                                &s->login, &s->passwd);
+#else
+                ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
+                               "imap login:\"%V\"", &s->login);
+#endif
 
                 s->args.nelts = 0;
                 s->buffer->pos = s->buffer->start;
@@ -584,8 +588,10 @@ ngx_pop3_auth_state(ngx_event_t *rev)
 
                     ngx_memcpy(s->passwd.data, arg[0].data, s->passwd.len);
 
+#if (NGX_DEBUG_IMAP_PASSWD)
                     ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
                                    "pop3 passwd: \"%V\"", &s->passwd);
+#endif
 
                     s->args.nelts = 0;
                     s->buffer->pos = s->buffer->start;
--- a/src/imap/ngx_imap_proxy_module.c
+++ b/src/imap/ngx_imap_proxy_module.c
@@ -156,6 +156,7 @@ ngx_imap_proxy_block_read(ngx_event_t *r
 static void
 ngx_imap_proxy_imap_handler(ngx_event_t *rev)
 {
+    char                   *action;
     u_char                 *p;
     ngx_int_t               rc;
     ngx_str_t               line;
@@ -293,6 +294,11 @@ ngx_imap_proxy_imap_handler(ngx_event_t 
         ngx_add_timer(s->connection->read, pcf->timeout);
         ngx_del_timer(c->read);
 
+        action = c->log->action;
+        c->log->action = NULL;
+        ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
+        c->log->action = action;
+
         c->log->action = "proxying";
     }
 }
@@ -301,6 +307,7 @@ ngx_imap_proxy_imap_handler(ngx_event_t 
 static void
 ngx_imap_proxy_pop3_handler(ngx_event_t *rev)
 {
+    char                   *action;
     u_char                 *p;
     ngx_int_t               rc;
     ngx_str_t               line;
@@ -418,6 +425,11 @@ ngx_imap_proxy_pop3_handler(ngx_event_t 
         ngx_add_timer(s->connection->read, pcf->timeout);
         ngx_del_timer(c->read);
 
+        action = c->log->action;
+        c->log->action = NULL;
+        ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
+        c->log->action = action;
+
         c->log->action = "proxying";
     }
 }
@@ -507,6 +519,7 @@ ngx_imap_proxy_read_response(ngx_imap_se
 static void
 ngx_imap_proxy_handler(ngx_event_t *ev)
 {
+    char                   *action;
     size_t                  size;
     ssize_t                 n;
     ngx_buf_t              *b;
@@ -603,7 +616,17 @@ ngx_imap_proxy_handler(ngx_event_t *ev)
         if (size && src->read->ready) {
             n = src->recv(src, b->last, size);
 
-            if (n == NGX_ERROR || n == 0) {
+            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;
             }
--- a/src/imap/ngx_imap_ssl_module.c
+++ b/src/imap/ngx_imap_ssl_module.c
@@ -11,12 +11,21 @@
 
 #define NGX_DEFLAUT_CERTIFICATE      "cert.pem"
 #define NGX_DEFLAUT_CERTIFICATE_KEY  "cert.pem"
+#define NGX_DEFLAUT_CIPHERS  "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
 
 
 static void *ngx_imap_ssl_create_conf(ngx_conf_t *cf);
 static char *ngx_imap_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child);
 
 
+static ngx_conf_bitmask_t  ngx_imap_ssl_protocols[] = { 
+    { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
+    { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
+    { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_command_t  ngx_imap_ssl_commands[] = {
 
     { ngx_string("ssl"),
@@ -40,6 +49,13 @@ static ngx_command_t  ngx_imap_ssl_comma
       offsetof(ngx_imap_ssl_conf_t, certificate_key),
       NULL },
 
+    { ngx_string("ssl_protocols"),
+      NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_bitmask_slot,
+      NGX_IMAP_SRV_CONF_OFFSET,
+      offsetof(ngx_imap_ssl_conf_t, protocols),
+      &ngx_imap_ssl_protocols },
+
     { ngx_string("ssl_ciphers"),
       NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
@@ -47,6 +63,13 @@ static ngx_command_t  ngx_imap_ssl_comma
       offsetof(ngx_imap_ssl_conf_t, ciphers),
       NULL },
 
+    { ngx_string("ssl_prefer_server_ciphers"),
+      NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_IMAP_SRV_CONF_OFFSET,
+      offsetof(ngx_imap_ssl_conf_t, prefer_server_ciphers),
+      NULL },
+
       ngx_null_command
 };
 
@@ -92,6 +115,8 @@ ngx_imap_ssl_create_conf(ngx_conf_t *cf)
     /*
      * set by ngx_pcalloc():  
      *
+     *     scf->protocols = 0;
+     *
      *     scf->certificate.len = 0;
      *     scf->certificate.data = NULL;
      *     scf->certificate_key.len = 0;
@@ -101,6 +126,7 @@ ngx_imap_ssl_create_conf(ngx_conf_t *cf)
      */
 
     scf->enable = NGX_CONF_UNSET;
+    scf->prefer_server_ciphers = NGX_CONF_UNSET;
 
     return scf;
 }
@@ -118,39 +144,41 @@ ngx_imap_ssl_merge_conf(ngx_conf_t *cf, 
         return NGX_CONF_OK;
     }
 
+    ngx_conf_merge_value(conf->prefer_server_ciphers,
+                         prev->prefer_server_ciphers, 0);
+
+    ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
+                         (NGX_CONF_BITMASK_SET
+                          |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1));
+
     ngx_conf_merge_str_value(conf->certificate, prev->certificate,
                              NGX_DEFLAUT_CERTIFICATE);
 
     ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
                              NGX_DEFLAUT_CERTIFICATE_KEY);
 
-    ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, "");
+    ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFLAUT_CIPHERS);
 
 
-    /* TODO: configure methods */
+    conf->ssl.log = cf->log;
 
-    conf->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
-
-    if (conf->ssl_ctx == NULL) {
-        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, "SSL_CTX_new() failed");
+    if (ngx_ssl_create(&conf->ssl, conf->protocols) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
-    if (ngx_pool_cleanup_add(cf->pool, ngx_ssl_cleanup_ctx, conf->ssl_ctx)
-        == NULL)
+    if (ngx_pool_cleanup_add(cf->pool, ngx_ssl_cleanup_ctx, &conf->ssl) == NULL)
     {
         return NGX_CONF_ERROR;
     }
 
-
-#if 0
-    SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL);
-    SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_NO_SSLv3);
-    SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_SINGLE_DH_USE);
-#endif
+    if (ngx_ssl_certificate(&conf->ssl, conf->certificate.data,
+                            conf->certificate_key.data) != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
 
     if (conf->ciphers.len) {
-        if (SSL_CTX_set_cipher_list(conf->ssl_ctx,
+        if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
                                    (const char *) conf->ciphers.data) == 0)
         {
             ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
@@ -159,35 +187,13 @@ ngx_imap_ssl_merge_conf(ngx_conf_t *cf, 
         }
     }
 
-    if (SSL_CTX_use_certificate_chain_file(conf->ssl_ctx,
-                                         (char *) conf->certificate.data) == 0)
-    {
-        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
-                      "SSL_CTX_use_certificate_chain_file(\"%s\") failed",
-                      conf->certificate.data);
+    if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
+    SSL_CTX_set_session_cache_mode(conf->ssl.ctx, SSL_SESS_CACHE_SERVER);
 
-    if (SSL_CTX_use_PrivateKey_file(conf->ssl_ctx,
-                                    (char *) conf->certificate_key.data,
-                                    SSL_FILETYPE_PEM) == 0)
-    {
-        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
-                      "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
-                      conf->certificate_key.data);
-        return NGX_CONF_ERROR;
-    }
-
-    SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL);
-
-    SSL_CTX_set_mode(conf->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-
-    SSL_CTX_set_read_ahead(conf->ssl_ctx, 1);
-
-    SSL_CTX_set_session_cache_mode(conf->ssl_ctx, SSL_SESS_CACHE_SERVER);
-
-    SSL_CTX_set_session_id_context(conf->ssl_ctx, ngx_imap_session_id_ctx,
+    SSL_CTX_set_session_id_context(conf->ssl.ctx, ngx_imap_session_id_ctx,
                                    sizeof(ngx_imap_session_id_ctx) - 1);
 
     return NGX_CONF_OK;
--- a/src/imap/ngx_imap_ssl_module.h
+++ b/src/imap/ngx_imap_ssl_module.h
@@ -15,12 +15,18 @@
 
 typedef struct {
     ngx_flag_t      enable;
+
+    ngx_ssl_t       ssl;
+
+    ngx_flag_t      prefer_server_ciphers;
+
+    ngx_uint_t      protocols;
+
     ngx_str_t       certificate;
     ngx_str_t       certificate_key;
 
     ngx_str_t       ciphers;
 
-    ngx_ssl_ctx_t  *ssl_ctx;
 } ngx_imap_ssl_conf_t;
 
 
--- a/src/os/unix/ngx_atomic.h
+++ b/src/os/unix/ngx_atomic.h
@@ -12,7 +12,7 @@
 #include <ngx_core.h>
 
 
-#if ( __i386__ )
+#if ( __i386__ || __i386 )
 
 #define NGX_HAVE_ATOMIC_OPS  1
 
@@ -109,7 +109,7 @@ ngx_atomic_cmp_set(ngx_atomic_t *lock, n
 }
 
 
-#elif ( __amd64__ )
+#elif ( __amd64__ || __amd64 )
 
 #define NGX_HAVE_ATOMIC_OPS  1
 
@@ -183,7 +183,7 @@ ngx_atomic_cmp_set(ngx_atomic_t *lock, n
 }
 
 
-#elif ( __sparc__ )
+#elif ( __sparc__ || __sparcv9 )
 
 #define NGX_HAVE_ATOMIC_OPS  1
 
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -77,7 +77,7 @@ sysctl_t sysctls[] = {
 void
 ngx_debug_init()
 {
-#if (NGX_DEBUG && !NGX_NO_DEBUG_MALLOC)
+#if (NGX_DEBUG_MALLOC)
 
 #if __FreeBSD_version >= 500014
     _malloc_options = "J";