changeset 473:8e8f3af115b5 release-0.1.11

nginx-0.1.11-RELEASE import *) Feature: the worker_priority directive. *) Change: both tcp_nopush and tcp_nodelay directives affect the transferred response. *) Bugfix: nginx did not call initgroups(). Thanks to Andrew Sitnikov and Andrei Nigmatulin. *) Change: now the ngx_http_autoindex_module shows the file size in the bytes. *) Bugfix: the ngx_http_autoindex_module returned the 500 error if the broken symlink was in a directory. *) Bugfix: the files bigger than 4G could not be transferred using sendfile. *) Bugfix: if the backend was resolved to several backends and there was an error while the response waiting then process may got caught in an endless loop. *) Bugfix: the worker process may exit with the "unknown cycle" message when the /dev/poll method was used. *) Bugfix: "close() channel failed" errors. *) Bugfix: the autodetection of the "nobody" and "nogroup" groups. *) Bugfix: the send_lowat directive did not work on Linux. *) Bugfix: the segmentation fault occurred if there was no events section in configuration. *) Bugfix: nginx could not be built on OpenBSD. *) Bugfix: the double slashes in "://" in the URI were converted to ":/".
author Igor Sysoev <igor@sysoev.ru>
date Thu, 02 Dec 2004 18:40:46 +0000
parents a004b617422d
children 99ad6d3b40ed
files auto/modules auto/options auto/os/conf auto/os/linux auto/types/value auto/unix docs/xml/nginx/changes.xml src/core/nginx.c src/core/nginx.h src/core/ngx_buf.h src/core/ngx_config.h src/core/ngx_cycle.c src/core/ngx_cycle.h src/core/ngx_output_chain.c src/core/ngx_string.c src/event/modules/ngx_devpoll_module.c src/event/ngx_event.c src/event/ngx_event_connect.c src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/event/ngx_event_pipe.c src/event/ngx_event_pipe.h src/http/modules/ngx_http_autoindex_handler.c src/http/modules/ngx_http_chunked_filter.c src/http/modules/ngx_http_index_handler.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/modules/proxy/ngx_http_proxy_upstream.c src/http/ngx_http_cache.h src/http/ngx_http_core_module.c src/http/ngx_http_header_filter.c src/http/ngx_http_log_handler.c src/http/ngx_http_parse.c src/http/ngx_http_request.c src/http/ngx_http_write_filter.c src/os/unix/ngx_aio_write_chain.c src/os/unix/ngx_files.h src/os/unix/ngx_freebsd_init.c src/os/unix/ngx_freebsd_sendfile_chain.c src/os/unix/ngx_linux_sendfile_chain.c src/os/unix/ngx_os.h src/os/unix/ngx_posix_init.c src/os/unix/ngx_process_cycle.c src/os/unix/ngx_solaris_sendfilev_chain.c src/os/unix/ngx_writev_chain.c src/os/win32/ngx_errno.c src/os/win32/ngx_os.h src/os/win32/ngx_win32_config.h src/os/win32/ngx_win32_init.c src/os/win32/ngx_wsasend_chain.c
diffstat 49 files changed, 984 insertions(+), 355 deletions(-) [+]
line wrap: on
line diff
--- a/auto/modules
+++ b/auto/modules
@@ -45,6 +45,11 @@ if [ $NGX_TEST_BUILD_RTSIG = YES ]; then
     CORE_SRCS="$CORE_SRCS $RTSIG_SRCS"
 fi
 
+if [ $NGX_TEST_BUILD_SOLARIS_SENDFILEV = YES ]; then
+    have=NGX_TEST_BUILD_SOLARIS_SENDFILEV . auto/have
+    CORE_SRCS="$CORE_SRCS $SOLARIS_SENDFILEV_SRCS"
+fi
+
 
 # the filter order is important
 #     ngx_http_write_filter
--- a/auto/options
+++ b/auto/options
@@ -25,6 +25,7 @@ CPU=NO
 NGX_TEST_BUILD_DEVPOLL=NO
 NGX_TEST_BUILD_EPOLL=NO
 NGX_TEST_BUILD_RTSIG=NO
+NGX_TEST_BUILD_SOLARIS_SENDFILEV=NO
 
 NGX_PLATFORM=
 NGX_WINE=
@@ -146,6 +147,7 @@ do
         --test-build-devpoll)            NGX_TEST_BUILD_DEVPOLL=YES ;;
         --test-build-epoll)              NGX_TEST_BUILD_EPOLL=YES   ;;
         --test-build-rtsig)              NGX_TEST_BUILD_RTSIG=YES   ;;
+        --test-build-solaris-sendfilev)  NGX_TEST_BUILD_SOLARIS_SENDFILEV=YES ;;
 
         *)
             echo "$0: error: invalid option \"$option\""
@@ -212,11 +214,6 @@ if test -z "$NGX_PREFIX"; then
 fi
 
 
-if test -z "$NGX_GROUP"; then
-    NGX_GROUP=NGX_USER
-fi
-
-
 case ".$NGX_SBIN_PATH" in
     ./*)
     ;;
--- a/auto/os/conf
+++ b/auto/os/conf
@@ -47,7 +47,26 @@ if [ $NGX_PLATFORM != win32 ]; then
 
     if test -z "$NGX_USER"; then
         NGX_USER=nobody
-        NGX_GROUP=nobody
+    fi
+
+    if [ -z "$NGX_GROUP" -a $NGX_USER = nobody ] ; then
+       if grep nobody /etc/group 2>&1 >/dev/null; then
+           echo "checking for nobody group ... found"
+           NGX_GROUP=nobody
+       else
+           echo "checking for nobody group ... not found"
+
+           if grep nogroup /etc/group 2>&1 >/dev/null; then
+               echo "checking for nogroup group ... found"
+               NGX_GROUP=nogroup
+           else 
+               echo "checking for nogroup group ... not found"
+               NGX_GROUP=nobody
+           fi
+       fi
+
+    else
+        NGX_GROUP=$NGX_USER
     fi
 
 
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -21,12 +21,6 @@ ngx_spacer='
 CC_AUX_FLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64"
 
 
-if test -z "$NGX_USER"; then
-    NGX_USER=nobody
-    NGX_GROUP=nogroup
-fi
-
-
 # Linux kernel version
 
 version=`grep "#define LINUX_VERSION_CODE" /usr/include/linux/version.h \
--- a/auto/types/value
+++ b/auto/types/value
@@ -7,3 +7,5 @@ cat << END >> $NGX_AUTO_CONFIG_H
 #ifndef $ngx_param
 #define $ngx_param  $ngx_value
 #endif
+
+END
--- a/auto/unix
+++ b/auto/unix
@@ -43,31 +43,15 @@ ngx_type="rlim_t"; ngx_types="int"; . au
 
 . auto/endianess
 
-
-# printf() formats
+ngx_type="size_t"; . auto/types/sizeof
+ngx_param=MAX_SIZE_T_VALUE; ngx_value=$ngx_max_value; . auto/types/value
 
-#CC_WARN=$CC_STRONG
-#ngx_fmt_collect=no
-#
-#ngx_fmt_name=OFF_T_FMT; ngx_type="off_t"; . auto/types/sizeof
-ngx_param=OFF_T_MAX_VALUE; ngx_value=$ngx_max_value; . auto/types/value
-#eval ngx_formats=\${ngx_${ngx_size}_fmt}; . auto/fmt/fmt
-#
-#ngx_fmt_name=TIME_T_FMT; ngx_type="time_t"; . auto/types/sizeof
+ngx_type="off_t"; . auto/types/sizeof
+ngx_param=MAX_OFF_T_VALUE; ngx_value=$ngx_max_value; . auto/types/value
+
+ngx_type="time_t"; . auto/types/sizeof
 ngx_param=TIME_T_SIZE; ngx_value=$ngx_size; . auto/types/value
 ngx_param=TIME_T_LEN; ngx_value=$ngx_max_len; . auto/types/value
-#eval ngx_formats=\${ngx_${ngx_size}_fmt}; . auto/fmt/fmt
-#
-#ngx_fmt_name=SIZE_T_FMT; ngx_type="size_t"; . auto/types/sizeof
-#eval ngx_formats=\${ngx_${ngx_size}_fmt}; . auto/fmt/fmt
-#
-#ngx_fmt_name=SIZE_T_X_FMT; . auto/fmt/xfmt
-#
-#ngx_fmt_name=PID_T_FMT; ngx_type="pid_t"; . auto/types/sizeof
-#eval ngx_formats=\${ngx_${ngx_size}_fmt}; . auto/fmt/fmt
-#
-#ngx_fmt_name=RLIM_T_FMT; ngx_type="rlim_t"; . auto/types/sizeof
-#eval ngx_formats=\${ngx_${ngx_size}_fmt}; . auto/fmt/fmt
 
 
 # syscalls, libc calls and some features
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -6,6 +6,147 @@
             title="nginx">
 
 
+<changes ver="0.1.11" date="02.12.2004">
+
+<change type="feature">
+<para lang="ru">
+директива worker_priority.
+</para>
+<para lang="en">
+the worker_priority directive.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+под FreeBSD директивы tcp_nopush и tcp_nodelay вместе влияют на передачу
+ответа.
+</para>
+<para lang="en">
+both tcp_nopush and tcp_nodelay directives affect the transferred response.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx не вызывал initgroups().<br/>
+Спасибо Андрею Ситникову и Андрею Нигматулину.
+</para>
+<para lang="en">
+nginx did not call initgroups().<br/>
+Thanks to Andrew Sitnikov and Andrei Nigmatulin.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+ngx_http_auto_index_module теперь выдаёт размер файлов в байтах.
+</para>
+<para lang="en">
+now the ngx_http_autoindex_module shows the file size in the bytes.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ngx_http_auto_index_module возвращал ошибку 500, если в каталоге есть
+битый symlink.
+</para>
+<para lang="en">
+the ngx_http_autoindex_module returned the 500 error if the broken symlink
+was in a directory.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+файлы больше 4G не передавались с использованием sendfile.
+</para>
+<para lang="en">
+the files bigger than 4G could not be transferred using sendfile.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если бэкенд резолвился в несколько адресов и при ожидании от него ответа
+происходила ошибка, то процесс зацикливался.
+</para>
+<para lang="en">
+if the backend was resolved to several backends and there was an error while
+the response waiting then process may got caught in an endless loop.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при использовании метода /dev/poll рабочий процесс мог завершиться
+с сообщением "unknown cycle".
+</para>
+<para lang="en">
+the worker process may exit with the "unknown cycle" message when the /dev/poll
+method was used.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ошибки "close() channel failed".
+</para>
+<para lang="en">
+"close() channel failed" errors.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+автоматическое определение групп nobody и nogroup.
+</para>
+<para lang="en">
+the autodetection of the nobody and nogroup groups.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+директива send_lowat не работала на Linux.
+</para>
+<para lang="en">
+the send_lowat directive did not work on Linux.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если в конфигурации не было раздела events, то происходил segmentation fault.
+</para>
+<para lang="en">
+the segmentation fault occurred if there was no events section
+in configuration.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx не собирался под OpenBSD.
+</para>
+<para lang="en">
+nginx could not be built on OpenBSD.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+двойные слэшы в "://" в URI превращались в ":/".
+</para>
+<para lang="en">
+the double slashes in "://" in the URI were converted to ":/".
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="0.1.10" date="26.11.2004">
 
 <change type="bugfix">
@@ -23,11 +164,10 @@ bug appeared in 0.1.9.
 
 <change type="bugfix">
 <para lang="ru">
-исправление в версии 0.1.9 для файлов больше на Linux не работало.
+исправление в версии 0.1.9 для файлов больше 2G на Linux не работало.
 </para>
 <para lang="en">
-the fix in 0.1.9 for the files bigger than 2G on Linux
-did not work.
+the fix in 0.1.9 for the files bigger than 2G on Linux did not work.
 </para>
 </change>
 
@@ -123,7 +263,7 @@ the proxy_max_temp_file_size directive.
 ошибка появилась в 0.1.5.
 </para>
 <para lang="en">
-on FreeBSD the segmentation fault may occure if the size of the transferred
+on FreeBSD the segmentation fault may occur if the size of the transferred
 file was changed;
 bug appeared in 0.1.5.
 </para>
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -16,6 +16,7 @@ static ngx_int_t ngx_save_argv(ngx_cycle
 static void *ngx_core_module_create_conf(ngx_cycle_t *cycle);
 static char *ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf);
 static char *ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
 static ngx_conf_enum_t  ngx_debug_points[] = {
@@ -80,6 +81,13 @@ static ngx_command_t  ngx_core_commands[
       0,
       NULL },
 
+    { ngx_string("worker_priority"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_set_priority,
+      0,
+      0,
+      NULL },
+
     { ngx_string("pid"),
       NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
@@ -447,6 +455,7 @@ static void *ngx_core_module_create_conf
      *
      * ccf->pid = NULL;
      * ccf->newpid = NULL;
+     * ccf->priority = 0;
      */
     ccf->daemon = NGX_CONF_UNSET;
     ccf->master = NGX_CONF_UNSET;
@@ -494,6 +503,7 @@ static char *ngx_core_module_init_conf(n
             return NGX_CONF_ERROR;
         }
 
+        ccf->username = NGX_USER;
         ccf->user = pwd->pw_uid;
 
         grp = getgrnam(NGX_GROUP);
@@ -562,6 +572,8 @@ static char *ngx_set_user(ngx_conf_t *cf
 
     value = (ngx_str_t *) cf->args->elts;
 
+    ccf->username = (char *) value[1].data;
+
     pwd = getpwnam((const char *) value[1].data);
     if (pwd == NULL) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
@@ -586,3 +598,42 @@ static char *ngx_set_user(ngx_conf_t *cf
 
 #endif
 }
+
+
+static char *ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_core_conf_t  *ccf = conf;
+
+    ngx_str_t        *value;
+    ngx_uint_t        n, minus;
+
+    if (ccf->priority != 0) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    if (value[1].data[0] == '-') {
+        n = 1;
+        minus = 1;
+
+    } else if (value[1].data[0] == '+') {
+        n = 1;
+        minus = 0;
+
+    } else {
+        n = 0;
+        minus = 0;
+    }
+
+    ccf->priority = ngx_atoi(&value[1].data[n], value[1].len - n);
+    if (ccf->priority == NGX_ERROR) {
+        return "invalid number";
+    }
+
+    if (minus) {
+        ccf->priority = -ccf->priority;
+    }
+
+    return NGX_CONF_OK;
+}
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.1.10"
+#define NGINX_VER          "nginx/0.1.11"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_NEWPID_EXT     ".newbin"
--- a/src/core/ngx_buf.h
+++ b/src/core/ngx_buf.h
@@ -109,8 +109,8 @@ typedef struct {
         ((b->flush || b->last_buf) && !ngx_buf_in_memory(b) && !b->in_file)
 
 #define ngx_buf_size(b)                                                      \
-        (ngx_buf_in_memory(b) ? (size_t) (b->last - b->pos):                 \
-                                (size_t) (b->file_last - b->file_pos))
+        (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos):                  \
+                                (b->file_last - b->file_pos))
 
 ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size);
 ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs);
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -39,6 +39,11 @@
 #endif
 
 
+#ifndef NGX_HAVE_SO_SNDLOWAT
+#define NGX_HAVE_SO_SNDLOWAT     1
+#endif
+
+
 #if !(NGX_WIN32)
 
 #define ngx_signal_helper(n)     SIG##n
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -50,7 +50,6 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t 
     ngx_open_file_t    *file;
     ngx_listening_t    *ls, *nls;
     ngx_core_conf_t    *ccf;
-    ngx_event_conf_t   *ecf;
     ngx_core_module_t  *module;
 
     log = old_cycle->log;
@@ -434,12 +433,6 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t 
     }
 
 
-    ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
-
-    ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
-                  "using the \"%s\" event method", ecf->name);
-
-
     /* close and delete stuff that lefts from an old cycle */
 
     /* close the unneeded listening sockets */
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -17,51 +17,54 @@
 
 
 struct ngx_cycle_s {
-    void           ****conf_ctx;
-    ngx_pool_t        *pool;
+    void                  ****conf_ctx;
+    ngx_pool_t               *pool;
 
-    ngx_log_t         *log;
-    ngx_log_t         *new_log;
+    ngx_log_t                *log;
+    ngx_log_t                *new_log;
 
-    ngx_array_t        listening;
-    ngx_array_t        pathes;
-    ngx_list_t         open_files;
+    ngx_array_t               listening;
+    ngx_array_t               pathes;
+    ngx_list_t                open_files;
 
-    ngx_uint_t         connection_n;
-    ngx_connection_t  *connections;
-    ngx_event_t       *read_events;
-    ngx_event_t       *write_events;
+    ngx_uint_t                connection_n;
+    ngx_connection_t         *connections;
+    ngx_event_t              *read_events;
+    ngx_event_t              *write_events;
 
-    ngx_cycle_t       *old_cycle;
+    ngx_cycle_t              *old_cycle;
 
-    ngx_str_t          conf_file;
-    ngx_str_t          root;
+    ngx_str_t                 conf_file;
+    ngx_str_t                 root;
 };
 
 
 typedef struct {
-     ngx_flag_t  daemon;
-     ngx_flag_t  master;
+     ngx_flag_t               daemon;
+     ngx_flag_t               master;
 
-     ngx_int_t   worker_processes;
-     ngx_int_t   debug_points;
+     ngx_int_t                worker_processes;
+     ngx_int_t                debug_points;
 
-     ngx_uid_t   user;
-     ngx_gid_t   group;
+     int                      priority;
 
-     ngx_str_t   pid;
-     ngx_str_t   newpid;
+     char                    *username;
+     ngx_uid_t                user;
+     ngx_gid_t                group;
+
+     ngx_str_t                pid;
+     ngx_str_t                newpid;
 
 #if (NGX_THREADS)
-     ngx_int_t   worker_threads;
-     size_t      thread_stack_size;
+     ngx_int_t                worker_threads;
+     size_t                   thread_stack_size;
 #endif
 
 } ngx_core_conf_t;
 
 
 typedef struct {
-     ngx_pool_t  *pool;   /* pcre's malloc() pool */
+     ngx_pool_t              *pool;   /* pcre's malloc() pool */
 } ngx_core_tls_t;
 
 
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -28,7 +28,8 @@ static ngx_int_t ngx_output_chain_copy_b
 ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
 {
     int           rc, last;
-    size_t        size, bsize;
+    off_t         bsize;
+    size_t        size;
     ngx_chain_t  *cl, *out, **last_out;
 
     if (ctx->in == NULL && ctx->busy == NULL) {
@@ -81,6 +82,8 @@ ngx_int_t ngx_output_chain(ngx_output_ch
                 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
                               "zero size buf");
 
+                ngx_debug_point();
+
                 ctx->in = ctx->in->next;
 
                 continue;
@@ -118,18 +121,18 @@ ngx_int_t ngx_output_chain(ngx_output_ch
 
                     if (ctx->in->buf->last_buf) {
 
-                        if (bsize < ctx->bufs.size) {
+                        if (bsize < (off_t) ctx->bufs.size) {
 
                            /*
                             * allocate small temp buf for the small last buf
                             * or its small last part
                             */
 
-                            size = bsize;
+                            size = (size_t) bsize;
 
                         } else if (ctx->bufs.num == 1
-                                   && (bsize < ctx->bufs.size
-                                                     + (ctx->bufs.size >> 2)))
+                                   && (bsize < (off_t) (ctx->bufs.size
+                                                     + (ctx->bufs.size >> 2))))
                         {
                             /*
                              * allocate a temp buf that equals
@@ -137,7 +140,7 @@ ngx_int_t ngx_output_chain(ngx_output_ch
                              * than 1.25 of bufs.size and a temp buf is single
                              */
 
-                            size = bsize;
+                            size = (size_t) bsize;
                         }
                     }
 
@@ -306,12 +309,12 @@ static ngx_int_t ngx_output_chain_add_co
 static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src,
                                            ngx_uint_t sendfile)
 {
-    size_t   size;
+    off_t    size;
     ssize_t  n;
 
     size = ngx_buf_size(src);
 
-    if (size > (size_t) (dst->end - dst->pos)) {
+    if (size > dst->end - dst->pos) {
         size = dst->end - dst->pos;
     }
 
@@ -324,9 +327,9 @@ static ngx_int_t ngx_output_chain_copy_b
 #endif
 
     if (ngx_buf_in_memory(src)) {
-        ngx_memcpy(dst->pos, src->pos, size);
-        src->pos += size;
-        dst->last += size;
+        ngx_memcpy(dst->pos, src->pos, (size_t) size);
+        src->pos += (size_t) size;
+        dst->last += (size_t) size;
 
         if (src->in_file) {
 
@@ -351,7 +354,7 @@ static ngx_int_t ngx_output_chain_copy_b
         }
 
     } else {
-        n = ngx_read_file(src->file, dst->pos, size, src->file_pos);
+        n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos);
 
         if (n == NGX_ERROR) {
             return n;
@@ -363,9 +366,9 @@ static ngx_int_t ngx_output_chain_copy_b
         }
 #endif
 
-        if ((size_t) n != size) {
+        if (n != size) {
             ngx_log_error(NGX_LOG_ALERT, src->file->log, 0,
-                          ngx_read_file_n " reads only %z of %uz from file",
+                          ngx_read_file_n " reads only %z of %O from file",
                           n, size);
             if (n == 0) {
                 return NGX_ERROR;
@@ -399,10 +402,19 @@ ngx_int_t ngx_chain_writer(void *data, n
 {
     ngx_chain_writer_ctx_t *ctx = data;
 
+    off_t         size;
     ngx_chain_t  *cl;
 
 
-    for (/* void */; in; in = in->next) {
+    for (size = 0; in; in = in->next) {
+
+#if 1
+        if (ngx_buf_size(in->buf) == 0 && !ngx_buf_special(in->buf)) {
+            ngx_debug_point();
+        }
+#endif
+
+        size += ngx_buf_size(in->buf);
 
         ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
                        "chain writer buf size: %uz", ngx_buf_size(in->buf));
@@ -419,6 +431,23 @@ ngx_int_t ngx_chain_writer(void *data, n
     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
                    "chain writer in: %p", ctx->out);
 
+    for (cl = ctx->out; cl; cl = cl->next) {
+
+#if 1
+
+        if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
+            ngx_debug_point();
+        }
+
+#endif
+
+        size += ngx_buf_size(cl->buf);
+    }
+
+    if (size == 0) {
+        return NGX_OK;
+    }
+
     ctx->out = ngx_send_chain(ctx->connection, ctx->out, ctx->limit);
 
     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -30,7 +30,7 @@ u_char *ngx_cpystrn(u_char *dst, u_char 
 
 /*
  * supported formats:
- *    %[0][width]O              off_t
+ *    %[0][width][x][X]O        off_t
  *    %[0][width]T              time_t
  *    %[0][width][u][x|X]z      ssize_t/size_t
  *    %[0][width][u][x|X]d      int/u_int
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -435,6 +435,16 @@ int ngx_devpoll_process_events(ngx_cycle
         c = &ngx_cycle->connections[event_list[i].fd];
 
         if (c->fd == -1) {
+            if (ngx_cycle->read_events[event_list[i].fd].closed) {
+                continue;
+            }
+
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event");
+            continue;
+        }
+
+#if 0
+        if (c->fd == -1) {
             old_cycle = ngx_old_cycles.elts;
             for (j = 0; j < ngx_old_cycles.nelts; j++) {
                 if (old_cycle[j] == NULL) {
@@ -451,6 +461,7 @@ int ngx_devpoll_process_events(ngx_cycle
             ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "unknown cycle");
             exit(1);
         }
+#endif
 
         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                        "devpoll: fd:%d, ev:%04Xd, rev:%04Xd",
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -174,10 +174,25 @@ static ngx_int_t ngx_event_module_init(n
 {
 #if !(NGX_WIN32)
 
-    size_t             size;
-    char              *shared;
-    ngx_core_conf_t   *ccf;
-    ngx_event_conf_t  *ecf;
+    size_t               size;
+    void              ***cf;
+    char                *shared;
+    ngx_core_conf_t     *ccf;
+    ngx_event_conf_t    *ecf;
+
+    cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module);
+
+    if (cf == NULL) {
+        ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+                      "no \"events\" section in configuration");
+        return NGX_ERROR;
+    }
+
+    ecf = (*cf)[ngx_event_core_module.ctx_index];
+
+    ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+                  "using the \"%s\" event method", ecf->name);
+
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
@@ -185,8 +200,6 @@ static ngx_int_t ngx_event_module_init(n
         return NGX_OK;
     }
 
-    ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
-
 
     /* TODO: 128 is cache line size */
 
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -81,9 +81,12 @@ ngx_int_t ngx_event_connect_peer(ngx_pee
             for ( ;; ) {
                 peer = &pc->peers->peers[pc->cur_peer];
 
-                if (peer->fails <= pc->peers->max_fails
-                    || (now - peer->accessed > pc->peers->fail_timeout))
-                {
+                if (peer->fails <= pc->peers->max_fails) {
+                    break;
+                }
+
+                if (now - peer->accessed > pc->peers->fail_timeout) {
+                    peer->fails = 0;
                     break;
                 }
 
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -9,7 +9,9 @@
 #include <ngx_event.h>
 
 
+static void ngx_ssl_write_handler(ngx_event_t *wev);
 static ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size);
+static void ngx_ssl_read_handler(ngx_event_t *rev);
 
 
 ngx_int_t ngx_ssl_init(ngx_log_t *log)
@@ -69,6 +71,25 @@ ssize_t ngx_ssl_recv(ngx_connection_t *c
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n); 
 
     if (n > 0) {
+        if (c->ssl->saved_write_handler) {
+
+            c->write->event_handler = c->ssl->saved_write_handler;
+            c->ssl->saved_write_handler = NULL;
+            c->write->ready = 1;
+
+            if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            ngx_post_event(c->write);
+
+            ngx_mutex_unlock(ngx_posted_events_mutex);
+        }
+
         return n;
     }
 
@@ -93,13 +114,27 @@ ssize_t ngx_ssl_recv(ngx_connection_t *c
     if (sslerr == SSL_ERROR_WANT_WRITE) {
         ngx_log_error(NGX_LOG_ALERT, c->log, err,
                       "SSL wants to write%s", handshake);
-        return NGX_ERROR;
-#if 0
+
+        c->write->ready = 0;
+
+        if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        /*
+         * we do not set the timer because there is already the read event timer
+         */
+
+        if (c->ssl->saved_write_handler == NULL) {
+            c->ssl->saved_write_handler = c->write->event_handler;
+            c->write->event_handler = ngx_ssl_write_handler;
+        }
+
         return NGX_AGAIN;
-#endif
     }
 
     c->ssl->no_rcv_shut = 1;
+    c->ssl->no_send_shut = 1;
 
     if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
         ngx_log_error(NGX_LOG_INFO, c->log, err,
@@ -115,9 +150,18 @@ ssize_t ngx_ssl_recv(ngx_connection_t *c
 }
 
 
+static void ngx_ssl_write_handler(ngx_event_t *wev)
+{
+    ngx_connection_t  *c;
+
+    c = wev->data;
+    c->read->event_handler(c->read);
+}
+
+
 /*
  * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer
- * before SSL_write() call to decrease a SSL overhead.
+ * before the SSL_write() call to decrease a SSL overhead.
  *
  * Besides for protocols such as HTTP it is possible to always buffer
  * the output to decrease a SSL overhead some more.
@@ -155,6 +199,14 @@ ngx_chain_t *ngx_ssl_send_chain(ngx_conn
         return in;
     }
 
+
+    /* the maximum limit size is the maximum uint32_t value - the page size */
+
+    if (limit == 0 || limit > NGX_MAX_UINT32_VALUE - ngx_pagesize) {
+        limit = NGX_MAX_UINT32_VALUE - ngx_pagesize;
+    }
+
+
     send = 0;
     flush = (in == NULL) ? 1 : 0;
 
@@ -252,6 +304,25 @@ static ssize_t ngx_ssl_write(ngx_connect
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n);
 
     if (n > 0) {
+        if (c->ssl->saved_read_handler) {
+
+            c->read->event_handler = c->ssl->saved_read_handler;
+            c->ssl->saved_read_handler = NULL;
+            c->read->ready = 1;
+
+            if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            ngx_post_event(c->read);
+
+            ngx_mutex_unlock(ngx_posted_events_mutex);
+        }
+
         return n;
     }
 
@@ -277,13 +348,28 @@ static ssize_t ngx_ssl_write(ngx_connect
 
         ngx_log_error(NGX_LOG_ALERT, c->log, err,
                       "SSL wants to read%s", handshake);
-        return NGX_ERROR;
-#if 0
+
+        c->read->ready = 0;
+
+        if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        /*
+         * we do not set the timer because there is already
+         * the write event timer
+         */
+
+        if (c->ssl->saved_read_handler == NULL) {
+            c->ssl->saved_read_handler = c->read->event_handler;
+            c->read->event_handler = ngx_ssl_read_handler;
+        }
+
         return NGX_AGAIN;
-#endif
     }
 
     c->ssl->no_rcv_shut = 1;
+    c->ssl->no_send_shut = 1;
 
     ngx_ssl_error(NGX_LOG_ALERT, c->log, err, "SSL_write() failed");
 
@@ -291,21 +377,42 @@ static ssize_t ngx_ssl_write(ngx_connect
 }
 
 
+static void ngx_ssl_read_handler(ngx_event_t *rev)
+{
+    ngx_connection_t  *c;
+
+    c = rev->data;
+    c->write->event_handler(c->write);
+}
+
+
 ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c)
 {
-    int         n, sslerr;
+    int         n, sslerr, mode;
     ngx_uint_t  again;
 
-    if (c->timedout) {
-        SSL_set_shutdown(c->ssl->ssl, SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN);
+    if (!c->ssl->shutdown_set) {
+
+        /* it seems that SSL_set_shutdown() could be called once only */
+
+        if (c->read->timedout) {
+            mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
 
-    } else {
-        if (c->ssl->no_rcv_shut) {
-            SSL_set_shutdown(c->ssl->ssl, SSL_RECEIVED_SHUTDOWN);
+        } else {
+            mode = 0;
+
+            if (c->ssl->no_rcv_shut) {
+                mode = SSL_RECEIVED_SHUTDOWN;
+            }
+
+            if (c->ssl->no_send_shut) {
+                mode |= SSL_SENT_SHUTDOWN;
+            }
         }
 
-        if (c->ssl->no_send_shut) {
-            SSL_set_shutdown(c->ssl->ssl, SSL_SENT_SHUTDOWN);
+        if (mode) {
+            SSL_set_shutdown(c->ssl->ssl, mode);
+            c->ssl->shutdown_set = 1;
         }
     }
 
@@ -319,17 +426,17 @@ ngx_int_t ngx_ssl_shutdown(ngx_connectio
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
 
+        if (n == 1 || (n == 0 && c->read->timedout)) {
+            SSL_free(c->ssl->ssl);
+            c->ssl = NULL;
+            return NGX_OK;
+        }
+
         if (n == 0) {
             again = 1;
             break;
         }
 
-        if (n == 1) {
-            SSL_free(c->ssl->ssl);
-            c->ssl = NULL;
-            return NGX_OK;
-        }
-
         break;
     }
 
@@ -342,7 +449,7 @@ ngx_int_t ngx_ssl_shutdown(ngx_connectio
 
     if (again || sslerr == SSL_ERROR_WANT_READ) {
 
-        ngx_add_timer(c->read, 10000);
+        ngx_add_timer(c->read, 30000);
 
         if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
             return NGX_ERROR;
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -18,11 +18,13 @@
 typedef struct {
     SSL                   *ssl;
     ngx_buf_t             *buf;
-    ngx_event_handler_pt   saved_handler;
+    ngx_event_handler_pt   saved_read_handler;
+    ngx_event_handler_pt   saved_write_handler;
 
     unsigned               buffer:1;
     unsigned               no_rcv_shut:1;
     unsigned               no_send_shut:1;
+    unsigned               shutdown_set:1;
 } ngx_ssl_t;
 
 
@@ -48,10 +50,5 @@ ngx_int_t ngx_ssl_shutdown(ngx_connectio
 void ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
                    char *fmt, ...);
 
-#define ngx_ssl_set_nosendshut(ssl)                                          \
-            if (ssl) {                                                       \
-                ssl->no_send_shut = 1;                                       \
-            }
-
 
 #endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -379,7 +379,7 @@ ngx_int_t ngx_event_pipe_read_upstream(n
 
 ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
 {
-    size_t        bsize;
+    off_t         bsize;
     ngx_uint_t    flush;
     ngx_buf_t    *b;
     ngx_chain_t  *out, **ll, *cl, *tl;
@@ -442,7 +442,7 @@ ngx_int_t ngx_event_pipe_write_to_downst
         }
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
-                       "pipe write busy: %uz", bsize);
+                       "pipe write busy: %O", bsize);
 
         out = NULL;
         ll = NULL;
--- a/src/event/ngx_event_pipe.h
+++ b/src/event/ngx_event_pipe.h
@@ -62,7 +62,7 @@ struct ngx_event_pipe_s {
     ngx_bufs_t         bufs;
     ngx_buf_tag_t      tag;
 
-    size_t             busy_size;
+    ssize_t            busy_size;
 
     off_t              read_length;
 
--- a/src/http/modules/ngx_http_autoindex_handler.c
+++ b/src/http/modules/ngx_http_autoindex_handler.c
@@ -105,11 +105,10 @@ static u_char tail[] =
 
 static ngx_int_t ngx_http_autoindex_handler(ngx_http_request_t *r)
 {
-    u_char                         *last, scale;
+    u_char                         *last;
     size_t                          len;
-    off_t                           length;
     ngx_tm_t                        tm;
-    ngx_int_t                       rc, size;
+    ngx_int_t                       rc;
     ngx_uint_t                      i, level;
     ngx_err_t                       err;
     ngx_buf_t                      *b;
@@ -307,7 +306,7 @@ static ngx_int_t ngx_http_autoindex_hand
                + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof("&gt;") - 2
                + sizeof("</a>") - 1
                + sizeof(" 28-Sep-1970 12:00 ") - 1
-               + sizeof("1023G") - 1
+               + 19
                + 2;
     }
 
@@ -383,44 +382,11 @@ static ngx_int_t ngx_http_autoindex_hand
                               tm.ngx_tm_min);
 
         if (entry[i].dir) {
-            b->last = ngx_cpymem(b->last, "   -", sizeof("   -") - 1);
+            b->last = ngx_cpymem(b->last,  "                  -",
+                                 sizeof("                  -") - 1);
 
         } else {
-            length = entry[i].size;
-
-            if (length > 1024 * 1024 * 1024 - 1) {
-                size = (ngx_int_t) (length / (1024 * 1024 * 1024));
-                if ((length % (1024 * 1024 * 1024))
-                                                > (1024 * 1024 * 1024 / 2 - 1))
-                {
-                    size++;
-                }
-                scale = 'G';
-
-            } else if (length > 1024 * 1024 - 1) {
-                size = (ngx_int_t) (length / (1024 * 1024));
-                if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) {
-                    size++;
-                }
-                scale = 'M';
-
-            } else if (length > 9999) {
-                size = (ngx_int_t) (length / 1024);
-                if (length % 1024 > 511) {
-                    size++;
-                }
-                scale = 'K';
-
-            } else {
-                size = (ngx_int_t) length;
-                scale = ' ';
-            }
-
-            b->last = ngx_sprintf(b->last, "%4i", size);
-
-            if (scale != ' ') {
-                *b->last++ = scale;
-            }
+            b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
         }
 
         *b->last++ = CR;
--- a/src/http/modules/ngx_http_chunked_filter.c
+++ b/src/http/modules/ngx_http_chunked_filter.c
@@ -63,7 +63,7 @@ static ngx_int_t ngx_http_chunked_body_f
                                               ngx_chain_t *in)
 {
     u_char       *chunk;
-    size_t        size;
+    off_t         size;
     ngx_buf_t    *b;
     ngx_chain_t   out, tail, *cl, *tl, **ll;
 
@@ -106,13 +106,14 @@ static ngx_int_t ngx_http_chunked_body_f
             return NGX_ERROR;
         }
 
-        if (!(chunk = ngx_palloc(r->pool, sizeof("00000000" CRLF) - 1))) {
+        chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
+        if (chunk == NULL) {
             return NGX_ERROR;
         }
 
         b->temporary = 1;
         b->pos = chunk;
-        b->last = ngx_sprintf(chunk, "%xz" CRLF, size);
+        b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
 
         out.buf = b;
     }
--- a/src/http/modules/ngx_http_index_handler.c
+++ b/src/http/modules/ngx_http_index_handler.c
@@ -448,8 +448,7 @@ static char *ngx_http_index_merge_loc_co
     ngx_http_index_loc_conf_t  *prev = parent;
     ngx_http_index_loc_conf_t  *conf = child;
 
-    ngx_uint_t  i;
-    ngx_str_t  *index, *prev_index;
+    ngx_str_t  *index;
 
     if (conf->max_index_len == 0) {
         if (prev->max_index_len != 0) {
@@ -465,6 +464,8 @@ static char *ngx_http_index_merge_loc_co
         return NGX_CONF_OK;
     }
 
+#if 0
+
     if (prev->max_index_len != 0) {
 
         prev_index = prev->indices.elts;
@@ -476,6 +477,8 @@ static char *ngx_http_index_merge_loc_co
         }
     }
 
+#endif
+
     if (conf->max_index_len < prev->max_index_len) {
         conf->max_index_len = prev->max_index_len;
     }
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -275,12 +275,9 @@ ngx_module_t  ngx_http_proxy_module = {
 
 
 static ngx_http_log_op_name_t ngx_http_proxy_log_fmt_ops[] = {
-    { ngx_string("proxy"), /* STUB */ 100,
-                           ngx_http_proxy_log_proxy_state },
-    { ngx_string("proxy_cache_state"), sizeof("BYPASS") - 1,
-                                       ngx_http_proxy_log_cache_state },
-    { ngx_string("proxy_reason"), sizeof("BPS") - 1,
-                                  ngx_http_proxy_log_reason },
+    { ngx_string("proxy"), 0, ngx_http_proxy_log_proxy_state },
+    { ngx_string("proxy_cache_state"), 0, ngx_http_proxy_log_cache_state },
+    { ngx_string("proxy_reason"), 0, ngx_http_proxy_log_reason },
     { ngx_null_string, 0, NULL }
 };
 
@@ -792,111 +789,180 @@ u_char *ngx_http_proxy_log_error(void *d
 static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r,
                                               u_char *buf, uintptr_t data)
 {
-    ngx_http_proxy_ctx_t  *p;
+    ngx_uint_t               i;
+    ngx_http_proxy_ctx_t    *p;
+    ngx_http_proxy_state_t  *state;
 
     p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
 
     if (p == NULL) {
+        if (buf == NULL) {
+            return (u_char *) 1;
+        }
+
         *buf = '-';
         return buf + 1;
     }
 
-    if (p->state->cache_state == 0) {
-        *buf++ = '-';
 
-    } else {
-        buf = ngx_cpymem(buf, cache_states[p->state->cache_state - 1].data,
-                         cache_states[p->state->cache_state - 1].len);
-    }
-
-    *buf++ = '/';
-
-    if (p->state->expired == 0) {
-        *buf++ = '-';
-
-    } else {
-        buf = ngx_sprintf(buf, "%T", p->state->expired);
-    }
-
-    *buf++ = '/';
-
-    if (p->state->bl_time == 0) {
-        *buf++ = '-';
-
-    } else {
-        buf = ngx_sprintf(buf, "%T", p->state->bl_time);
+    if (buf == NULL) {
+        /* find the request line length */
+        return (u_char *) (uintptr_t) (p->states.nelts * /* STUB */ 100);
     }
 
-    *buf++ = '/';
+
+    i = 0;
+    state = p->states.elts;
 
-    *buf++ = '*';
+    for ( ;; ) {
+        if (state[i].cache_state == 0) {
+            *buf++ = '-';
 
-    *buf++ = ' ';
+        } else {
+            buf = ngx_cpymem(buf, cache_states[state[i].cache_state - 1].data,
+                             cache_states[state[i].cache_state - 1].len);
+        }
 
-    if (p->state->status == 0) {
-        *buf++ = '-';
+        *buf++ = '/';
+
+        if (state[i].expired == 0) {
+            *buf++ = '-';
 
-    } else {
-        buf = ngx_sprintf(buf, "%ui", p->state->status);
-    }
+        } else {
+            buf = ngx_sprintf(buf, "%T", state[i].expired);
+        }
+
+        *buf++ = '/';
+
+        if (state[i].bl_time == 0) {
+            *buf++ = '-';
 
-    *buf++ = '/';
+        } else {
+            buf = ngx_sprintf(buf, "%T", state[i].bl_time);
+        }
 
-    if (p->state->reason == 0) {
-        *buf++ = '-';
+        *buf++ = '/';
+
+        *buf++ = '*';
+
+        *buf++ = ' ';
 
-    } else {
-        buf = ngx_cpymem(buf, cache_reasons[p->state->reason - 1].data,
-                         cache_reasons[p->state->reason - 1].len);
-    }
+        if (state[i].status == 0) {
+            *buf++ = '-';
+
+        } else {
+            buf = ngx_sprintf(buf, "%ui", state[i].status);
+        }
 
-    *buf++ = '/';
+        *buf++ = '/';
+
+        if (state[i].reason == 0) {
+            *buf++ = '-';
+
+        } else {
+            buf = ngx_cpymem(buf, cache_reasons[state[i].reason - 1].data,
+                             cache_reasons[state[i].reason - 1].len);
+        }
 
-    if (p->state->reason < NGX_HTTP_PROXY_CACHE_XAE) {
-        *buf++ = '-';
+        *buf++ = '/';
+
+        if (state[i].reason < NGX_HTTP_PROXY_CACHE_XAE) {
+            *buf++ = '-';
+
+        } else {
+            buf = ngx_sprintf(buf, "%T", state[i].expires);
+        }
 
-    } else {
-        buf = ngx_sprintf(buf, "%T", p->state->expires);
+        *buf++ = ' ';
+        *buf++ = '*';
+
+        if (++i == p->states.nelts) {
+            return buf;
+        }
+
+        *buf++ = ',';
+        *buf++ = ' ';
     }
-
-    *buf++ = ' ';
-    *buf++ = '*';
-
-    return buf;
 }
 
 
 static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r,
                                               u_char *buf, uintptr_t data)
 {
-    ngx_http_proxy_ctx_t  *p;
+    ngx_uint_t               i;
+    ngx_http_proxy_ctx_t    *p;
+    ngx_http_proxy_state_t  *state;
 
     p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
 
     if (p == NULL || p->state->cache_state == 0) {
+        if (buf == NULL) {
+            return (u_char *) 1;
+        }
+
         *buf = '-';
         return buf + 1;
     }
 
-    return ngx_cpymem(buf, cache_states[p->state->cache_state - 1].data,
-                      cache_states[p->state->cache_state - 1].len);
+    if (buf == NULL) {
+        /* find the request line length */
+        return (u_char *) (p->states.nelts * sizeof("BYPASS") - 1);
+    }
+
+    i = 0;
+    state = p->states.elts;
+
+    for ( ;; ) {
+        buf = ngx_cpymem(buf, cache_states[state[i].cache_state - 1].data,
+                         cache_states[state[i].cache_state - 1].len);
+
+        if (++i == p->states.nelts) {
+            return buf;
+        }
+
+        *buf++ = ',';
+        *buf++ = ' ';
+    }
 }
 
 
 static u_char *ngx_http_proxy_log_reason(ngx_http_request_t *r, u_char *buf,
                                          uintptr_t data)
 {
-    ngx_http_proxy_ctx_t  *p;
+    ngx_uint_t               i;
+    ngx_http_proxy_ctx_t    *p;
+    ngx_http_proxy_state_t  *state;
 
     p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
 
     if (p == NULL || p->state->reason == 0) {
+        if (buf == NULL) {
+            return (u_char *) 1;
+        }
+
         *buf = '-';
         return buf + 1;
     }
 
-    return ngx_cpymem(buf, cache_reasons[p->state->reason - 1].data,
-                      cache_reasons[p->state->reason - 1].len);
+    if (buf == NULL) {
+        /* find the request line length */
+        return (u_char *) (p->states.nelts * sizeof("BPS") - 1);
+    }
+
+    i = 0;
+    state = p->states.elts;
+
+    for ( ;; ) {
+        buf = ngx_cpymem(buf, cache_reasons[state[i].reason - 1].data,
+                         cache_reasons[state[i].reason - 1].len);
+
+        if (++i == p->states.nelts) {
+            return buf;
+        }
+
+        *buf++ = ',';
+        *buf++ = ' ';
+    }
 }
 
 
@@ -1387,10 +1453,9 @@ static char *ngx_http_proxy_parse_upstre
 
 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
 {
+#if (NGX_FREEBSD)
     ssize_t *np = data;
 
-#if (NGX_FREEBSD)
-
     if (*np >= ngx_freebsd_net_inet_tcp_sendspace) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "\"proxy_send_lowat\" must be less than %d "
@@ -1401,6 +1466,7 @@ static char *ngx_http_proxy_lowat_check(
     }
 
 #elif !(NGX_HAVE_SO_SNDLOWAT)
+    ssize_t *np = data;
 
     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                        "\"proxy_send_lowat\" is not supported, ignored");
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c
@@ -528,6 +528,7 @@ static void ngx_http_proxy_reinit_upstre
 {
     ngx_chain_t             *cl;
     ngx_output_chain_ctx_t  *output;
+    ngx_http_proxy_state_e   state;
 
     /* reinit the request chain */
 
@@ -560,11 +561,17 @@ static void ngx_http_proxy_reinit_upstre
 
     /* add one more state */
 
+    state = p->state->cache_state;
+
     if (!(p->state = ngx_push_array(&p->states))) {
         ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
     }
 
+    ngx_memzero(p->state, sizeof(ngx_http_proxy_state_t));
+
+    p->state->cache_state = state; 
+
     p->status = 0;
     p->status_count = 0;
 }
@@ -719,9 +726,9 @@ static void ngx_http_proxy_connect(ngx_h
     writer->out = NULL;
     writer->last = &writer->out;
     writer->connection = c;
-    writer->limit = OFF_T_MAX_VALUE;
+    writer->limit = 0;
 
-    if (p->upstream->peer.tries > 1 && p->request_sent) {
+    if (p->request_sent) {
         ngx_http_proxy_reinit_upstream(p);
     }
 
@@ -803,13 +810,13 @@ static void ngx_http_proxy_send_request(
                           p->request_sent ? NULL:
                                             p->request->request_body->bufs);
 
+    p->request_sent = 1;
+
     if (rc == NGX_ERROR) {
         ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
         return;
     }
 
-    p->request_sent = 1;
-
     if (c->write->timer_set) {
         ngx_del_timer(c->write);
     }
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -97,6 +97,11 @@ typedef struct {
 } ngx_http_cache_t;
 
 
+typedef struct {
+    ngx_path_t                path;
+    ngx_str_t                 key;
+} ngx_http_cache_ctx_t;
+
 
 #define NGX_HTTP_CACHE_STALE     1
 #define NGX_HTTP_CACHE_AGED      2
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1815,10 +1815,9 @@ static char *ngx_set_error_log(ngx_conf_
 
 static char *ngx_http_lowat_check(ngx_conf_t *cf, void *post, void *data)
 {
+#if (NGX_FREEBSD)
     ssize_t *np = data;
 
-#if (NGX_FREEBSD)
-
     if (*np >= ngx_freebsd_net_inet_tcp_sendspace) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "\"send_lowat\" must be less than %d "
@@ -1829,6 +1828,7 @@ static char *ngx_http_lowat_check(ngx_co
     }
 
 #elif !(NGX_HAVE_SO_SNDLOWAT)
+    ssize_t *np = data;
 
     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                        "\"send_lowat\" is not supported, ignored");
--- a/src/http/ngx_http_header_filter.c
+++ b/src/http/ngx_http_header_filter.c
@@ -252,9 +252,7 @@ static ngx_int_t ngx_http_header_filter(
          * Konqueror keeps the connection alive for about N seconds.
          */
 
-        if (clcf->keepalive_header
-            && (r->headers_in.gecko || r->headers_in.konqueror))
-        {
+        if (clcf->keepalive_header) {
             len += sizeof("Keep-Alive: timeout=") - 1 + TIME_T_LEN + 2;
         }
 
@@ -384,9 +382,7 @@ static ngx_int_t ngx_http_header_filter(
         b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF,
                              sizeof("Connection: keep-alive" CRLF) - 1);
 
-        if (clcf->keepalive_header
-            && (r->headers_in.gecko || r->headers_in.konqueror))
-        {
+        if (clcf->keepalive_header) {
             b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF,
                                   clcf->keepalive_header);
         }
--- a/src/http/ngx_http_log_handler.c
+++ b/src/http/ngx_http_log_handler.c
@@ -166,7 +166,10 @@ ngx_int_t ngx_http_log_handler(ngx_http_
         len++;
 #endif
 
-        ngx_test_null(line, ngx_palloc(r->pool, len), NGX_ERROR);
+        if (!(line = ngx_palloc(r->pool, len))) {
+            return NGX_ERROR;
+        }
+
         p = line;
 
         for (i = 0; i < log[l].ops->nelts; i++) {
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -665,6 +665,8 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
     u_char  c, ch, decoded, *p, *u;
     enum {
         sw_usual = 0,
+        sw_colon,
+        sw_colon_slash,
         sw_slash,
         sw_dot,
         sw_dot_dot,
@@ -730,8 +732,14 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
             case '?':
                 r->args_start = p;
                 break;
+            case ':':
+                state = sw_colon;
+                *u++ = ch;
+                break;
             case '.':
                 r->uri_ext = u + 1;
+                *u++ = ch;
+                break;
             default:
                 *u++ = ch;
                 break;
@@ -739,6 +747,61 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
             ch = *p++;
             break;
 
+        case sw_colon:
+            switch(ch) {
+#if (NGX_WIN32)
+            case '\\':
+                state = sw_colon_slash;
+                *u++ = '/';
+                break;
+#endif
+            case '/':
+                state = sw_colon_slash;
+                *u++ = ch;
+                break;
+            case ':':
+                *u++ = ch;
+                break;
+            case '%':
+                quoted_state = state;
+                state = sw_quoted;
+                break;
+            default:
+                state = sw_usual;
+                *u++ = ch;
+                break;
+            }
+            ch = *p++;
+            break;
+
+        case sw_colon_slash:
+            switch(ch) {
+#if (NGX_WIN32)
+            case '\\':
+                state = sw_slash;
+                *u++ = '/';
+                break;
+#endif
+            case '/':
+                state = sw_slash;
+                *u++ = ch;
+                break;
+            case '.':
+                state = sw_dot;
+                *u++ = ch;
+                break;
+            case '%':
+                quoted_state = state;
+                state = sw_quoted;
+                break;
+            default:
+                state = sw_usual;
+                *u++ = ch;
+                break;
+            }
+            ch = *p++;
+            break;
+
         case sw_slash:
             switch(ch) {
 #if (NGX_WIN32)
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1190,8 +1190,9 @@ static ngx_int_t ngx_http_process_reques
 
 #if 0
             /* MSIE ignores the SSL "close notify" alert */
-
-            ngx_ssl_set_nosendshut(r->connection->ssl);
+            if (c->ssl) {
+                r->connection->ssl->no_send_shut = 1;
+            }
 #endif
         }
 
@@ -1269,7 +1270,7 @@ void ngx_http_finalize_request(ngx_http_
     }
 
     if (r->connection->read->pending_eof) {
-#if (NGX_KQUEUE)
+#if (NGX_HAVE_KQUEUE)
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log,
                        r->connection->read->kq_errno,
                        "kevent() reported about an closed connection");
@@ -1702,24 +1703,26 @@ static void ngx_http_set_keepalive(ngx_h
         }
 
         c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
+        tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
 
     } else {
-        if (clcf->tcp_nodelay && !c->tcp_nodelay) {
-            tcp_nodelay = 1;
-
-            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
-
-            if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
-                               (const void *) &tcp_nodelay, sizeof(int)) == -1)
-            {
-                ngx_connection_error(c, ngx_socket_errno,
-                                     "setsockopt(TCP_NODELAY) failed");
-                ngx_http_close_connection(c);
-                return;
-            }
-
-            c->tcp_nodelay = 1;
+        tcp_nodelay = 1;
+    }
+
+    if (tcp_nodelay && clcf->tcp_nodelay && !c->tcp_nodelay) {
+
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
+
+        if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
+                           (const void *) &tcp_nodelay, sizeof(int)) == -1)
+        {
+            ngx_connection_error(c, ngx_socket_errno,
+                                 "setsockopt(TCP_NODELAY) failed");
+            ngx_http_close_connection(c);
+            return;
         }
+
+        c->tcp_nodelay = 1;
     }
 
 #if 0
@@ -1761,6 +1764,11 @@ static void ngx_http_keepalive_handler(n
             ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
                           "kevent() reported that client %V closed "
                           "keepalive connection", ctx->client);
+#if (NGX_HTTP_SSL)
+            if (c->ssl) {
+                c->ssl->no_send_shut = 1;
+            }
+#endif
             ngx_http_close_connection(c);
             return;
         }
--- a/src/http/ngx_http_write_filter.c
+++ b/src/http/ngx_http_write_filter.c
@@ -152,8 +152,7 @@ ngx_int_t ngx_http_write_filter(ngx_http
 
     sent = c->sent;
 
-    chain = c->send_chain(c, ctx->out,
-                          clcf->limit_rate ? clcf->limit_rate: OFF_T_MAX_VALUE);
+    chain = c->send_chain(c, ctx->out, clcf->limit_rate);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http write filter %p", chain);
--- a/src/os/unix/ngx_aio_write_chain.c
+++ b/src/os/unix/ngx_aio_write_chain.c
@@ -20,6 +20,12 @@ ngx_chain_t *ngx_aio_write_chain(ngx_con
     ngx_err_t     err;
     ngx_chain_t  *cl;
 
+    /* the maximum limit size is the maximum size_t value - the page size */
+
+    if (limit == 0 || limit > MAX_SIZE_T_VALUE - ngx_pagesize) {
+        limit = MAX_SIZE_T_VALUE - ngx_pagesize;
+    }
+
     send = 0;
     sent = 0;
     cl = in;
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -104,7 +104,7 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, 
 #else
 #define ngx_de_namelen(dir)      ngx_strlen((dir)->de->d_name)
 #endif
-#define ngx_de_info(name, dir)   stat((const char *) name, &(dir)->info)
+#define ngx_de_info(name, dir)   lstat((const char *) name, &(dir)->info)
 #define ngx_de_info_n            "stat()"
 #define ngx_de_is_dir(dir)       (S_ISDIR((dir)->info.st_mode))
 #define ngx_de_is_file(dir)      (S_ISREG((dir)->info.st_mode))
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -204,6 +204,9 @@ ngx_int_t ngx_os_init(ngx_log_t *log)
     }
 
 
+    ngx_tcp_nodelay_and_tcp_nopush = 1;
+
+
     return ngx_posix_init(log);
 }
 
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -37,9 +37,8 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
 {
     int              rc;
     u_char          *prev;
-    off_t            fprev, sent, send, sprev, aligned;
-    size_t           hsize, fsize;
-    ssize_t          size;
+    off_t            size, send, prev_send, aligned, sent, fprev;
+    size_t           header_size, file_size;
     ngx_uint_t       eintr, eagain, complete;
     ngx_err_t        err;
     ngx_buf_t       *file;
@@ -67,6 +66,12 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
 
 #endif
 
+    /* the maximum limit size is the maximum size_t value - the page size */
+
+    if (limit == 0 || limit > MAX_SIZE_T_VALUE - ngx_pagesize) {
+        limit = MAX_SIZE_T_VALUE - ngx_pagesize;
+    }
+
     send = 0;
     eagain = 0;
 
@@ -82,11 +87,11 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
 
     for ( ;; ) {
         file = NULL;
-        fsize = 0;
-        hsize = 0;
+        file_size = 0;
+        header_size = 0;
         eintr = 0;
         complete = 0;
-        sprev = send;
+        prev_send = send;
 
         header.nelts = 0;
         trailer.nelts = 0;
@@ -115,7 +120,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             }
 
             if (prev == cl->buf->pos) {
-                iov->iov_len += size;
+                iov->iov_len += (size_t) size;
 
             } else {
                 if (!(iov = ngx_array_push(&header))) {
@@ -123,11 +128,11 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
                 }
 
                 iov->iov_base = (void *) cl->buf->pos;
-                iov->iov_len = size;
+                iov->iov_len = (size_t) size;
             }
 
-            prev = cl->buf->pos + size;
-            hsize += size;
+            prev = cl->buf->pos + (size_t) size;
+            header_size += (size_t) size;
             send += size;
         }
 
@@ -138,7 +143,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             /* coalesce the neighbouring file bufs */
 
             do {
-                size = (size_t) (cl->buf->file_last - cl->buf->file_pos);
+                size = cl->buf->file_last - cl->buf->file_pos;
 
                 if (send + size > limit) {
                     size = limit - send;
@@ -151,7 +156,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
                     }
                 }
 
-                fsize += size;
+                file_size += (size_t) size;
                 send += size;
                 fprev = cl->buf->file_pos + size;
                 cl = cl->next;
@@ -189,7 +194,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
                 }
 
                 if (prev == cl->buf->pos) {
-                    iov->iov_len += size;
+                    iov->iov_len += (size_t) size;
 
                 } else {
                     if (!(iov = ngx_array_push(&trailer))) {
@@ -197,10 +202,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
                     }
 
                     iov->iov_base = (void *) cl->buf->pos;
-                    iov->iov_len = size;
+                    iov->iov_len = (size_t) size;
                 }
 
-                prev = cl->buf->pos + size;
+                prev = cl->buf->pos + (size_t) size;
                 send += size;
                 cl = cl->next;
             }
@@ -245,13 +250,13 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
              */
 
             if (ngx_freebsd_sendfile_nbytes_bug == 0) {
-                hsize = 0;
+                header_size = 0;
             }
 
             sent = 0;
 
             rc = sendfile(file->file->fd, c->fd, file->file_pos,
-                          fsize + hsize, &hdtr, &sent, 0);
+                          file_size + header_size, &hdtr, &sent, 0);
 
             if (rc == -1) {
                 err = ngx_errno;
@@ -265,8 +270,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
                     }
 
                     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
-                                   "sendfile() sent only %O bytes",
-                                   sent);
+                                   "sendfile() sent only %O bytes", sent);
 
                 } else {
                     wev->error = 1;
@@ -291,13 +295,13 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
 
             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
                            "sendfile: %d, @%O %O:%uz",
-                           rc, file->file_pos, sent, fsize + hsize);
+                           rc, file->file_pos, sent, file_size + header_size);
 
         } else {
             rc = writev(c->fd, header.elts, header.nelts);
 
             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                           "writev: %d of %uz", rc, hsize);
+                           "writev: %d of %uz", rc, header_size);
 
             if (rc == -1) {
                 err = ngx_errno;
@@ -320,7 +324,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             sent = rc > 0 ? rc : 0;
         }
 
-        if (send - sprev == sent) {
+        if (send - prev_send == sent) {
             complete = 1;
         }
 
@@ -353,7 +357,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             }
 
             if (ngx_buf_in_memory(cl->buf)) {
-                cl->buf->pos += sent;
+                cl->buf->pos += (size_t) sent;
             }
 
             if (cl->buf->in_file) {
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -25,11 +25,10 @@
 ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
                                       off_t limit)
 {
-    int              rc;
+    int              rc, tcp_nodelay;
     u_char          *prev;
-    off_t            fprev, send, sprev, aligned;
-    size_t           fsize;
-    ssize_t          size, sent;
+    off_t            size, send, prev_send, aligned, sent, fprev;
+    size_t           file_size;
     ngx_uint_t       eintr, complete;
     ngx_err_t        err;
     ngx_buf_t       *file;
@@ -49,6 +48,14 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
         return in;
     }
 
+
+    /* the maximum limit size is the maximum size_t value - the page size */
+
+    if (limit == 0 || limit > MAX_SIZE_T_VALUE - ngx_pagesize) {
+        limit = MAX_SIZE_T_VALUE - ngx_pagesize;
+    }
+
+
     send = 0;
 
     header.elts = headers;
@@ -58,10 +65,10 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
 
     for ( ;; ) {
         file = NULL;
-        fsize = 0;
+        file_size = 0;
         eintr = 0;
         complete = 0;
-        sprev = send;
+        prev_send = send;
 
         header.nelts = 0;
 
@@ -89,7 +96,7 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
             }
 
             if (prev == cl->buf->pos) {
-                iov->iov_len += size;
+                iov->iov_len += (size_t) size;
 
             } else {
                 if (!(iov = ngx_array_push(&header))) {
@@ -97,10 +104,10 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
                 }
 
                 iov->iov_base = (void *) cl->buf->pos;
-                iov->iov_len = size;
+                iov->iov_len = (size_t) size;
             }
 
-            prev = cl->buf->pos + size;
+            prev = cl->buf->pos + (size_t) size;
             send += size;
         }
 
@@ -111,25 +118,62 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
             && cl
             && cl->buf->in_file)
         {
-            if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
-                err = ngx_errno;
+
+            /* the TCP_CORK and TCP_NODELAY are mutually exclusive */
+
+            if (c->tcp_nodelay) {
+
+                tcp_nodelay = 0;
+
+                if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
+                               (const void *) &tcp_nodelay, sizeof(int)) == -1)
+                {
+                    err = ngx_errno;
 
-                /*
-                 * there is a tiny chance to be interrupted, however
-                 * we continue a processing without the TCP_CORK
-                 */
+                    /*
+                     * there is a tiny chance to be interrupted, however
+                     * we continue a processing with the TCP_NODELAY
+                     * and without the TCP_CORK
+                     */
+
+                    if (err != NGX_EINTR) { 
+                        wev->error = 1;
+                        ngx_connection_error(c, ngx_socket_errno,
+                                             "setsockopt(TCP_NODELAY) failed");
+                        return NGX_CHAIN_ERROR;
+                    }
+
+                } else {
+                    c->tcp_nodelay = 0;
 
-                if (err != NGX_EINTR) { 
-                    wev->error = 1;
-                    ngx_connection_error(c, err, ngx_tcp_nopush_n " failed");
-                    return NGX_CHAIN_ERROR;
+                    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                                   "no tcp_nodelay");
                 }
+            }
+
+            if (!c->tcp_nodelay) {
+
+                if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
+                    err = ngx_errno;
 
-            } else {
-                c->tcp_nopush = NGX_TCP_NOPUSH_SET;
+                    /*
+                     * there is a tiny chance to be interrupted, however
+                     * we continue a processing without the TCP_CORK
+                     */
 
-                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                               "tcp_nopush");
+                    if (err != NGX_EINTR) { 
+                        wev->error = 1;
+                        ngx_connection_error(c, err,
+                                             ngx_tcp_nopush_n " failed");
+                        return NGX_CHAIN_ERROR;
+                    }
+
+                } else {
+                    c->tcp_nopush = NGX_TCP_NOPUSH_SET;
+    
+                    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                                   "tcp_nopush");
+                }
             }
         }
 
@@ -141,7 +185,7 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
             /* coalesce the neighbouring file bufs */
 
             do {
-                size = (size_t) (cl->buf->file_last - cl->buf->file_pos);
+                size = cl->buf->file_last - cl->buf->file_pos;
 
                 if (send + size > limit) {
                     size = limit - send;
@@ -154,7 +198,7 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
                     }
                 }
 
-                fsize += size;
+                file_size += (size_t) size;
                 send += size;
                 fprev = cl->buf->file_pos + size;
                 cl = cl->next;
@@ -172,7 +216,7 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
 #else
             offset = (int32_t) file->file_pos;
 #endif
-            rc = sendfile(c->fd, file->file->fd, &offset, fsize);
+            rc = sendfile(c->fd, file->file->fd, &offset, file_size);
 
             if (rc == -1) {
                 err = ngx_errno;
@@ -195,8 +239,8 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
             sent = rc > 0 ? rc : 0;
 
             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
-                           "sendfile: %d, @%O %z:%uz",
-                           rc, file->file_pos, sent, fsize);
+                           "sendfile: %d, @%O %O:%uz",
+                           rc, file->file_pos, sent, file_size);
 
         } else {
             rc = writev(c->fd, header.elts, header.nelts);
@@ -221,10 +265,10 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
 
             sent = rc > 0 ? rc : 0;
 
-            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %z", sent);
+            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %O", sent);
         }
 
-        if (send - sprev == sent) {
+        if (send - prev_send == sent) {
             complete = 1;
         }
 
@@ -257,7 +301,7 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
             }
 
             if (ngx_buf_in_memory(cl->buf)) {
-                cl->buf->pos += sent;
+                cl->buf->pos += (size_t) sent;
             }
 
             if (cl->buf->in_file) {
--- a/src/os/unix/ngx_os.h
+++ b/src/os/unix/ngx_os.h
@@ -50,7 +50,8 @@ ngx_chain_t *ngx_writev_chain(ngx_connec
 extern ngx_os_io_t  ngx_os_io;
 extern ngx_int_t    ngx_ncpu;
 extern ngx_int_t    ngx_max_sockets;
-extern ngx_int_t    ngx_inherited_nonblocking;
+extern ngx_uint_t   ngx_inherited_nonblocking;
+extern ngx_uint_t   ngx_tcp_nodelay_and_tcp_nopush;
 
 #define ngx_stderr_fileno  STDERR_FILENO
 
--- a/src/os/unix/ngx_posix_init.c
+++ b/src/os/unix/ngx_posix_init.c
@@ -8,9 +8,10 @@
 #include <ngx_core.h>
 
 
-ngx_int_t  ngx_ncpu;
-ngx_int_t  ngx_max_sockets;
-ngx_int_t  ngx_inherited_nonblocking;
+ngx_int_t   ngx_ncpu;
+ngx_int_t   ngx_max_sockets;
+ngx_uint_t  ngx_inherited_nonblocking;
+ngx_uint_t  ngx_tcp_nodelay_and_tcp_nopush;
 
 
 struct rlimit  rlmt;
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -17,7 +17,7 @@ static void ngx_signal_worker_processes(
 static ngx_uint_t ngx_reap_childs(ngx_cycle_t *cycle);
 static void ngx_master_exit(ngx_cycle_t *cycle);
 static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data);
-static void ngx_worker_process_init(ngx_cycle_t *cycle);
+static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority);
 static void ngx_channel_handler(ngx_event_t *ev);
 #if (NGX_THREADS)
 static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle);
@@ -564,6 +564,33 @@ static ngx_uint_t ngx_reap_childs(ngx_cy
                     continue;
                 }
 
+
+                ch.command = NGX_CMD_OPEN_CHANNEL;
+                ch.pid = ngx_processes[ngx_process_slot].pid;
+                ch.slot = ngx_process_slot;
+                ch.fd = ngx_processes[ngx_process_slot].channel[0];
+
+                for (n = 0; n < ngx_last_process; n++) {
+
+                    if (n == ngx_process_slot
+                        || ngx_processes[n].pid == -1
+                        || ngx_processes[n].channel[0] == -1)
+                    {
+                        continue;
+                    }
+
+                    ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+                          "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
+                          ch.slot, ch.pid, ch.fd,
+                          n, ngx_processes[n].pid,
+                          ngx_processes[n].channel[0]);
+
+                    /* TODO: NGX_AGAIN */
+
+                    ngx_write_channel(ngx_processes[n].channel[0],
+                                      &ch, sizeof(ngx_channel_t), cycle->log);
+                }
+
                 live = 1;
 
                 continue;
@@ -611,7 +638,7 @@ static void ngx_worker_process_cycle(ngx
     ngx_err_t          err;
     ngx_core_conf_t   *ccf;
 
-    ngx_worker_process_init(cycle);
+    ngx_worker_process_init(cycle, 1);
 
     ngx_setproctitle("worker process");
 
@@ -718,7 +745,7 @@ static void ngx_worker_process_cycle(ngx
 }
 
 
-static void ngx_worker_process_init(ngx_cycle_t *cycle)
+static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority)
 {
     sigset_t           set;
     ngx_int_t          n;
@@ -739,6 +766,13 @@ static void ngx_worker_process_init(ngx_
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
     if (geteuid() == 0) {
+        if (priority && ccf->priority != 0) {
+            if (setpriority(PRIO_PROCESS, 0, ccf->priority) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                              "setpriority(%d) failed", ccf->priority);
+            }
+        }
+
         if (setgid(ccf->group) == -1) {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                           "setgid(%d) failed", ccf->group);
@@ -746,6 +780,12 @@ static void ngx_worker_process_init(ngx_
             exit(2);
         }
 
+        if (initgroups(ccf->username, ccf->group) == -1) {
+            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                          "initgroups(%s, %d) failed",
+                          ccf->username, ccf->group);
+        }
+
         if (setuid(ccf->user) == -1) {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                           "setuid(%d) failed", ccf->user);
@@ -1041,7 +1081,7 @@ static void ngx_garbage_collector_cycle(
     ngx_path_t       **path;
     ngx_event_t       *ev;
 
-    ngx_worker_process_init(cycle);
+    ngx_worker_process_init(cycle, 0);
 
     ev = &cycle->read_events[ngx_channel];
 
--- a/src/os/unix/ngx_solaris_sendfilev_chain.c
+++ b/src/os/unix/ngx_solaris_sendfilev_chain.c
@@ -9,6 +9,28 @@
 #include <ngx_event.h>
 
 
+#if (NGX_TEST_BUILD_SOLARIS_SENDFILEV)
+
+/* Solaris declarations */
+
+typedef struct sendfilevec {
+    int     sfv_fd;
+    u_int   sfv_flag;
+    off_t   sfv_off;
+    size_t  sfv_len;
+} sendfilevec_t;
+
+#define SFV_FD_SELF  -2
+
+static ssize_t sendfilev(int fd, const struct sendfilevec *vec,
+                         int sfvcnt, size_t *xferred)
+{
+    return -1;
+}
+
+#endif
+
+
 #define NGX_SENDFILEVECS   16
 
 
@@ -17,8 +39,9 @@ ngx_chain_t *ngx_solaris_sendfilev_chain
 {
     int             fd;
     u_char         *prev;
-    off_t           fprev, sprev, send, aligned;
-    ssize_t         size, sent, n;
+    off_t           size, send, prev_send, aligned, fprev;
+    size_t          sent;
+    ssize_t         n;
     ngx_int_t       eintr, complete;
     ngx_err_t       err;
     sendfilevec_t  *sfv, sfvs[NGX_SENDFILEVECS];
@@ -36,6 +59,14 @@ ngx_chain_t *ngx_solaris_sendfilev_chain
         return ngx_writev_chain(c, in, limit);
     }
 
+
+    /* the maximum limit size is the maximum size_t value - the page size */
+
+    if (limit == 0 || limit > MAX_SIZE_T_VALUE - ngx_pagesize) {
+        limit = MAX_SIZE_T_VALUE - ngx_pagesize;
+    }
+
+
     send = 0;
     complete = 0;
 
@@ -51,7 +82,7 @@ ngx_chain_t *ngx_solaris_sendfilev_chain
         sfv = NULL;
         eintr = 0;
         sent = 0;
-        sprev = send;
+        prev_send = send;
 
         vec.nelts = 0;
 
@@ -73,7 +104,7 @@ ngx_chain_t *ngx_solaris_sendfilev_chain
                 }
 
                 if (prev == cl->buf->pos) {
-                    sfv->sfv_len += size;
+                    sfv->sfv_len += (size_t) size;
 
                 } else {
                     if (!(sfv = ngx_array_push(&vec))) {
@@ -83,16 +114,16 @@ ngx_chain_t *ngx_solaris_sendfilev_chain
                     sfv->sfv_fd = SFV_FD_SELF;
                     sfv->sfv_flag = 0;
                     sfv->sfv_off = (off_t) (uintptr_t) cl->buf->pos;
-                    sfv->sfv_len = size;
+                    sfv->sfv_len = (size_t) size;
                 }
 
-                prev = cl->buf->pos + size;
+                prev = cl->buf->pos + (size_t) size;
                 send += size;
 
             } else {
                 prev = NULL;
 
-                size = (size_t) (cl->buf->file_last - cl->buf->file_pos);
+                size = cl->buf->file_last - cl->buf->file_pos;
 
                 if (send + size > limit) {
                     size = limit - send;
@@ -106,7 +137,7 @@ ngx_chain_t *ngx_solaris_sendfilev_chain
                 }
 
                 if (fd == cl->buf->file->fd && fprev == cl->buf->file_pos) {
-                    sfv->sfv_len += size;
+                    sfv->sfv_len += (size_t) size;
 
                 } else {
                     if (!(sfv = ngx_array_push(&vec))) {
@@ -117,7 +148,7 @@ ngx_chain_t *ngx_solaris_sendfilev_chain
                     sfv->sfv_fd = fd;
                     sfv->sfv_flag = 0;
                     sfv->sfv_off = cl->buf->file_pos;
-                    sfv->sfv_len = size;
+                    sfv->sfv_len = (size_t) size;
                 }
 
                 fprev = cl->buf->file_pos + size;
@@ -136,7 +167,7 @@ ngx_chain_t *ngx_solaris_sendfilev_chain
                 }
 
                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
-                              "sendfilev() sent only %z bytes", sent);
+                              "sendfilev() sent only %uz bytes", sent);
 
             } else {
                 wev->error = 1;
@@ -148,7 +179,7 @@ ngx_chain_t *ngx_solaris_sendfilev_chain
         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
                        "sendfilev: %z %z", n, sent);
 
-        if (send - sprev == sent) {
+        if (send - prev_send == (off_t) sent) {
             complete = 1;
         }
 
@@ -166,8 +197,8 @@ ngx_chain_t *ngx_solaris_sendfilev_chain
 
             size = ngx_buf_size(cl->buf);
 
-            if (sent >= size) {
-                sent -= size;
+            if ((off_t) sent >= size) {
+                sent = (size_t) ((off_t) sent - size);
 
                 if (ngx_buf_in_memory(cl->buf)) {
                     cl->buf->pos = cl->buf->last;
--- a/src/os/unix/ngx_writev_chain.c
+++ b/src/os/unix/ngx_writev_chain.c
@@ -16,7 +16,7 @@ ngx_chain_t *ngx_writev_chain(ngx_connec
 {
     u_char        *prev;
     ssize_t        n, size, sent;
-    off_t          send, sprev;
+    off_t          send, prev_send;
     ngx_uint_t     eintr, complete;
     ngx_err_t      err;
     ngx_array_t    vec;
@@ -42,6 +42,12 @@ ngx_chain_t *ngx_writev_chain(ngx_connec
 
 #endif
 
+    /* the maximum limit size is the maximum size_t value - the page size */
+
+    if (limit == 0 || limit > MAX_SIZE_T_VALUE - ngx_pagesize) {
+        limit = MAX_SIZE_T_VALUE - ngx_pagesize;
+    }
+
     send = 0;
     complete = 0;
 
@@ -54,7 +60,7 @@ ngx_chain_t *ngx_writev_chain(ngx_connec
         prev = NULL;
         iov = NULL;
         eintr = 0;
-        sprev = send;
+        prev_send = send;
 
         vec.nelts = 0;
 
@@ -118,7 +124,7 @@ ngx_chain_t *ngx_writev_chain(ngx_connec
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %z", sent);
 
-        if (send - sprev == sent) {
+        if (send - prev_send == sent) {
             complete = 1;
         }
 
--- a/src/os/win32/ngx_errno.c
+++ b/src/os/win32/ngx_errno.c
@@ -43,7 +43,11 @@ static ngx_str_t  wsa_errors[] = {
     ngx_null_string,                                               /* 10039 */
     ngx_null_string,                                               /* 10040 */
     ngx_null_string,                                               /* 10041 */
-    ngx_null_string,                                               /* 10042 */
+
+    /* WSAENOPROTOOPT 10042 */
+    ngx_string("An unknown, invalid, or unsupported option or level was "
+               "specified in a getsockopt or setsockopt call"),
+
     ngx_null_string,                                               /* 10043 */
     ngx_null_string,                                               /* 10044 */
     ngx_null_string,                                               /* 10045 */
--- a/src/os/win32/ngx_os.h
+++ b/src/os/win32/ngx_os.h
@@ -48,6 +48,7 @@ extern ngx_uint_t   ngx_ncpu;
 extern ngx_uint_t   ngx_max_wsabufs;
 extern ngx_int_t    ngx_max_sockets;
 extern ngx_uint_t   ngx_inherited_nonblocking;
+extern ngx_uint_t   ngx_tcp_nodelay_and_tcp_nopush;
 extern ngx_uint_t   ngx_win32_version;
 extern ngx_fd_t     ngx_stderr_fileno;
 
--- a/src/os/win32/ngx_win32_config.h
+++ b/src/os/win32/ngx_win32_config.h
@@ -141,5 +141,10 @@ typedef uint32_t          ngx_atomic_t;
 #define NGX_HAVE_SENDFILE  1
 #endif
 
+#ifndef NGX_HAVE_SO_SNDLOWAT
+/* setsockopt(SO_SNDLOWAT) returns error WSAENOPROTOOPT */
+#define NGX_HAVE_SO_SNDLOWAT         0
+#endif
+
 
 #endif /* _NGX_WIN32_CONFIG_H_INCLUDED_ */
--- a/src/os/win32/ngx_win32_init.c
+++ b/src/os/win32/ngx_win32_init.c
@@ -13,6 +13,8 @@ ngx_uint_t  ngx_ncpu;
 ngx_uint_t  ngx_max_wsabufs;
 ngx_int_t   ngx_max_sockets;
 ngx_uint_t  ngx_inherited_nonblocking = 1;
+ngx_uint_t  ngx_tcp_nodelay_and_tcp_nopush;
+
 ngx_fd_t    ngx_stderr_fileno;
 
 
--- a/src/os/win32/ngx_wsasend_chain.c
+++ b/src/os/win32/ngx_wsasend_chain.c
@@ -17,7 +17,7 @@ ngx_chain_t *ngx_wsasend_chain(ngx_conne
 {
     int           rc;
     u_char       *prev;
-    u_long        size, sent, send, sprev;
+    u_long        size, sent, send, prev_send;
     ngx_uint_t    complete;
     ngx_err_t     err;
     ngx_event_t  *wev;
@@ -32,6 +32,12 @@ ngx_chain_t *ngx_wsasend_chain(ngx_conne
         return in;
     }
 
+    /* the maximum limit size is the maximum u_long value - the page size */
+
+    if (limit == 0 || limit > NGX_MAX_UINT32_VALUE - ngx_pagesize) {
+        limit = NGX_MAX_UINT32_VALUE - ngx_pagesize;
+    }
+
     send = 0;
     complete = 0;
 
@@ -48,7 +54,7 @@ ngx_chain_t *ngx_wsasend_chain(ngx_conne
     for ( ;; ) {
         prev = NULL;
         wsabuf = NULL;
-        sprev = send;
+        prev_send = send;
 
         vec.nelts = 0;
 
@@ -105,7 +111,7 @@ ngx_chain_t *ngx_wsasend_chain(ngx_conne
         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
                        "WSASend: fd:%d, s:%ul", c->fd, sent);
 
-        if (send - sprev == sent) {
+        if (send - prev_send == sent) {
             complete = 1;
         }
 
@@ -153,8 +159,7 @@ ngx_chain_t *ngx_overlapped_wsasend_chai
 {
     int               rc;
     u_char           *prev;
-    size_t            size;
-    u_long            send, sent;
+    u_long            size, send, sent;
     LPWSABUF          wsabuf;
     ngx_err_t         err;
     ngx_event_t      *wev;
@@ -175,6 +180,12 @@ ngx_chain_t *ngx_overlapped_wsasend_chai
     if (!wev->complete) {
 
         /* post the overlapped WSASend() */
+
+        /* the maximum limit size is the maximum u_long value - the page size */
+
+        if (limit == 0 || limit > NGX_MAX_UINT32_VALUE - ngx_pagesize) {
+            limit = NGX_MAX_UINT32_VALUE - ngx_pagesize;
+        }
  
         /*
          * WSABUFs must be 4-byte aligned otherwise