changeset 364:a39aab45a53f NGINX_0_6_26

nginx 0.6.26 *) Bugfix: the "proxy_store" and "fastcgi_store" directives did not check a response length. *) Bugfix: a segmentation fault occurred in worker process, if big value was used in a "expires" directive. Thanks to Joaquin Cuenca Abela. *) Bugfix: nginx incorrectly detected cache line size on Pentium 4. Thanks to Gena Makhomed. *) Bugfix: in proxied or FastCGI subrequests a client original method was used instead of the GET method. *) Bugfix: socket leak in HTTPS mode if deferred accept was used. Thanks to Ben Maurer. *) Bugfix: nginx issued the bogus error message "SSL_shutdown() failed (SSL: )"; bug appeared in 0.6.23. *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" error; bug appeared in 0.6.23.
author Igor Sysoev <http://sysoev.ru>
date Mon, 11 Feb 2008 00:00:00 +0300
parents 6999caedb665
children 9b0140fa1132
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_connection.c src/core/ngx_cpuinfo.c src/core/ngx_inet.c src/core/ngx_resolver.c src/core/ngx_string.c src/core/ngx_times.c src/event/modules/ngx_eventport_module.c src/event/modules/ngx_rtsig_module.c src/event/ngx_event_connect.c src/event/ngx_event_openssl.c src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h src/http/ngx_http_upstream_round_robin.c src/os/unix/ngx_errno.h src/os/unix/ngx_recv.c
diffstat 25 files changed, 222 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,29 @@
 
+Changes with nginx 0.6.26                                        11 Feb 2008
+
+    *) Bugfix: the "proxy_store" and "fastcgi_store" directives did not 
+       check a response length.
+
+    *) Bugfix: a segmentation fault occurred in worker process, if big 
+       value was used in a "expires" directive.
+       Thanks to Joaquin Cuenca Abela.
+
+    *) Bugfix: nginx incorrectly detected cache line size on Pentium 4.
+       Thanks to Gena Makhomed.
+
+    *) Bugfix: in proxied or FastCGI subrequests a client original method 
+       was used instead of the GET method.
+
+    *) Bugfix: socket leak in HTTPS mode if deferred accept was used.
+       Thanks to Ben Maurer.
+
+    *) Bugfix: nginx issued the bogus error message "SSL_shutdown() failed 
+       (SSL: )"; bug appeared in 0.6.23.
+
+    *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" 
+       error; bug appeared in 0.6.23.
+
+
 Changes with nginx 0.6.25                                        08 Jan 2008
 
     *) Change: now the "server_name_in_redirect" directive is used instead 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,32 @@
 
+Изменения в nginx 0.6.26                                          11.02.2008
+
+    *) Исправление: директивы proxy_store и fastcgi_store не проверяли 
+       длину ответа.
+
+    *) Исправление: при использовании большого значения в директиве expires 
+       в рабочем процессе происходил segmentation fault.
+       Спасибо Joaquin Cuenca Abela.
+
+    *) Исправление: nginx неверно определял длину строки кэша на 
+       Pentium 4.
+       Спасибо Gena Makhomed.
+
+    *) Исправление: в проксированных подзапросах и подзапросах к 
+       FastCGI-серверу вместо метода GET использовался оригинальный метод 
+       клиента.
+
+    *) Исправление: утечки сокетов в режиме HTTPS при использовании 
+       отложенного accept'а.
+       Спасибо Ben Maurer.
+
+    *) Исправление: nginx выдавал ошибочное сообщение "SSL_shutdown() 
+       failed (SSL: )"; ошибка появилась в 0.6.23.
+
+    *) Исправление: при использовании HTTPS запросы могли завершаться с 
+       ошибкой "bad write retry"; ошибка появилась в 0.6.23.
+
+
 Изменения в nginx 0.6.25                                          08.01.2008
 
     *) Изменение: вместо специального параметра "*" в директиве server_name 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.6.25"
+#define NGINX_VERSION      "0.6.26"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -767,6 +767,9 @@ ngx_connection_error(ngx_connection_t *c
         || err == NGX_ENOTCONN
         || err == NGX_ETIMEDOUT
         || err == NGX_ECONNREFUSED
+        || err == NGX_ENETDOWN
+        || err == NGX_ENETUNREACH
+        || err == NGX_EHOSTDOWN
         || err == NGX_EHOSTUNREACH)
     {
         switch (c->log_error) {
--- a/src/core/ngx_cpuinfo.c
+++ b/src/core/ngx_cpuinfo.c
@@ -92,13 +92,22 @@ ngx_cpuinfo(void)
 
     if (ngx_strcmp(vendor, "GenuineIntel") == 0) {
 
-        switch (cpu[0] & 0xf00) {
+        switch ((cpu[0] & 0xf00) >> 8) {
 
         /* Pentium */
         case 5:
+            ngx_cacheline_size = 32;
+            break;
+
         /* Pentium Pro, II, III */
         case 6:
             ngx_cacheline_size = 32;
+
+            if ((cpu[0] & 0xf0) >= 0xd0) {
+                /* Intel Core */
+                ngx_cacheline_size = 64;
+            }
+
             break;
 
         /*
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -212,7 +212,7 @@ ngx_sprint_uchar(u_char *text, u_char c,
 
     c2 = c % 10;
 
-    *text++ = (u_char) (c2 + '0');
+    *text = (u_char) (c2 + '0');
     n++;
 
     return n;
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -215,10 +215,9 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx
 
     if (ctx->event) {
         ngx_resolver_free_locked(r, ctx->event);
+        ctx->event = NULL;
     }
 
-    ngx_resolver_free_locked(r, ctx);
-
     /* unlock alloc mutex */
 
     return NGX_ERROR;
@@ -787,9 +786,9 @@ ngx_resolver_resend(ngx_resolver_t *r, n
                 rn->expire = now + r->resend_timeout;
 
                 ngx_queue_insert_head(queue, &rn->queue);
-
-                continue;
             }
+
+            continue;
         }
 
         ngx_rbtree_delete(tree, &rn->node);
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -147,7 +147,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c
             sign = 1;
             hexadecimal = 0;
             max_width = 0;
-            slen = 0;
+            slen = (size_t) -1;
 
             p = temp + NGX_INT64_LEN;
 
@@ -182,7 +182,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c
                     continue;
 
                 case '*':
-                    slen = va_arg(args, u_int);
+                    slen = va_arg(args, size_t);
                     fmt++;
                     continue;
 
@@ -221,13 +221,15 @@ ngx_vsnprintf(u_char *buf, size_t max, c
             case 's':
                 p = va_arg(args, u_char *);
 
-                if (slen == 0) {
+                if (slen == (size_t) -1) {
                     while (*p && buf < last) {
                         *buf++ = *p++;
                     }
 
                 } else {
-                    buf = ngx_cpymem(buf, p, slen);
+                    len = (buf + slen < last) ? slen : (size_t) (last - buf);
+
+                    buf = ngx_cpymem(buf, p, len);
                 }
 
                 fmt++;
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -203,18 +203,21 @@ ngx_http_cookie_time(u_char *buf, time_t
 void
 ngx_gmtime(time_t t, ngx_tm_t *tp)
 {
-    ngx_int_t  sec, min, hour, mday, mon, year, wday, yday, days;
+    ngx_uint_t  n, sec, min, hour, mday, mon, year, wday, yday, days;
 
-    days = (ngx_int_t) (t / 86400);
+    /* the calculation is valid for positive time_t only */
+    n = (ngx_uint_t) t;
+
+    days = n / 86400;
 
     /* Jaunary 1, 1970 was Thursday */
     wday = (4 + days) % 7;
 
-    t %= 86400;
-    hour = (ngx_int_t) (t / 3600);
-    t %= 3600;
-    min = (ngx_int_t) (t / 60);
-    sec = (ngx_int_t) (t % 60);
+    n %= 86400;
+    hour = n / 3600;
+    n %= 3600;
+    min = n / 60;
+    sec = n % 60;
 
     /* the algorithm based on Gauss's formula */
 
--- a/src/event/modules/ngx_eventport_module.c
+++ b/src/event/modules/ngx_eventport_module.c
@@ -40,11 +40,6 @@ typedef struct  port_notify {
     void       *portnfy_user;   /* user defined */
 } port_notify_t;
 
-typedef struct itimerspec {     /* definition per POSIX.4 */
-    struct timespec it_interval;/* timer period */
-    struct timespec it_value;   /* timer expiration */
-} itimerspec_t;
-
 int port_create(void)
 {
     return -1;
@@ -106,7 +101,7 @@ static char *ngx_eventport_init_conf(ngx
 static int            ep = -1;
 static port_event_t  *event_list;
 static ngx_uint_t     nevents;
-static timer_t        event_timer = -1;
+static timer_t        event_timer = (timer_t) -1;
 
 static ngx_str_t      eventport_name = ngx_string("eventport");
 
@@ -237,13 +232,13 @@ ngx_eventport_init(ngx_cycle_t *cycle, n
 static void
 ngx_eventport_done(ngx_cycle_t *cycle)
 {
-    if (event_timer != -1) {
+    if (event_timer != (timer_t) -1) {
         if (timer_delete(event_timer) == -1) {
             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                           "timer_delete() failed");
         }
 
-        event_timer = -1;
+        event_timer = (timer_t) -1;
     }
 
     if (close(ep) == -1) {
--- a/src/event/modules/ngx_rtsig_module.c
+++ b/src/event/modules/ngx_rtsig_module.c
@@ -12,8 +12,7 @@
 #if (NGX_TEST_BUILD_RTSIG)
 
 #define F_SETSIG       10
-#define SIGRTMIN       33
-#define si_fd          __spare__[0]
+#define si_fd          _reason.__spare__.__spare2__[0]
 #define KERN_RTSIGNR   30
 #define KERN_RTSIGMAX  31
 
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -143,8 +143,14 @@ ngx_event_connect_peer(ngx_peer_connecti
 
         if (err != NGX_EINPROGRESS && err != NGX_EAGAIN) {
 
-            if (err == NGX_ECONNREFUSED || err == NGX_EHOSTUNREACH) {
+            if (err == NGX_ECONNREFUSED
+                || err == NGX_ENETDOWN
+                || err == NGX_ENETUNREACH
+                || err == NGX_EHOSTDOWN
+                || err == NGX_EHOSTUNREACH)
+            {
                 level = NGX_LOG_ERR;
+
             } else {
                 level = NGX_LOG_CRIT;
             }
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -187,6 +187,13 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
         SSL_CTX_set_options(ssl->ctx, ngx_ssl_protocols[protocols >> 1]);
     }
 
+    /*
+     * we need this option because in ngx_ssl_send_chain()
+     * we may switch to a buffered write and may copy leftover part of
+     * previously unbuffered data to our internal buffer
+     */
+    SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
     SSL_CTX_set_read_ahead(ssl->ctx, 1);
 
     return NGX_OK;
@@ -1035,19 +1042,16 @@ ngx_ssl_shutdown(ngx_connection_t *c)
 
     sslerr = 0;
 
-    /* SSL_shutdown() never return -1, on error it return 0 */
-
-    if (n != 1) {
+    /* SSL_shutdown() never returns -1, on error it returns 0 */
+
+    if (n != 1 && ERR_peek_error()) {
         sslerr = SSL_get_error(c->ssl->connection, n);
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
                        "SSL_get_error: %d", sslerr);
     }
 
-    if (n == 1
-        || sslerr == SSL_ERROR_ZERO_RETURN
-        || (sslerr == 0 && c->timedout))
-    {
+    if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {
         SSL_free(c->ssl->connection);
         c->ssl = NULL;
 
@@ -1111,6 +1115,7 @@ static void
 ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
     char *text)
 {
+    int         n;
     ngx_uint_t  level;
 
     level = NGX_LOG_CRIT;
@@ -1124,6 +1129,9 @@ ngx_ssl_connection_error(ngx_connection_
             || err == NGX_ETIMEDOUT
 #endif
             || err == NGX_ECONNREFUSED
+            || err == NGX_ENETDOWN
+            || err == NGX_ENETUNREACH
+            || err == NGX_EHOSTDOWN
             || err == NGX_EHOSTUNREACH)
         {
             switch (c->log_error) {
@@ -1141,6 +1149,35 @@ ngx_ssl_connection_error(ngx_connection_
                 break;
             }
         }
+
+    } else if (sslerr == SSL_ERROR_SSL) {
+
+        n = ERR_GET_REASON(ERR_peek_error());
+
+            /* handshake failures */
+        if (n == SSL_R_NO_SHARED_CIPHER
+            || n == SSL_R_UNEXPECTED_MESSAGE
+            || n == SSL_R_WRONG_VERSION_NUMBER
+            || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
+            || n == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED
+            || n == SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER
+            || n == SSL_R_TLSV1_ALERT_UNKNOWN_CA)
+        {
+            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);
@@ -1150,18 +1187,21 @@ ngx_ssl_connection_error(ngx_connection_
 static void
 ngx_ssl_clear_error(ngx_log_t *log)
 {
-    if (ERR_peek_error()) {
+    while (ERR_peek_error()) {
         ngx_ssl_error(NGX_LOG_ALERT, log, 0, "ignoring stale global SSL error");
     }
+
+    ERR_clear_error();
 }
 
 
 void ngx_cdecl
 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;
+    u_long    n;
+    va_list   args;
+    u_char   *p, *last;
+    u_char    errstr[NGX_MAX_CONF_ERRSTR];
 
     last = errstr + NGX_MAX_CONF_ERRSTR;
 
@@ -1171,7 +1211,7 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_
 
     p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
 
-    while (p < last) {
+    for ( ;; ) {
 
         n = ERR_get_error();
 
@@ -1179,6 +1219,10 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_
             break;
         }
 
+        if (p >= last) {
+            continue;
+        }
+
         *p++ = ' ';
 
         ERR_error_string_n(n, (char *) p, last - p);
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -1140,7 +1140,7 @@ ngx_http_dav_create_loc_conf(ngx_conf_t 
      *     conf->methods = 0;
      */
 
-    conf->min_delete_depth = NGX_CONF_UNSET;
+    conf->min_delete_depth = NGX_CONF_UNSET_UINT;
     conf->access = NGX_CONF_UNSET_UINT;
     conf->create_full_put_path = NGX_CONF_UNSET;
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -135,33 +135,6 @@ static char *ngx_http_fastcgi_upstream_f
     ngx_command_t *cmd, void *conf);
 
 
-static ngx_http_fastcgi_request_start_t  ngx_http_fastcgi_request_start = {
-    { 1,                                               /* version */
-      NGX_HTTP_FASTCGI_BEGIN_REQUEST,                  /* type */
-      0,                                               /* request_id_hi */
-      1,                                               /* request_id_lo */
-      0,                                               /* content_length_hi */
-      sizeof(ngx_http_fastcgi_begin_request_t),        /* content_length_lo */
-      0,                                               /* padding_length */
-      0 },                                             /* reserved */
-
-    { 0,                                               /* role_hi */
-      NGX_HTTP_FASTCGI_RESPONDER,                      /* role_lo */
-      0, /* NGX_HTTP_FASTCGI_KEEP_CONN */              /* flags */
-      { 0, 0, 0, 0, 0 } },                             /* reserved[5] */
-
-    { 1,                                               /* version */
-      NGX_HTTP_FASTCGI_PARAMS,                         /* type */
-      0,                                               /* request_id_hi */
-      1 },                                             /* request_id_lo */
-
-};
-
-
-static ngx_str_t  ngx_http_fastcgi_script_name =
-    ngx_string("fastcgi_script_name");
-
-
 static ngx_conf_post_t  ngx_http_fastcgi_lowat_post =
     { ngx_http_fastcgi_lowat_check };
 
@@ -412,12 +385,40 @@ ngx_module_t  ngx_http_fastcgi_module = 
 };
 
 
+static ngx_http_fastcgi_request_start_t  ngx_http_fastcgi_request_start = {
+    { 1,                                               /* version */
+      NGX_HTTP_FASTCGI_BEGIN_REQUEST,                  /* type */
+      0,                                               /* request_id_hi */
+      1,                                               /* request_id_lo */
+      0,                                               /* content_length_hi */
+      sizeof(ngx_http_fastcgi_begin_request_t),        /* content_length_lo */
+      0,                                               /* padding_length */
+      0 },                                             /* reserved */
+
+    { 0,                                               /* role_hi */
+      NGX_HTTP_FASTCGI_RESPONDER,                      /* role_lo */
+      0, /* NGX_HTTP_FASTCGI_KEEP_CONN */              /* flags */
+      { 0, 0, 0, 0, 0 } },                             /* reserved[5] */
+
+    { 1,                                               /* version */
+      NGX_HTTP_FASTCGI_PARAMS,                         /* type */
+      0,                                               /* request_id_hi */
+      1 },                                             /* request_id_lo */
+
+};
+
+
+static ngx_str_t  ngx_http_fastcgi_script_name =
+    ngx_string("fastcgi_script_name");
+
+
 static ngx_str_t  ngx_http_fastcgi_hide_headers[] = {
     ngx_string("Status"),
     ngx_string("X-Accel-Expires"),
     ngx_string("X-Accel-Redirect"),
     ngx_string("X-Accel-Limit-Rate"),
-    ngx_string("X-Accel-Buffer"),
+    ngx_string("X-Accel-Buffering"),
+    ngx_string("X-Accel-Charset"),
     ngx_null_string
 };
 
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -435,7 +435,8 @@ static ngx_str_t  ngx_http_proxy_hide_he
     ngx_string("X-Accel-Expires"),
     ngx_string("X-Accel-Redirect"),
     ngx_string("X-Accel-Limit-Rate"),
-    ngx_string("X-Accel-Buffer"),
+    ngx_string("X-Accel-Buffering"),
+    ngx_string("X-Accel-Charset"),
     ngx_null_string
 };
 
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.6.25';
+our $VERSION = '0.6.26';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -652,6 +652,9 @@ ngx_module_t  ngx_http_core_module = {
 };
 
 
+static ngx_str_t  ngx_http_core_get_method = { 3, (u_char *) "GET " };
+
+
 void
 ngx_http_handler(ngx_http_request_t *r)
 {
@@ -1760,7 +1763,7 @@ ngx_http_subrequest(ngx_http_request_t *
     sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0;
 
     sr->unparsed_uri = r->unparsed_uri;
-    sr->method_name = r->method_name;
+    sr->method_name = ngx_http_core_get_method;
     sr->http_protocol = r->http_protocol;
 
     if (ngx_http_set_exten(sr) != NGX_OK) {
@@ -2909,7 +2912,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
         if (conf->resolver == NULL) {
             conf->resolver = ngx_resolver_create(NULL, cf->cycle->new_log);
             if (conf->resolver == NULL) {
-                return NGX_OK;
+                return NGX_CONF_ERROR;
             }
         }
     }
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -479,6 +479,15 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
     n = recv(c->fd, (char *) buf, 1, MSG_PEEK);
 
     if (n == -1 && ngx_socket_errno == NGX_EAGAIN) {
+
+        if (!rev->timer_set) {
+            ngx_add_timer(rev, c->listening->post_accept_timeout);
+        }
+
+        if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
+            ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        }
+
         return;
     }
 
@@ -985,10 +994,9 @@ ngx_http_read_request_header(ngx_http_re
     }
 
     if (n == NGX_AGAIN) {
-        if (!r->header_timeout_set) {
+        if (!rev->timer_set) {
             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
             ngx_add_timer(rev, cscf->client_header_timeout);
-            r->header_timeout_set = 1;
         }
 
         if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -427,8 +427,6 @@ struct ngx_http_request_s {
     unsigned                          fast_subrequest:1;
     unsigned                          subrequest_in_memory:1;
 
-    unsigned                          header_timeout_set:1;
-
     unsigned                          gzip:2;
 
     unsigned                          proxy:1;
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1352,6 +1352,8 @@ ngx_http_upstream_process_header(ngx_eve
     r->headers_out.status = u->headers_in.status_n;
     r->headers_out.status_line = u->headers_in.status_line;
 
+    u->headers_in.content_length_n = r->headers_out.content_length_n;
+
     if (r->headers_out.content_length_n != -1) {
         u->length = (size_t) r->headers_out.content_length_n;
 
@@ -1955,6 +1957,7 @@ ngx_http_upstream_process_downstream(ngx
 static void
 ngx_http_upstream_process_body(ngx_event_t *ev)
 {
+    ngx_temp_file_t      *tf;
     ngx_event_pipe_t     *p;
     ngx_connection_t     *c, *downstream;
     ngx_http_log_ctx_t   *ctx;
@@ -2049,18 +2052,22 @@ ngx_http_upstream_process_body(ngx_event
 
         if (u->store) {
 
-            if (p->upstream_eof && u->headers_in.status_n == NGX_HTTP_OK) {
-
+            tf = u->pipe->temp_file;
+
+            if (p->upstream_eof
+                && u->headers_in.status_n == NGX_HTTP_OK
+                && (u->headers_in.content_length_n == -1
+                    || (u->headers_in.content_length_n == tf->offset)))
+            {
                 ngx_http_upstream_store(r, u);
 
             } else if ((p->upstream_error
                         || (p->upstream_eof
                             && u->headers_in.status_n != NGX_HTTP_OK))
-                       && u->pipe->temp_file->file.fd != NGX_INVALID_FILE)
+                       && tf->file.fd != NGX_INVALID_FILE)
             {
-                if (ngx_delete_file(u->pipe->temp_file->file.name.data)
-                    == NGX_FILE_ERROR)
-                {
+                if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
+
                     ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                                   ngx_delete_file_n " \"%s\" failed",
                                   u->pipe->temp_file->file.name.data);
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -192,6 +192,8 @@ typedef struct {
     ngx_table_elt_t                *content_encoding;
 #endif
 
+    off_t                           content_length_n;
+
     ngx_array_t                     cache_control;
 } ngx_http_upstream_headers_in_t;
 
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -605,7 +605,7 @@ ngx_http_upstream_get_peer(ngx_http_upst
         }
 
         for (i = 0; i < peers->number; i++) {
-            peer[i].current_weight += peer[i].weight;
+            peer[i].current_weight = peer[i].weight;
         }
     }
 }
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -37,6 +37,9 @@ typedef int               ngx_err_t;
 #define NGX_ETIMEDOUT     ETIMEDOUT
 #define NGX_ECONNREFUSED  ECONNREFUSED
 #define NGX_ENAMETOOLONG  ENAMETOOLONG
+#define NGX_ENETDOWN      ENETDOWN
+#define NGX_ENETUNREACH   ENETUNREACH
+#define NGX_EHOSTDOWN     EHOSTDOWN
 #define NGX_EHOSTUNREACH  EHOSTUNREACH
 #define NGX_ENOSYS        ENOSYS
 #define NGX_ECANCELED     ECANCELED
--- a/src/os/unix/ngx_recv.c
+++ b/src/os/unix/ngx_recv.c
@@ -41,6 +41,7 @@ ngx_unix_recv(ngx_connection_t *c, u_cha
                 return 0;
 
             } else {
+                rev->ready = 0;
                 return NGX_AGAIN;
             }
         }