changeset 212:56688ed172c8 NGINX_0_3_53

nginx 0.3.53 *) Change: the "add_header" directive adds the string to 204, 301, and 302 responses. *) Feature: the "server" directive in the "upstream" context supports the "weight" parameter. *) Feature: the "server_name" directive supports the "*" wildcard. *) Feature: nginx supports the request body size more than 2G. *) Bugfix: if a client was successfully authorized using "satisfy_any on", then anyway the message "access forbidden by rule" was written in the log. *) Bugfix: the "PUT" method may erroneously not create a file and return the 409 code. *) Bugfix: if the IMAP/POP3 backend returned an error, then nginx continued proxying anyway.
author Igor Sysoev <http://sysoev.ru>
date Fri, 07 Jul 2006 00:00:00 +0400
parents f04a54878110
children 405beeeadf7f
files CHANGES CHANGES.ru html/50x.html src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_conf_file.h src/core/ngx_inet.c src/core/ngx_inet.h src/core/ngx_parse.c src/core/ngx_parse.h src/event/modules/ngx_devpoll_module.c src/event/modules/ngx_epoll_module.c src/event/ngx_event.c src/event/ngx_event_connect.c src/http/modules/ngx_http_access_module.c src/http/modules/ngx_http_auth_basic_module.c src/http/modules/ngx_http_charset_filter_module.c src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_gzip_filter_module.c src/http/modules/ngx_http_headers_filter_module.c src/http/modules/ngx_http_log_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_realip_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/ngx_http_userid_filter_module.c src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_header_filter_module.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_request_body.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h src/imap/ngx_imap.h src/imap/ngx_imap_core_module.c src/imap/ngx_imap_proxy_module.c src/os/unix/ngx_errno.h
diffstat 40 files changed, 414 insertions(+), 162 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,27 @@
 
+Changes with nginx 0.3.53                                        07 Jul 2006
+
+    *) Change: the "add_header" directive adds the string to 204, 301, and 
+       302 responses.
+
+    *) Feature: the "server" directive if the "upstream" context supports 
+       the "weight" parameter.
+
+    *) Feature: the "server_name" directive supports the "*" wildcard.
+
+    *) Feature: nginx supports the request body size more than 2G.
+
+    *) Bugfix: if a client was successfully authorized using "satisfy_any 
+       on", then anyway the "access forbidden by rule" message was written 
+       in the log.
+
+    *) Bugfix: the "PUT" method may erroneously not create a file and 
+       return the 409 code.
+
+    *) Bugfix: if the IMAP/POP3 backend returned an error, then nginx 
+       continued proxying anyway.
+
+
 Changes with nginx 0.3.52                                        03 Jul 2006
 
     *) Change: the ngx_http_index_module behavior for the "POST /" requests 
@@ -1390,8 +1413,8 @@ Changes with nginx 0.1.23               
     *) Feature: the %request_time log parameter.
 
     *) Feature: if the request has no the "Host" header line, then the 
-       proxy_preserve_host directive set this header line to the first 
-       server name of the server_name directive.
+       "proxy_preserve_host" directive set this header line to the first 
+       server name of the "server_name" directive.
 
     *) Bugfix: nginx could not be built on platforms different from i386, 
        amd64, sparc и ppc; bug appeared in 0.1.22.
@@ -1587,8 +1610,8 @@ Changes with nginx 0.1.13               
     *) Feature: the server_names_hash and server_names_hash_threshold 
        directives.
 
-    *) Bugfix: the *.domain.tld names in the server_name directive did not 
-       work.
+    *) Bugfix: the *.domain.tld names in the "server_name" directive did 
+       not work.
 
     *) Bugfix: the %request_length log parameter logged the incorrect 
        length.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,27 @@
 
+Изменения в nginx 0.3.53                                          07.07.2006
+
+    *) Изменение: директива add_header добавляет строки в ответы с кодом 
+       204, 301 и 302.
+
+    *) Добавление: директива server в блоке upstream поддерживает параметр 
+       weight.
+
+    *) Добавление: директива server_name поддерживает маску "*".
+
+    *) Добавление: nginx поддерживает тело запроса больше 2G.
+
+    *) Исправление: если при использовании "satisfy_any on" клиент успешно 
+       проходил аутентификацию, в лог всё равно записалоcь сообщение 
+       "access forbidden by rule".
+
+    *) Исправление: метод PUT мог ошибочно не создать файл и вернуть код 
+       409.
+
+    *) Исправление: если во время аутентификации IMAP/POP3 бэкенд возвращал 
+       ошибку, nginx продолжал проксирование.
+
+
 Изменения в nginx 0.3.52                                          03.07.2006
 
     *) Изменение: восстановлено поведение модуля ngx_http_index_module для 
--- a/html/50x.html
+++ b/html/50x.html
@@ -6,9 +6,13 @@ body { font-family: Tahoma, Verdana, Ari
 </style>
 </head>
 <body bgcolor="white" text="black">
-<p>
+<table width="100%" height="100%">
+<tr>
+<td align="center" valign="middle">
 The page you are looking for is temporarily unavailable.<br/>
 Please try again later.
-</p>
+</td>
+</tr>
+</table>
 </body>
 </html>
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.52"
+#define NGINX_VER          "nginx/0.3.53"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -1036,6 +1036,37 @@ ngx_conf_set_size_slot(ngx_conf_t *cf, n
 
 
 char *
+ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char  *p = conf;
+
+    off_t            *op;
+    ngx_str_t        *value;
+    ngx_conf_post_t  *post;
+
+
+    op = (off_t *) (p + cmd->offset);
+    if (*op != NGX_CONF_UNSET) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    *op = ngx_parse_offset(&value[1]);
+    if (*op == (off_t) NGX_ERROR) {
+        return "invalid value";
+    }
+
+    if (cmd->post) {
+        post = cmd->post;
+        return post->post_handler(cf, post, op);
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+char *
 ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char  *p = conf;
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -236,8 +236,8 @@ char *ngx_conf_check_num_bounds(ngx_conf
         conf = default;                                                      \
     }
 
-#define ngx_conf_init_unsigned_value(conf, default)                          \
-    if (conf == (unsigned) NGX_CONF_UNSET) {                                 \
+#define ngx_conf_init_uint_value(conf, default)                              \
+    if (conf == NGX_CONF_UNSET_UINT) {                                       \
         conf = default;                                                      \
     }
 
@@ -261,7 +261,7 @@ char *ngx_conf_check_num_bounds(ngx_conf
         conf = (prev == NULL) ? default : prev;                              \
     }
 
-#define ngx_conf_merge_unsigned_value(conf, prev, default)                   \
+#define ngx_conf_merge_uint_value(conf, prev, default)                       \
     if (conf == NGX_CONF_UNSET_UINT) {                                       \
         conf = (prev == NGX_CONF_UNSET_UINT) ? default : prev;               \
     }
@@ -281,6 +281,11 @@ char *ngx_conf_check_num_bounds(ngx_conf
         conf = (prev == NGX_CONF_UNSET_SIZE) ? default : prev;               \
     }
 
+#define ngx_conf_merge_off_value(conf, prev, default)                        \
+    if (conf == NGX_CONF_UNSET) {                                            \
+        conf = (prev == NGX_CONF_UNSET) ? default : prev;                    \
+    }
+
 #define ngx_conf_merge_str_value(conf, prev, default)                        \
     if (conf.data == NULL) {                                                 \
         if (prev.data) {                                                     \
@@ -328,6 +333,7 @@ char *ngx_conf_set_str_array_slot(ngx_co
 char *ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -479,7 +479,6 @@ ngx_inet_resolve_peer(ngx_conf_t *cf, ng
         }
 
         peers->number = i;
-        peers->weight = 1;
 
         for (i = 0; h->h_addr_list[i] != NULL; i++) {
 
@@ -511,6 +510,10 @@ ngx_inet_resolve_peer(ngx_conf_t *cf, ng
                                       - peers->peer[i].name.data;
 
             peers->peer[i].uri_separator = "";
+
+            peers->peer[i].weight = NGX_CONF_UNSET_UINT;
+            peers->peer[i].max_fails = NGX_CONF_UNSET_UINT;
+            peers->peer[i].fail_timeout = NGX_CONF_UNSET;
         }
 
     } else {
@@ -643,7 +646,6 @@ ngx_inet_upstream_parse(ngx_conf_t *cf, 
         }
 
         peers->number = i;
-        peers->weight = 1;
 
         for (i = 0; h->h_addr_list[i] != NULL; i++) {
 
@@ -677,6 +679,10 @@ ngx_inet_upstream_parse(ngx_conf_t *cf, 
             peers->peer[i].name.len = len + u->port_text.len;
 
             peers->peer[i].uri_separator = "";
+
+            peers->peer[i].weight = NGX_CONF_UNSET_UINT;
+            peers->peer[i].max_fails = NGX_CONF_UNSET_UINT;
+            peers->peer[i].fail_timeout = NGX_CONF_UNSET;
         }
 
     } else {
--- a/src/core/ngx_inet.h
+++ b/src/core/ngx_inet.h
@@ -29,6 +29,7 @@ typedef struct {
     ngx_str_t           name;
     char               *uri_separator;
 
+    ngx_uint_t          current_weight;
     ngx_uint_t          weight;
 
     ngx_uint_t          fails;
@@ -45,7 +46,6 @@ typedef struct {
 
 struct ngx_peers_s {
     ngx_uint_t          current;
-    ngx_uint_t          weight;
 
     ngx_uint_t          number;
     ngx_uint_t          last_cached;
--- a/src/core/ngx_parse.c
+++ b/src/core/ngx_parse.c
@@ -47,6 +47,51 @@ ngx_parse_size(ngx_str_t *line)
 }
 
 
+off_t
+ngx_parse_offset(ngx_str_t *line)
+{
+    u_char     last;
+    off_t      offset;
+    size_t     len;
+    ngx_int_t  scale;
+
+    len = line->len;
+    last = line->data[len - 1];
+
+    switch (last) {
+    case 'K':
+    case 'k':
+        len--;
+        scale = 1024;
+        break;
+
+    case 'M':
+    case 'm':
+        len--;
+        scale = 1024 * 1024;
+        break;
+
+    case 'G':
+    case 'g':
+        len--;
+        scale = 1024 * 1024 * 1024;
+        break;
+
+    default:
+        scale = 1;
+    }
+
+    offset = ngx_atoof(line->data, len);
+    if (offset == NGX_ERROR) {
+        return NGX_ERROR;
+    }
+
+    offset *= scale;
+
+    return offset;
+}
+
+
 ngx_int_t
 ngx_parse_time(ngx_str_t *line, ngx_int_t sec)
 {
--- a/src/core/ngx_parse.h
+++ b/src/core/ngx_parse.h
@@ -16,6 +16,7 @@
 
 
 ssize_t ngx_parse_size(ngx_str_t *line);
+off_t ngx_parse_offset(ngx_str_t *line);
 ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_int_t sec);
 
 
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -510,8 +510,8 @@ ngx_devpoll_init_conf(ngx_cycle_t *cycle
 {
     ngx_devpoll_conf_t *dpcf = conf;
 
-    ngx_conf_init_unsigned_value(dpcf->changes, 32);
-    ngx_conf_init_unsigned_value(dpcf->events, 32);
+    ngx_conf_init_uint_value(dpcf->changes, 32);
+    ngx_conf_init_uint_value(dpcf->events, 32);
 
     return NGX_CONF_OK;
 }
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -479,11 +479,13 @@ ngx_epoll_process_events(ngx_cycle_t *cy
                            c->fd, revents);
         }
 
+#if 0
         if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
             ngx_log_error(NGX_LOG_ALERT, log, 0,
                           "strange epoll_wait() events fd:%d ev:%04XD",
                           c->fd, revents);
         }
+#endif
 
         if ((revents & (EPOLLERR|EPOLLHUP))
              && (revents & (EPOLLIN|EPOLLOUT)) == 0)
@@ -564,7 +566,7 @@ ngx_epoll_init_conf(ngx_cycle_t *cycle, 
 {
     ngx_epoll_conf_t *epcf = conf;
 
-    ngx_conf_init_unsigned_value(epcf->events, 512);
+    ngx_conf_init_uint_value(epcf->events, 512);
 
     return NGX_CONF_OK;
 }
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -1205,10 +1205,10 @@ ngx_event_init_conf(ngx_cycle_t *cycle, 
         return NGX_CONF_ERROR;
     }
 
-    ngx_conf_init_unsigned_value(ecf->connections, connections);
+    ngx_conf_init_uint_value(ecf->connections, connections);
     cycle->connection_n = ecf->connections;
 
-    ngx_conf_init_unsigned_value(ecf->use, module->ctx_index);
+    ngx_conf_init_uint_value(ecf->use, module->ctx_index);
 
     event_module = module->ctx;
     ngx_conf_init_ptr_value(ecf->name, event_module->name->data);
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -81,8 +81,6 @@ ngx_event_connect_peer(ngx_peer_connecti
                     pc->peers->current = 0;
                 }
 
-                pc->peers->weight = pc->peers->peer[pc->peers->current].weight;
-
                 pc->tries--;
 
                 if (pc->tries) {
@@ -92,16 +90,16 @@ ngx_event_connect_peer(ngx_peer_connecti
                 goto failed;
             }
 
-            pc->peers->weight--;
+            peer->current_weight--;
 
-            if (pc->peers->weight == 0) {
+            if (peer->current_weight == 0) {
+                peer->current_weight = peer->weight;
+
                 pc->peers->current++;
 
                 if (pc->peers->current >= pc->peers->number) {
                     pc->peers->current = 0;
                 }
-
-                pc->peers->weight = pc->peers->peer[pc->peers->current].weight;
             }
 
         } else {
@@ -131,6 +129,20 @@ ngx_event_connect_peer(ngx_peer_connecti
 
                 goto failed;
             }
+
+            peer->current_weight--;
+
+            if (peer->current_weight == 0) {
+                peer->current_weight = peer->weight;
+
+                if (pc->cur_peer == pc->peers->current) {
+                    pc->peers->current++;
+
+                    if (pc->peers->current >= pc->peers->number) {
+                        pc->peers->current = 0;
+                    }
+                }
+            }
         }
     }
 
@@ -358,15 +370,22 @@ failed:
 void
 ngx_event_connect_peer_failed(ngx_peer_connection_t *pc, ngx_uint_t down)
 {
-    time_t  now;
+    time_t       now;
+    ngx_peer_t  *peer;
 
     if (down) {
         now = ngx_time();
 
         /* ngx_lock_mutex(pc->peers->mutex); */
 
-        pc->peers->peer[pc->cur_peer].fails++;
-        pc->peers->peer[pc->cur_peer].accessed = now;
+        peer = &pc->peers->peer[pc->cur_peer];
+
+        peer->fails++;
+        peer->accessed = now;
+
+        if (peer->current_weight > 1) {
+            peer->current_weight /= 2;
+        }
 
         /* ngx_unlock_mutex(pc->peers->mutex); */
     }
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -92,6 +92,7 @@ ngx_http_access_handler(ngx_http_request
     ngx_uint_t                   i;
     struct sockaddr_in          *sin;
     ngx_http_access_rule_t      *rule;
+    ngx_http_core_loc_conf_t    *clcf;
     ngx_http_access_loc_conf_t  *alcf;
 
     alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module);
@@ -113,8 +114,12 @@ ngx_http_access_handler(ngx_http_request
 
         if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) {
             if (rule[i].deny) {
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "access forbidden by rule");
+                clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+                if (!clcf->satisfy_any) {
+                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                                  "access forbidden by rule");
+                }
 
                 return NGX_HTTP_FORBIDDEN;
             }
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -136,7 +136,7 @@ ngx_http_auth_basic_handler(ngx_http_req
     fd = ngx_open_file(alcf->user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
 
     if (fd == NGX_INVALID_FILE) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
+        ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                       ngx_open_file_n " \"%s\" failed", alcf->user_file.data);
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -188,7 +188,7 @@ ngx_http_charset_header_filter(ngx_http_
 {
     u_char                        *ct;
     ngx_int_t                      charset, source_charset;
-    ngx_str_t                     *mc;
+    ngx_str_t                     *mc, *from, *to;
     ngx_uint_t                     n;
     ngx_http_charset_t            *charsets;
     ngx_http_charset_ctx_t        *ctx;
@@ -288,13 +288,10 @@ ngx_http_charset_header_filter(ngx_http_
             return ngx_http_next_header_filter(r);
         }
 
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "no \"charset_map\" between the charsets "
-                      "\"%V\" and \"%V\"",
-                      &charsets[lcf->source_charset].name,
-                      &r->main->headers_out.charset);
+        from = &charsets[lcf->source_charset].name;
+        to = &r->main->headers_out.charset;
 
-        return ngx_http_next_header_filter(r);
+        goto no_charset_map;
     }
 
     source_charset = ngx_http_charset_get_charset(charsets, n,
@@ -308,11 +305,12 @@ ngx_http_charset_header_filter(ngx_http_
                               r->headers_out.charset.data)
                 != 0)
         {
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "no \"charset_map\" between the charsets "
-                          "\"%V\" and \"%V\"",
-                          &r->headers_out.charset,
-                          &r->main->headers_out.charset);
+            from = &r->headers_out.charset;
+            to = (charset == NGX_HTTP_NO_CHARSET) ?
+                                           &r->main->headers_out.charset:
+                                           &charsets[charset].name;
+
+            goto no_charset_map;
         }
 
         return ngx_http_next_header_filter(r);
@@ -322,18 +320,24 @@ ngx_http_charset_header_filter(ngx_http_
         && (charsets[source_charset].tables == NULL
             || charsets[source_charset].tables[charset] == NULL))
     {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "no \"charset_map\" between the charsets "
-                      "\"%V\" and \"%V\"",
-                      &charsets[source_charset].name, &charsets[charset].name);
+        from = &charsets[source_charset].name;
+        to = &charsets[charset].name;
 
-        return ngx_http_next_header_filter(r);
+        goto no_charset_map;
     }
 
     r->headers_out.content_type.len = r->headers_out.content_type_len;
 
     return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset,
                                         source_charset);
+
+no_charset_map:
+
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                  "no \"charset_map\" between the charsets "
+                  "\"%V\" and \"%V\"", from, to);
+
+    return ngx_http_next_header_filter(r);
 }
 
 
@@ -392,12 +396,15 @@ ngx_http_charset_set_charset(ngx_http_re
     ctx->from_utf8 = charsets[source_charset].utf8;
     ctx->to_utf8 = charsets[charset].utf8;
 
+    r->filter_need_in_memory = 1;
+
     if ((ctx->to_utf8 || ctx->from_utf8) && r == r->main) {
         ngx_http_clear_content_length(r);
+
+    } else {
+        r->filter_need_temporary = 1;
     }
 
-    r->filter_need_in_memory = 1;
-
     return ngx_http_next_header_filter(r);
 }
 
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -251,17 +251,20 @@ ngx_http_dav_put_handler(ngx_http_reques
 
     } else {
         status = NGX_HTTP_NO_CONTENT;
-    }
+
+        if (ngx_is_dir(&fi)) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR,
+                          "\"%s\" could not be created", path.data);
 
-    if (ngx_is_dir(&fi)) {
-        if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                          ngx_delete_file_n " \"%s\" failed",
-                          temp->data);
+            if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) {
+                ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+                              ngx_delete_file_n " \"%s\" failed",
+                              temp->data);
+            }
+
+            ngx_http_finalize_request(r, NGX_HTTP_CONFLICT);
+            return;
         }
-
-        ngx_http_finalize_request(r, NGX_HTTP_CONFLICT);
-        return;
     }
 
     if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -1565,6 +1565,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     uintptr_t                    *code;
     ngx_str_t                    *header;
     ngx_uint_t                    i, j;
+    ngx_peer_t                   *peer;
     ngx_array_t                   hide_headers;
     ngx_keyval_t                 *src;
     ngx_hash_key_t               *hk;
@@ -1693,20 +1694,23 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
                                |NGX_HTTP_UPSTREAM_FT_ERROR
                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
 
-    ngx_conf_merge_unsigned_value(conf->upstream.max_fails,
+    ngx_conf_merge_uint_value(conf->upstream.max_fails,
                               prev->upstream.max_fails, 1);
 
     ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
                               prev->upstream.fail_timeout, 10);
 
-    if (conf->upstream_peers && !conf->upstream_peers->balanced) {
+    if (conf->upstream_peers) {
+        peer = conf->upstream_peers->peers->peer;
         for (i = 0; i < conf->upstream_peers->peers->number; i++) {
-            conf->upstream_peers->peers->peer[i].weight = 1;
-            conf->upstream_peers->peers->peer[i].max_fails =
-                                                   conf->upstream.max_fails;
-            conf->upstream_peers->peers->peer[i].fail_timeout =
-                                                   conf->upstream.fail_timeout;
+            ngx_conf_init_uint_value(peer[i].weight, 1);
+            peer[i].current_weight = peer[i].weight;
+            ngx_conf_init_uint_value(peer[i].max_fails,
+                              conf->upstream.max_fails);
+            ngx_conf_init_value(peer[i].fail_timeout,
+                              conf->upstream.fail_timeout);
         }
+
     }
 
     ngx_conf_merge_path_value(conf->upstream.temp_path,
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -1087,7 +1087,7 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf,
 
     ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4, ngx_pagesize);
 
-    ngx_conf_merge_unsigned_value(conf->http_version, prev->http_version,
+    ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
                               NGX_HTTP_VERSION_11);
     ngx_conf_merge_bitmask_value(conf->proxied, prev->proxied,
                               (NGX_CONF_BITMASK_SET|NGX_HTTP_GZIP_PROXIED_OFF));
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -103,9 +103,12 @@ ngx_http_headers_filter(ngx_http_request
     ngx_http_header_val_t    *h;
     ngx_http_headers_conf_t  *conf;
 
-    if ((r->headers_out.status != NGX_HTTP_OK
-         && r->headers_out.status != NGX_HTTP_NOT_MODIFIED)
-        || r != r->main)
+    if (r != r->main
+        || (r->headers_out.status != NGX_HTTP_OK
+            && r->headers_out.status != NGX_HTTP_NO_CONTENT
+            && r->headers_out.status != NGX_HTTP_MOVED_PERMANENTLY
+            && r->headers_out.status != NGX_HTTP_MOVED_TEMPORARILY
+            && r->headers_out.status != NGX_HTTP_NOT_MODIFIED))
     {
         return ngx_http_next_header_filter(r);
     }
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -478,7 +478,7 @@ static u_char *
 ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op)
 {
-    return ngx_sprintf(buf, "%z", r->request_length);
+    return ngx_sprintf(buf, "%O", r->request_length);
 }
 
 
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -560,7 +560,7 @@ ngx_http_memcached_merge_loc_conf(ngx_co
                                |NGX_HTTP_UPSTREAM_FT_ERROR
                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
 
-    ngx_conf_merge_unsigned_value(conf->upstream.max_fails,
+    ngx_conf_merge_uint_value(conf->upstream.max_fails,
                               prev->upstream.max_fails, 1);
 
     ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -1520,6 +1520,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
     uintptr_t                    *code;
     ngx_str_t                    *header;
     ngx_uint_t                    i, j;
+    ngx_peer_t                   *peer;
     ngx_array_t                   hide_headers;
     ngx_keyval_t                 *src, *s, *h;
     ngx_hash_key_t               *hk;
@@ -1647,19 +1648,21 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
                                |NGX_HTTP_UPSTREAM_FT_ERROR
                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
 
-    ngx_conf_merge_unsigned_value(conf->upstream.max_fails,
+    ngx_conf_merge_uint_value(conf->upstream.max_fails,
                               prev->upstream.max_fails, 1);
 
     ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
                               prev->upstream.fail_timeout, 10);
 
-    if (conf->upstream_peers && !conf->upstream_peers->balanced) {
+    if (conf->upstream_peers) {
+        peer = conf->upstream_peers->peers->peer;
         for (i = 0; i < conf->upstream_peers->peers->number; i++) {
-            conf->upstream_peers->peers->peer[i].weight = 1;
-            conf->upstream_peers->peers->peer[i].max_fails =
-                                                   conf->upstream.max_fails;
-            conf->upstream_peers->peers->peer[i].fail_timeout =
-                                                   conf->upstream.fail_timeout;
+            ngx_conf_init_uint_value(peer[i].weight, 1);
+            peer[i].current_weight = peer[i].weight;
+            ngx_conf_init_uint_value(peer[i].max_fails,
+                              conf->upstream.max_fails);
+            ngx_conf_init_value(peer[i].fail_timeout,
+                              conf->upstream.fail_timeout);
         }
     }
 
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -243,7 +243,7 @@ ngx_http_realip_merge_loc_conf(ngx_conf_
         conf->from = prev->from;
     }
 
-    ngx_conf_merge_unsigned_value(conf->xfwd, prev->xfwd, 0);
+    ngx_conf_merge_uint_value(conf->xfwd, prev->xfwd, 0);
 
     return NGX_CONF_OK;
 }
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -245,7 +245,7 @@ ngx_http_rewrite_merge_loc_conf(ngx_conf
     ngx_conf_merge_value(conf->log, prev->log, 0);
     ngx_conf_merge_value(conf->uninitialized_variable_warn,
                          prev->uninitialized_variable_warn, 1);
-    ngx_conf_merge_unsigned_value(conf->stack_size, prev->stack_size, 10);
+    ngx_conf_merge_uint_value(conf->stack_size, prev->stack_size, 10);
 
     if (conf->codes == NULL) {
         return NGX_CONF_OK;
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -670,8 +670,8 @@ ngx_http_userid_merge_conf(ngx_conf_t *c
     ngx_http_userid_conf_t *prev = parent;
     ngx_http_userid_conf_t *conf = child;
 
-    ngx_conf_merge_unsigned_value(conf->enable, prev->enable,
-                                  NGX_HTTP_USERID_OFF);
+    ngx_conf_merge_uint_value(conf->enable, prev->enable,
+                              NGX_HTTP_USERID_OFF);
 
     ngx_conf_merge_str_value(conf->name, prev->name, "uid");
     ngx_conf_merge_str_value(conf->domain, prev->domain, "");
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -833,9 +833,9 @@ ngx_http_perl_init_main_conf(ngx_conf_t 
     ngx_http_perl_main_conf_t *pmcf = conf;
 
 #if (NGX_HAVE_PERL_CLONE || NGX_HAVE_PERL_MULTIPLICITY)
-    ngx_conf_init_unsigned_value(pmcf->interp_max, 10);
+    ngx_conf_init_uint_value(pmcf->interp_max, 10);
 #else
-    ngx_conf_init_unsigned_value(pmcf->interp_max, 1);
+    ngx_conf_init_uint_value(pmcf->interp_max, 1);
 #endif
 
     pmcf->free_perls = ngx_pcalloc(cf->pool,
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -242,7 +242,7 @@ static ngx_command_t  ngx_http_core_comm
 
     { ngx_string("client_max_body_size"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
+      ngx_conf_set_off_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_core_loc_conf_t, client_max_body_size),
       NULL },
@@ -634,6 +634,12 @@ ngx_http_core_run_phases(ngx_http_reques
         }
 
         if (r->phase == NGX_HTTP_ACCESS_PHASE && r->access_code) {
+
+            if (r->access_code == NGX_HTTP_FORBIDDEN) {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "access forbidden by rule");
+            }
+
             ngx_http_finalize_request(r, r->access_code);
             return;
         }
@@ -690,15 +696,15 @@ ngx_http_find_location_config(ngx_http_r
     ngx_http_update_location_config(r);
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http cl:%z max:%uz",
+                   "http cl:%O max:%O",
                    r->headers_in.content_length_n, clcf->client_max_body_size);
 
     if (r->headers_in.content_length_n != -1
         && clcf->client_max_body_size
-        && clcf->client_max_body_size < (size_t) r->headers_in.content_length_n)
+        && clcf->client_max_body_size < r->headers_in.content_length_n)
     {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "client intented to send too large body: %z bytes",
+                      "client intented to send too large body: %O bytes",
                       r->headers_in.content_length_n);
 
         return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
@@ -2015,7 +2021,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
      *     lcf->alias = 0;
      */
 
-    lcf->client_max_body_size = NGX_CONF_UNSET_SIZE;
+    lcf->client_max_body_size = NGX_CONF_UNSET;
     lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
     lcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
     lcf->satisfy_any = NGX_CONF_UNSET;
@@ -2086,12 +2092,12 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
         conf->post_action = prev->post_action;
     }
 
-    ngx_conf_merge_unsigned_value(conf->types_hash_max_size,
-                                  prev->types_hash_max_size, 1024);
-
-    ngx_conf_merge_unsigned_value(conf->types_hash_bucket_size,
-                                  prev->types_hash_bucket_size,
-                                  ngx_cacheline_size);
+    ngx_conf_merge_uint_value(conf->types_hash_max_size,
+                              prev->types_hash_max_size, 1024);
+
+    ngx_conf_merge_uint_value(conf->types_hash_bucket_size,
+                              prev->types_hash_bucket_size,
+                              ngx_cacheline_size);
 
     conf->types_hash_bucket_size = ngx_align(conf->types_hash_bucket_size,
                                              ngx_cacheline_size);
@@ -2175,7 +2181,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_str_value(conf->default_type,
                               prev->default_type, "text/plain");
 
-    ngx_conf_merge_size_value(conf->client_max_body_size,
+    ngx_conf_merge_off_value(conf->client_max_body_size,
                               prev->client_max_body_size, 1 * 1024 * 1024);
     ngx_conf_merge_size_value(conf->client_body_buffer_size,
                               prev->client_body_buffer_size,
@@ -2451,6 +2457,11 @@ ngx_http_core_server_name(ngx_conf_t *cf
 
         ch = value[i].data[0];
 
+        if (value[i].len == 1 && ch == '*') {
+            cscf->wildcard = 1;
+            continue;
+        }
+
         if (value[i].len == 0
             || (ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
             || (ch == '.' && value[i].len < 2))
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -116,6 +116,8 @@ typedef struct {
 
     ngx_flag_t                 optimize_server_names;
     ngx_flag_t                 ignore_invalid_headers;
+
+    ngx_uint_t                 wildcard;  /* unsigned  wildcard:1 */
 } ngx_http_core_srv_conf_t;
 
 
@@ -213,7 +215,8 @@ struct ngx_http_core_loc_conf_s {
     ngx_hash_t    types_hash;
     ngx_str_t     default_type;
 
-    size_t        client_max_body_size;    /* client_max_body_size */
+    off_t         client_max_body_size;    /* client_max_body_size */
+
     size_t        client_body_buffer_size; /* client_body_buffer_size */
     size_t        send_lowat;              /* send_lowat */
     size_t        postpone_output;         /* postpone_output */
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -84,7 +84,7 @@ static ngx_str_t ngx_http_status_lines[]
     ngx_string("406 Not Acceptable"),
     ngx_null_string,  /* "407 Proxy Authentication Required" */
     ngx_string("408 Request Time-out"),
-    ngx_null_string,  /* "409 Conflict" */
+    ngx_string("409 Conflict"),
     ngx_string("410 Gone"),
     ngx_string("411 Length Required"),
     ngx_null_string,  /* "412 Precondition Failed" */
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1235,7 +1235,7 @@ ngx_http_process_request_header(ngx_http
 
     if (r->headers_in.content_length) {
         r->headers_in.content_length_n =
-                            ngx_atosz(r->headers_in.content_length->value.data,
+                            ngx_atoof(r->headers_in.content_length->value.data,
                                       r->headers_in.content_length->value.len);
 
         if (r->headers_in.content_length_n == NGX_ERROR) {
@@ -1395,6 +1395,13 @@ ngx_http_find_virtual_server(ngx_http_re
         }
     }
 
+    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+    if (cscf->wildcard) {
+        r->server_name.len = len;
+        r->server_name.data = host;
+    }
+
     return;
 
 found:
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -192,7 +192,7 @@ typedef struct {
     ngx_array_t                       cookies;
 
     size_t                            host_name_len;
-    ssize_t                           content_length_n;
+    off_t                             content_length_n;
     time_t                            keep_alive_n;
 
     unsigned                          connection_type:2;
@@ -250,7 +250,7 @@ typedef struct {
     ngx_temp_file_t                  *temp_file;
     ngx_chain_t                      *bufs;
     ngx_buf_t                        *buf;
-    size_t                            rest;
+    off_t                             rest;
     ngx_chain_t                      *to_write;
     ngx_http_client_body_handler_pt   post_handler;
 } ngx_http_request_body_t;
@@ -366,7 +366,7 @@ struct ngx_http_request_s {
     /* used to learn the Apache compatible response length without a header */
     size_t                            header_size;
 
-    size_t                            request_length;
+    off_t                             request_length;
 
     void                            **err_ctx;
     ngx_uint_t                        err_status;
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -30,7 +30,8 @@ ngx_int_t
 ngx_http_read_client_request_body(ngx_http_request_t *r,
     ngx_http_client_body_handler_pt post_handler)
 {
-    ssize_t                    size, preread;
+    size_t                     preread;
+    ssize_t                    size;
     ngx_buf_t                 *b;
     ngx_chain_t               *cl, **next;
     ngx_http_request_body_t   *rb;
@@ -95,7 +96,7 @@ ngx_http_read_client_request_body(ngx_ht
 
             /* the whole request body was pre-read */
 
-            r->header_in->pos += r->headers_in.content_length_n;
+            r->header_in->pos += (size_t) r->headers_in.content_length_n;
             r->request_length += r->headers_in.content_length_n;
 
             if (r->request_body_in_file_only) {
@@ -143,8 +144,8 @@ ngx_http_read_client_request_body(ngx_ht
     size = clcf->client_body_buffer_size;
     size += size >> 2;
 
-    if (rb->rest < (size_t) size) {
-        size = rb->rest;
+    if (rb->rest < size) {
+        size = (ssize_t) rb->rest;
 
         if (r->request_body_in_single_buf) {
             size += preread;
@@ -242,7 +243,7 @@ ngx_http_do_read_client_request_body(ngx
         size = rb->buf->end - rb->buf->last;
 
         if (size > rb->rest) {
-            size = rb->rest;
+            size = (size_t) rb->rest;
         }
 
         n = c->recv(c, rb->buf->last, size);
@@ -429,7 +430,7 @@ ngx_http_discard_body(ngx_http_request_t
             r->headers_in.content_length_n -= size;
 
         } else {
-            r->header_in->pos += r->headers_in.content_length_n;
+            r->header_in->pos += (size_t) r->headers_in.content_length_n;
             r->headers_in.content_length_n = 0;
             return NGX_OK;
         }
@@ -468,7 +469,8 @@ ngx_http_read_discarded_body_handler(ngx
 static ngx_int_t
 ngx_http_read_discarded_body(ngx_http_request_t *r)
 {
-    ssize_t  size, n;
+    size_t   size;
+    ssize_t  n;
     u_char   buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -478,12 +480,9 @@ ngx_http_read_discarded_body(ngx_http_re
         return NGX_OK;
     }
 
-
-    size = r->headers_in.content_length_n;
-
-    if (size > NGX_HTTP_DISCARD_BUFFER_SIZE) {
-        size = NGX_HTTP_DISCARD_BUFFER_SIZE;
-    }
+    size = (r->headers_in.content_length_n > NGX_HTTP_DISCARD_BUFFER_SIZE) ?
+                NGX_HTTP_DISCARD_BUFFER_SIZE:
+                (size_t) r->headers_in.content_length_n;
 
     n = r->connection->recv(r->connection, buffer, size);
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -226,7 +226,7 @@ static ngx_command_t  ngx_http_upstream_
       NULL },
 
     { ngx_string("server"),
-      NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12,
       ngx_http_upstream_server,
       NGX_HTTP_SRV_CONF_OFFSET,
       0,
@@ -2729,7 +2729,6 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_co
     }
 
     uscf->peers->number = n;
-    uscf->peers->weight = 1;
 
     n = 0;
 
@@ -2750,6 +2749,8 @@ ngx_http_upstream_server(ngx_conf_t *cf,
 
     ngx_str_t                    *value;
     ngx_url_t                     u;
+    ngx_int_t                     weight;
+    ngx_uint_t                    i;
     ngx_peers_t                 **peers;
 
     if (uscf->servers == NULL) {
@@ -2780,9 +2781,41 @@ ngx_http_upstream_server(ngx_conf_t *cf,
         return NGX_CONF_ERROR;
     }
 
+    weight = 1;
+
+    if (cf->args->nelts == 3) {
+
+        value = &value[2];
+
+        if (ngx_strncmp(value->data, "weight=", 7) == 0) {
+
+            weight = ngx_atoi(&value->data[7], value->len - 7);
+
+            if (weight == NGX_ERROR || weight == 0) {
+                goto invalid;
+            }
+
+        } else {
+            goto invalid;
+        }
+    }
+
+    for (i = 0; i < u.peers->number; i++) {
+        u.peers->peer[i].weight = weight;
+        u.peers->peer[i].current_weight = weight;
+        u.peers->peer[i].max_fails = NGX_CONF_UNSET_UINT;
+        u.peers->peer[i].fail_timeout = NGX_CONF_UNSET;
+    }
+
     *peers = u.peers;
 
     return NGX_CONF_OK;
+
+invalid:
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", value);
+
+    return NGX_CONF_ERROR;
 }
 
 
@@ -2893,8 +2926,7 @@ ngx_http_upstream_init_main_conf(ngx_con
         }
 
         uscfp[i]->peers = ngx_inet_resolve_peer(cf, &uscfp[i]->host,
-                          uscfp[i]->port);
-
+                                                uscfp[i]->port);
         if (uscfp[i]->peers == NULL) {
             return NGX_CONF_ERROR;
         }
@@ -2908,6 +2940,7 @@ ngx_http_upstream_init_main_conf(ngx_con
         }
     }
 
+
     if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
         != NGX_OK)
     {
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -56,8 +56,6 @@ typedef struct {
     ngx_str_t                       file_name;
     ngx_uint_t                      line;
     in_port_t                       port;
-
-    ngx_uint_t                      balanced;    /* unsigned  balanced:1; */
 } ngx_http_upstream_srv_conf_t;
 
 
--- a/src/imap/ngx_imap.h
+++ b/src/imap/ngx_imap.h
@@ -109,7 +109,7 @@ typedef enum {
     ngx_imap_start = 0,
     ngx_imap_login,
     ngx_imap_user,
-    ngx_imap_passwd,
+    ngx_imap_passwd
 } ngx_imap_state_e;
 
 
--- a/src/imap/ngx_imap_core_module.c
+++ b/src/imap/ngx_imap_core_module.c
@@ -205,7 +205,7 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t 
                               prev->imap_client_buffer_size,
                               (size_t) ngx_pagesize);
     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
-    ngx_conf_merge_unsigned_value(conf->protocol, prev->protocol,
+    ngx_conf_merge_uint_value(conf->protocol, prev->protocol,
                               NGX_IMAP_IMAP_PROTOCOL);
     ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0);
 
--- a/src/imap/ngx_imap_proxy_module.c
+++ b/src/imap/ngx_imap_proxy_module.c
@@ -23,7 +23,7 @@ static void ngx_imap_proxy_imap_handler(
 static void ngx_imap_proxy_pop3_handler(ngx_event_t *rev);
 static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev);
 static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s,
-    ngx_uint_t what);
+    ngx_uint_t state);
 static void ngx_imap_proxy_handler(ngx_event_t *ev);
 static void ngx_imap_proxy_internal_server_error(ngx_imap_session_t *s);
 static void ngx_imap_proxy_close_session(ngx_imap_session_t *s);
@@ -32,10 +32,6 @@ static char *ngx_imap_proxy_merge_conf(n
     void *child);
 
 
-#define NGX_IMAP_WAIT_OK      0
-#define NGX_IMAP_WAIT_NEXT    1
-
-
 static ngx_command_t  ngx_imap_proxy_commands[] = {
 
     { ngx_string("proxy"),
@@ -201,8 +197,7 @@ ngx_imap_proxy_imap_handler(ngx_event_t 
         }
     }
 
-    rc = ngx_imap_proxy_read_response(s, s->imap_state == ngx_imap_start ?
-                                      NGX_IMAP_WAIT_OK : NGX_IMAP_WAIT_NEXT);
+    rc = ngx_imap_proxy_read_response(s, s->imap_state);
 
     if (rc == NGX_AGAIN) {
         return;
@@ -274,6 +269,23 @@ ngx_imap_proxy_imap_handler(ngx_event_t 
         s->imap_state = ngx_imap_passwd;
         break;
 
+    case ngx_imap_passwd:
+        s->connection->read->handler = ngx_imap_proxy_handler;
+        s->connection->write->handler = ngx_imap_proxy_handler;
+        rev->handler = ngx_imap_proxy_handler;
+        c->write->handler = ngx_imap_proxy_handler;
+
+        pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module);
+        ngx_add_timer(s->connection->read, pcf->timeout);
+        ngx_del_timer(c->read);
+
+        c->log->action = NULL;
+        ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
+
+        ngx_imap_proxy_handler(s->connection->write);
+
+        return;
+
     default:
 #if (NGX_SUPPRESS_WARN)
         line.len = 0;
@@ -293,20 +305,6 @@ ngx_imap_proxy_imap_handler(ngx_event_t 
 
     s->proxy->buffer->pos = s->proxy->buffer->start;
     s->proxy->buffer->last = s->proxy->buffer->start;
-
-    if (s->imap_state == ngx_imap_passwd) {
-        s->connection->read->handler = ngx_imap_proxy_handler;
-        s->connection->write->handler = ngx_imap_proxy_handler;
-        rev->handler = ngx_imap_proxy_handler;
-        c->write->handler = ngx_imap_proxy_handler;
-
-        pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module);
-        ngx_add_timer(s->connection->read, pcf->timeout);
-        ngx_del_timer(c->read);
-
-        c->log->action = NULL;
-        ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
-    }
 }
 
 
@@ -344,7 +342,7 @@ ngx_imap_proxy_pop3_handler(ngx_event_t 
         }
     }
 
-    rc = ngx_imap_proxy_read_response(s, NGX_IMAP_WAIT_OK);
+    rc = ngx_imap_proxy_read_response(s, 0);
 
     if (rc == NGX_AGAIN) {
         return;
@@ -395,6 +393,23 @@ ngx_imap_proxy_pop3_handler(ngx_event_t 
         s->imap_state = ngx_pop3_passwd;
         break;
 
+    case ngx_pop3_passwd:
+        s->connection->read->handler = ngx_imap_proxy_handler;
+        s->connection->write->handler = ngx_imap_proxy_handler;
+        rev->handler = ngx_imap_proxy_handler;
+        c->write->handler = ngx_imap_proxy_handler;
+
+        pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module);
+        ngx_add_timer(s->connection->read, pcf->timeout);
+        ngx_del_timer(c->read);
+
+        c->log->action = NULL;
+        ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
+
+        ngx_imap_proxy_handler(s->connection->write);
+
+        return;
+
     default:
 #if (NGX_SUPPRESS_WARN)
         line.len = 0;
@@ -414,20 +429,6 @@ ngx_imap_proxy_pop3_handler(ngx_event_t 
 
     s->proxy->buffer->pos = s->proxy->buffer->start;
     s->proxy->buffer->last = s->proxy->buffer->start;
-
-    if (s->imap_state == ngx_pop3_passwd) {
-        s->connection->read->handler = ngx_imap_proxy_handler;
-        s->connection->write->handler = ngx_imap_proxy_handler;
-        rev->handler = ngx_imap_proxy_handler;
-        c->write->handler = ngx_imap_proxy_handler;
-
-        pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module);
-        ngx_add_timer(s->connection->read, pcf->timeout);
-        ngx_del_timer(c->read);
-
-        c->log->action = NULL;
-        ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
-    }
 }
 
 
@@ -449,7 +450,7 @@ ngx_imap_proxy_dummy_handler(ngx_event_t
 
 
 static ngx_int_t
-ngx_imap_proxy_read_response(ngx_imap_session_t *s, ngx_uint_t what)
+ngx_imap_proxy_read_response(ngx_imap_session_t *s, ngx_uint_t state)
 {
     u_char     *p;
     ssize_t     n;
@@ -496,15 +497,29 @@ ngx_imap_proxy_read_response(ngx_imap_se
         }
 
     } else {
-        if (what == NGX_IMAP_WAIT_OK) {
+        switch (state) {
+
+        case ngx_imap_start:
             if (p[0] == '*' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
                 return NGX_OK;
             }
+            break;
 
-        } else {
+        case ngx_imap_login:
+        case ngx_imap_user:
             if (p[0] == '+') {
                 return NGX_OK;
             }
+            break;
+
+        case ngx_imap_passwd:
+            if (ngx_strncmp(p, s->tag.data, s->tag.len) == 0) {
+                p += s->tag.len;
+                if (p[0] == 'O' && p[1] == 'K') {
+                    return NGX_OK;
+                }
+            }
+            break;
         }
     }
 
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -24,6 +24,7 @@ typedef int               ngx_err_t;
 #define NGX_EBUSY         EBUSY
 #define NGX_EEXIST        EEXIST
 #define NGX_ENOTDIR       ENOTDIR
+#define NGX_EISDIR        EISDIR
 #define NGX_EINVAL        EINVAL
 #define NGX_ENOSPC        ENOSPC
 #define NGX_EPIPE         EPIPE