changeset 276:c5c2b2883984 NGINX_0_5_8

nginx 0.5.8 *) Bugfix: a segmentation fault might occur if "client_body_in_file_only on" was used and a request body was small. *) Bugfix: a segmentation fault occurred if "client_body_in_file_only on" and "proxy_pass_request_body off" or "fastcgi_pass_request_body off" directives were used, and nginx switched to a next upstream. *) Bugfix: if the "proxy_buffering off" directive was used and a client connection was non-active, then the connection was closed after send timeout; bug appeared in 0.4.7. *) Bugfix: if the "epoll" method was used and a client closed a connection prematurely, then nginx closed the connection after a send timeout only. *) Bugfix: the "[alert] zero size buf" error when FastCGI server was used. *) Bugfixes in the "limit_zone" directive.
author Igor Sysoev <http://sysoev.ru>
date Fri, 19 Jan 2007 00:00:00 +0300
parents 1779577cb845
children b3aec7787b8e
files CHANGES CHANGES.ru conf/nginx.conf src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_cycle.c src/core/ngx_file.c src/core/ngx_file.h src/core/ngx_log.c src/event/ngx_event_openssl.c src/event/ngx_event_pipe.c src/http/modules/ngx_http_auth_basic_module.c src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_empty_gif_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_flv_module.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_limit_zone_module.c src/http/modules/ngx_http_static_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/nginx.xs src/http/ngx_http_header_filter_module.c src/http/ngx_http_parse_time.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_request_body.c src/http/ngx_http_special_response.c src/http/ngx_http_upstream.c src/os/unix/ngx_files.c src/os/unix/ngx_files.h
diffstat 30 files changed, 234 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,28 @@
 
+Changes with nginx 0.5.8                                         19 Jan 2007
+
+    *) Bugfix: a segmentation fault might occur if 
+       "client_body_in_file_only on" was used and a request body was small.
+
+    *) Bugfix: a segmentation fault occurred if 
+       "client_body_in_file_only on" and "proxy_pass_request_body off" or 
+       "fastcgi_pass_request_body off" directives were used, and nginx 
+       switched to a next upstream.
+
+    *) Bugfix: if the "proxy_buffering off" directive was used and a client 
+       connection was non-active, then the connection was closed after send 
+       timeout; bug appeared in 0.4.7.
+
+    *) Bugfix: if the "epoll" method was used and a client closed a 
+       connection prematurely, then nginx closed the connection after a 
+       send timeout only.
+
+    *) Bugfix: the "[alert] zero size buf" error when FastCGI server was 
+       used.
+
+    *) Bugfixes in the "limit_zone" directive.
+
+
 Changes with nginx 0.5.7                                         15 Jan 2007
 
     *) Feature: the ssl_session_cache storage optimization.
@@ -79,7 +103,7 @@ Changes with nginx 0.5.3                
     *) Feature: the $r->variable method supports variables that do not 
        exist in nginx configuration.
 
-    *) Bugfix: the $r->has_request_body method did work.
+    *) Bugfix: the $r->has_request_body method did not work.
 
 
 Changes with nginx 0.5.2                                         11 Dec 2006
@@ -463,8 +487,8 @@ Changes with nginx 0.3.55               
        returns all "Cookie" header lines.
 
     *) Bugfix: a segmentation fault occurred if 
-       "client_body_in_file_only on" was used and nginx was switches to a 
-       next upstream.
+       "client_body_in_file_only on" was used and nginx switched to a next 
+       upstream.
 
     *) Bugfix: on some condition while reconfiguration character codes 
        inside the "charset_map" may be treated invalid; bug appeared in 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,29 @@
 
+Изменения в nginx 0.5.8                                           19.01.2007
+
+    *) Исправление: если использовалась директива 
+       "client_body_in_file_only on" и тело запроса было небольшое, то мог 
+       произойти segmentation fault.
+
+    *) Исправление: происходил segmentation fault, если использовались 
+       директивы "client_body_in_file_only on" и 
+       "proxy_pass_request_body off" или "fastcgi_pass_request_body off", и 
+       делался переход к следующему бэкенду.
+
+    *) Исправление: если при использовании директивы "proxy_buffering off" 
+       соединение с клиентом было неактивно, то оно закрывалось по таймуту, 
+       заданному директивой send_timeout; ошибка появилась в 0.4.7.
+
+    *) Исправление: если при использовании метода epoll клиент закрывал 
+       преждевременно соединение со своей стороны, то nginx закрывал это 
+       соединение только по истечении таймаута на передачу.
+
+    *) Исправление: ошибки "[alert] zero size buf" при работе с 
+       FastCGI-сервером.
+
+    *) Исправление ошибок в директиве limit_zone.
+
+
 Изменения в nginx 0.5.7                                           15.01.2007
 
     *) Добавление: оптимизация использования памяти в ssl_session_cache.
@@ -13,7 +38,7 @@
        add_after_body происходил segmentation fault, если в заголовке 
        ответа нет строки "Content-Type".
 
-    *) Исправление: библиотека OpenSSL всегда собирался с поддержкой 
+    *) Исправление: библиотека OpenSSL всегда собиралась с поддержкой 
        потоков.
        Спасибо Дену Иванову.
 
--- a/conf/nginx.conf
+++ b/conf/nginx.conf
@@ -29,7 +29,6 @@ http {
 
     #keepalive_timeout  0;
     keepalive_timeout  65;
-    tcp_nodelay        on;
 
     #gzip  on;
 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.5.7"
+#define NGINX_VERSION      "0.5.8"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -76,7 +76,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t
 
         /* open configuration file */
 
-        fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
+        fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
         if (fd == NGX_INVALID_FILE) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                                ngx_open_file_n " \"%s\" failed",
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -312,7 +312,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
         }
 
         file[i].fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR,
-                                   NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND);
+                                   NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND,
+                                   NGX_FILE_DEFAULT_ACCESS);
 
         ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
                        "log: %p %d \"%s\"",
@@ -849,7 +850,8 @@ ngx_create_pidfile(ngx_str_t *name, ngx_
     trunc = ngx_test_config ? 0 : NGX_FILE_TRUNCATE;
 
     file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR,
-                            NGX_FILE_CREATE_OR_OPEN|trunc);
+                            NGX_FILE_CREATE_OR_OPEN|trunc,
+                            NGX_FILE_DEFAULT_ACCESS);
 
     if (file.fd == NGX_INVALID_FILE) {
         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
@@ -959,7 +961,8 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx
         }
 
         fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR,
-                           NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND);
+                           NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND,
+                           NGX_FILE_DEFAULT_ACCESS);
 
         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                        "reopen file \"%s\", old:%d new:%d",
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -19,7 +19,7 @@ ngx_write_chain_to_temp_file(ngx_temp_fi
 
     if (tf->file.fd == NGX_INVALID_FILE) {
         rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
-                                  tf->persistent, tf->mode);
+                                  tf->persistent, tf->access);
 
         if (rc == NGX_ERROR || rc == NGX_AGAIN) {
             return rc;
@@ -37,7 +37,7 @@ ngx_write_chain_to_temp_file(ngx_temp_fi
 
 ngx_int_t
 ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
-    ngx_uint_t persistent, ngx_uint_t mode)
+    ngx_uint_t persistent, ngx_uint_t access)
 {
     ngx_err_t                 err;
     ngx_atomic_uint_t         n;
@@ -72,7 +72,7 @@ ngx_create_temp_file(ngx_file_t *file, n
             return NGX_ERROR;
         }
 
-        file->fd = ngx_open_tempfile(file->name.data, persistent, mode);
+        file->fd = ngx_open_tempfile(file->name.data, persistent, access);
 
         ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
                        "temp fd:%d", file->fd);
@@ -445,8 +445,8 @@ ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_s
 
     prev = ctx->data;
 
-    if (ctx->size) {
-        data = ngx_alloc(ctx->size, ctx->log);
+    if (ctx->alloc) {
+        data = ngx_alloc(ctx->alloc, ctx->log);
         if (data == NULL) {
             goto failed;
         }
@@ -529,6 +529,10 @@ ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_s
             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
                            "tree file \"%s\"", file.data);
 
+            ctx->size = ngx_de_size(&dir);
+            ctx->access = ngx_de_access(&dir);
+            ctx->mtime = ngx_de_mtime(&dir);
+
             if (ctx->file_handler(ctx, &file) == NGX_ABORT) {
                 goto failed;
             }
@@ -538,6 +542,9 @@ ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_s
             ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
                            "tree enter dir \"%s\"", file.data);
 
+            ctx->access = ngx_de_access(&dir);
+            ctx->mtime = ngx_de_mtime(&dir);
+
             if (ctx->pre_tree_handler(ctx, &file) == NGX_ABORT) {
                 goto failed;
             }
@@ -546,6 +553,9 @@ ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_s
                 goto failed;
             }
 
+            ctx->access = ngx_de_access(&dir);
+            ctx->mtime = ngx_de_mtime(&dir);
+
             if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) {
                 goto failed;
             }
@@ -571,7 +581,7 @@ done:
         ngx_free(buf.data);
     }
 
-    if (ctx->data) {
+    if (ctx->alloc) {
         ngx_free(ctx->data);
         ctx->data = prev;
     }
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -49,7 +49,7 @@ typedef struct {
     ngx_pool_t         *pool;
     char               *warn;
 
-    ngx_uint_t          mode;
+    ngx_uint_t          access;
 
     unsigned            log_level:8;
     unsigned            persistent:1;
@@ -58,25 +58,30 @@ typedef struct {
 
 typedef struct ngx_tree_ctx_s  ngx_tree_ctx_t;
 
-typedef ngx_int_t (*ngx_tree_init_handler_pt) (ngx_tree_ctx_t *ctx,
-    ngx_tree_ctx_t *prev);
+typedef ngx_int_t (*ngx_tree_init_handler_pt) (void *ctx, void *prev);
 typedef ngx_int_t (*ngx_tree_handler_pt) (ngx_tree_ctx_t *ctx, ngx_str_t *name);
 
 struct ngx_tree_ctx_s {
+    off_t                      size;
+    ngx_uint_t                 access;
+    time_t                     mtime;
+
     ngx_tree_init_handler_pt   init_handler;
     ngx_tree_handler_pt        file_handler;
     ngx_tree_handler_pt        pre_tree_handler;
     ngx_tree_handler_pt        post_tree_handler;
     ngx_tree_handler_pt        spec_handler;
+
     void                      *data;
-    size_t                     size;
+    size_t                     alloc;
+
     ngx_log_t                 *log;
 };
 
 
 ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain);
 ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
-    ngx_pool_t *pool, ngx_uint_t persistent,ngx_uint_t mode);
+    ngx_pool_t *pool, ngx_uint_t persistent,ngx_uint_t access);
 void ngx_create_hashed_filename(ngx_file_t *file, ngx_path_t *path);
 ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path);
 ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access);
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -209,7 +209,7 @@ ngx_log_init(void)
     ngx_stderr_fileno = GetStdHandle(STD_ERROR_HANDLE);
 
     ngx_stderr.fd = ngx_open_file(NGX_ERROR_LOG_PATH, NGX_FILE_RDWR,
-                                  NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND);
+                                  NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND, 0);
 
     if (ngx_stderr.fd == NGX_INVALID_FILE) {
         ngx_message_box("nginx", MB_OK, ngx_errno,
@@ -279,7 +279,7 @@ ngx_set_error_log_levels(ngx_conf_t *cf,
 
                 if (log->log_level != 0) {
                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                                       "invalid log level \"%s\"",
+                                       "duplicate log level \"%s\"",
                                        value[i].data);
                     return NGX_CONF_ERROR;
                 }
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -1620,7 +1620,7 @@ ngx_ssl_session_rbtree_insert_value(ngx_
 
         } else if (node->key > temp->key) {
 
-            if (temp->right == sentinel) { 
+            if (temp->right == sentinel) {
                 temp->right = node;
                 break;
             }
@@ -1642,9 +1642,9 @@ ngx_ssl_session_rbtree_insert_value(ngx_
                 }
 
                 temp = temp->left;
-    
+
             } else {
-    
+
                 if (temp->right == sentinel) {
                     temp->right = node;
                     break;
@@ -1659,7 +1659,7 @@ ngx_ssl_session_rbtree_insert_value(ngx_
     node->left = sentinel;
     node->right = sentinel;
     ngx_rbt_red(node);
-}   
+}
 
 
 void
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -420,7 +420,7 @@ static ngx_int_t
 ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
 {
     size_t             bsize;
-    ngx_uint_t         flush;
+    ngx_uint_t         flush, prev_last_shadow;
     ngx_chain_t       *out, **ll, *cl;
     ngx_connection_t  *downstream;
 
@@ -511,13 +511,13 @@ ngx_event_pipe_write_to_downstream(ngx_e
         out = NULL;
         ll = NULL;
         flush = 0;
+        prev_last_shadow = 1;
 
         for ( ;; ) {
             if (p->out) {
                 cl = p->out;
 
                 if (cl->buf->recycled
-                    && cl->buf->last_shadow
                     && bsize + cl->buf->last - cl->buf->pos > p->busy_size)
                 {
                     flush = 1;
@@ -541,10 +541,24 @@ ngx_event_pipe_write_to_downstream(ngx_e
                     && cl->buf->last_shadow
                     && bsize + cl->buf->last - cl->buf->pos > p->busy_size)
                 {
+                    if (!prev_last_shadow) {
+                        p->in = p->in->next;
+
+                        cl->next = NULL;
+
+                        if (out) {
+                            *ll = cl;
+                        } else {
+                            out = cl;
+                        }
+                    }
+
                     flush = 1;
                     break;
                 }
 
+                prev_last_shadow = cl->buf->last_shadow;
+
                 p->in = p->in->next;
 
             } else {
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -133,7 +133,7 @@ ngx_http_auth_basic_handler(ngx_http_req
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    fd = ngx_open_file(alcf->user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
+    fd = ngx_open_file(alcf->user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
 
     if (fd == NGX_INVALID_FILE) {
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -19,8 +19,7 @@ typedef struct {
 
 
 static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r);
-static ngx_int_t ngx_http_dav_no_init(ngx_tree_ctx_t *ctx,
-    ngx_tree_ctx_t *prev);
+static ngx_int_t ngx_http_dav_no_init(void *ctx, void *prev);
 static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path);
 static ngx_int_t ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path);
 static ngx_int_t ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path);
@@ -131,7 +130,7 @@ ngx_http_dav_handler(ngx_http_request_t 
     case NGX_HTTP_PUT:
 
         if (r->uri.data[r->uri.len - 1] == '/') {
-            return NGX_DECLINED;
+            return NGX_HTTP_BAD_REQUEST;
         }
 
         r->request_body_in_file_only = 1;
@@ -190,7 +189,7 @@ ngx_http_dav_handler(ngx_http_request_t 
                 tree.post_tree_handler = ngx_http_dav_delete_dir;
                 tree.spec_handler = ngx_http_dav_delete_file;
                 tree.data = NULL;
-                tree.size = 0;
+                tree.alloc = 0;
                 tree.log = r->connection->log;
 
                 if (ngx_walk_tree(&tree, &path) == NGX_OK) {
@@ -270,7 +269,7 @@ ngx_http_dav_handler(ngx_http_request_t 
 
 
 static ngx_int_t
-ngx_http_dav_no_init(ngx_tree_ctx_t *ctx, ngx_tree_ctx_t *prev)
+ngx_http_dav_no_init(void *ctx, void *prev)
 {
     return NGX_OK;
 }
--- a/src/http/modules/ngx_http_empty_gif_module.c
+++ b/src/http/modules/ngx_http_empty_gif_module.c
@@ -158,7 +158,7 @@ ngx_http_empty_gif_handler(ngx_http_requ
         return rc;
     }
 
-    return ngx_http_output_filter(r, &out);;
+    return ngx_http_output_filter(r, &out);
 }
 
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -1308,11 +1308,8 @@ ngx_http_fastcgi_input_filter(ngx_event_
 
         /* STUB */ b->num = buf->num;
 
-        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
-
         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
-                       "input buf %p %z", b->pos, b->last - b->pos);
-
+                       "input buf #%d %p", b->num, b->pos);
 
         if (f->pos + f->length < f->last) {
 
@@ -1354,7 +1351,7 @@ ngx_http_fastcgi_input_filter(ngx_event_
         b->last_shadow = 1;
 
         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
-                       "input buf last %p %z", b->pos, b->last - b->pos);
+                       "input buf %p %z", b->pos, b->last - b->pos);
 
         return NGX_OK;
     }
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -109,7 +109,7 @@ ngx_http_flv_handler(ngx_http_request_t 
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
+    fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
 
     if (fd == NGX_INVALID_FILE) {
         err = ngx_errno;
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -245,7 +245,7 @@ ngx_http_index_handler(ngx_http_request_
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        fd = ngx_open_file(ctx->path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
+        fd = ngx_open_file(ctx->path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
 
         if (fd == (ngx_fd_t) NGX_AGAIN) {
             ctx->current = i;
--- a/src/http/modules/ngx_http_limit_zone_module.c
+++ b/src/http/modules/ngx_http_limit_zone_module.c
@@ -179,7 +179,7 @@ ngx_http_limit_zone_handler(ngx_http_req
         do {
             lz = (ngx_http_limit_zone_node_t *) &node->color;
 
-            rc = ngx_memn2cmp(lz->data, vv->data, (size_t) lz->len, len);
+            rc = ngx_memn2cmp(vv->data, lz->data, len, (size_t) lz->len);
 
             if (rc == 0) {
                 if ((ngx_uint_t) lz->conn < lzcf->conn) {
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -126,7 +126,7 @@ ngx_http_static_handler(ngx_http_request
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
+    fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
 
     if (fd == NGX_INVALID_FILE) {
         err = ngx_errno;
--- 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.5.7';
+our $VERSION = '0.5.8';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -632,7 +632,7 @@ sendfile(r, filename, offset = -1, bytes
         XSRETURN_EMPTY;
     }
 
-    fd = ngx_open_file((u_char *) filename, NGX_FILE_RDONLY, NGX_FILE_OPEN);
+    fd = ngx_open_file((u_char *) filename, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
 
     if (fd == NGX_INVALID_FILE) {
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -87,7 +87,7 @@ static ngx_str_t ngx_http_status_lines[]
     ngx_string("409 Conflict"),
     ngx_string("410 Gone"),
     ngx_string("411 Length Required"),
-    ngx_null_string,  /* "412 Precondition Failed" */
+    ngx_string("412 Precondition Failed"),
     ngx_string("413 Request Entity Too Large"),
     ngx_null_string,  /* "414 Request-URI Too Large", but we never send it
                        * because we treat such requests as the HTTP/0.9
--- a/src/http/ngx_http_parse_time.c
+++ b/src/http/ngx_http_parse_time.c
@@ -243,8 +243,8 @@ time_t ngx_http_parse_time(u_char *value
      */
 
     if (--month <= 0) {
-       month += 12;
-       year -= 1;
+        month += 12;
+        year -= 1;
     }
 
     /* Gauss's formula for Grigorian days from 1 March 1 BC */
@@ -255,7 +255,7 @@ time_t ngx_http_parse_time(u_char *value
 
             /*
              * 719527 days were between March 1, 1 BC and March 1, 1970,
-             * 31 and 28 days in January and February 1970
+             * 31 and 28 days were in January and February 1970
              */
 
             - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -141,6 +141,9 @@ ngx_http_header_t  ngx_http_headers_in[]
     { ngx_string("Destination"), offsetof(ngx_http_headers_in_t, destination),
                  ngx_http_process_header_line },
 
+    { ngx_string("Overwrite"), offsetof(ngx_http_headers_in_t, overwrite),
+                 ngx_http_process_header_line },
+
     { ngx_string("Date"), offsetof(ngx_http_headers_in_t, date),
                  ngx_http_process_header_line },
 #endif
@@ -1762,20 +1765,77 @@ ngx_http_writer(ngx_http_request_t *r)
 static void
 ngx_http_block_read(ngx_http_request_t *r)
 {
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http read blocked");
+    int                n;
+    char               buf[1];
+    ngx_err_t          err;
+    ngx_event_t       *rev;
+    ngx_connection_t  *c;
+
+    c = r->connection;
+    rev = c->read;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read blocked");
+
+#if (NGX_HAVE_KQUEUE)
+
+    if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
+
+        if (!rev->pending_eof) {
+            return;
+        }
+
+        rev->eof = 1;
+        c->error = 1;
+        err = rev->kq_errno;
+
+        goto closed;
+    }
+
+#endif
+
+    n = recv(c->fd, buf, 1, MSG_PEEK);
+
+    if (n == 0) {
+        rev->eof = 1;
+        c->error = 1;
+        err = 0;
+
+        goto closed;
+
+    } else if (n == -1) {
+        err = ngx_socket_errno;
+
+        if (err != NGX_EAGAIN) {
+            rev->eof = 1;
+            c->error = 1;
+
+            goto closed;
+        }
+    }
 
     /* aio does not call this handler */
 
-    if ((ngx_event_flags & NGX_USE_LEVEL_EVENT)
-        && r->connection->read->active)
-    {
-        if (ngx_del_event(r->connection->read, NGX_READ_EVENT, 0)
-            == NGX_ERROR)
-        {
+    if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) {
+
+        if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
             ngx_http_close_request(r, 0);
         }
     }
+
+    return;
+
+closed:
+
+    if (err) {
+        rev->error = 1;
+    }
+
+    ngx_log_error(NGX_LOG_INFO, c->log, err,
+                  "client closed prematurely connection");
+
+    ngx_http_close_request(r, 0);
+
+    return;
 }
 
 
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -77,6 +77,7 @@
 #define NGX_HTTP_REQUEST_TIME_OUT          408
 #define NGX_HTTP_CONFLICT                  409
 #define NGX_HTTP_LENGTH_REQUIRED           411
+#define NGX_HTTP_PRECONDITION_FAILED       412
 #define NGX_HTTP_REQUEST_ENTITY_TOO_LARGE  413
 #define NGX_HTTP_REQUEST_URI_TOO_LARGE     414
 #define NGX_HTTP_UNSUPPORTED_MEDIA_TYPE    415
@@ -193,6 +194,7 @@ typedef struct {
 #if (NGX_HTTP_DAV)
     ngx_table_elt_t                  *depth;
     ngx_table_elt_t                  *destination;
+    ngx_table_elt_t                  *overwrite;
     ngx_table_elt_t                  *date;
 #endif
 
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -74,13 +74,13 @@ ngx_http_read_client_request_body(ngx_ht
             tf->persistent = r->request_body_in_persistent_file;
 
             if (r->request_body_file_group_access) {
-                tf->mode = 0660;
+                tf->access = 0660;
             }
 
             rb->temp_file = tf;
 
             if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
-                                     tf->persistent, tf->mode)
+                                     tf->persistent, tf->access)
                 != NGX_OK)
             {
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -163,6 +163,8 @@ ngx_http_read_client_request_body(ngx_ht
 
             /* the whole request body may be placed in r->header_in */
 
+            rb->to_write = rb->bufs;
+
             r->read_event_handler = ngx_http_read_client_request_body_handler;
 
             return ngx_http_do_read_client_request_body(r);
@@ -400,7 +402,7 @@ ngx_http_write_request_body(ngx_http_req
         tf->persistent = r->request_body_in_persistent_file;
 
         if (r->request_body_file_group_access) {
-            tf->mode = 0660;
+            tf->access = 0660;
         }
 
         rb->temp_file = tf;
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -139,6 +139,14 @@ static char error_411_page[] =
 ;
 
 
+static char error_412_page[] =
+"<html>" CRLF
+"<head><title>412 Precondition Failed</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>412 Precondition Failed</h1></center>" CRLF
+;
+
+
 static char error_413_page[] =
 "<html>" CRLF
 "<head><title>413 Request Entity Too Large</title></head>" CRLF
@@ -274,7 +282,7 @@ static ngx_str_t error_pages[] = {
     ngx_string(error_409_page),
     ngx_string(error_410_page),
     ngx_string(error_411_page),
-    ngx_null_string,             /* 412 */
+    ngx_string(error_412_page),
     ngx_string(error_413_page),
     ngx_string(error_414_page),
     ngx_string(error_415_page),
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -569,8 +569,11 @@ ngx_http_upstream_connect(ngx_http_reque
         }
     }
 
-    if (r->request_body && r->request_body->temp_file && r == r->main) {
-
+    if (r->request_body
+        && r->request_body->buf
+        && r->request_body->temp_file
+        && r == r->main)
+    {
         /*
          * the r->request_body->buf can be reused for one request only,
          * the subrequests should allocate their own temporay bufs
@@ -1700,7 +1703,7 @@ ngx_http_upstream_process_non_buffered_b
         }
     }
 
-    if (downstream->write->active) {
+    if (downstream->write->active && !downstream->write->ready) {
         ngx_add_timer(downstream->write, clcf->send_timeout);
 
     } else if (downstream->write->timer_set) {
@@ -1712,7 +1715,7 @@ ngx_http_upstream_process_non_buffered_b
         return;
     }
 
-    if (upstream->read->active) {
+    if (upstream->read->active && !upstream->read->ready) {
         ngx_add_timer(upstream->read, u->conf->read_timeout);
 
     } else if (upstream->read->timer_set) {
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -112,11 +112,12 @@ ngx_write_file(ngx_file_t *file, u_char 
 
 
 ngx_fd_t
-ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t mode)
+ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access)
 {
     ngx_fd_t  fd;
 
-    fd = open((const char *) name, O_CREAT|O_EXCL|O_RDWR, mode ? mode : 0600);
+    fd = open((const char *) name, O_CREAT|O_EXCL|O_RDWR,
+              access ? access : 0600);
 
     if (fd != -1 && !persistent) {
         unlink((const char *) name);
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -17,17 +17,20 @@
 
 
 
-#define ngx_open_file(name, access, create)                                 \
-    open((const char *) name, access|create, 0644)
+#define ngx_open_file(name, mode, create, access)                            \
+    open((const char *) name, mode|create, access)
 #define ngx_open_file_n          "open()"
 
 #define NGX_FILE_RDONLY          O_RDONLY
+#define NGX_FILE_WRONLY          O_WRONLY
 #define NGX_FILE_RDWR            O_RDWR
 #define NGX_FILE_CREATE_OR_OPEN  O_CREAT
 #define NGX_FILE_OPEN            0
 #define NGX_FILE_TRUNCATE        O_TRUNC
 #define NGX_FILE_APPEND          O_APPEND
 
+#define NGX_FILE_DEFAULT_ACCESS  0644
+
 
 #define ngx_close_file           close
 #define ngx_close_file_n         "close()"
@@ -38,7 +41,7 @@
 
 
 ngx_fd_t ngx_open_tempfile(u_char *name, ngx_uint_t persistent,
-    ngx_uint_t mode);
+    ngx_uint_t access);
 #define ngx_open_tempfile_n      "open()"
 
 
@@ -52,7 +55,12 @@ ssize_t ngx_write_chain_to_file(ngx_file
     off_t offset, ngx_pool_t *pool);
 
 
+#define ngx_read_fd              read
+#define ngx_read_fd_n            "read()"
+
 #define ngx_write_fd             write
+#define ngx_write_fd_n           "write()"
+
 #define ngx_linefeed(p)          *p++ = LF;
 #define NGX_LINEFEED_SIZE        1
 
@@ -79,6 +87,7 @@ ngx_int_t ngx_set_file_time(u_char *name
 #define ngx_is_file(sb)          (S_ISREG((sb)->st_mode))
 #define ngx_is_link(sb)          (S_ISLNK((sb)->st_mode))
 #define ngx_is_exec(sb)          ((sb)->st_mode & S_IXUSR)
+#define ngx_file_access(sb)      ((sb)->st_mode & 0777)
 #define ngx_file_size(sb)        (sb)->st_size
 #define ngx_file_mtime(sb)       (sb)->st_mtime
 #define ngx_file_uniq(sb)        (sb)->st_ino
@@ -126,6 +135,7 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, 
 #define ngx_de_is_dir(dir)       (S_ISDIR((dir)->info.st_mode))
 #define ngx_de_is_file(dir)      (S_ISREG((dir)->info.st_mode))
 #define ngx_de_is_link(dir)      (S_ISLNK((dir)->info.st_mode))
+#define ngx_de_access(dir)       (((dir)->info.st_mode) & 0777)
 #define ngx_de_size(dir)         (dir)->info.st_size
 #define ngx_de_mtime(dir)        (dir)->info.st_mtime