changeset 530:4c5d2c627a6c NGINX_0_8_17

nginx 0.8.17 *) Security: now "/../" are disabled in "Destination" request header line. *) Change: now $host variable value is always low case. *) Feature: the $ssl_session_id variable. *) Bugfix: socket leak; the bug had appeared in 0.8.11.
author Igor Sysoev <http://sysoev.ru>
date Mon, 28 Sep 2009 00:00:00 +0400
parents b8ac674b0ec9
children 7688992d2abb
files CHANGES CHANGES.ru auto/lib/openssl/conf auto/lib/openssl/make src/core/nginx.h src/core/ngx_connection.c src/core/ngx_open_file_cache.c src/core/ngx_output_chain.c src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_core_module.c src/http/ngx_http_parse.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_request_body.c src/http/ngx_http_script.c src/http/ngx_http_upstream.c src/os/unix/ngx_atomic.h src/os/unix/ngx_files.c
diffstat 24 files changed, 262 insertions(+), 151 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,16 @@
 
+Changes with nginx 0.8.17                                        28 Sep 2009
+
+    *) Security: now "/../" are disabled in "Destination" request header 
+       line.
+
+    *) Change: now $host variable value is always low case.
+
+    *) Feature: the $ssl_session_id variable.
+
+    *) Bugfix: socket leak; the bug had appeared in 0.8.11.
+
+
 Changes with nginx 0.8.16                                        22 Sep 2009
 
     *) Feature: the "image_filter_transparency" directive.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,16 @@
 
+Изменения в nginx 0.8.17                                          28.09.2009
+
+    *) Безопасность: теперь символы "/../" запрещены в строке "Destination" 
+       в заголовке запроса.
+
+    *) Изменение: теперь значение переменной $host всегда в нижнем регистре.
+
+    *) Добавление: переменная $ssl_session_id.
+
+    *) Исправление: утечки сокетов; ошибка появилась в 0.8.11.
+
+
 Изменения в nginx 0.8.16                                          22.09.2009
 
     *) Добавление: директива image_filter_transparency.
--- a/auto/lib/openssl/conf
+++ b/auto/lib/openssl/conf
@@ -25,10 +25,10 @@ if [ $OPENSSL != NONE ]; then
             have=NGX_OPENSSL . auto/have
             have=NGX_SSL . auto/have
 
-            CORE_INCS="$CORE_INCS $OPENSSL/openssl/include"
-            CORE_DEPS="$CORE_DEPS $OPENSSL/openssl/include/openssl/ssl.h"
-            CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libssl.a"
-            CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libcrypto.a"
+            CORE_INCS="$CORE_INCS $OPENSSL/.openssl/include"
+            CORE_DEPS="$CORE_DEPS $OPENSSL/.openssl/include/openssl/ssl.h"
+            CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libssl.a"
+            CORE_LIBS="$CORE_LIBS $OPENSSL/.openssl/lib/libcrypto.a"
             CORE_LIBS="$CORE_LIBS $NGX_LIBDL"
         ;;
     esac
--- a/auto/lib/openssl/make
+++ b/auto/lib/openssl/make
@@ -46,13 +46,13 @@ END
         esac
 
         case $OPENSSL in
-            /*) ngx_prefix="$OPENSSL/openssl" ;;
-            *)  ngx_prefix="$PWD/$OPENSSL/openssl" ;;
+            /*) ngx_prefix="$OPENSSL/.openssl" ;;
+            *)  ngx_prefix="$PWD/$OPENSSL/.openssl" ;;
         esac
 
         cat << END                                            >> $NGX_MAKEFILE
 
-$OPENSSL/openssl/include/openssl/ssl.h:	$NGX_MAKEFILE
+$OPENSSL/.openssl/include/openssl/ssl.h:	$NGX_MAKEFILE
 	cd $OPENSSL \\
 	&& \$(MAKE) clean \\
 	&& ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8016
-#define NGINX_VERSION      "0.8.16"
+#define nginx_version         8017
+#define NGINX_VERSION      "0.8.17"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -917,12 +917,8 @@ ngx_connection_error(ngx_connection_t *c
             level = NGX_LOG_INFO;
             break;
 
-        case NGX_ERROR_ERR:
+        default:
             level = NGX_LOG_ERR;
-            break;
-
-        default:
-            level = NGX_LOG_ALERT;
         }
 
     } else {
--- a/src/core/ngx_open_file_cache.c
+++ b/src/core/ngx_open_file_cache.c
@@ -525,7 +525,7 @@ ngx_open_and_stat_file(u_char *name, ngx
         of->fd = fd;
 
         if (of->directio <= ngx_file_size(&fi)) {
-            if (ngx_directio_on(fd) == -1) {
+            if (ngx_directio_on(fd) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                               ngx_directio_on_n " \"%s\" failed", name);
 
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -514,7 +514,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
 #if (NGX_HAVE_ALIGNED_DIRECTIO)
 
         if (ctx->unaligned) {
-            if (ngx_directio_off(src->file->fd) == -1) {
+            if (ngx_directio_off(src->file->fd) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
                               ngx_directio_off_n " \"%s\" failed",
                               src->file->name.data);
@@ -550,7 +550,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
 
             err = ngx_errno;
 
-            if (ngx_directio_on(src->file->fd) == -1) {
+            if (ngx_directio_on(src->file->fd) == NGX_FILE_ERROR) {
                 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
                               ngx_directio_on_n " \"%s\" failed",
                               src->file->name.data);
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -1588,7 +1588,7 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_
     hash = ngx_crc32_short(sess->session_id, sess->session_id_length);
 
     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                   "http ssl new session: %08XD:%d:%d",
+                   "ssl new session: %08XD:%d:%d",
                    hash, sess->session_id_length, len);
 
     sess_id->node.key = hash;
@@ -1651,7 +1651,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_
     *copy = 0;
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                   "http ssl get session: %08XD:%d", hash, len);
+                   "ssl get session: %08XD:%d", hash, len);
 
     shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn),
                                    ngx_ssl_session_cache_index);
@@ -1765,7 +1765,7 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx
     hash = ngx_crc32_short(id, len);
 
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
-                   "http ssl remove session: %08XD:%uz", hash, len);
+                   "ssl remove session: %08XD:%uz", hash, len);
 
     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
 
@@ -1929,6 +1929,40 @@ ngx_ssl_get_cipher_name(ngx_connection_t
 
 
 ngx_int_t
+ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+    int           len;
+    u_char       *p, *buf;
+    SSL_SESSION  *sess;
+
+    sess = SSL_get0_session(c->ssl->connection);
+
+    len = i2d_SSL_SESSION(sess, NULL);
+
+    buf = ngx_alloc(len, c->log);
+    if (buf == NULL) {
+        return NGX_ERROR;
+    }
+
+    s->len = 2 * len;
+    s->data = ngx_pnalloc(pool, 2 * len);
+    if (s->data == NULL) {
+        ngx_free(buf);
+        return NGX_ERROR;
+    }
+
+    p = buf;
+    i2d_SSL_SESSION(sess, &p);
+
+    ngx_hex_dump(s->data, buf, len);
+
+    ngx_free(buf);
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
 {
     size_t   len;
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -118,6 +118,8 @@ ngx_int_t ngx_ssl_get_protocol(ngx_conne
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
+ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool,
+    ngx_str_t *s);
 ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool,
     ngx_str_t *s);
 ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool,
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -516,8 +516,8 @@ ngx_http_dav_copy_move_handler(ngx_http_
     size_t                    len, root;
     ngx_err_t                 err;
     ngx_int_t                 rc, depth;
-    ngx_uint_t                overwrite, slash, dir;
-    ngx_str_t                 path, uri;
+    ngx_uint_t                overwrite, slash, dir, flags;
+    ngx_str_t                 path, uri, duri, args;
     ngx_tree_ctx_t            tree;
     ngx_copy_file_t           cf;
     ngx_file_info_t           fi;
@@ -594,6 +594,14 @@ invalid_destination:
 
 destination_done:
 
+    duri.len = last - p;
+    duri.data = p;
+    flags = 0;
+
+    if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) {
+        goto invalid_destination;
+    }
+
     if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/')
         || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/'))
     {
@@ -656,9 +664,7 @@ overwrite_done:
                    "http copy from: \"%s\"", path.data);
 
     uri = r->uri;
-
-    r->uri.len = last - p;
-    r->uri.data = p;
+    r->uri = duri;
 
     ngx_http_map_uri_to_path(r, &copy.path, &root, 0);
 
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -222,7 +222,10 @@ ngx_http_index_handler(ngx_http_request_
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
             }
 
-            if (of.err == NGX_ENOTDIR || of.err == NGX_EACCES) {
+            if (of.err == NGX_ENOTDIR
+                || of.err == NGX_ENAMETOOLONG
+                || of.err == NGX_EACCES)
+            {
                 return ngx_http_index_error(r, clcf, path.data, of.err);
             }
 
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -1908,7 +1908,7 @@ ngx_http_ssi_include(ngx_http_request_t 
 
     args.len = 0;
     args.data = NULL;
-    flags = 0;
+    flags = NGX_HTTP_LOG_UNSAFE;
 
     if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
         return NGX_HTTP_SSI_ERROR;
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -184,6 +184,9 @@ static ngx_http_variable_t  ngx_http_ssl
     { ngx_string("ssl_cipher"), NULL, ngx_http_ssl_static_variable,
       (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
+    { ngx_string("ssl_session_id"), NULL, ngx_http_ssl_variable,
+      (uintptr_t) ngx_ssl_get_session_id, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
     { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 },
 
--- 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.8.16';
+our $VERSION = '0.8.17';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -994,7 +994,6 @@ ngx_http_core_post_rewrite_phase(ngx_htt
                       "rewrite or internal redirection cycle "
                       "while processing \"%V\"", &r->uri);
 
-        r->main->count++;
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
         return NGX_OK;
     }
@@ -1233,7 +1232,10 @@ ngx_http_core_try_files_phase(ngx_http_r
         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
             != NGX_OK)
         {
-            if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) {
+            if (of.err != NGX_ENOENT
+                && of.err != NGX_ENOTDIR
+                && of.err != NGX_ENAMETOOLONG)
+            {
                 ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
                               "%s \"%s\" failed", of.failed, path.data);
             }
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -1322,8 +1322,10 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
 
 unsafe:
 
-    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                  "unsafe URI \"%V\" was detected", uri);
+    if (*flags & NGX_HTTP_LOG_UNSAFE) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "unsafe URI \"%V\" was detected", uri);
+    }
 
     return NGX_ERROR;
 }
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -31,7 +31,8 @@ static ngx_int_t ngx_http_process_cookie
 
 static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r);
 static void ngx_http_process_request(ngx_http_request_t *r);
-static ssize_t ngx_http_validate_host(u_char *host, size_t len);
+static ssize_t ngx_http_validate_host(ngx_http_request_t *r, u_char **host,
+    size_t len, ngx_uint_t alloc);
 static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r,
     u_char *host, size_t len);
 
@@ -627,6 +628,7 @@ int
 ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
 {
     size_t                    len;
+    u_char                   *host;
     const char               *servername;
     ngx_connection_t         *c;
     ngx_http_request_t       *r;
@@ -651,7 +653,15 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *
 
     r = c->data;
 
-    if (ngx_http_find_virtual_server(r, (u_char *) servername, len) != NGX_OK) {
+    host = (u_char *) servername;
+
+    len = ngx_http_validate_host(r, &host, len, 1);
+
+    if (len <= 0) {
+        return SSL_TLSEXT_ERR_NOACK;
+    }
+
+    if (ngx_http_find_virtual_server(r, host, len) != NGX_OK) {
         return SSL_TLSEXT_ERR_NOACK;
     }
 
@@ -670,6 +680,7 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *
 static void
 ngx_http_process_request_line(ngx_event_t *rev)
 {
+    u_char                    *host;
     ssize_t                    n;
     ngx_int_t                  rc, rv;
     ngx_connection_t          *c;
@@ -801,18 +812,25 @@ ngx_http_process_request_line(ngx_event_
                            "http exten: \"%V\"", &r->exten);
 
             if (r->host_start && r->host_end) {
-                n = ngx_http_validate_host(r->host_start,
-                                           r->host_end - r->host_start);
-
-                if (n <= 0) {
+
+                host = r->host_start;
+                n = ngx_http_validate_host(r, &host,
+                                           r->host_end - r->host_start, 0);
+
+                if (n == 0) {
                     ngx_log_error(NGX_LOG_INFO, c->log, 0,
                                   "client sent invalid host in request line");
                     ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
                     return;
                 }
 
+                if (n < 0) {
+                    ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+                    return;
+                }
+
                 r->headers_in.server.len = n;
-                r->headers_in.server.data = r->host_start;
+                r->headers_in.server.data = host;
             }
 
             if (r->http_version < NGX_HTTP_VERSION_10) {
@@ -1312,27 +1330,34 @@ static ngx_int_t
 ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
-    ssize_t  len;
+    u_char   *host;
+    ssize_t   len;
 
     if (r->headers_in.host == NULL) {
         r->headers_in.host = h;
     }
 
-    len = ngx_http_validate_host(h->value.data, h->value.len);
-
-    if (len <= 0) {
+    host = h->value.data;
+    len = ngx_http_validate_host(r, &host, h->value.len, 0);
+
+    if (len == 0) {
         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                       "client sent invalid host header");
         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
         return NGX_ERROR;
     }
 
+    if (len < 0) {
+        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return NGX_ERROR;
+    }
+
     if (r->headers_in.server.len) {
         return NGX_OK;
     }
 
     r->headers_in.server.len = len;
-    r->headers_in.server.data = h->value.data;
+    r->headers_in.server.data = host;
 
     return NGX_OK;
 }
@@ -1588,21 +1613,23 @@ ngx_http_process_request(ngx_http_reques
 
 
 static ssize_t
-ngx_http_validate_host(u_char *host, size_t len)
+ngx_http_validate_host(ngx_http_request_t *r, u_char **host, size_t len,
+    ngx_uint_t alloc)
 {
-    u_char      ch;
-    size_t      i, last;
-    ngx_uint_t  dot;
+    u_char      *h, ch;
+    size_t       i, last;
+    ngx_uint_t   dot;
 
     last = len;
+    h = *host;
     dot = 0;
 
     for (i = 0; i < len; i++) {
-        ch = host[i];
+        ch = h[i];
 
         if (ch == '.') {
             if (dot) {
-                return -1;
+                return 0;
             }
 
             dot = 1;
@@ -1617,7 +1644,11 @@ ngx_http_validate_host(u_char *host, siz
         }
 
         if (ngx_path_separator(ch) || ch == '\0') {
-            return -1;
+            return 0;
+        }
+
+        if (ch >= 'A' || ch < 'Z') {
+            alloc = 1;
         }
     }
 
@@ -1625,6 +1656,15 @@ ngx_http_validate_host(u_char *host, siz
         last--;
     }
 
+    if (alloc) {
+        *host = ngx_pnalloc(r->pool, last) ;
+        if (*host == NULL) {
+            return -1;
+        }
+
+        ngx_strlow(*host, h, last);
+    }
+
     return last;
 }
 
@@ -1632,29 +1672,15 @@ ngx_http_validate_host(u_char *host, siz
 static ngx_int_t
 ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len)
 {
-    u_char                    *server;
-    ngx_uint_t                 hash;
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
-    u_char                     buf[32];
 
     if (r->virtual_names == NULL) {
         return NGX_DECLINED;
     }
 
-    if (len <= 32) {
-        server = buf;
-
-    } else {
-        server = ngx_pnalloc(r->pool, len);
-        if (server == NULL) {
-            return NGX_ERROR;
-        }
-    }
-
-    hash = ngx_hash_strlow(server, host, len);
-
-    cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len);
+    cscf = ngx_hash_find_combined(&r->virtual_names->names,
+                                  ngx_hash_key(host, len), host, len);
 
     if (cscf) {
         goto found;
@@ -1670,7 +1696,7 @@ ngx_http_find_virtual_server(ngx_http_re
         ngx_http_server_name_t  *sn;
 
         name.len = len;
-        name.data = server;
+        name.data = host;
 
         ncaptures = 0;
 
@@ -1686,16 +1712,6 @@ ngx_http_find_virtual_server(ngx_http_re
                 if (r->captures == NULL) {
                     return NGX_ERROR;
                 }
-
-                if (server == buf) {
-                    server = ngx_pnalloc(r->pool, len);
-                    if (server == NULL) {
-                        return NGX_ERROR;
-                    }
-
-                    ngx_memcpy(server, buf, len);
-                    name.data = server;
-                }
             }
 
             n = ngx_regex_exec(sn[i].regex, &name, r->captures, ncaptures);
@@ -1717,7 +1733,7 @@ ngx_http_find_virtual_server(ngx_http_re
             cscf = sn[i].core_srv_conf;
 
             r->ncaptures = ncaptures;
-            r->captures_data = server;
+            r->captures_data = host;
 
             goto found;
         }
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -60,6 +60,7 @@
 #define NGX_HTTP_ZERO_IN_URI               1
 #define NGX_HTTP_SUBREQUEST_IN_MEMORY      2
 #define NGX_HTTP_SUBREQUEST_WAITED         4
+#define NGX_HTTP_LOG_UNSAFE                8
 
 
 #define NGX_HTTP_OK                        200
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -477,8 +477,9 @@ ngx_http_discard_request_body(ngx_http_r
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    r->count++;
-    (void) ngx_http_read_discarded_request_body(r);
+    if (ngx_http_read_discarded_request_body(r) != NGX_OK) {
+        r->count++;
+    }
 
     return NGX_OK;
 }
@@ -562,12 +563,16 @@ ngx_http_read_discarded_request_body(ngx
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http read discarded body");
 
-    do {
+    for ( ;; ) {
         if (r->headers_in.content_length_n == 0) {
             r->read_event_handler = ngx_http_block_reading;
             return NGX_OK;
         }
 
+        if (!r->connection->read->ready) {
+            return NGX_AGAIN;
+        }
+
         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;
@@ -588,10 +593,7 @@ ngx_http_read_discarded_request_body(ngx
         }
 
         r->headers_in.content_length_n -= n;
-
-    } while (r->connection->read->ready);
-
-    return NGX_AGAIN;
+    }
 }
 
 
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -1417,7 +1417,10 @@ ngx_http_script_file_code(ngx_http_scrip
     if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
         != NGX_OK)
     {
-        if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) {
+        if (of.err != NGX_ENOENT
+            && of.err != NGX_ENOTDIR
+            && of.err != NGX_ENAMETOOLONG)
+        {
             ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
                           "%s \"%s\" failed", of.failed, value->data);
         }
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -532,7 +532,8 @@ ngx_http_upstream_init_request(ngx_http_
             if (ngx_http_upstream_create_round_robin_peer(r, u->resolved)
                 != NGX_OK)
             {
-                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+                ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
                 return;
             }
 
@@ -564,7 +565,8 @@ ngx_http_upstream_init_request(ngx_http_
 
         ctx = ngx_resolve_start(clcf->resolver, &temp);
         if (ctx == NULL) {
-            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
             return;
         }
 
@@ -572,7 +574,7 @@ ngx_http_upstream_init_request(ngx_http_
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                           "no resolver defined to resolve %V", host);
 
-            ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
+            ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
             return;
         }
 
@@ -586,7 +588,8 @@ ngx_http_upstream_init_request(ngx_http_
 
         if (ngx_resolve_name(ctx) != NGX_OK) {
             u->resolved->ctx = NULL;
-            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
             return;
         }
 
@@ -596,7 +599,8 @@ ngx_http_upstream_init_request(ngx_http_
 found:
 
     if (uscf->peer.init(r, uscf) != NGX_OK) {
-        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
     }
 
@@ -789,11 +793,13 @@ static void
 ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
 {
     ngx_http_request_t            *r;
+    ngx_http_upstream_t           *u;
     ngx_http_upstream_resolved_t  *ur;
 
     r = ctx->data;
 
-    r->upstream->resolved->ctx = NULL;
+    u = r->upstream;
+    ur = u->resolved;
 
     if (ctx->state) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -801,12 +807,10 @@ ngx_http_upstream_resolve_handler(ngx_re
                       &ctx->name, ctx->state,
                       ngx_resolver_strerror(ctx->state));
 
-        ngx_resolve_name_done(ctx);
-        ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
+        ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
         return;
     }
 
-    ur = r->upstream->resolved;
     ur->naddrs = ctx->naddrs;
     ur->addrs = ctx->addrs;
 
@@ -827,14 +831,15 @@ ngx_http_upstream_resolve_handler(ngx_re
 #endif
 
     if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) {
-        ngx_resolve_name_done(ctx);
-        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
     }
 
     ngx_resolve_name_done(ctx);
-
-    ngx_http_upstream_connect(r, r->upstream);
+    ur->ctx = NULL;
+
+    ngx_http_upstream_connect(r, u);
 }
 
 
@@ -921,10 +926,6 @@ ngx_http_upstream_check_broken_connectio
         return;
     }
 
-    if (u->peer.connection == NULL) {
-        return;
-    }
-
 #if (NGX_HAVE_KQUEUE)
 
     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
@@ -956,7 +957,6 @@ ngx_http_upstream_check_broken_connectio
         if (u->peer.connection == NULL) {
             ngx_http_upstream_finalize_request(r, u,
                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
-            return;
         }
 
         return;
@@ -1019,7 +1019,6 @@ ngx_http_upstream_check_broken_connectio
     if (u->peer.connection == NULL) {
         ngx_http_upstream_finalize_request(r, u,
                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
-        return;
     }
 }
 
@@ -1797,7 +1796,7 @@ ngx_http_upstream_process_headers(ngx_ht
         uri = &u->headers_in.x_accel_redirect->value;
         args.len = 0;
         args.data = NULL;
-        flags = 0;
+        flags = NGX_HTTP_LOG_UNSAFE;
 
         if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
             ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
@@ -2837,6 +2836,7 @@ ngx_http_upstream_cleanup(void *data)
 
     if (u->resolved && u->resolved->ctx) {
         ngx_resolve_name_done(u->resolved->ctx);
+        u->resolved->ctx = NULL;
     }
 
     ngx_http_upstream_finalize_request(r, u, NGX_DONE);
@@ -2856,6 +2856,11 @@ ngx_http_upstream_finalize_request(ngx_h
         *u->cleanup = NULL;
     }
 
+    if (u->resolved && u->resolved->ctx) {
+        ngx_resolve_name_done(u->resolved->ctx);
+        u->resolved->ctx = NULL;
+    }
+
     if (u->state && u->state->response_sec) {
         tp = ngx_timeofday();
         u->state->response_sec = tp->sec - u->state->response_sec;
--- a/src/os/unix/ngx_atomic.h
+++ b/src/os/unix/ngx_atomic.h
@@ -31,7 +31,7 @@
 
 typedef int64_t                     ngx_atomic_int_t;
 typedef uint64_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-9223372036854775808") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
 
 #define ngx_atomic_cmp_set(lock, old, new)                                    \
     OSAtomicCompareAndSwap64Barrier(old, new, (int64_t *) lock)
@@ -43,7 +43,7 @@ typedef uint64_t                    ngx_
 
 typedef int32_t                     ngx_atomic_int_t;
 typedef uint32_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-2147483648") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
 
 #define ngx_atomic_cmp_set(lock, old, new)                                    \
     OSAtomicCompareAndSwap32Barrier(old, new, (int32_t *) lock)
@@ -68,7 +68,7 @@ typedef volatile ngx_atomic_uint_t  ngx_
 typedef int32_t                     ngx_atomic_int_t;
 typedef uint32_t                    ngx_atomic_uint_t;
 typedef volatile ngx_atomic_uint_t  ngx_atomic_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-2147483648") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
 
 
 #if ( __SUNPRO_C )
@@ -109,7 +109,7 @@ ngx_cpu_pause(void);
 typedef int64_t                     ngx_atomic_int_t;
 typedef uint64_t                    ngx_atomic_uint_t;
 typedef volatile ngx_atomic_uint_t  ngx_atomic_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-9223372036854775808") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
 
 
 #if ( __SUNPRO_C )
@@ -151,13 +151,13 @@ ngx_cpu_pause(void);
 
 typedef int64_t                     ngx_atomic_int_t;
 typedef uint64_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-9223372036854775808") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
 
 #else
 
 typedef int32_t                     ngx_atomic_int_t;
 typedef uint32_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-2147483648") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
 
 #endif
 
@@ -188,13 +188,13 @@ typedef volatile ngx_atomic_uint_t  ngx_
 
 typedef int64_t                     ngx_atomic_int_t;
 typedef uint64_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-9223372036854775808") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-9223372036854775808") - 1)
 
 #else
 
 typedef int32_t                     ngx_atomic_int_t;
 typedef uint32_t                    ngx_atomic_uint_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-2147483648") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
 
 #endif
 
@@ -216,7 +216,7 @@ typedef volatile ngx_atomic_uint_t  ngx_
 typedef int32_t                     ngx_atomic_int_t;
 typedef uint32_t                    ngx_atomic_uint_t;
 typedef volatile ngx_atomic_uint_t  ngx_atomic_t;
-#define NGX_ATOMIC_T_LEN            sizeof("-2147483648") - 1
+#define NGX_ATOMIC_T_LEN            (sizeof("-2147483648") - 1)
 
 
 static ngx_inline ngx_atomic_uint_t
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -22,7 +22,7 @@ ngx_read_file(ngx_file_t *file, u_char *
 
     if (n == -1) {
         ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
-                      "pread() failed, file \"%s\"", file->name.data);
+                      "pread() \"%s\" failed", file->name.data);
         return NGX_ERROR;
     }
 
@@ -30,7 +30,8 @@ ngx_read_file(ngx_file_t *file, u_char *
 
     if (file->sys_offset != offset) {
         if (lseek(file->fd, offset, SEEK_SET) == -1) {
-            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "lseek() \"%s\" failed", file->name.data);
             return NGX_ERROR;
         }
 
@@ -40,7 +41,8 @@ ngx_read_file(ngx_file_t *file, u_char *
     n = read(file->fd, buf, size);
 
     if (n == -1) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "read() failed");
+        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                      "read() \"%s\" failed", file->name.data);
         return NGX_ERROR;
     }
 
@@ -57,57 +59,66 @@ ngx_read_file(ngx_file_t *file, u_char *
 ssize_t
 ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
 {
-    ssize_t  n;
+    ssize_t  n, written;
 
     ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
                    "write: %d, %p, %uz, %O", file->fd, buf, size, offset);
 
+    written = 0;
+
 #if (NGX_HAVE_PWRITE)
 
-    n = pwrite(file->fd, buf, size, offset);
+    for ( ;; ) {
+        n = pwrite(file->fd, buf, size, offset);
+
+        if (n == -1) {
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "pwrite() \"%s\" failed", file->name.data);
+            return NGX_ERROR;
+        }
 
-    if (n == -1) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "pwrite() failed");
-        return NGX_ERROR;
-    }
+        file->offset += n;
+        written += n;
 
-    if ((size_t) n != size) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, 0,
-                      "pwrite() has written only %z of %uz", n, size);
-        return NGX_ERROR;
+        if ((size_t) n == size) {
+            return written;
+        }
+
+        offset += n;
+        size -= n;
     }
 
 #else
 
     if (file->sys_offset != offset) {
         if (lseek(file->fd, offset, SEEK_SET) == -1) {
-            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "lseek() \"%s\" failed", file->name.data);
             return NGX_ERROR;
         }
 
         file->sys_offset = offset;
     }
 
-    n = write(file->fd, buf, size);
+    for ( ;; ) {
+        n = write(file->fd, buf, size);
 
-    if (n == -1) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "write() failed");
-        return NGX_ERROR;
-    }
+        if (n == -1) {
+            ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
+                          "write() \"%s\" failed", file->name.data);
+            return NGX_ERROR;
+        }
 
-    if ((size_t) n != size) {
-        ngx_log_error(NGX_LOG_CRIT, file->log, 0,
-                      "write() has written only %z of %uz", n, size);
-        return NGX_ERROR;
-    }
+        file->offset += n;
+        written += n;
 
-    file->sys_offset += n;
-
-#endif
+        if ((size_t) n == size) {
+            return written;
+        }
 
-    file->offset += n;
-
-    return n;
+        size -= n;
+    }
+#endif
 }
 
 
@@ -191,7 +202,7 @@ ngx_write_chain_to_file(ngx_file_t *file
         if (file->sys_offset != offset) {
             if (lseek(file->fd, offset, SEEK_SET) == -1) {
                 ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
-                              "lseek() failed");
+                              "lseek() \"%s\" failed", file->name.data);
                 return NGX_ERROR;
             }
 
@@ -202,13 +213,14 @@ ngx_write_chain_to_file(ngx_file_t *file
 
         if (n == -1) {
             ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
-                          "writev() failed");
+                          "writev() \"%s\" failed", file->name.data);
             return NGX_ERROR;
         }
 
         if ((size_t) n != size) {
             ngx_log_error(NGX_LOG_CRIT, file->log, 0,
-                          "writev() has written only %z of %uz", n, size);
+                          "writev() \"%s\" has written only %z of %uz",
+                          file->name.data, n, size);
             return NGX_ERROR;
         }
 
@@ -394,7 +406,7 @@ ngx_directio_on(ngx_fd_t fd)
     flags = fcntl(fd, F_GETFL);
 
     if (flags == -1) {
-        return -1;
+        return NGX_FILE_ERROR;
     }
 
     return fcntl(fd, F_SETFL, flags | O_DIRECT);
@@ -409,7 +421,7 @@ ngx_directio_off(ngx_fd_t fd)
     flags = fcntl(fd, F_GETFL);
 
     if (flags == -1) {
-        return -1;
+        return NGX_FILE_ERROR;
     }
 
     return fcntl(fd, F_SETFL, flags & ~O_DIRECT);