changeset 28:7ca9bdc82b3f NGINX_0_1_14

nginx 0.1.14 *) Feature: the autoconfiguration directives: --http-client-body-temp-path=PATH, --http-proxy-temp-path=PATH, and --http-fastcgi-temp-path=PATH *) Change: the directory name for the temporary files with the client request body is specified by directive client_body_temp_path, by default it is <prefix>/client_body_temp. *) Feature: the ngx_http_fastcgi_module and the directives: fastcgi_pass, fastcgi_root, fastcgi_index, fastcgi_params, fastcgi_connect_timeout, fastcgi_send_timeout, fastcgi_read_timeout, fastcgi_send_lowat, fastcgi_header_buffer_size, fastcgi_buffers, fastcgi_busy_buffers_size, fastcgi_temp_path, fastcgi_max_temp_file_size, fastcgi_temp_file_write_size, fastcgi_next_upstream, and fastcgi_x_powered_by. *) Bugfix: the "[alert] zero size buf" error; bug appeared in 0.1.3. *) Change: the URI must be specified after the host name in the proxy_pass directive. *) Change: the %3F symbol in the URI was considered as the argument string start. *) Feature: the unix domain sockets support in the ngx_http_proxy_module. *) Feature: the ssl_engine and ssl_ciphers directives. Thanks to Sergey Skvortsov for SSL-accelerator.
author Igor Sysoev <http://sysoev.ru>
date Tue, 18 Jan 2005 00:00:00 +0300
parents 66901c2556fd
children 3efadd1f18f7
files CHANGES CHANGES.ru LICENSE auto/cc/icc auto/lib/openssl/conf auto/lib/openssl/make auto/lib/zlib/make auto/modules auto/options auto/os/conf auto/sources auto/summary auto/unix configure src/core/nginx.c src/core/nginx.h src/core/ngx_buf.h src/core/ngx_conf_file.h src/core/ngx_connection.c src/core/ngx_connection.h src/core/ngx_core.h src/core/ngx_cycle.c src/core/ngx_file.c src/core/ngx_file.h src/core/ngx_inet.c src/core/ngx_inet.h src/core/ngx_output_chain.c src/core/ngx_regex.c src/core/ngx_string.c src/core/ngx_string.h src/core/ngx_unix_domain.c src/core/ngx_unix_domain.h src/event/ngx_event_accept.c src/event/ngx_event_connect.c src/event/ngx_event_connect.h src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/event/ngx_event_pipe.c src/http/modules/ngx_http_access_handler.c src/http/modules/ngx_http_fastcgi_handler.c src/http/modules/ngx_http_gzip_filter.c src/http/modules/ngx_http_ssl_module.c src/http/modules/ngx_http_ssl_module.h src/http/modules/ngx_http_userid_filter.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/modules/proxy/ngx_http_proxy_handler.h src/http/modules/proxy/ngx_http_proxy_header.c src/http/modules/proxy/ngx_http_proxy_upstream.c src/http/ngx_http.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_log_handler.c src/http/ngx_http_log_handler.h src/http/ngx_http_parse.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_upstream.c src/http/ngx_http_upstream.h src/http/ngx_http_write_filter.c src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_freebsd_sendfile_chain.c src/os/unix/ngx_linux_config.h src/os/unix/ngx_linux_sendfile_chain.c src/os/unix/ngx_posix_config.h src/os/unix/ngx_process_cycle.c src/os/unix/ngx_solaris_config.h
diffstat 68 files changed, 5384 insertions(+), 1250 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,35 @@
+
+Changes with nginx 0.1.14                                        18 Jan 2005
+
+    *) Feature: the autoconfiguration directives: 
+       --http-client-body-temp-path=PATH, --http-proxy-temp-path=PATH, and 
+       --http-fastcgi-temp-path=PATH
+
+    *) Change: the directory name for the temporary files with the client 
+       request body is specified by directive client_body_temp_path, by 
+       default it is <prefix>/client_body_temp.
+
+    *) Feature: the ngx_http_fastcgi_module and the directives: fastcgi_pass, 
+       fastcgi_root, fastcgi_index, fastcgi_params, fastcgi_connect_timeout, 
+       fastcgi_send_timeout, fastcgi_read_timeout, fastcgi_send_lowat, 
+       fastcgi_header_buffer_size, fastcgi_buffers, 
+       fastcgi_busy_buffers_size, fastcgi_temp_path, 
+       fastcgi_max_temp_file_size, fastcgi_temp_file_write_size, 
+       fastcgi_next_upstream, and fastcgi_x_powered_by.
+
+    *) Bugfix: the "[alert] zero size buf" error; bug appeared in 0.1.3.
+
+    *) Change: the URI must be specified after the host name in the 
+       proxy_pass directive.
+
+    *) Change: the %3F symbol in the URI was considered as the argument 
+       string start.
+
+    *) Feature: the unix domain sockets support in the ngx_http_proxy_module.
+
+    *) Feature: the ssl_engine and ssl_ciphers directives.
+       Thanks to Sergey Skvortsov for SSL-accelerator.
+
 
 Changes with nginx 0.1.13                                        21 Dec 2004
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,3 +1,36 @@
+
+Изменения в nginx 0.1.14                                          18.01.2005
+
+    *) Добавление: параметры автоконфигурации 
+       --http-client-body-temp-path=PATH, --http-proxy-temp-path=PATH и 
+       --http-fastcgi-temp-path=PATH
+
+    *) Изменение: имя каталога с временными файлами, содержащие тело запроса 
+       клиента, задаётся директивой client_body_temp_path, по умолчанию 
+       <prefix>/client_body_temp.
+
+    *) Добавление: модуль ngx_http_fastcgi_module и директивы fastcgi_pass, 
+       fastcgi_root, fastcgi_index, fastcgi_params, fastcgi_connect_timeout, 
+       fastcgi_send_timeout, fastcgi_read_timeout, fastcgi_send_lowat, 
+       fastcgi_header_buffer_size, fastcgi_buffers, 
+       fastcgi_busy_buffers_size, fastcgi_temp_path, 
+       fastcgi_max_temp_file_size, fastcgi_temp_file_write_size, 
+       fastcgi_next_upstream и fastcgi_x_powered_by.
+
+    *) Исправление: ошибка "[alert] zero size buf"; ошибка появилась в 0.1.3.
+
+    *) Изменение: в директиве proxy_pass нужно обязательно указывать URI 
+       после имени хоста.
+
+    *) Изменение: если в URI встречался символ %3F, то он считался началом 
+       строки аргументов.
+
+    *) Добавление: поддержка unix domain сoкетов в модуле 
+       ngx_http_proxy_module.
+
+    *) Добавление: директивы ssl_engine и ssl_ciphers.
+       Спасибо Сергею Скворцову за SSL-акселератор.
+
 
 Изменения в nginx 0.1.13                                          21.12.2004
 
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2002-2004 Igor Sysoev
+ * Copyright (C) 2002-2005 Igor Sysoev
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
--- a/auto/cc/icc
+++ b/auto/cc/icc
@@ -57,6 +57,12 @@ fi
 CFLAGS="$CFLAGS -w1"
 #CFLAGS="$CFLAGS -w2"
 
+# disable the ICC 8.0 errors:
+#    error #181: argument is incompatible with corresponding format
+#                string conversion
+#    error #269: invalid format string conversion
+CFLAGS="$CFLAGS -wd181 -wd269"
+
 # stop on warning
 CFLAGS="$CFLAGS -Werror"
 
--- a/auto/lib/openssl/conf
+++ b/auto/lib/openssl/conf
@@ -13,9 +13,15 @@ if [ $OPENSSL != NONE ]; then
             LINK_DEPS="$LINK_DEPS $OPENSSL/libssl.a $OPENSSL/libcrypto.a"
             CORE_LIBS="$CORE_LIBS $OPENSSL/libssl.a $OPENSSL/libcrypto.a"
         ;;
+    esac
 
+    case "$NGX_SYSTEM" in
+        SunOS|Linux)
+            CORE_LIBS="$CORE_LIBS -ldl"
+        ;;
     esac
 
+
 else
 
     if [ $NGX_PLATFORM != win32 ]; then
--- a/auto/lib/openssl/make
+++ b/auto/lib/openssl/make
@@ -6,6 +6,7 @@ case $NGX_PLATFORM in
     *)
         echo "$OPENSSL/libssl.a:"                                 >> $MAKEFILE
         echo "	cd $OPENSSL \\"                                   >> $MAKEFILE
+        echo "	&& \$(MAKE) clean \\"                             >> $MAKEFILE
         echo "	&& CC=\"\$(CC)\" \\"                              >> $MAKEFILE
         echo "	./config threads no-shared \\"                    >> $MAKEFILE
         echo "	&& \$(MAKE)"                                      >> $MAKEFILE
--- a/auto/lib/zlib/make
+++ b/auto/lib/zlib/make
@@ -54,7 +54,7 @@ END
 
 $ZLIB/libz.a:	$NGX_MAKEFILE
 	cd $ZLIB \\
-	&& make clean \\
+	&& \$(MAKE) clean \\
 	&& cp contrib/asm586/match.S . \\
 	&& CFLAGS="$ZLIB_OPT -DASMV" CC="\$(CC)" \\
 		./configure \\
@@ -71,7 +71,7 @@ END
 
 $ZLIB/libz.a:	$NGX_MAKEFILE
 	cd $ZLIB \\
-	&& make clean \\
+	&& \$(MAKE) clean \\
 	&& cp contrib/asm686/match.S . \\
 	&& CFLAGS="$ZLIB_OPT -DASMV" CC="\$(CC)" \\
 		./configure \\
@@ -104,7 +104,7 @@ if [ $done = NO ]; then
 
 $ZLIB/libz.a:	$NGX_MAKEFILE
 	cd $ZLIB \\
-	&& make clean \\
+	&& \$(MAKE) clean \\
 	&& CFLAGS="$ZLIB_OPT" CC="\$(CC)" \\
 		./configure \\
 	&& \$(MAKE) libz.a
--- a/auto/modules
+++ b/auto/modules
@@ -140,6 +140,11 @@ if [ $HTTP_PROXY = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_PROXY_SRCS"
 fi
 
+if [ $HTTP_FASTCGI = YES ]; then
+    HTTP_MODULES="$HTTP_MODULES $HTTP_FASTCGI_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_FASTCGI_SRCS"
+fi
+
 # STUB
 #USE_MD5=YES
 #HTTP_SRCS="$HTTP_SRCS $HTPP_CACHE_SRCS"
--- a/auto/options
+++ b/auto/options
@@ -11,7 +11,6 @@ NGX_ERROR_LOG_PATH=
 NGX_PID_PATH=
 NGX_USER=
 NGX_GROUP=
-NGX_HTTP_LOG_PATH=
 
 CC=${CC:-gcc}
 CPP=
@@ -40,6 +39,12 @@ EVENT_AIO=NO
 USE_THREADS=NO
 
 HTTP=YES
+
+NGX_HTTP_LOG_PATH=
+NGX_HTTP_CLIENT_TEMP_PATH=
+NGX_HTTP_PROXY_TEMP_PATH=
+NGX_HTTP_FASTCGI_TEMP_PATH=
+
 HTTP_CHARSET=YES
 HTTP_GZIP=YES
 HTTP_SSL=NO
@@ -50,6 +55,7 @@ HTTP_AUTOINDEX=YES
 HTTP_STATUS=NO
 HTTP_REWRITE=YES
 HTTP_PROXY=YES
+HTTP_FASTCGI=YES
 
 IMAP=NO
 
@@ -107,6 +113,9 @@ do
 
         --without-http)                  HTTP=NO                    ;;
         --http-log-path=*)               NGX_HTTP_LOG_PATH="$value" ;;
+        --http-client-body-temp-path=*)  NGX_HTTP_CLIENT_TEMP_PATH="$value" ;;
+        --http-proxy-temp-path=*)        NGX_HTTP_PROXY_TEMP_PATH="$value" ;;
+        --http-fastcgi-temp-path=*)      NGX_HTTP_FASTCGI_TEMP_PATH="$value" ;;
 
         --with-http_ssl_module)          HTTP_SSL=YES               ;;
         --without-http_charset_module)   HTTP_CHARSET=NO            ;;
@@ -118,6 +127,7 @@ do
         --without-http_status_module)    HTTP_STATUS=NO             ;;
         --without-http_rewrite_module)   HTTP_REWRITE=NO            ;;
         --without-http_proxy_module)     HTTP_PROXY=NO              ;;
+        --without-http_fastcgi_module)   HTTP_FASTCGI=NO            ;;
 
         --with-imap)                     IMAP=YES                   ;;
 
@@ -161,30 +171,69 @@ if [ $help = yes ]; then
 
 cat << END
 
-  --help                           this message
+  --help                             this message
+
+  --prefix=PATH                      set the installation prefix
+  --sbin-path=PATH                   set path to the nginx binary file
+  --conf-path=PATH                   set path to the nginx.conf file
+  --error-log-path=PATH              set path to the error log
+  --pid-path=PATH                    set path to nginx.pid file
+
+  --user=USER                        set non-privilege user
+                                     for the worker processes
+  --group=GROUP                      set non-privilege group
+                                     for the worker processes
+
+  --builddir=DIR                     set the build directory
 
-  --user=USER                      set non-privilege user
-                                   for the worker processes
-  --group=GROUP                    set non-privilege group
-                                   for the worker processes
+  --with-rtsig_module                enable rtsig module
+  --with-select_module               enable select module
+  --without-select_module            disable select module
+  --with-poll_module                 enable poll module
+  --without-poll_module              disable poll module
 
-  --with-select_module             enable select module
-  --without-select_module          disable select module
-  --with-poll_module               enable poll module
-  --without-poll_module            disable poll module
+  --with-http_ssl_module             enable ngx_http_ssl_module
+  --without-http_charset_module      disable ngx_http_charset_module
+  --without-http_gzip_module         disable ngx_http_gzip_module
+  --without-http_userid_module       disable ngx_http_userid_module
+  --without-http_access_module       disable ngx_http_access_module
+  --without-http_autoindex_module    disable ngx_http_autoindex_module
+  --without-http_rewrite_module      disable ngx_http_rewrite_module
+  --without-http_proxy_module        disable ngx_http_proxy_module
+  --without-http_fastcgi_module      disable ngx_http_fastcgi_module
 
-  --without-http_charset_module    disable ngx_http_charset_module
-  --without-http_rewrite_module    disable ngx_http_rewrite_module
-  --without-http_gzip_module       disable ngx_http_gzip_module
-  --without-http_proxy_module      disable ngx_http_proxy_module
+  --http-log-path=PATH               set path to the http access log
+  --http-client-body-temp-path=PATH  set path to the http client request body
+                                     temporary files path
+  --http-proxy-temp-path=PATH        set path to the http proxy temporary
+                                     files path
+  --http-fastcgi-temp-path=PATH      set path to the http fastcgi temporary
+                                     files path
+
+  --with-cc=PATH                     set path to C compiler
+  --with-cpp=PATH                    set path to C preprocessor
+  --with-cc-opt=OPTIONS              set additional options for C compiler
+  --with-ld-opt=OPTIONS              set additional options for linker
+  --with-cpu-opt=CPU                 build for specified CPU, the valid values:
+                                     pentium, pentiumpro, pentium4, sparc64
 
-  --with-cc-opt=OPTIONS            additional options for compiler
-  --with-ld-opt=OPTIONS            additional options for linker
+  --without-pcre                     disable PCRE libarary usage
+  --with-pcre=DIR                    set path to PCRE library sources
+  --with-pcre-opt=OPTIONS            set additional options for PCRE building
+
+  --with-md5=DIR                     set path to md5 library sources
+  --with-md5-opt=OPTIONS             set additional options for md5 building
+  --with-md5-asm                     use md5 assembler sources
 
-  --with-pcre=DIR                  path to PCRE library
-  --with-md5=DIR                   path to md5 library
-  --with-zlib=DIR                  path to zlib library
-  --with-openssl=DIR               path to OpenSSL library
+  --with-zlib=DIR                    set path to zlib library sources
+  --with-zlib-opt=OPTIONS            set additional options for zlib building
+  --with-zlib-asm=CPU                use zlib assembler sources optimized
+                                     for specified CPU, the valid values:
+                                     pentium, pentiumpro
+
+  --with-openssl=DIR                 set path to OpenSSL library sources
+
+  --with-debug                       enable the debugging logging
 
 END
 
@@ -201,6 +250,7 @@ if [ $HTTP = NO ]; then
     HTTP_STATUS=NO
     HTTP_REWRITE=NO
     HTTP_PROXY=NO
+    HTTP_FASTCGI=NO
 fi
 
 
@@ -284,3 +334,45 @@ case ".$NGX_HTTP_LOG_PATH" in
         NGX_HTTP_LOG_PATH=$NGX_PREFIX/$NGX_HTTP_LOG_PATH
     ;;
 esac
+
+
+case ".$NGX_HTTP_CLIENT_TEMP_PATH" in
+    ./*)
+    ;;
+
+    .)
+        NGX_HTTP_CLIENT_TEMP_PATH=$NGX_PREFIX/client_body_temp
+    ;;
+
+    *)
+        NGX_HTTP_CLIENT_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_CLIENT_TEMP_PATH
+    ;;
+esac
+
+
+case ".$NGX_HTTP_PROXY_TEMP_PATH" in
+    ./*)
+    ;;
+
+    .)
+        NGX_HTTP_PROXY_TEMP_PATH=$NGX_PREFIX/proxy_temp
+    ;;
+
+    *)
+        NGX_HTTP_PROXY_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_PROXY_TEMP_PATH
+    ;;
+esac
+
+
+case ".$NGX_HTTP_FASTCGI_TEMP_PATH" in
+    ./*)
+    ;;
+
+    .)
+        NGX_HTTP_FASTCGI_TEMP_PATH=$NGX_PREFIX/fastcgi_temp
+    ;;
+
+    *)
+        NGX_HTTP_FASTCGI_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_FASTCGI_TEMP_PATH
+    ;;
+esac
--- a/auto/os/conf
+++ b/auto/os/conf
@@ -5,13 +5,13 @@
 if test -z "$NGX_PLATFORM"; then
     echo "checking for OS"
 
-    SYSTEM=`uname -s 2>/dev/null`
-    RELEASE=`uname -r 2>/dev/null`
-    MACHINE=`uname -m 2>/dev/null`
+    NGX_SYSTEM=`uname -s 2>/dev/null`
+    NGX_RELEASE=`uname -r 2>/dev/null`
+    NGX_MACHINE=`uname -m 2>/dev/null`
 
-    echo " + $SYSTEM $RELEASE $MACHINE"
+    echo " + $NGX_SYSTEM $NGX_RELEASE $NGX_MACHINE"
 
-    NGX_PLATFORM="$SYSTEM:$RELEASE:$MACHINE";
+    NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE";
 else
     echo "building for $NGX_PLATFORM"
 fi
@@ -43,6 +43,15 @@ case $NGX_PLATFORM in
 esac
 
 
+case $NGX_MACHINE in
+
+     i386|i686|i86pc|amd64)
+         have=NGX_HAVE_NONALIGNED . auto/have
+     ;;
+
+esac
+
+
 if [ $NGX_PLATFORM != win32 ]; then
 
      NGX_USER=${NGX_USER:-nobody}
--- a/auto/sources
+++ b/auto/sources
@@ -110,6 +110,7 @@ OPENSSL_SRCS=src/event/ngx_event_openssl
 UNIX_INCS="$CORE_INCS $EVENT_INCS src/os/unix"
 
 UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \
+            src/core/ngx_unix_domain.h \
             src/os/unix/ngx_time.h \
             src/os/unix/ngx_types.h \
             src/os/unix/ngx_errno.h \
@@ -125,6 +126,7 @@ UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \
             src/os/unix/ngx_process_cycle.h"
 
 UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \
+            src/core/ngx_unix_domain.c \
             src/os/unix/ngx_time.c \
             src/os/unix/ngx_errno.c \
             src/os/unix/ngx_alloc.c \
@@ -203,9 +205,13 @@ NGX_WIN32_ICONS="src/os/win32/nginx.ico 
 NGX_WIN32_RC="src/os/win32/nginx.rc"
 
 
+# the http modules that have their logging formats
+# must be after ngx_http_log_module
+
 HTTP_MODULES="ngx_http_module \
               ngx_http_core_module \
-              ngx_http_log_module"
+              ngx_http_log_module \
+              ngx_http_upstream_module"
 
 HTTP_CACHE_MODULE=ngx_http_cache_module
 
@@ -231,6 +237,7 @@ HTTP_DEPS="src/http/ngx_http.h \
            src/http/ngx_http_config.h \
            src/http/ngx_http_core_module.h \
            src/http/ngx_http_cache.h \
+           src/http/ngx_http_upstream.h \
            src/http/ngx_http_busy_lock.h \
            src/http/ngx_http_log_handler.h"
 
@@ -244,6 +251,7 @@ HTTP_SRCS="src/http/ngx_http.c \
            src/http/ngx_http_copy_filter.c \
            src/http/ngx_http_log_handler.c \
            src/http/ngx_http_request_body.c \
+           src/http/ngx_http_upstream.c \
            src/http/ngx_http_parse_time.c \
            src/http/modules/ngx_http_static_handler.c \
            src/http/modules/ngx_http_index_handler.c \
@@ -308,6 +316,10 @@ HTTP_PROXY_SRCS="src/http/modules/proxy/
 #                 src/http/modules/proxy/ngx_http_proxy_cache.c \
 
 
+HTTP_FASTCGI_MODULE=ngx_http_fastcgi_module
+HTTP_FASTCGI_SRCS=src/http/modules/ngx_http_fastcgi_handler.c
+
+
 IMAP_INCS="src/imap"
 
 IMAP_DEPS="src/imap/ngx_imap.h"
--- a/auto/summary
+++ b/auto/summary
@@ -101,14 +101,39 @@ END
 fi
 
 
-echo "  nginx path prefix: $NGX_PREFIX"
-echo "  nginx binary file: $NGX_SBIN_PATH"
-echo "  nginx configuration file: $NGX_CONF_PATH"
-echo "  nginx pid file: $NGX_PID_PATH"
+if [ $HTTP_SSL = YES ]; then
+    if [ $OPENSSL = NONE -o $OPENSSL = NO ]; then
+
+cat << END
+$0: error: the HTTP SSL module requires the OpenSSL library.
+You can either do not enable the module, or install the OpenSSL library
+into the system, or build the OpenSSL library statically from the source
+with nginx by using --with-openssl=<path> option.
+
+END
+
+        exit 1
+    fi
+fi
+
+
+cat << END
+  nginx path prefix: $NGX_PREFIX
+  nginx binary file: $NGX_SBIN_PATH
+  nginx configuration file: $NGX_CONF_PATH
+  nginx pid file: $NGX_PID_PATH
+END
+
 if test -n "$NGX_ERROR_LOG_PATH"; then
     echo "  nginx error log file: $NGX_ERROR_LOG_PATH"
 else
     echo "  nginx logs errors to stderr"
 fi
-echo "  nginx http access log file: $NGX_HTTP_LOG_PATH"
-echo
+
+cat << END
+  nginx http access log file: $NGX_HTTP_LOG_PATH
+  nginx http client request body temporary files: $NGX_HTTP_CLIENT_TEMP_PATH
+  nginx http proxy temporary files: $NGX_HTTP_PROXY_TEMP_PATH
+  nginx http fastcgi temporary files: $NGX_HTTP_FASTCGI_TEMP_PATH
+
+END
--- a/auto/unix
+++ b/auto/unix
@@ -2,6 +2,9 @@
 # Copyright (C) Igor Sysoev
 
 
+have=NGX_HAVE_UNIX_DOMAIN . auto/have
+
+
 CC_WARN=
 ngx_fmt_collect=yes
 
--- a/configure
+++ b/configure
@@ -51,7 +51,14 @@ have=NGX_PID_PATH value="\"$NGX_PID_PATH
 if test -n "$NGX_ERROR_LOG_PATH"; then
     have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define
 fi
+
 have=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/define
+have=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\""
+. auto/define
+have=NGX_HTTP_PROXY_TEMP_PATH value="\"$NGX_HTTP_PROXY_TEMP_PATH\""
+. auto/define
+have=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\""
+. auto/define
 
 have=NGX_USER value="\"$NGX_USER\"" . auto/define
 have=NGX_GROUP value="\"$NGX_GROUP\"" . auto/define
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -451,12 +451,15 @@ static void *ngx_core_module_create_conf
     if (!(ccf = ngx_pcalloc(cycle->pool, sizeof(ngx_core_conf_t)))) {
         return NULL;
     }
-    /* set by pcalloc()
+
+    /*
+     * set by pcalloc()
      *
-     * ccf->pid = NULL;
-     * ccf->newpid = NULL;
-     * ccf->priority = 0;
+     *     ccf->pid = NULL;
+     *     ccf->newpid = NULL;
+     *     ccf->priority = 0;
      */
+
     ccf->daemon = NGX_CONF_UNSET;
     ccf->master = NGX_CONF_UNSET;
     ccf->worker_processes = NGX_CONF_UNSET;
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.1.13"
+#define NGINX_VER          "nginx/0.1.14"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_NEWPID_EXT     ".newbin"
--- a/src/core/ngx_buf.h
+++ b/src/core/ngx_buf.h
@@ -69,7 +69,7 @@ typedef struct {
 } ngx_bufs_t;
 
 
-typedef int  (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *out);
+typedef ngx_int_t (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *in);
 
 typedef struct {
     ngx_buf_t                   *buf;
@@ -141,7 +141,7 @@ ngx_chain_t *ngx_create_chain_of_bufs(ng
 
 
 ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in);
-ngx_int_t ngx_chain_writer(void *data, ngx_chain_t *in);
+ngx_int_t ngx_chain_writer(void *ctx, ngx_chain_t *in);
 
 ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
                              ngx_chain_t *in);
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -239,8 +239,8 @@ char *ngx_conf_check_num_bounds(ngx_conf
     }
 
 #define ngx_conf_merge_str_value(conf, prev, default)                        \
-    if (conf.len == 0) {                                                     \
-        if (prev.len) {                                                      \
+    if (conf.data == NULL) {                                                 \
+        if (prev.data) {                                                      \
             conf.len = prev.len;                                             \
             conf.data = prev.data;                                           \
         } else {                                                             \
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -18,7 +18,7 @@ ngx_listening_t *ngx_listening_inet_stre
 {
     size_t               len;
     ngx_listening_t     *ls;
-    struct sockaddr_in  *addr_in;
+    struct sockaddr_in  *sin;
 
     if (!(ls = ngx_array_push(&cf->cycle->listening))) {
         return NULL;
@@ -26,13 +26,13 @@ ngx_listening_t *ngx_listening_inet_stre
 
     ngx_memzero(ls, sizeof(ngx_listening_t));
 
-    if (!(addr_in = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) {
+    if (!(sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) {
         return NULL;
     }
 
-    addr_in->sin_family = AF_INET;
-    addr_in->sin_addr.s_addr = addr;
-    addr_in->sin_port = htons(port);
+    sin->sin_family = AF_INET;
+    sin->sin_addr.s_addr = addr;
+    sin->sin_port = htons(port);
 
 
     ls->addr_text.data = ngx_palloc(cf->pool,
@@ -50,8 +50,7 @@ ngx_listening_t *ngx_listening_inet_stre
     ls->fd = (ngx_socket_t) -1;
     ls->family = AF_INET;
     ls->type = SOCK_STREAM;
-    ls->protocol = IPPROTO_IP;
-    ls->sockaddr = (struct sockaddr *) addr_in;
+    ls->sockaddr = (struct sockaddr *) sin;
     ls->socklen = sizeof(struct sockaddr_in);
     ls->addr = offsetof(struct sockaddr_in, sin_addr);
     ls->addr_text_max_len = INET_ADDRSTRLEN;
@@ -65,7 +64,7 @@ ngx_int_t ngx_set_inherited_sockets(ngx_
     size_t               len;
     ngx_uint_t           i;
     ngx_listening_t     *ls;
-    struct sockaddr_in  *addr_in;
+    struct sockaddr_in  *sin;
 
     ls = cycle->listening.elts;
     for (i = 0; i < cycle->listening.nelts; i++) {
@@ -86,9 +85,9 @@ ngx_int_t ngx_set_inherited_sockets(ngx_
             continue;
         }
 
-        addr_in = (struct sockaddr_in *) ls[i].sockaddr;
+        sin = (struct sockaddr_in *) ls[i].sockaddr;
 
-        if (addr_in->sin_family != AF_INET) {
+        if (sin->sin_family != AF_INET) {
             ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
                           "the inherited socket #%d has "
                           "unsupported family", ls[i].fd);
@@ -105,7 +104,7 @@ ngx_int_t ngx_set_inherited_sockets(ngx_
             return NGX_ERROR;
         }
 
-        ls[i].family = addr_in->sin_family;
+        ls[i].family = sin->sin_family;
         len = ngx_sock_ntop(ls[i].family, ls[i].sockaddr,
                             ls[i].addr_text.data, INET_ADDRSTRLEN);
         if (len == 0) {
@@ -113,7 +112,7 @@ ngx_int_t ngx_set_inherited_sockets(ngx_
         }
 
         ls[i].addr_text.len = ngx_sprintf(ls[i].addr_text.data + len, ":%d",
-                                        ntohs(addr_in->sin_port))
+                                          ntohs(sin->sin_port))
                               - ls[i].addr_text.data;
     }
 
@@ -163,7 +162,7 @@ ngx_int_t ngx_open_listening_sockets(ngx
                 continue;
             }
 
-            s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol);
+            s = ngx_socket(ls[i].family, ls[i].type, 0);
 
             if (s == -1) {
                 ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
@@ -313,7 +312,7 @@ void ngx_close_connection(ngx_connection
 {
     ngx_socket_t  fd;
 
-    if (c->pool == NULL) {
+    if (c->fd == -1) {
         ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
         return;
     }
@@ -388,8 +387,6 @@ void ngx_close_connection(ngx_connection
     c->fd = (ngx_socket_t) -1;
     c->data = NULL;
 
-    ngx_destroy_pool(c->pool);
-
     if (ngx_close_socket(fd) == -1) {
 
         /* we use ngx_cycle->log because c->log was in c->pool */
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -23,7 +23,6 @@ typedef struct {
 
     int               family;
     int               type;
-    int               protocol;
 
     void            (*handler)(ngx_connection_t *c); /* handler of accepted
                                                         connection */
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -18,6 +18,7 @@ typedef struct ngx_open_file_s   ngx_ope
 typedef struct ngx_command_s     ngx_command_t;
 typedef struct ngx_file_s        ngx_file_t;
 typedef struct ngx_event_s       ngx_event_t;
+typedef struct ngx_peers_s       ngx_peers_t;
 typedef struct ngx_connection_s  ngx_connection_t;
 
 typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
@@ -60,6 +61,9 @@ typedef void (*ngx_event_handler_pt)(ngx
 #include <ngx_rbtree.h>
 #include <ngx_times.h>
 #include <ngx_inet.h>
+#if (NGX_HAVE_UNIX_DOMAIN)
+#include <ngx_unix_domain.h>
+#endif
 #include <ngx_cycle.h>
 #include <ngx_process_cycle.h>
 #include <ngx_conf_file.h>
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -9,7 +9,7 @@
 #include <ngx_event.h>
 
 
-static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *s1, struct sockaddr *s2);
+static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2);
 static void ngx_clean_old_cycles(ngx_event_t *ev);
 
 
@@ -531,18 +531,18 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t 
 }
 
 
-static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *s1, struct sockaddr *s2)
+static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2)
 {
     struct sockaddr_in  *sin1, *sin2;
 
     /* AF_INET only */
 
-    if (s1->sa_family != AF_INET || s2->sa_family != AF_INET) {
+    if (sa1->sa_family != AF_INET || sa2->sa_family != AF_INET) {
         return NGX_DECLINED;
     }
 
-    sin1 = (struct sockaddr_in *) s1;
-    sin2 = (struct sockaddr_in *) s2;
+    sin1 = (struct sockaddr_in *) sa1;
+    sin2 = (struct sockaddr_in *) sa2;
 
     if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
         return NGX_DECLINED;
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -193,7 +193,7 @@ char *ngx_conf_set_path_slot(ngx_conf_t 
     ssize_t      level;
     ngx_uint_t   i, n;
     ngx_str_t   *value;
-    ngx_path_t  *path, **pp, **slot;
+    ngx_path_t  *path, **slot;
 
     slot = (ngx_path_t **) (p + cmd->offset);
 
@@ -209,7 +209,7 @@ char *ngx_conf_set_path_slot(ngx_conf_t 
 
     path->name = value[1];
     path->len = 0;
-    path->gc_handler = (ngx_gc_handler_pt) cmd->post;
+    path->cleaner = (ngx_gc_handler_pt) cmd->post;
     path->conf_file = cf->conf_file->file.name.data;
     path->line = cf->conf_file->line;
 
@@ -227,42 +227,65 @@ char *ngx_conf_set_path_slot(ngx_conf_t 
         path->level[i++] = 0;
     }
 
+    *slot = path;
 
-    pp = cf->cycle->pathes.elts;
+    if (ngx_add_path(cf, slot) == NGX_ERROR) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot)
+{
+    ngx_uint_t   i, n;
+    ngx_path_t  *path, **p;
+
+    path = *slot;
+
+    p = cf->cycle->pathes.elts;
     for (i = 0; i < cf->cycle->pathes.nelts; i++) {
-        if (pp[i]->name.len == path->name.len
-            && ngx_strcmp(pp[i]->name.data, path->name.data) == 0)
+        if (p[i]->name.len == path->name.len
+            && ngx_strcmp(p[i]->name.data, path->name.data) == 0)
         {
             for (n = 0; n < 3; n++) {
-                if (pp[i]->level[n] != path->level[n]) {
+                if (p[i]->level[n] != path->level[n]) {
+                    if (path->conf_file == NULL) {
+                        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                                      "the path name \"%V\" in %s:%ui has "
+                                      "the same name as default path but "
+                                      "the different levels, you need to "
+                                      "define default path in http section",
+                                      &p[i]->name, p[i]->conf_file, p[i]->line);
+                        return NGX_ERROR;
+                    }
+
                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                                   "the same \"%V\" path name in %s:%ui "
-                                   "has the different levels than",
-                                   &pp[i]->name, pp[i]->conf_file, pp[i]->line);
-                    return NGX_CONF_ERROR;
+                                      "the same path name \"%V\" in %s:%ui "
+                                      "has the different levels than",
+                                      &p[i]->name, p[i]->conf_file, p[i]->line);
+                    return NGX_ERROR;
                 }
 
-                if (pp[i]->level[n] == 0) {
+                if (p[i]->level[n] == 0) {
                     break;
                 }
             }
 
-            *slot = pp[i];
+            *slot = p[i];
 
-            return NGX_CONF_OK;
+            return NGX_OK;
         }
     }
 
-    *slot = path;
-
-
-    if (!(pp = ngx_array_push(&cf->cycle->pathes))) {
-        return NGX_CONF_ERROR;
+    if (!(p = ngx_array_push(&cf->cycle->pathes))) {
+        return NGX_ERROR;
     }
 
-    *pp = path;
+    *p = path;
 
-    return NGX_CONF_OK;
+    return NGX_OK;
 }
 
 
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -35,7 +35,7 @@ struct ngx_path_s {
     ngx_str_t           name;
     ngx_uint_t          len;
     ngx_uint_t          level[3];
-    ngx_gc_handler_pt   gc_handler;
+    ngx_gc_handler_pt   cleaner;
 
     u_char             *conf_file;
     ngx_uint_t          line;
@@ -58,6 +58,7 @@ ngx_int_t ngx_create_temp_file(ngx_file_
                                ngx_pool_t *pool, int persistent);
 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_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot);
 ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user);
 
 void ngx_init_temp_number();
@@ -66,19 +67,34 @@ ngx_uint_t ngx_next_temp_number(ngx_uint
 char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
-#define ngx_conf_merge_path_value(conf, prev, path, l1, l2, l3, pool)        \
-    if (conf == NULL) {                                                      \
-        if (prev == NULL) {                                                  \
-            ngx_test_null(conf, ngx_palloc(pool, sizeof(ngx_path_t)), NULL); \
-            conf->name.len = sizeof(path) - 1;                               \
-            conf->name.data = (u_char *) path;                               \
-            conf->level[0] = l1;                                             \
-            conf->level[1] = l2;                                             \
-            conf->level[2] = l3;                                             \
-            conf->len = l1 + l2 + l3 + (l1 ? 1:0) + (l2 ? 1:0) + (l3 ? 1:0); \
-        } else {                                                             \
-            conf = prev;                                                     \
-        }                                                                    \
+#define ngx_conf_merge_path_value(curr, prev, path, l1, l2, l3, clean, cf)    \
+    if (curr == NULL) {                                                       \
+        if (prev == NULL) {                                                   \
+            if (!(curr = ngx_palloc(cf->pool, sizeof(ngx_path_t)))) {         \
+                return NGX_CONF_ERROR;                                        \
+            }                                                                 \
+                                                                              \
+            curr->name.len = sizeof(path) - 1;                                \
+            curr->name.data = (u_char *) path;                                \
+                                                                              \
+            if (ngx_conf_full_name(cf->cycle, &curr->name) == NGX_ERROR) {    \
+                return NGX_CONF_ERROR;                                        \
+            }                                                                 \
+                                                                              \
+            curr->level[0] = l1;                                              \
+            curr->level[1] = l2;                                              \
+            curr->level[2] = l3;                                              \
+            curr->len = l1 + l2 + l3 + (l1 ? 1:0) + (l2 ? 1:0) + (l3 ? 1:0);  \
+            curr->cleaner = clean;                                            \
+            curr->conf_file = NULL;                                           \
+                                                                              \
+            if (ngx_add_path(cf, &curr) == NGX_ERROR) {                       \
+                return NGX_CONF_ERROR;                                        \
+            }                                                                 \
+                                                                              \
+        } else {                                                              \
+            curr = prev;                                                      \
+        }                                                                     \
     }
 
 
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -4,9 +4,10 @@
  */
 
 
-
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_event_connect.h>
 
 
 /*
@@ -16,7 +17,7 @@
  * and they are faster by 1.5-2.5 times, so it is worth to keep them.
  *
  * By the way, the implementation using ngx_sprintf() is faster by 2.5-3 times
- * than using FreeBSD libc's snrpintf().
+ * than using FreeBSD libc's snprintf().
  */
 
 
@@ -64,13 +65,13 @@ static ngx_inline size_t ngx_sprint_ucha
 
 /* AF_INET only */
 
-size_t ngx_sock_ntop(int family, struct sockaddr *addr, u_char *text,
+size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text,
                      size_t len)
 {
     u_char              *p;
     size_t               n;
     ngx_uint_t           i;
-    struct sockaddr_in  *addr_in;
+    struct sockaddr_in  *sin;
 
     if (len == 0) {
         return 0;
@@ -80,8 +81,8 @@ size_t ngx_sock_ntop(int family, struct 
         return 0;
     }
 
-    addr_in = (struct sockaddr_in *) addr;
-    p = (u_char *) &addr_in->sin_addr;
+    sin = (struct sockaddr_in *) sa;
+    p = (u_char *) &sin->sin_addr;
 
     if (len > INET_ADDRSTRLEN) {
         len = INET_ADDRSTRLEN;
@@ -216,56 +217,259 @@ ngx_int_t ngx_ptocidr(ngx_str_t *text, v
 }
 
 
-#if 0
-
-ngx_int_t ngx_inet_addr_port(ngx_conf_t *cf, ngx_command_t *cmd,
-                             ngx_str_t *addr_port)
+ngx_peers_t *ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u)
 {
-    u_char          *host;
-    ngx_int_t        port;
-    ngx_uint_t       p;
-    struct hostent  *h;
+    char                *err;
+    u_char              *host;
+    in_addr_t            in_addr;
+    ngx_uint_t           i, len;
+    ngx_peers_t         *peers;
+    struct hostent      *h;
+    struct sockaddr_in  *sin;
+
+    err = ngx_inet_parse_host_port(u);
+
+    if (err) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "%s in upstream \"%V\"", err, &u->name);
+        return NULL;
+    }
+
+    if (u->default_port) {
+        if (u->default_port_value == 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "no port in upstream \"%V\"", &u->name);
+            return NULL;
+        }
+
+        u->port = u->default_port_value;
+
+        if (!(u->port_text.data = ngx_palloc(cf->pool, sizeof("65536") - 1))) {
+            return NULL;
+        }
+
+        u->port_text.len = ngx_sprintf(u->port_text.data, "%d",
+                                       u->default_port_value)
+                           - u->port_text.data;
+
+    } else if (u->port) {
+        if (u->port == u->default_port_value) {
+            u->default_port = 1;
+        }
+
+    } else {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "no port in upstream \"%V\"", &u->name);
+        return NULL;
+    }
+
+    if (u->host.len == 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "no host in upstream \"%V\"", &u->name);
+        return NULL;
+    }
+
+    u->port = htons(u->port);
+
+    if (!(host = ngx_palloc(cf->pool, u->host.len + 1))) {
+        return NULL;
+    }
+
+    ngx_cpystrn(host, u->host.data, u->host.len + 1);
+
+    /* AF_INET only */
+
+    in_addr = inet_addr((char *) host);
+
+    if (in_addr == INADDR_NONE) {
+        h = gethostbyname((char *) host);
+
+        if (h == NULL || h->h_addr_list[0] == NULL) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "host %s is not found in upstream \"%V\"",
+                               host, &u->name);
+            return NULL;
+        }
+
+        for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
+
+        /* MP: ngx_shared_palloc() */
+
+        peers = ngx_pcalloc(cf->pool,
+                            sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1));
+
+        if (peers == NULL) {
+            return NULL;
+        }
+
+        peers->number = i;
+        peers->weight = 1;
+
+        for (i = 0; h->h_addr_list[i] != NULL; i++) {
+
+            if (!(sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) {
+                return NULL;
+            }
+
+            sin->sin_family = AF_INET;
+            sin->sin_port = u->port;
+            sin->sin_addr.s_addr = *(in_addr_t *)(h->h_addr_list[i]);
+
+            peers->peer[i].sockaddr = (struct sockaddr *) sin;
+            peers->peer[i].socklen = sizeof(struct sockaddr_in);
+
+            len = INET_ADDRSTRLEN - 1 + 1 + u->port_text.len;
+    
+            if (!(peers->peer[i].name.data = ngx_palloc(cf->pool, len))) {
+                return NULL;
+            }
+
+            len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin,
+                                peers->peer[i].name.data, len);
+
+            peers->peer[i].name.data[len++] = ':';
 
-    for (p = 0; p < addr_port->len; p++) {
-        if (addr_port->data[p] == ':') {
+            ngx_memcpy(peers->peer[i].name.data + len,
+                       u->port_text.data, u->port_text.len);
+
+            peers->peer[i].name.len = len + u->port_text.len;
+
+            peers->peer[i].uri_separator = "";
+
+            peers->peer[i].weight = 1;
+            peers->peer[i].max_fails = 1;
+            peers->peer[i].fail_timeout = 60;
+        }
+
+    } else {
+
+        /* MP: ngx_shared_palloc() */
+
+        if (!(peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)))) {
+            return NULL;
+        }
+
+        if (!(sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) {
+            return NULL;
+        }
+
+        peers->number = 1;
+
+        sin->sin_family = AF_INET;
+        sin->sin_port = u->port;
+        sin->sin_addr.s_addr = in_addr;
+
+        peers->peer[0].sockaddr = (struct sockaddr *) sin;
+        peers->peer[0].socklen = sizeof(struct sockaddr_in);
+
+        len = u->host.len + 1 + u->port_text.len;
+
+        peers->peer[0].name.len = len;
+
+        if (!(peers->peer[0].name.data = ngx_palloc(cf->pool, len))) {
+            return NULL;
+        }
+
+        len = u->host.len;
+
+        ngx_memcpy(peers->peer[0].name.data, u->host.data, len);
+
+        peers->peer[0].name.data[len++] = ':';
+
+        ngx_memcpy(peers->peer[0].name.data + len,
+                   u->port_text.data, u->port_text.len);
+
+        peers->peer[0].uri_separator = "";
+    }
+
+    return peers;
+}
+
+
+char *ngx_inet_parse_host_port(ngx_inet_upstream_t *u)
+{
+    size_t      i;
+    ngx_int_t   port;
+    ngx_str_t  *url;
+
+    url = &u->url;
+
+    if (u->port_only) {
+        i = 0;
+
+    } else {
+        if (url->data[0] == ':' || url->data[0] == '/') {
+            return "invalid host";
+        }
+
+        i = 1;
+    }
+
+    u->host.data = url->data;
+    u->host_header = *url;
+
+    for (/* void */; i < url->len; i++) {
+
+        if (url->data[i] == ':') {
+            u->port_text.data = &url->data[i] + 1;
+            u->host.len = i;
+
+            if (!u->uri_part) {
+                u->port_text.len = &url->data[url->len] - u->port_text.data;
+                break;
+            }
+        }
+
+        if (url->data[i] == '/') {
+            u->uri.data = &url->data[i];
+            u->uri.len = url->len - i;
+            u->host_header.len = i;
+
+            if (u->host.len == 0) {
+                u->host.len = i;
+            }
+
+            if (u->port_text.data == NULL) {
+                u->default_port = 1;
+                return NULL;
+            }
+
+            u->port_text.len = &url->data[i] - u->port_text.data;
+
+            if (u->port_text.len == 0) {
+                return "invalid port";
+            }
+
             break;
         }
     }
 
-    in_addr->host.len = p;
-    if (!(in_addr->host.data = ngx_palloc(pool, p + 1))) {
-        return NGX_ERROR;
-    }
+    if (u->port_text.data == NULL) {
+        port = ngx_atoi(url->data, url->len);
+
+        if (port == NGX_ERROR) {
+            u->default_port = 1;
+            u->host.len = url->len;
+
+            return NULL;
+        }
 
-    ngx_cpystrn(in_addr->host.data, addr_port->data, p + 1);
+        u->port_text = *url;
+        u->wildcard = 1;
 
-    if (p == addr_port->len) {
-        p = 0;
+    } else {
+        if (u->port_text.len == 0) {
+            return "no URI";
+        }
+
+        port = ngx_atoi(u->port_text.data, u->port_text.len);
+
+        if (port == NGX_ERROR || port < 1 || port > 65536) {
+            return "invalid port";
+        }
     }
 
-    port = ngx_atoi(&addr[p], args[1].len - p);
-    if (port == NGX_ERROR && p == 0) {
-
-        /* default port */
-        iap->port = 0;
-
-    } else if ((port == NGX_ERROR && p != 0) /* "listen host:NONNUMBER" */
-               || (port < 1 || port > 65536)) { /* "listen 99999" */
+    u->port = (in_port_t) port;
 
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "invalid port \"%s\" in \"%s\" directive, "
-                           "it must be a number between 1 and 65535",
-                           &addr[p], cmd->name.data);
-
-        return NGX_CONF_ERROR;
-
-    } else if (p == 0) {
-        ls->addr = INADDR_ANY;
-        ls->port = (in_port_t) port;
-        return NGX_CONF_OK;
-    }
-
-    return NGX_OK;
+    return NULL;
 }
-
-#endif
--- a/src/core/ngx_inet.h
+++ b/src/core/ngx_inet.h
@@ -8,17 +8,44 @@
 #define _NGX_INET_H_INCLUDED_
 
 
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
 typedef struct {
     in_addr_t  addr;
     in_addr_t  mask;
 } ngx_inet_cidr_t;
 
 
-size_t ngx_sock_ntop(int family, struct sockaddr *addr, u_char *text,
+typedef struct {
+    ngx_str_t     name;           /* "schema:host:port/uri" */
+    ngx_str_t     url;            /* "host:port/uri" */
+    ngx_str_t     host;
+    ngx_str_t     uri;
+    ngx_str_t     host_header;    /* "host:port" */
+    ngx_str_t     port_text;      /* "port" */
+
+    in_port_t     port;
+
+    in_port_t     default_port_value;
+
+    unsigned      default_port:1;
+    unsigned      wildcard:1;
+
+    unsigned      uri_part:1;
+    unsigned      port_only:1;
+} ngx_inet_upstream_t;
+
+
+size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text,
                      size_t len);
 size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len);
 
 ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr);
 
+ngx_peers_t *ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u);
+char *ngx_inet_parse_host_port(ngx_inet_upstream_t *u);
+
 
 #endif /* _NGX_INET_H_INCLUDED_ */
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -80,7 +80,7 @@ ngx_int_t ngx_output_chain(ngx_output_ch
             if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) {
 
                 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
-                              "zero size buf");
+                              "zero size buf in output");
 
                 ngx_debug_point();
 
--- a/src/core/ngx_regex.c
+++ b/src/core/ngx_regex.c
@@ -54,11 +54,11 @@ ngx_regex_t *ngx_regex_compile(ngx_str_t
     if (re == NULL) {
        if ((size_t) erroff == pattern->len) {
            ngx_snprintf(err->data, err->len - 1,
-                        "pcre_compile() failed: %s in \"%s\"",
+                        "pcre_compile() failed: %s in \"%s\"%Z",
                         errstr, pattern->data);
         } else {
            ngx_snprintf(err->data, err->len - 1,
-                        "pcre_compile() failed: %s in \"%s\" at \"%s\"",
+                        "pcre_compile() failed: %s in \"%s\" at \"%s\"%Z",
                         errstr, pattern->data, pattern->data + erroff);
         }
     }
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -86,7 +86,11 @@ u_char *ngx_snprintf(u_char *buf, size_t
 
 u_char *ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args)
 {
-    u_char         *p, zero, *last, temp[NGX_INT64_LEN];
+    u_char         *p, zero, *last, temp[NGX_INT64_LEN + 1];
+                                    /*
+                                     * really we need temp[NGX_INT64_LEN] only,
+                                     * but icc shows the warning
+                                     */
     int             d;
     size_t          len;
     uint32_t        ui32;
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -64,7 +64,7 @@ typedef struct {
 
 /* msvc and icc compile memcpy() to the inline "rep movs" */
 #define ngx_memcpy(dst, src, n)   memcpy(dst, src, n)
-#define ngx_cpymem(dst, src, n)   ((u_char *) memcpy(dst, src, n)) + n
+#define ngx_cpymem(dst, src, n)   ((u_char *) memcpy(dst, src, n)) + (n)
 
 
 /* msvc and icc compile memcmp() to the inline loop */
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_unix_domain.c
@@ -0,0 +1,84 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_event_connect.h>
+
+
+/* Solaris has predefined "#define sun 1" */
+#undef sun
+
+
+ngx_peers_t *ngx_unix_upstream_parse(ngx_conf_t *cf,
+                                     ngx_unix_domain_upstream_t *u)
+{
+    size_t               len;
+    ngx_uint_t           i;
+    ngx_peers_t         *peers;
+    struct sockaddr_un  *sun;
+
+    len = u->url.len - 5;
+
+    if (u->uri_part) {
+        for (i = 5; i < u->url.len; i++) {
+            if (u->url.data[i] == ':') {
+                len = i - 5;
+                u->uri.len = u->url.len - 5 - len - 1;
+                u->uri.data = u->url.data + 5 + len + 1;
+
+                break;
+            }
+        }
+
+        if (u->uri.len == 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "the unix domain upstream \"%V\" has no URI",
+                               &u->name);
+            return NULL;
+        }
+    }
+
+    if (len == 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "the unix domain socket \"%V\" has no path",
+                           &u->name);
+        return NULL;
+    }
+
+    if (len + 1 > sizeof(sun->sun_path)) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "the unix domain socket path \"%V\" is too long",
+                           &u->name);
+        return NULL;
+    }
+
+    /* MP: ngx_shared_palloc() */
+
+    if (!(peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)))) {
+        return NULL;
+    }
+
+    if (!(sun = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_un)))) {
+        return NULL;
+    }
+
+    peers->number = 1;
+
+    sun->sun_family = AF_UNIX;
+    ngx_cpystrn((u_char *) sun->sun_path, u->url.data + 5, len + 1);
+
+    peers->peer[0].sockaddr = (struct sockaddr *) sun;
+    peers->peer[0].socklen = sizeof(struct sockaddr_un);
+
+    peers->peer[0].name.len = 5 + len;
+    peers->peer[0].name.data = u->url.data;
+
+    peers->peer[0].uri_separator = ":";
+
+    return peers;
+}
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_unix_domain.h
@@ -0,0 +1,29 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_UNIX_DOMAIN_H_INCLUDED_
+#define _NGX_UNIX_DOMAIN_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+    ngx_str_t     name;           /* "schema:unix:path:/uri" */
+    ngx_str_t     url;            /* "unix:path:/uri" */
+    ngx_str_t     uri;
+
+    ngx_uint_t    uri_part;       /* unsigned  uri_part:1; */
+} ngx_unix_domain_upstream_t;
+
+
+ngx_peers_t *ngx_unix_upstream_parse(ngx_conf_t *cf,
+                                     ngx_unix_domain_upstream_t *u);
+
+
+#endif /* _NGX_UNIX_DOMAIN_H_INCLUDED_ */
+
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -313,12 +313,12 @@ void ngx_event_accept(ngx_event_t *ev)
 
         uint32_t            *addr;
         in_addr_t            i;
-        struct sockaddr_in  *addr_in;
+        struct sockaddr_in  *sin;
 
-        addr_in = (struct sockaddr_in *) sa;
+        sin = (struct sockaddr_in *) sa;
         addr = ecf->debug_connection.elts;
         for (i = 0; i < ecf->debug_connection.nelts; i++) {
-            if (addr[i] == addr_in->sin_addr.s_addr) {
+            if (addr[i] == sin->sin_addr.s_addr) {
                 log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL;
                 break;
             }
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -25,7 +25,6 @@ ngx_int_t ngx_event_connect_peer(ngx_pee
     ngx_event_t         *rev, *wev;
     ngx_connection_t    *c;
     ngx_event_conf_t    *ecf;
-    struct sockaddr_in   addr;
 
     now = ngx_time();
 
@@ -54,7 +53,7 @@ ngx_int_t ngx_event_connect_peer(ngx_pee
     pc->connection = NULL;
 
     if (pc->peers->number == 1) {
-        peer = &pc->peers->peers[0];
+        peer = &pc->peers->peer[0];
 
     } else {
 
@@ -64,45 +63,47 @@ ngx_int_t ngx_event_connect_peer(ngx_pee
 
             /* it's a first try - get a current peer */
 
-            pc->cur_peer = pc->peers->current++;
+            pc->cur_peer = pc->peers->current;
+
+            pc->peers->weight--;
+
+            if (pc->peers->weight == 0) {
+                pc->peers->current++;
+            }
 
             if (pc->peers->current >= pc->peers->number) {
                 pc->peers->current = 0;
             }
+
+            if (pc->peers->weight == 0) {
+                pc->peers->weight = pc->peers->peer[pc->peers->current].weight;
+            }
         }
 
-        if (pc->peers->max_fails == 0) {
-            peer = &pc->peers->peers[pc->cur_peer];
-
-        } else {
-
-            /* the peers support a fault tolerance */
+        for ( ;; ) {
+            peer = &pc->peers->peer[pc->cur_peer];
 
-            for ( ;; ) {
-                peer = &pc->peers->peers[pc->cur_peer];
+            if (peer->fails <= peer->max_fails) {
+                break;
+            }
 
-                if (peer->fails <= pc->peers->max_fails) {
-                    break;
-                }
+            if (now - peer->accessed > peer->fail_timeout) {
+                peer->fails = 0;
+                break;
+            }
 
-                if (now - peer->accessed > pc->peers->fail_timeout) {
-                    peer->fails = 0;
-                    break;
-                }
+            pc->cur_peer++;
 
-                pc->cur_peer++;
+            if (pc->cur_peer >= pc->peers->number) {
+                pc->cur_peer = 0;
+            }
 
-                if (pc->cur_peer >= pc->peers->number) {
-                    pc->cur_peer = 0;
-                }
-
-                pc->tries--;
+            pc->tries--;
 
-                if (pc->tries == 0) {
-                    /* ngx_unlock_mutex(pc->peers->mutex); */
+            if (pc->tries == 0) {
+                /* ngx_unlock_mutex(pc->peers->mutex); */
 
-                    return NGX_ERROR;
-                }
+                return NGX_ERROR;
             }
         }
     }
@@ -110,7 +111,7 @@ ngx_int_t ngx_event_connect_peer(ngx_pee
     /* ngx_unlock_mutex(pc->peers->mutex); */
 
 
-    s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+    s = ngx_socket(peer->sockaddr->sa_family, SOCK_STREAM, 0);
 
     if (s == -1) {
         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
@@ -257,16 +258,10 @@ ngx_int_t ngx_event_connect_peer(ngx_pee
         }
     } 
 
-    ngx_memzero(&addr, sizeof(struct sockaddr_in));
+    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0,
+                   "connect to %V, #%d", &peer->name, c->number);
 
-    addr.sin_family = AF_INET;
-    addr.sin_port = peer->port;
-    addr.sin_addr.s_addr = peer->addr;
-
-    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0,
-                   "connect to %V, #%d", &peer->addr_port_text, c->number);
-
-    rc = connect(s, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));
+    rc = connect(s, peer->sockaddr, peer->socklen);
 
     if (rc == -1) {
         err = ngx_socket_errno;
@@ -367,8 +362,8 @@ void ngx_event_connect_peer_failed(ngx_p
 
     /* ngx_lock_mutex(pc->peers->mutex); */
 
-    pc->peers->peers[pc->cur_peer].fails++;
-    pc->peers->peers[pc->cur_peer].accessed = now;
+    pc->peers->peer[pc->cur_peer].fails++;
+    pc->peers->peer[pc->cur_peer].accessed = now;
 
     /* ngx_unlock_mutex(pc->peers->mutex); */
 
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -17,34 +17,40 @@
 
 
 typedef struct {
-    in_addr_t          addr;
-    ngx_str_t          host;
-    in_port_t          port;
-    ngx_str_t          addr_port_text;
+    struct sockaddr    *sockaddr;
+    socklen_t           socklen;
+
+    ngx_str_t           name;
+    char               *uri_separator;
 
-    ngx_int_t          fails;
-    time_t             accessed;
+    ngx_uint_t          weight;
+
+    ngx_uint_t          fails;
+    time_t              accessed;
+
+    ngx_uint_t          max_fails;
+    time_t              fail_timeout;
 } ngx_peer_t;
 
 
-typedef struct {
-    ngx_int_t           current;
-    ngx_int_t           number;
-    ngx_int_t           max_fails;
-    time_t              fail_timeout;
-    ngx_int_t           last_cached;
+struct ngx_peers_s {
+    ngx_uint_t          current;
+    ngx_uint_t          weight;
+
+    ngx_uint_t          number;
+    ngx_uint_t          last_cached;
 
  /* ngx_mutex_t        *mutex; */
     ngx_connection_t  **cached;
 
-    ngx_peer_t          peers[1];
-} ngx_peers_t;
+    ngx_peer_t          peer[1];
+};
 
 
 typedef struct {
     ngx_peers_t       *peers;
-    ngx_int_t          cur_peer;
-    ngx_int_t          tries;
+    ngx_uint_t         cur_peer;
+    ngx_uint_t         tries;
 
     ngx_connection_t  *connection;
 #if (NGX_THREADS)
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -8,6 +8,8 @@
 #include <ngx_core.h>
 #include <ngx_event.h>
 
+#include <openssl/engine.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);
@@ -16,8 +18,11 @@ static void ngx_ssl_read_handler(ngx_eve
 
 ngx_int_t ngx_ssl_init(ngx_log_t *log)
 {
+    ENGINE  *engine;
+
     SSL_library_init();
     SSL_load_error_strings();
+    ENGINE_load_builtin_engines();
 
     return NGX_OK;
 }
@@ -71,6 +76,48 @@ 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 (NGX_DEBUG)
+
+        if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->ssl)) {
+            char         buf[129], *s, *d;
+            SSL_CIPHER  *cipher;
+
+            c->ssl->handshaked = 1;
+
+            cipher = SSL_get_current_cipher(c->ssl->ssl);
+
+            if (cipher) {
+                SSL_CIPHER_description(cipher, &buf[1], 128);
+
+                for (s = &buf[1], d = buf; *s; s++) {
+                    if (*s == ' ' && *d == ' ') {
+                        continue;
+                    }
+
+                    if (*s == '\n' || *s == '\r') {
+                        continue;
+                    }
+
+                    *++d = *s;
+                }
+
+                if (*d != ' ') {
+                    d++;
+                }
+
+                *d = '\0';
+
+                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                               "SSL cipher: \"%s\"", &buf[1]); 
+            } else {
+                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+                               "SSL no shared ciphers"); 
+            }
+        }
+
+#endif
+
         if (c->ssl->saved_write_handler) {
 
             c->write->event_handler = c->ssl->saved_write_handler;
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -25,6 +25,10 @@ typedef struct {
     unsigned               no_rcv_shut:1;
     unsigned               no_send_shut:1;
     unsigned               shutdown_set:1;
+
+#if (NGX_DEBUG)
+    unsigned               handshaked:1;
+#endif
 } ngx_ssl_t;
 
 
--- 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)
 {
-    off_t         bsize;
+    size_t        bsize;
     ngx_uint_t    flush;
     ngx_buf_t    *b;
     ngx_chain_t  *out, **ll, *cl, *tl;
@@ -433,16 +433,18 @@ ngx_int_t ngx_event_pipe_write_to_downst
             break;
         }
 
-        /* bsize is the size of the busy bufs */
+        /* bsize is the size of the busy recycled bufs */
 
         bsize = 0;
 
         for (cl = p->busy; cl; cl = cl->next) {
-            bsize += cl->buf->end - cl->buf->start;
+            if (cl->buf->recycled) {
+                bsize += cl->buf->end - cl->buf->start;
+            }
         }
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
-                       "pipe write busy: %O", bsize);
+                       "pipe write busy: %uz", bsize);
 
         out = NULL;
         ll = NULL;
@@ -452,19 +454,23 @@ ngx_int_t ngx_event_pipe_write_to_downst
             if (p->out) {
                 cl = p->out;
 
-                if (bsize + ngx_buf_size(cl->buf) > p->busy_size) {
+                if (cl->buf->recycled
+                    && bsize + cl->buf->last - cl->buf->pos > p->busy_size)
+                {
                     flush = 1;
                     break;
                 }
 
                 p->out = p->out->next;
-                ngx_event_pipe_free_shadow_raw_buf(&p->free_raw_bufs,
-                                                   cl->buf);
+
+                ngx_event_pipe_free_shadow_raw_buf(&p->free_raw_bufs, cl->buf);
 
             } else if (!p->cachable && p->in) {
                 cl = p->in;
 
-                if (bsize + ngx_buf_size(cl->buf) > p->busy_size) {
+                if (cl->buf->recycled
+                    && bsize + cl->buf->last - cl->buf->pos > p->busy_size)
+                {
                     flush = 1;
                     break;
                 }
@@ -475,7 +481,10 @@ ngx_int_t ngx_event_pipe_write_to_downst
                 break;
             }
 
-            bsize += ngx_buf_size(cl->buf);
+            if (cl->buf->recycled) {
+                bsize += cl->buf->last - cl->buf->pos;
+            }
+
             cl->next = NULL;
             ngx_chain_add_link(out, ll, cl);
         }
@@ -618,8 +627,6 @@ static ngx_int_t ngx_event_pipe_write_ch
 
         b->in_file = 1;
         b->temp_file = 1;
-        b->temporary = 0;
-        b->recycled = 0;
 
         ngx_chain_add_link(p->out, p->last_out, cl);
 
@@ -668,7 +675,7 @@ ngx_int_t ngx_event_pipe_copy_input_filt
 
     ngx_alloc_link_and_set_buf(cl, b, p->pool, NGX_ERROR);
 
-    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "buf #%d", b->num);
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
 
     ngx_chain_add_link(p->in, p->last_in, cl);
 
@@ -781,7 +788,14 @@ static ngx_int_t ngx_event_pipe_drain_ch
                 b = cl->buf->shadow;
                 b->pos = b->last = b->start;
                 b->shadow = NULL;
-                ngx_alloc_link_and_set_buf(tl, b, p->pool, NGX_ABORT);
+
+                if (!(tl = ngx_alloc_chain_link(p->pool))) {
+                    return NGX_ABORT;
+                }
+
+                tl->buf = b;
+                tl->next = NULL;
+
                 ngx_event_pipe_add_free_buf(&p->free_raw_bufs, tl);
 
                 cl->buf->last_shadow = 0;
--- a/src/http/modules/ngx_http_access_handler.c
+++ b/src/http/modules/ngx_http_access_handler.c
@@ -80,7 +80,7 @@ ngx_module_t  ngx_http_access_module = {
 static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r)
 {
     ngx_uint_t                   i;
-    struct sockaddr_in          *addr_in;
+    struct sockaddr_in          *sin;
     ngx_http_access_rule_t      *rule;
     ngx_http_access_loc_conf_t  *alcf;
 
@@ -92,16 +92,16 @@ static ngx_int_t ngx_http_access_handler
 
     /* AF_INET only */
 
-    addr_in = (struct sockaddr_in *) r->connection->sockaddr;
+    sin = (struct sockaddr_in *) r->connection->sockaddr;
 
     rule = alcf->rules->elts;
     for (i = 0; i < alcf->rules->nelts; i++) {
 
         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "%08XD %08XD %08XD",
-                       addr_in->sin_addr.s_addr, rule[i].mask, rule[i].addr);
+                       sin->sin_addr.s_addr, rule[i].mask, rule[i].addr);
 
-        if ((addr_in->sin_addr.s_addr & rule[i].mask) == rule[i].addr) {
+        if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) {
             if (rule[i].deny) {
                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                               "access forbidden by rule");
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_fastcgi_handler.c
@@ -0,0 +1,1968 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+#include <nginx.h>
+
+
+typedef struct {
+    ngx_http_upstream_conf_t        upstream;
+
+    ngx_peers_t                    *peers;
+
+    ngx_uint_t                      params;
+
+    ngx_str_t                       root;
+    ngx_str_t                       index;
+
+    ngx_str_t                      *location;
+} ngx_http_fastcgi_loc_conf_t;
+
+
+typedef struct {
+    ngx_list_t                      headers;
+
+    ngx_table_elt_t                *status;
+
+    ngx_table_elt_t                *content_type;
+    ngx_table_elt_t                *content_length;
+    ngx_table_elt_t                *x_powered_by;
+
+#if (NGX_HTTP_GZIP)
+    ngx_table_elt_t                *content_encoding;
+#endif
+} ngx_http_fastcgi_headers_in_t;
+
+
+typedef struct {
+    ngx_http_fastcgi_headers_in_t   headers_in;
+} ngx_http_fastcgi_upstream_t;
+
+
+typedef enum {
+    ngx_http_fastcgi_st_version = 0,
+    ngx_http_fastcgi_st_type,
+    ngx_http_fastcgi_st_request_id_hi,
+    ngx_http_fastcgi_st_request_id_lo,
+    ngx_http_fastcgi_st_content_length_hi,
+    ngx_http_fastcgi_st_content_length_lo,
+    ngx_http_fastcgi_st_padding_length,
+    ngx_http_fastcgi_st_reserved,
+    ngx_http_fastcgi_st_data,
+    ngx_http_fastcgi_st_padding,
+} ngx_http_fastcgi_state_e;
+
+
+typedef struct {
+    ngx_http_fastcgi_state_e      state;
+    u_char                       *pos;
+    u_char                       *last;
+    ngx_uint_t                    type;
+    size_t                        length;
+    size_t                        padding;
+
+    ngx_http_fastcgi_upstream_t  *upstream;
+} ngx_http_fastcgi_ctx_t;
+
+
+#define NGX_HTTP_FASTCGI_REMOTE_ADDR          0x0002
+#define NGX_HTTP_FASTCGI_REMOTE_USER          0x0004
+#define NGX_HTTP_FASTCGI_SERVER_NAME          0x0008
+#define NGX_HTTP_FASTCGI_SERVER_ADDR          0x0010
+#define NGX_HTTP_FASTCGI_SERVER_PORT          0x0020
+#define NGX_HTTP_FASTCGI_SCRIPT_NAME          0x0040
+#define NGX_HTTP_FASTCGI_AUTH_TYPE            0x0080
+#define NGX_HTTP_FASTCGI_SERVER_PROTOCOL      0x0100
+#define NGX_HTTP_FASTCGI_SERVER_SOFTWARE      0x0200
+#define NGX_HTTP_FASTCGI_GATEWAY_INTERFACE    0x0400
+#define NGX_HTTP_FASTCGI_REQUEST_URI          0x0800
+#define NGX_HTTP_FASTCGI_REDIRECT_STATUS      0x1000
+
+
+#define NGX_HTTP_FASTCGI_RESPONDER      1
+
+#define NGX_HTTP_FASTCGI_BEGIN_REQUEST  1
+#define NGX_HTTP_FASTCGI_ABORT_REQUEST  2
+#define NGX_HTTP_FASTCGI_END_REQUEST    3
+#define NGX_HTTP_FASTCGI_PARAMS         4
+#define NGX_HTTP_FASTCGI_STDIN          5
+#define NGX_HTTP_FASTCGI_STDOUT         6
+#define NGX_HTTP_FASTCGI_STDERR         7
+#define NGX_HTTP_FASTCGI_DATA           8
+
+
+typedef struct {
+    u_char  version;
+    u_char  type;
+    u_char  request_id_hi;
+    u_char  request_id_lo;
+    u_char  content_length_hi;
+    u_char  content_length_lo;
+    u_char  padding_length;
+    u_char  reserved;
+} ngx_http_fastcgi_header_t;
+
+
+typedef struct {
+    u_char  role_hi;
+    u_char  role_lo;
+    u_char  flags;
+    u_char  reserved[5];
+} ngx_http_fastcgi_begin_request_t;
+
+
+static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r);
+static ngx_int_t ngx_http_fastcgi_send_header(ngx_http_request_t *r);
+static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
+                                               ngx_buf_t *buf);
+static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r,
+                                                 ngx_http_fastcgi_ctx_t *f);
+static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r);
+static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r,
+                                              ngx_int_t rc);
+
+static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
+                                   void *conf);
+static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
+                                          void *data);
+static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf,
+                                             void *parent, void *child);
+
+
+static ngx_str_t ngx_http_fastcgi_methods[] = {
+    ngx_string("GET"),
+    ngx_string("HEAD"),
+    ngx_string("POST")
+};
+
+
+static ngx_http_header_t ngx_http_fastcgi_headers_in[] = {
+    { ngx_string("Status"), offsetof(ngx_http_fastcgi_headers_in_t, status) },
+
+    { ngx_string("Content-Type"),
+                       offsetof(ngx_http_fastcgi_headers_in_t, content_type) },
+
+    { ngx_string("Content-Length"),
+                     offsetof(ngx_http_fastcgi_headers_in_t, content_length) },
+
+    { ngx_string("X-Powered-By"),
+                       offsetof(ngx_http_fastcgi_headers_in_t, x_powered_by) },
+
+#if (NGX_HTTP_GZIP)
+    { ngx_string("Content-Encoding"),
+                   offsetof(ngx_http_fastcgi_headers_in_t, content_encoding) },
+#endif
+
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_conf_post_t  ngx_http_fastcgi_lowat_post =
+                                             { ngx_http_fastcgi_lowat_check } ;
+
+static ngx_conf_bitmask_t  ngx_http_fastcgi_next_upstream_masks[] = {
+    { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
+    { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
+    { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
+    { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
+    { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_conf_bitmask_t  ngx_http_fastcgi_params_masks[] = {
+    { ngx_string("remote_addr"), NGX_HTTP_FASTCGI_REMOTE_ADDR },
+    { ngx_string("server_port"), NGX_HTTP_FASTCGI_SERVER_PORT },
+    { ngx_string("server_addr"), NGX_HTTP_FASTCGI_SERVER_ADDR },
+    { ngx_string("server_name"), NGX_HTTP_FASTCGI_SERVER_NAME },
+    { ngx_string("script_name"), NGX_HTTP_FASTCGI_SCRIPT_NAME },
+
+    { ngx_string("server_protocol"), NGX_HTTP_FASTCGI_SERVER_PROTOCOL },
+    { ngx_string("server_software"), NGX_HTTP_FASTCGI_SERVER_SOFTWARE },
+    { ngx_string("gateway_interface"), NGX_HTTP_FASTCGI_GATEWAY_INTERFACE },
+
+    { ngx_string("redirect_status"), NGX_HTTP_FASTCGI_REDIRECT_STATUS },
+    { ngx_string("request_uri"), NGX_HTTP_FASTCGI_REQUEST_URI },
+
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_command_t  ngx_http_fastcgi_commands[] = {
+
+    { ngx_string("fastcgi_pass"),
+      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_fastcgi_pass,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("fastcgi_root"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, root),
+      NULL },
+
+    { ngx_string("fastcgi_index"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, index),
+      NULL },
+
+    { ngx_string("fastcgi_connect_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.connect_timeout),
+      NULL },
+
+    { ngx_string("fastcgi_send_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_timeout),
+      NULL },
+
+    { ngx_string("fastcgi_send_lowat"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_lowat),
+      &ngx_http_fastcgi_lowat_post },
+
+    { ngx_string("fastcgi_header_buffer_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.header_buffer_size),
+      NULL },
+
+    { ngx_string("fastcgi_x_powered_by"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.x_powered_by),
+      NULL },
+
+    { ngx_string("fastcgi_read_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.read_timeout),
+      NULL },
+
+    { ngx_string("fastcgi_buffers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_bufs_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.bufs),
+      NULL },
+
+    { ngx_string("fastcgi_busy_buffers_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size),
+      NULL },
+
+    { ngx_string("fastcgi_temp_path"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
+      ngx_conf_set_path_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_path),
+      (void *) ngx_garbage_collector_temp_handler },
+
+    { ngx_string("fastcgi_max_temp_file_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_temp_file_size),
+      NULL },
+
+    { ngx_string("fastcgi_temp_file_write_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_file_write_size),
+      NULL },
+
+    { ngx_string("fastcgi_next_upstream"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
+      ngx_conf_set_bitmask_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
+      &ngx_http_fastcgi_next_upstream_masks },
+
+    { ngx_string("fastcgi_params"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
+      ngx_conf_set_bitmask_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, params),
+      &ngx_http_fastcgi_params_masks },
+
+      ngx_null_command
+};
+
+
+ngx_http_module_t  ngx_http_fastcgi_module_ctx = {
+    NULL,                                  /* pre conf */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_fastcgi_create_loc_conf,      /* create location configuration */
+    ngx_http_fastcgi_merge_loc_conf        /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_fastcgi_module = {
+    NGX_MODULE,
+    &ngx_http_fastcgi_module_ctx,          /* module context */
+    ngx_http_fastcgi_commands,             /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init module */
+    NULL                                   /* init process */
+};
+
+
+static ngx_int_t ngx_http_fastcgi_handler(ngx_http_request_t *r)
+{
+    ngx_int_t                     rc;
+    ngx_http_upstream_t          *u;
+    ngx_http_fastcgi_loc_conf_t  *flcf;
+
+    flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
+
+    if (!(u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    u->peer.log = r->connection->log;
+    u->peer.log_error = NGX_ERROR_ERR;
+    u->peer.peers = flcf->peers;
+    u->peer.tries = flcf->peers->number;
+#if (NGX_THREADS)
+    u->peer.lock = &r->connection->lock;
+#endif
+
+    u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module;
+
+    u->conf = &flcf->upstream;
+
+    u->location = flcf->location;
+
+    u->create_request = ngx_http_fastcgi_create_request;
+    u->reinit_request = ngx_http_fastcgi_reinit_request;
+    u->process_header = ngx_http_fastcgi_process_header;
+    u->send_header = ngx_http_fastcgi_send_header;
+    u->abort_request = ngx_http_fastcgi_abort_request;
+    u->finalize_request = ngx_http_fastcgi_finalize_request;
+
+    u->pipe.input_filter = ngx_http_fastcgi_input_filter;
+    u->pipe.input_ctx = r;
+
+    u->log_ctx = r->connection->log->data;
+    u->log_handler = ngx_http_upstream_log_error;
+
+    u->schema.len = sizeof("fastcgi://") - 1;
+    u->schema.data = (u_char *) "fastcgi://";
+    u->uri.len = sizeof("/") - 1;
+    u->uri.data = (u_char *) "/";
+
+    r->upstream = u;
+
+    rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
+
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+        return rc;
+    }
+
+    return NGX_DONE;
+}
+
+
+static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r)
+{
+    u_char                             ch, *pos, addr_text[INET_ADDRSTRLEN];
+    size_t                             size, len, index, padding, addr_len;
+    off_t                              file_pos;
+    ngx_buf_t                         *b;
+    socklen_t                          slen;
+    ngx_chain_t                       *cl, *body;
+    ngx_uint_t                         i, n, next;
+    ngx_list_part_t                   *part;
+    ngx_table_elt_t                   *header;
+    struct sockaddr_in                 sin;
+    ngx_http_fastcgi_header_t         *h;
+    ngx_http_fastcgi_loc_conf_t       *flcf;
+    ngx_http_fastcgi_begin_request_t  *br;
+
+    flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
+
+    if ((flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) && r->in_addr == 0) {
+
+        slen = sizeof(struct sockaddr_in);
+        if (getsockname(r->connection->fd,
+                        (struct sockaddr *) &sin, &slen) == -1)
+        {
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log,
+                          ngx_socket_errno, "getsockname() failed");
+            return NGX_ERROR;
+        }
+
+        r->in_addr = sin.sin_addr.s_addr;
+    }
+
+    addr_len = ngx_inet_ntop(r->connection->listening->family, &r->in_addr,
+                             addr_text, INET_ADDRSTRLEN);
+    if (addr_len == 0) {
+        return NGX_ERROR;
+    }
+
+
+    if (r->upstream->method) {
+        len = 1 + 1 + sizeof("REQUEST_METHOD") - 1
+                + ngx_http_fastcgi_methods[r->upstream->method - 1].len;
+    
+    } else {
+        len = 1 + ((r->method_name.len - 1 > 127) ? 4 : 1)
+                                            + sizeof("REQUEST_METHOD") - 1
+                                            + r->method_name.len - 1;
+    }
+
+
+    index = (r->uri.data[r->uri.len - 1] == '/') ? flcf->index.len : 0;
+
+    len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1)
+             + sizeof("PATH_TRANSLATED") - 1
+             + flcf->root.len + r->uri.len + index;
+
+    if (r->args.len) {
+        len += 1 + ((r->args.len > 127) ? 4 : 1) + sizeof("QUERY_STRING") - 1
+                                                 + r->args.len;
+    }
+
+    if (r->headers_in.content_length_n > 0) {
+        len += 1 + ((r->headers_in.content_length->value.len > 127) ? 4 : 1)
+                 + sizeof("CONTENT_LENGTH") - 1
+                 + r->headers_in.content_length->value.len;
+    }
+
+
+    if (r->headers_in.content_type) {
+        len += 1 + ((r->headers_in.content_type->value.len > 127) ? 4 : 1)
+                 + sizeof("CONTENT_TYPE") - 1
+                 + r->headers_in.content_type->value.len;
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) {
+        len += 1 + 1 + sizeof("REDIRECT_STATUS200") - 1;
+    }
+
+    if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) {
+        len += 1 + ((r->uri.len > 127) ? 4 : 1)
+                 + sizeof("REQUEST_URI") - 1 + r->uri.len;
+    }
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) {
+        len += 1 + ((r->uri.len + index > 127) ? 4 : 1)
+                 + sizeof("SCRIPT_NAME") - 1 + r->uri.len + index ;
+    }
+
+    if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) {
+        len += 1 + 1 + sizeof("REMOTE_ADDR") - 1 + r->connection->addr_text.len;
+    }
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) {
+        len += 1 + 1 + sizeof("SERVER_NAME") - 1 + r->server_name.len;
+    }
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) {
+        len += 1 + 1 + sizeof("SERVER_PORT") - 1 + r->port_text->len - 1;
+    }
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) {
+        len += 1 + 1 + sizeof("SERVER_ADDR") - 1 + addr_len;
+    }
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL
+        && r->http_protocol.len)
+    {
+        len += 1 + ((r->http_protocol.len > 127) ? 4 : 1)
+                 + sizeof("SERVER_PROTOCOL") - 1 + r->http_protocol.len;
+    }
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) {
+        len += 1 + 1 + sizeof("SERVER_SOFTWARE") - 1 + sizeof(NGINX_VER) - 1;
+    }
+
+    if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) {
+        len += 1 + 1 + sizeof("GATEWAY_INTERFACE") - 1 + sizeof("CGI/1.1") - 1;
+    }
+
+
+    part = &r->headers_in.headers.part;
+    header = part->elts;
+
+    for (i = 0; /* void */; i++) {
+
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
+                break;
+            }
+
+            part = part->next;
+            header = part->elts;
+            i = 0;
+        }
+
+        len += ((header[i].key.len > 127) ? 4 : 1)
+               + ((header[i].value.len > 127) ? 4 : 1)
+               + 5 + header[i].key.len + header[i].value.len;
+    }
+
+
+    if (len > 65535) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      "fastcgi: the request record is too big");
+        return NGX_ERROR;
+    }
+
+
+    padding = 8 - len % 8;
+    padding = (padding == 8) ? 0 : padding;
+
+
+    size = sizeof(ngx_http_fastcgi_header_t)
+           + sizeof(ngx_http_fastcgi_begin_request_t)
+
+           + sizeof(ngx_http_fastcgi_header_t)  /* NGX_HTTP_FASTCGI_PARAMS */
+           + len + padding
+           + sizeof(ngx_http_fastcgi_header_t)  /* NGX_HTTP_FASTCGI_PARAMS */
+
+           + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */
+
+
+    if (!(b = ngx_create_temp_buf(r->pool, size))) {
+        return NGX_ERROR;
+    }
+
+    if (!(cl = ngx_alloc_chain_link(r->pool))) {
+        return NGX_ERROR;
+    }
+
+    cl->buf = b;
+
+    h = (ngx_http_fastcgi_header_t *) b->pos;
+
+    h->version = 1;
+    h->type = NGX_HTTP_FASTCGI_BEGIN_REQUEST;
+    h->request_id_hi = 0;
+    h->request_id_lo = 1;
+    h->content_length_hi = 0;
+    h->content_length_lo = sizeof(ngx_http_fastcgi_begin_request_t);
+    h->padding_length = 0;
+    h->reserved = 0;
+
+    br = (ngx_http_fastcgi_begin_request_t *)
+                                  (b->pos + sizeof(ngx_http_fastcgi_header_t));
+    br->role_hi = 0;
+    br->role_lo = NGX_HTTP_FASTCGI_RESPONDER;
+    br->flags = 0; /* NGX_HTTP_FASTCGI_KEEP_CONN */
+    br->reserved[0] = 0;
+    br->reserved[1] = 0;
+    br->reserved[2] = 0;
+    br->reserved[3] = 0;
+    br->reserved[4] = 0;
+
+    h = (ngx_http_fastcgi_header_t *)
+             (b->pos + sizeof(ngx_http_fastcgi_header_t)
+                     + sizeof(ngx_http_fastcgi_begin_request_t));
+
+    h->version = 1;
+    h->type = NGX_HTTP_FASTCGI_PARAMS;
+    h->request_id_hi = 0;
+    h->request_id_lo = 1;
+    h->content_length_hi = (u_char) ((len >> 8) & 0xff);
+    h->content_length_lo = (u_char) (len & 0xff);
+    h->padding_length = (u_char) padding;
+    h->reserved = 0;
+
+    b->last = b->pos + sizeof(ngx_http_fastcgi_header_t)
+                     + sizeof(ngx_http_fastcgi_begin_request_t)
+                     + sizeof(ngx_http_fastcgi_header_t);
+
+
+    *b->last++ = sizeof("PATH_TRANSLATED") - 1;
+
+    len = flcf->root.len + r->uri.len + index;
+    if (len > 127) {
+        *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+        *b->last++ = (u_char) ((len >> 16) & 0xff);
+        *b->last++ = (u_char) ((len >> 8) & 0xff);
+        *b->last++ = (u_char) (len & 0xff);
+
+    } else {
+        *b->last++ = (u_char) len;
+    }
+
+    b->last = ngx_cpymem(b->last, "PATH_TRANSLATED",
+                         sizeof("PATH_TRANSLATED") - 1);
+    b->last = ngx_cpymem(b->last, flcf->root.data, flcf->root.len);
+    b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
+
+    if (index) {
+        b->last = ngx_cpymem(b->last, flcf->index.data, index);
+    }
+
+
+    *b->last++ = sizeof("REQUEST_METHOD") - 1;
+
+    if (r->upstream->method) {
+        *b->last++ = (u_char)
+                         ngx_http_fastcgi_methods[r->upstream->method - 1].len;
+
+        b->last = ngx_cpymem(b->last, "REQUEST_METHOD",
+                             sizeof("REQUEST_METHOD") - 1);
+
+        b->last = ngx_cpymem(b->last,
+                        ngx_http_fastcgi_methods[r->upstream->method - 1].data,
+                        ngx_http_fastcgi_methods[r->upstream->method - 1].len);
+
+    } else {
+        len = r->method_name.len - 1;
+        if (len > 127) {
+            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+            *b->last++ = (u_char) ((len >> 16) & 0xff);
+            *b->last++ = (u_char) ((len >> 8) & 0xff);
+            *b->last++ = (u_char) (len & 0xff);
+
+        } else {
+            *b->last++ = (u_char) len;
+        }
+
+        b->last = ngx_cpymem(b->last, "REQUEST_METHOD",
+                             sizeof("REQUEST_METHOD") - 1);
+        b->last = ngx_cpymem(b->last, r->method_name.data, len);
+    }
+
+
+    if (r->args.len) {
+        *b->last++ = sizeof("QUERY_STRING") - 1;
+
+        len = r->args.len;
+        if (len > 127) {
+            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+            *b->last++ = (u_char) ((len >> 16) & 0xff);
+            *b->last++ = (u_char) ((len >> 8) & 0xff);
+            *b->last++ = (u_char) (len & 0xff);
+
+        } else {
+            *b->last++ = (u_char) len;
+        }
+
+        b->last = ngx_cpymem(b->last, "QUERY_STRING",
+                             sizeof("QUERY_STRING") - 1);
+        b->last = ngx_cpymem(b->last, r->args.data, len);
+    }
+
+
+    if (r->headers_in.content_length_n > 0) {
+        *b->last++ = sizeof("CONTENT_LENGTH") - 1;
+
+        len = r->headers_in.content_length->value.len;
+        if (len > 127) {
+            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+            *b->last++ = (u_char) ((len >> 16) & 0xff);
+            *b->last++ = (u_char) ((len >> 8) & 0xff);
+            *b->last++ = (u_char) (len & 0xff);
+
+        } else {
+            *b->last++ = (u_char) len;
+        }
+
+        b->last = ngx_cpymem(b->last, "CONTENT_LENGTH",
+                             sizeof("CONTENT_LENGTH") - 1);
+        b->last = ngx_cpymem(b->last, r->headers_in.content_length->value.data,
+                             len);
+    }
+
+
+    if (r->headers_in.content_type) {
+        *b->last++ = sizeof("CONTENT_TYPE") - 1;
+
+        len = r->headers_in.content_type->value.len;
+        if (len > 127) {
+            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+            *b->last++ = (u_char) ((len >> 16) & 0xff);
+            *b->last++ = (u_char) ((len >> 8) & 0xff);
+            *b->last++ = (u_char) (len & 0xff);
+
+        } else {
+            *b->last++ = (u_char) len;
+        }
+
+        b->last = ngx_cpymem(b->last, "CONTENT_TYPE",
+                             sizeof("CONTENT_TYPE") - 1);
+        b->last = ngx_cpymem(b->last, r->headers_in.content_type->value.data,
+                             len);
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) {
+        *b->last++ = sizeof("REDIRECT_STATUS") - 1;
+        *b->last++ = sizeof("200") - 1;
+        b->last = ngx_cpymem(b->last, "REDIRECT_STATUS200",
+                             sizeof("REDIRECT_STATUS200") - 1);
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) {
+        *b->last++ = sizeof("REQUEST_URI") - 1;
+
+        len = r->uri.len;
+        if (len > 127) {
+            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+            *b->last++ = (u_char) ((len >> 16) & 0xff);
+            *b->last++ = (u_char) ((len >> 8) & 0xff);
+            *b->last++ = (u_char) (len & 0xff);
+
+        } else {
+            *b->last++ = (u_char) len;
+        }
+
+        b->last = ngx_cpymem(b->last, "REQUEST_URI", sizeof("REQUEST_URI") - 1);
+        b->last = ngx_cpymem(b->last, r->uri.data, len);
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) {
+        *b->last++ = sizeof("SCRIPT_NAME") - 1;
+
+        len = r->uri.len + index;
+        if (len > 127) {
+            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+            *b->last++ = (u_char) ((len >> 16) & 0xff);
+            *b->last++ = (u_char) ((len >> 8) & 0xff);
+            *b->last++ = (u_char) (len & 0xff);
+
+        } else {
+            *b->last++ = (u_char) len;
+        }
+
+        b->last = ngx_cpymem(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME") - 1);
+        b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
+
+        if (index) {
+            b->last = ngx_cpymem(b->last, flcf->index.data, index);
+        }
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) {
+        *b->last++ = sizeof("REMOTE_ADDR") - 1;
+        *b->last++ = (u_char) (r->connection->addr_text.len);
+        b->last = ngx_cpymem(b->last, "REMOTE_ADDR", sizeof("REMOTE_ADDR") - 1);
+        b->last = ngx_cpymem(b->last, r->connection->addr_text.data,
+                             r->connection->addr_text.len);
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) {
+        *b->last++ = sizeof("SERVER_NAME") - 1;
+        *b->last++ = (u_char) r->server_name.len;
+        b->last = ngx_cpymem(b->last, "SERVER_NAME", sizeof("SERVER_NAME") - 1);
+        b->last = ngx_cpymem(b->last, r->server_name.data, r->server_name.len);
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) {
+        *b->last++ = sizeof("SERVER_PORT") - 1;
+        *b->last++ = (u_char) (r->port_text->len - 1);
+        b->last = ngx_cpymem(b->last, "SERVER_PORT", sizeof("SERVER_PORT") - 1);
+        b->last = ngx_cpymem(b->last, r->port_text->data + 1,
+                             r->port_text->len - 1);
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) {
+        *b->last++ = sizeof("SERVER_ADDR") - 1;
+        *b->last++ = (u_char) addr_len;
+        b->last = ngx_cpymem(b->last, "SERVER_ADDR", sizeof("SERVER_ADDR") - 1);
+        b->last = ngx_cpymem(b->last, addr_text, addr_len);
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL
+        && r->http_protocol.len)
+    {
+        *b->last++ = sizeof("SERVER_PROTOCOL") - 1;
+
+        len = r->http_protocol.len;
+        if (len > 127) {
+            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+            *b->last++ = (u_char) ((len >> 16) & 0xff);
+            *b->last++ = (u_char) ((len >> 8) & 0xff);
+            *b->last++ = (u_char) (len & 0xff);
+
+        } else {
+            *b->last++ = (u_char) len;
+        }
+
+        b->last = ngx_cpymem(b->last, "SERVER_PROTOCOL",
+                             sizeof("SERVER_PROTOCOL") - 1);
+        b->last = ngx_cpymem(b->last, r->http_protocol.data, len);
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) {
+        *b->last++ = sizeof("SERVER_SOFTWARE") - 1;
+        *b->last++ = (u_char) (sizeof(NGINX_VER) - 1);
+        b->last = ngx_cpymem(b->last, "SERVER_SOFTWARE",
+                             sizeof("SERVER_SOFTWARE") - 1);
+        b->last = ngx_cpymem(b->last, NGINX_VER, sizeof(NGINX_VER) - 1);
+    }
+
+
+    if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) {
+        *b->last++ = sizeof("GATEWAY_INTERFACE") - 1;
+        *b->last++ = (u_char) (sizeof("CGI/1.1") - 1);
+        b->last = ngx_cpymem(b->last, "GATEWAY_INTERFACE",
+                             sizeof("GATEWAY_INTERFACE") - 1);
+        b->last = ngx_cpymem(b->last, "CGI/1.1", sizeof("CGI/1.1") - 1);
+    }
+
+
+    part = &r->headers_in.headers.part;
+    header = part->elts;
+
+    for (i = 0; /* void */; i++) {
+
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
+                break;
+            }
+
+            part = part->next;
+            header = part->elts;
+            i = 0;
+        }
+
+        len = 5 + header[i].key.len;
+        if (len > 127) {
+            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+            *b->last++ = (u_char) ((len >> 16) & 0xff);
+            *b->last++ = (u_char) ((len >> 8) & 0xff);
+            *b->last++ = (u_char) (len & 0xff);
+
+        } else {
+            *b->last++ = (u_char) len;
+        }
+
+        len = header[i].value.len;
+        if (len > 127) {
+            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+            *b->last++ = (u_char) ((len >> 16) & 0xff);
+            *b->last++ = (u_char) ((len >> 8) & 0xff);
+            *b->last++ = (u_char) (len & 0xff);
+
+        } else {
+            *b->last++ = (u_char) len;
+        }
+
+        b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
+
+        for (n = 0; n < header[i].key.len; n++) {
+            ch = header[i].key.data[n];
+
+            if (ch >= 'a' && ch <= 'z') {
+                ch &= ~0x20;
+
+            } else if (ch == '-') {
+                ch = '_';
+            }
+
+            *b->last++ = ch;
+        }
+
+        b->last = ngx_cpymem(b->last, header[i].value.data,
+                             header[i].value.len);
+    }
+
+
+    if (padding) {
+        ngx_memzero(b->last, padding);
+        b->last += padding;
+    }
+
+
+    h = (ngx_http_fastcgi_header_t *) b->last;
+    b->last += sizeof(ngx_http_fastcgi_header_t);
+
+    h->version = 1;
+    h->type = NGX_HTTP_FASTCGI_PARAMS;
+    h->request_id_hi = 0;
+    h->request_id_lo = 1;
+    h->content_length_hi = 0;
+    h->content_length_lo = 0;
+    h->padding_length = 0;
+    h->reserved = 0;
+
+    h = (ngx_http_fastcgi_header_t *) b->last;
+    b->last += sizeof(ngx_http_fastcgi_header_t);
+
+    body = r->request_body->bufs;
+    r->request_body->bufs = cl;
+
+#if (NGX_SUPPRESS_WARN)
+    file_pos = 0;
+    pos = NULL;
+#endif
+
+    while (body) {
+
+        if (body->buf->in_file) {
+            file_pos = body->buf->file_pos;
+
+        } else {
+            pos = body->buf->pos;
+        }
+
+        next = 0;
+
+        do {
+            if (!(b = ngx_alloc_buf(r->pool))) {
+                return NGX_ERROR;
+            }
+
+            ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
+
+            if (body->buf->in_file) {
+                b->file_pos = file_pos;
+                file_pos += 32 * 1024;
+
+                if (file_pos > body->buf->file_last) {
+                    file_pos = body->buf->file_last;
+                    next = 1;
+                }
+
+                b->file_last = file_pos;
+                len = (ngx_uint_t) (file_pos - b->file_pos);
+
+            } else {
+                b->pos = pos;
+                pos += 32 * 1024;
+
+                if (pos > body->buf->last) {
+                    pos = body->buf->last;
+                    next = 1;
+                }
+
+                b->last = pos;
+                len = (ngx_uint_t) (pos - b->pos);
+            }
+
+            padding = 8 - len % 8;
+            padding = (padding == 8) ? 0 : padding;
+
+            h->version = 1;
+            h->type = NGX_HTTP_FASTCGI_STDIN;
+            h->request_id_hi = 0;
+            h->request_id_lo = 1;
+            h->content_length_hi = (u_char) ((len >> 8) & 0xff);
+            h->content_length_lo = (u_char) (len & 0xff);
+            h->padding_length = (u_char) padding;
+            h->reserved = 0;
+
+            if (!(cl->next = ngx_alloc_chain_link(r->pool))) {
+                return NGX_ERROR;
+            }
+
+            cl = cl->next;
+            cl->buf = b;
+
+            b = ngx_create_temp_buf(r->pool, sizeof(ngx_http_fastcgi_header_t)
+                                             + padding);
+            if (b == NULL) {
+                return NGX_ERROR;
+            }
+
+            if (padding) {
+                ngx_memzero(b->last, padding);
+                b->last += padding;
+            }
+
+            h = (ngx_http_fastcgi_header_t *) b->last;
+            b->last += sizeof(ngx_http_fastcgi_header_t);
+
+            if (!(cl->next = ngx_alloc_chain_link(r->pool))) {
+                return NGX_ERROR;
+            }
+
+            cl = cl->next;
+            cl->buf = b;
+
+        } while (!next);
+
+        body = body->next;
+    }
+
+    h->version = 1;
+    h->type = NGX_HTTP_FASTCGI_STDIN;
+    h->request_id_hi = 0;
+    h->request_id_lo = 1;
+    h->content_length_hi = 0;
+    h->content_length_lo = 0;
+    h->padding_length = 0;
+    h->reserved = 0;
+
+    cl->next = NULL;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r)
+{
+    ngx_http_fastcgi_ctx_t  *f;
+
+    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
+
+    if (f == NULL) {
+        return NGX_OK;
+    }
+
+    f->state = ngx_http_fastcgi_st_version;
+
+    ngx_memzero(&f->upstream->headers_in,
+                sizeof(ngx_http_fastcgi_headers_in_t));
+
+    if (f->upstream->headers_in.headers.part.elts) {
+        if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 5,
+                                         sizeof(ngx_table_elt_t)) == NGX_ERROR)
+        {
+            return NGX_ERROR;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r)
+{
+    u_char                  *start, *last;
+    ngx_str_t               *status_line;
+    ngx_int_t                rc, status;
+    ngx_uint_t               i;
+    ngx_table_elt_t         *h;
+    ngx_http_upstream_t     *u;
+    ngx_http_fastcgi_ctx_t  *f;
+
+    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
+
+    if (f == NULL) {
+        if (!(f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)))) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
+
+        f->upstream = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_upstream_t));
+        if (f->upstream == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 5,
+                                         sizeof(ngx_table_elt_t)) == NGX_ERROR)
+        {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+    }
+
+    u = r->upstream;
+
+    for ( ;; ) {
+
+        if (f->state < ngx_http_fastcgi_st_data) {
+
+            f->pos = u->header_in.pos;
+            f->last = u->header_in.last;
+
+            rc = ngx_http_fastcgi_process_record(r, f);
+
+            u->header_in.pos = f->pos;
+            u->header_in.last = f->last;
+
+            if (rc == NGX_AGAIN) {
+                return NGX_AGAIN;
+            }
+
+            if (rc == NGX_ERROR) {
+                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+            }
+
+            if (f->type != NGX_HTTP_FASTCGI_STDOUT) {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "upstream sent unexpected FastCGI record: %d",
+                              f->type);
+
+                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+            }
+
+            if (f->length == 0) {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "upstream closed prematurely FastCGI stdout");
+
+                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+            }
+        }
+
+        if (f->state == ngx_http_fastcgi_st_padding) {
+
+            if (u->header_in.pos + f->padding < u->header_in.last) {
+                f->state = ngx_http_fastcgi_st_version;
+                u->header_in.pos += f->padding;
+
+                continue;
+            }
+
+            if (u->header_in.pos + f->padding == u->header_in.last) {
+                f->state = ngx_http_fastcgi_st_version;
+                u->header_in.pos = u->header_in.last;
+
+                return NGX_AGAIN;
+            }
+
+            f->padding -= u->header_in.last - u->header_in.pos;
+            u->header_in.pos = u->header_in.last;
+
+            return NGX_AGAIN;
+        }
+
+        /* f->state == ngx_http_fastcgi_st_data */
+
+        start = u->header_in.pos;
+
+        if (u->header_in.pos + f->length < u->header_in.last) {
+
+            /*
+             * set u->header_in.last to the end of the FastCGI record data
+             * for ngx_http_parse_header_line()
+             */
+
+            last = u->header_in.last;
+            u->header_in.last = u->header_in.pos + f->length;
+
+        } else {
+            last = NULL;
+        }
+
+        for ( ;; ) {
+
+            rc = ngx_http_parse_header_line(r, &u->header_in);
+
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http fastcgi parser: %d", rc);
+
+            if (rc == NGX_AGAIN) {
+                break;
+            }
+
+            if (rc == NGX_OK) {
+
+                /* a header line has been parsed successfully */
+
+                if (!(h = ngx_list_push(&f->upstream->headers_in.headers))) {
+                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                }
+
+                h->key.len = r->header_name_end - r->header_name_start;
+                h->value.len = r->header_end - r->header_start;
+
+                h->key.data = ngx_palloc(r->pool,
+                                         h->key.len + 1 + h->value.len + 1);
+                if (h->key.data == NULL) {
+                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                }
+
+                h->value.data = h->key.data + h->key.len + 1;
+
+                ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
+                ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
+
+                for (i = 0; ngx_http_fastcgi_headers_in[i].name.len != 0; i++) {
+                    if (ngx_http_fastcgi_headers_in[i].name.len != h->key.len) {
+                        continue;
+                    }
+
+                    if (ngx_strcasecmp(ngx_http_fastcgi_headers_in[i].name.data,
+                                                             h->key.data) == 0)
+                    {
+                        *((ngx_table_elt_t **)
+                                 ((char *) &f->upstream->headers_in
+                                 + ngx_http_fastcgi_headers_in[i].offset)) = h;
+                        break;
+                    }
+                }
+
+                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                               "http fastcgi header: \"%V: %V\"",
+                               &h->key, &h->value);
+
+                continue;
+            }
+
+            if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
+
+                /* a whole header has been parsed successfully */
+
+                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                               "http fastcgi header done");
+
+                if (f->upstream->headers_in.status) {
+                    status_line = &f->upstream->headers_in.status->value;
+
+                    status = ngx_atoi(status_line->data, 3);
+
+                    if (status == NGX_ERROR) {
+                        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                    }
+
+                    r->headers_out.status = status;
+                    r->headers_out.status_line = *status_line;
+
+                } else {
+                    r->headers_out.status = 200;
+                    r->headers_out.status_line.len = sizeof("200 OK") - 1;
+                    r->headers_out.status_line.data = (u_char *) "200 OK";
+                }
+
+                u->state->status = r->headers_out.status;
+#if 0
+                if (u->cachable) {
+                    u->cachable = ngx_http_upstream_is_cachable(r);
+                }
+#endif
+
+                break;
+            }
+
+            /* there was error while a header line parsing */
+
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          ngx_http_upstream_header_errors[rc
+                                                - NGX_HTTP_PARSE_HEADER_ERROR]);
+
+            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+
+        }
+
+        if (last) {
+            u->header_in.last = last;
+        }
+
+        f->length -= u->header_in.pos - start;
+
+        if (rc == NGX_AGAIN) {
+            if (u->header_in.pos == u->header_in.last) {
+                return NGX_AGAIN;
+            }
+
+            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                          "upstream split a header in FastCGI records");
+
+            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+        }
+
+        if (f->length == 0) {
+            if (f->padding) {
+                f->state = ngx_http_fastcgi_st_padding;
+            } else {
+                f->state = ngx_http_fastcgi_st_version;
+            }
+        }
+
+        return NGX_OK;
+    }
+}
+
+
+static ngx_int_t ngx_http_fastcgi_send_header(ngx_http_request_t *r)
+{
+    ngx_uint_t                      i;
+    ngx_list_part_t                *part;
+    ngx_table_elt_t                *ho, *h;
+    ngx_http_fastcgi_ctx_t         *f;
+    ngx_http_fastcgi_headers_in_t  *headers_in;
+
+    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
+
+    headers_in = &f->upstream->headers_in;
+    part = &headers_in->headers.part;
+    h = part->elts;
+
+    for (i = 0; /* void */; i++) {
+
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
+                break;
+            }
+
+            part = part->next;
+            h = part->elts;
+            i = 0;
+        }
+
+        /* ignore some headers */
+
+        if (&h[i] == headers_in->status) {
+            continue;
+        }
+
+
+        if (&h[i] == headers_in->x_powered_by
+            && !r->upstream->conf->x_powered_by)
+        {
+            continue;
+        }
+
+
+        /* "Content-Type" is handled specially */
+
+        if (&h[i] == headers_in->content_type) {
+            r->headers_out.content_type = &h[i];
+            r->headers_out.content_type->key.len = 0;
+            continue;
+        }
+
+
+        /* copy some header pointers and set up r->headers_out */
+
+        if (!(ho = ngx_list_push(&r->headers_out.headers))) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        *ho = h[i];
+
+#if (NGX_HTTP_GZIP)
+        if (&h[i] == headers_in->content_encoding) {
+            r->headers_out.content_encoding = ho;
+            continue;
+        }
+#endif
+
+        if (&h[i] == headers_in->content_length) {
+            r->headers_out.content_length = ho;
+            r->headers_out.content_length_n = ngx_atoi(ho->value.data,
+                                                       ho->value.len);
+            continue;
+        }
+    }
+
+    return ngx_http_send_header(r);
+}
+
+
+static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
+                                               ngx_buf_t *buf)
+{
+    ngx_int_t                rc;
+    ngx_buf_t               *b;
+    ngx_str_t                line;
+    ngx_chain_t             *cl;
+    ngx_http_request_t      *r;
+    ngx_http_fastcgi_ctx_t  *f;
+
+    if (buf->pos == buf->last) {
+        return NGX_OK;
+    }
+
+    r = p->input_ctx;
+    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
+
+    b = NULL;
+
+    f->pos = buf->pos;
+    f->last = buf->last;
+
+    for ( ;; ) {
+        if (f->state < ngx_http_fastcgi_st_data) {
+
+            rc = ngx_http_fastcgi_process_record(r, f);
+
+            if (rc == NGX_AGAIN) {
+                break;
+            }
+
+            if (rc == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
+                f->state = ngx_http_fastcgi_st_version;
+                p->upstream_done = 1;
+
+                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
+                               "http fastcgi closed stdout");
+
+                continue;
+            }
+
+            if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
+                f->state = ngx_http_fastcgi_st_version;
+                p->upstream_done = 1;
+
+                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
+                               "http fastcgi sent end request");
+
+                break;
+            }
+        }
+
+
+        if (f->state == ngx_http_fastcgi_st_padding) {
+
+            if (f->pos + f->padding < f->last) {
+                f->state = ngx_http_fastcgi_st_version;
+                f->pos += f->padding;
+
+                continue;
+            }
+
+            if (f->pos + f->padding == f->last) {
+                f->state = ngx_http_fastcgi_st_version;
+
+                break;
+            }
+
+            f->padding -= f->last - f->pos;
+
+            break;
+        }
+
+
+        /* f->state == ngx_http_fastcgi_st_data */
+
+        if (f->type == NGX_HTTP_FASTCGI_STDERR) {
+
+            if (f->length) {
+                line.data = f->pos;
+
+                if (f->pos + f->length <= f->last) {
+                    line.len = f->length;
+                    f->pos += f->length;
+
+                } else { 
+                    line.len = f->last - f->pos;
+                    f->length -= f->last - f->pos;
+                    f->pos = f->last;
+                }
+
+                /*
+                 * TODO: copy split stderr output into buffer,
+                 *       clean it up
+                 */
+
+                ngx_log_error(NGX_LOG_ERR, p->log, 0,
+                              "FastCGI stderr: %V", &line);
+
+                if (f->pos == f->last) {
+                    break;
+                }
+            }
+
+            f->state = ngx_http_fastcgi_st_version;
+
+            continue;
+        }
+
+
+        /* f->type == NGX_HTTP_FASTCGI_STDOUT */
+
+        if (p->free) {
+            b = p->free->buf;
+            p->free = p->free->next;
+
+        } else {
+            if (!(b = ngx_alloc_buf(p->pool))) {
+                return NGX_ERROR;
+            }
+        }
+
+        ngx_memzero(b, sizeof(ngx_buf_t));
+
+        b->pos = f->pos;
+        b->shadow = buf;
+        b->tag = p->tag;
+        b->temporary = 1;
+        b->recycled = 1;
+        buf->shadow = b;
+
+        if (!(cl = ngx_alloc_chain_link(p->pool))) {
+            return NGX_ERROR;
+        }
+
+        cl->buf = b;
+        cl->next = NULL;
+
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
+
+        ngx_chain_add_link(p->in, p->last_in, cl);
+
+        if (f->pos + f->length < f->last) {
+
+            if (f->padding) {
+                f->state = ngx_http_fastcgi_st_padding;
+            } else {
+                f->state = ngx_http_fastcgi_st_version;
+            }
+
+            f->pos += f->length;
+            b->last = f->pos;
+
+            continue;
+        }
+
+        if (f->pos + f->length == f->last) {
+
+            if (f->padding) {
+                f->state = ngx_http_fastcgi_st_padding;
+            } else {
+                f->state = ngx_http_fastcgi_st_version;
+            }
+
+            b->last = f->last;
+
+            break;
+        }
+
+        f->length -= f->last - f->pos;
+
+        b->last = f->last;
+
+        break;
+
+    }
+
+    if (b) {
+        b->last_shadow = 1;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r,
+                                                 ngx_http_fastcgi_ctx_t *f)
+{
+    u_char                     ch, *p;
+    ngx_http_upstream_t       *u;
+    ngx_http_fastcgi_state_e   state;
+
+    u = r->upstream;
+
+    state = f->state;
+
+    for (p = f->pos; p < f->last; p++) {
+
+        ch = *p;
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http fastcgi record byte: %02Xd", ch);
+
+        switch (state) {
+
+        case ngx_http_fastcgi_st_version:
+            if (ch != 1) {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "upstream sent unsupported FastCGI "
+                              "protocol version: %d", ch);
+                return NGX_ERROR;
+            }
+            state = ngx_http_fastcgi_st_type;
+            break;
+
+        case ngx_http_fastcgi_st_type:
+            switch (ch) {
+            case NGX_HTTP_FASTCGI_STDOUT:
+            case NGX_HTTP_FASTCGI_STDERR:
+            case NGX_HTTP_FASTCGI_END_REQUEST:
+                 f->type = (ngx_uint_t) ch;
+                 break;
+            default:
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "upstream sent invalid FastCGI "
+                              "record type: %d", ch);
+                return NGX_ERROR;
+
+            }
+            state = ngx_http_fastcgi_st_request_id_hi;
+            break;
+
+        /* we support the single request per connection */
+
+        case ngx_http_fastcgi_st_request_id_hi:
+            if (ch != 0) {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "upstream sent unexpected FastCGI "
+                              "request id high byte: %d", ch);
+                return NGX_ERROR;
+            }
+            state = ngx_http_fastcgi_st_request_id_lo;
+            break;
+
+        case ngx_http_fastcgi_st_request_id_lo:
+            if (ch != 1) {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "upstream sent unexpected FastCGI "
+                              "request id low byte: %d", ch);
+                return NGX_ERROR;
+            }
+            state = ngx_http_fastcgi_st_content_length_hi;
+            break;
+
+        case ngx_http_fastcgi_st_content_length_hi:
+            f->length = ch << 8;
+            state = ngx_http_fastcgi_st_content_length_lo;
+            break;
+
+        case ngx_http_fastcgi_st_content_length_lo:
+            f->length |= (size_t) ch;
+            state = ngx_http_fastcgi_st_padding_length;
+            break;
+
+        case ngx_http_fastcgi_st_padding_length:
+            f->padding = (size_t) ch;
+            state = ngx_http_fastcgi_st_reserved;
+            break;
+
+        case ngx_http_fastcgi_st_reserved:
+            state = ngx_http_fastcgi_st_data;
+
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http fastcgi record length: %z", f->length);
+
+            f->pos = p + 1;
+            f->state = state;
+
+            return NGX_OK;
+
+        /* suppress warning */
+        case ngx_http_fastcgi_st_data:
+        case ngx_http_fastcgi_st_padding:
+            break;
+        }
+    }
+
+    f->pos = p + 1;
+    f->state = state;
+
+    return NGX_AGAIN;
+}
+
+
+static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "abort http fastcgi request");
+
+    return;
+}
+
+
+static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r,
+                                              ngx_int_t rc)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "finalize http fastcgi request");
+
+    return;
+}
+
+
+static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
+                                   void *conf)
+{
+    ngx_http_fastcgi_loc_conf_t *lcf = conf;
+
+    ngx_str_t                   *value;
+    ngx_inet_upstream_t          inet_upstream;
+    ngx_http_core_loc_conf_t    *clcf;
+#if (NGX_HAVE_UNIX_DOMAIN)
+    ngx_unix_domain_upstream_t   unix_upstream;
+#endif
+
+    value = cf->args->elts;
+
+    if (ngx_strncasecmp(value[1].data, "unix:", 5) == 0) {
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+        ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t));
+
+        unix_upstream.name = value[1];
+        unix_upstream.url = value[1];
+
+
+        if (!(lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream))) {
+            return NGX_CONF_ERROR;
+        }
+
+#else
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "the unix domain sockets are not supported "
+                           "on this platform");
+        return NGX_CONF_ERROR;
+
+#endif
+
+    } else {
+        ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t));
+
+        inet_upstream.name = value[1];
+        inet_upstream.url = value[1];
+    
+        if (!(lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream))) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+
+    lcf->location = &clcf->name;
+    clcf->handler = ngx_http_fastcgi_handler;
+
+    if (clcf->name.data[clcf->name.len - 1] == '/') {
+        clcf->auto_redirect = 1;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
+                                          void *data)
+{
+#if (NGX_FREEBSD)
+    ssize_t *np = data;
+
+    if (*np >= ngx_freebsd_net_inet_tcp_sendspace) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "\"fastcgi_send_lowat\" must be less than %d "
+                           "(sysctl net.inet.tcp.sendspace)",
+                           ngx_freebsd_net_inet_tcp_sendspace);
+
+        return NGX_CONF_ERROR;
+    }
+
+#elif !(NGX_HAVE_SO_SNDLOWAT)
+    ssize_t *np = data;
+
+    ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                       "\"fastcgi_send_lowat\" is not supported, ignored");
+
+    *np = 0;
+
+#endif
+
+    return NGX_CONF_OK;
+}
+
+
+static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_fastcgi_loc_conf_t  *conf;
+
+    if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t)))) {
+        return NGX_CONF_ERROR;
+    }
+
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     conf->upstream.bufs.num = 0;
+     *     conf->upstream.path = NULL;
+     *     conf->upstream.next_upstream = 0;
+     *     conf->upstream.temp_path = NULL;
+     *     conf->params = 0;
+     *     conf->root.len = 0;
+     *     conf->root.data = NULL;
+     *     conf->index.len = 0;
+     *     conf->index.data = NULL;
+     *     conf->location = NULL;
+     */
+
+    conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
+    conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
+    conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
+
+    conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE;
+    conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
+    conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE;
+
+    conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE; 
+    conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE;
+    
+    conf->upstream.x_powered_by = NGX_CONF_UNSET;
+
+    /* "fastcgi_cyclic_temp_file" is disabled */
+    conf->upstream.cyclic_temp_file = 0;
+
+    return conf;
+}
+
+
+static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf,
+                                             void *parent, void *child)
+{
+    ngx_http_fastcgi_loc_conf_t *prev = parent;
+    ngx_http_fastcgi_loc_conf_t *conf = child;
+
+    size_t  size;
+
+    ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
+                              prev->upstream.connect_timeout, 60000);
+    ngx_conf_merge_msec_value(conf->upstream.send_timeout,
+                              prev->upstream.send_timeout, 60000);
+    ngx_conf_merge_size_value(conf->upstream.send_lowat,
+                              prev->upstream.send_lowat, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.read_timeout,
+                              prev->upstream.read_timeout, 60000);
+
+    ngx_conf_merge_msec_value(conf->upstream.x_powered_by,
+                              prev->upstream.x_powered_by, 1);
+
+
+    ngx_conf_merge_size_value(conf->upstream.header_buffer_size, 
+                              prev->upstream.header_buffer_size,
+                              (size_t) ngx_pagesize);
+
+    ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
+                              8, ngx_pagesize);
+
+    if (conf->upstream.bufs.num < 2) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "there must be at least 2 \"fastcgi_buffers\"");
+        return NGX_CONF_ERROR;
+    }
+
+
+    size = conf->upstream.header_buffer_size;
+    if (size < conf->upstream.bufs.size) {
+        size = conf->upstream.bufs.size;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.busy_buffers_size, 
+                              prev->upstream.busy_buffers_size,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.busy_buffers_size == NGX_CONF_UNSET_SIZE) {
+        conf->upstream.busy_buffers_size = 2 * size;
+
+    } else if (conf->upstream.busy_buffers_size < size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+             "\"fastcgi_busy_buffers_size\" must be equal or bigger than "
+             "maximum of the value of \"fastcgi_header_buffer_size\" and "
+             "one of the \"fastcgi_buffers\"");
+
+        return NGX_CONF_ERROR;
+
+    } else if (conf->upstream.busy_buffers_size
+               > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
+    {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+             "\"fastcgi_busy_buffers_size\" must be less than "
+             "the size of all \"fastcgi_buffers\" minus one buffer");
+
+        return NGX_CONF_ERROR;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.temp_file_write_size, 
+                              prev->upstream.temp_file_write_size,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.temp_file_write_size == NGX_CONF_UNSET_SIZE) {
+        conf->upstream.temp_file_write_size = 2 * size;
+
+    } else if (conf->upstream.temp_file_write_size < size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+             "\"fastcgi_temp_file_write_size\" must be equal or bigger than "
+             "maximum of the value of \"fastcgi_header_buffer_size\" and "
+             "one of the \"fastcgi_buffers\"");
+
+        return NGX_CONF_ERROR;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.max_temp_file_size,
+                              prev->upstream.max_temp_file_size,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.max_temp_file_size == NGX_CONF_UNSET_SIZE) {
+
+        conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
+
+    } else if (conf->upstream.max_temp_file_size != 0
+               && conf->upstream.max_temp_file_size < size)
+    {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+             "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
+             "the temporary files usage or must be equal or bigger than "
+             "maximum of the value of \"fastcgi_header_buffer_size\" and "
+             "one of the \"fastcgi_buffers\"");
+
+        return NGX_CONF_ERROR;
+    }
+
+
+    ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
+                                 prev->upstream.next_upstream,
+                                 (NGX_CONF_BITMASK_SET
+                                  |NGX_HTTP_UPSTREAM_FT_ERROR
+                                  |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
+
+    ngx_conf_merge_path_value(conf->upstream.temp_path,
+                              prev->upstream.temp_path,
+                              NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0,
+                              ngx_garbage_collector_temp_handler, cf);
+
+
+    ngx_conf_merge_bitmask_value(conf->params, prev->params,
+                                 (NGX_CONF_BITMASK_SET
+                                  |NGX_HTTP_FASTCGI_REMOTE_ADDR
+                                  |NGX_HTTP_FASTCGI_REMOTE_USER
+                                  |NGX_HTTP_FASTCGI_SERVER_NAME
+                                  |NGX_HTTP_FASTCGI_SERVER_PORT
+                                  |NGX_HTTP_FASTCGI_SCRIPT_NAME
+                                  |NGX_HTTP_FASTCGI_AUTH_TYPE
+                                  |NGX_HTTP_FASTCGI_REQUEST_URI
+                                  |NGX_HTTP_FASTCGI_REDIRECT_STATUS));
+
+    ngx_conf_merge_str_value(conf->root, prev->root, "");
+
+    if (conf->root.len && conf->root.data[conf->root.len - 1] == '/') {
+        conf->root.len--;
+    }
+
+    ngx_conf_merge_str_value(conf->index, prev->index, "");
+
+    return NGX_CONF_OK;
+}
--- a/src/http/modules/ngx_http_gzip_filter.c
+++ b/src/http/modules/ngx_http_gzip_filter.c
@@ -80,12 +80,13 @@ static ngx_int_t ngx_http_gzip_proxied(n
 static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items,
                                         u_int size);
 static void ngx_http_gzip_filter_free(void *opaque, void *address);
-static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx);
+static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx);
 
 static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf,
-                                       uintptr_t data);
+                                       ngx_http_log_op_t *op);
 
-static ngx_int_t ngx_http_gzip_pre_conf(ngx_conf_t *cf);
+static ngx_int_t ngx_http_gzip_add_log_formats(ngx_conf_t *cf);
+
 static ngx_int_t ngx_http_gzip_filter_init(ngx_cycle_t *cycle);
 static void *ngx_http_gzip_create_conf(ngx_conf_t *cf);
 static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
@@ -205,7 +206,7 @@ static ngx_command_t  ngx_http_gzip_filt
 
 
 static ngx_http_module_t  ngx_http_gzip_filter_module_ctx = {
-    ngx_http_gzip_pre_conf,                /* pre conf */
+    ngx_http_gzip_add_log_formats,         /* pre conf */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -229,22 +230,23 @@ ngx_module_t  ngx_http_gzip_filter_modul
 
 
 static ngx_http_log_op_name_t ngx_http_gzip_log_fmt_ops[] = {
-    { ngx_string("gzip_ratio"), NGX_INT32_LEN + 3, ngx_http_gzip_log_ratio },
-    { ngx_null_string, 0, NULL }
+    { ngx_string("gzip_ratio"), NGX_INT32_LEN + 3,
+                                NULL, NULL, ngx_http_gzip_log_ratio },
+    { ngx_null_string, 0, NULL, NULL, NULL }
 };
 
 
 
 static u_char  gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
 
-#if (NGX_HAVE_LITTLE_ENDIAN)
+#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
 
 struct gztrailer {
     uint32_t  crc32;
     uint32_t  zlen;
 };
 
-#else /* NGX_HAVE_BIG_ENDIAN */
+#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */
 
 struct gztrailer {
     u_char  crc32[4];
@@ -497,11 +499,13 @@ static ngx_int_t ngx_http_gzip_body_filt
         if (rc != Z_OK) {
             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                           "deflateInit2() failed: %d", rc);
-            return ngx_http_gzip_error(ctx);
+            ngx_http_gzip_error(ctx);
+            return NGX_ERROR;
         }
 
         if (!(b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)))) {
-            return ngx_http_gzip_error(ctx);
+            ngx_http_gzip_error(ctx);
+            return NGX_ERROR;
         }
 
         b->memory = 1;
@@ -509,7 +513,8 @@ static ngx_int_t ngx_http_gzip_body_filt
         b->last = b->pos + 10;
 
         if (!(cl = ngx_alloc_chain_link(r->pool))) {
-            return ngx_http_gzip_error(ctx);
+            ngx_http_gzip_error(ctx);
+            return NGX_ERROR;
         }
         cl->buf = b;
         cl->next = NULL;
@@ -522,7 +527,8 @@ static ngx_int_t ngx_http_gzip_body_filt
          */
 
         if (ngx_http_next_body_filter(r, cl) == NGX_ERROR) {
-            return ngx_http_gzip_error(ctx);
+            ngx_http_gzip_error(ctx);
+            return NGX_ERROR;
         }
 
         ctx->last_out = &ctx->out;
@@ -533,7 +539,8 @@ static ngx_int_t ngx_http_gzip_body_filt
 
     if (in) {
         if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) {
-            return ngx_http_gzip_error(ctx);
+            ngx_http_gzip_error(ctx);
+            return NGX_ERROR;
         }
     }
 
@@ -607,7 +614,8 @@ static ngx_int_t ngx_http_gzip_body_filt
                     ctx->out_buf = ngx_create_temp_buf(r->pool,
                                                        conf->bufs.size);
                     if (ctx->out_buf == NULL) {
-                        return ngx_http_gzip_error(ctx);
+                        ngx_http_gzip_error(ctx);
+                        return NGX_ERROR;
                     }
 
                     ctx->out_buf->tag = (ngx_buf_tag_t)
@@ -634,7 +642,8 @@ static ngx_int_t ngx_http_gzip_body_filt
             if (rc != Z_OK && rc != Z_STREAM_END) {
                 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                               "deflate() failed: %d, %d", ctx->flush, rc);
-                return ngx_http_gzip_error(ctx);
+                ngx_http_gzip_error(ctx);
+                return NGX_ERROR;
             }
 
             ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -663,7 +672,8 @@ static ngx_int_t ngx_http_gzip_body_filt
                 /* zlib wants to output some more gzipped data */
 
                 if (!(cl = ngx_alloc_chain_link(r->pool))) {
-                    return ngx_http_gzip_error(ctx);
+                    ngx_http_gzip_error(ctx);
+                    return NGX_ERROR;
                 }
                 cl->buf = ctx->out_buf;
                 cl->next = NULL;
@@ -683,7 +693,8 @@ static ngx_int_t ngx_http_gzip_body_filt
                 ctx->flush = Z_NO_FLUSH;
 
                 if (!(cl = ngx_alloc_chain_link(r->pool))) {
-                    return ngx_http_gzip_error(ctx);
+                    ngx_http_gzip_error(ctx);
+                    return NGX_ERROR;
                 }
                 cl->buf = ctx->out_buf;
                 cl->next = NULL;
@@ -703,13 +714,15 @@ static ngx_int_t ngx_http_gzip_body_filt
                 if (rc != Z_OK) {
                     ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                                   "deflateEnd() failed: %d", rc);
-                    return ngx_http_gzip_error(ctx);
+                    ngx_http_gzip_error(ctx);
+                    return NGX_ERROR;
                 }
 
                 ngx_pfree(r->pool, ctx->preallocated);
 
                 if (!(cl = ngx_alloc_chain_link(r->pool))) {
-                    return ngx_http_gzip_error(ctx);
+                    ngx_http_gzip_error(ctx);
+                    return NGX_ERROR;
                 }
                 cl->buf = ctx->out_buf;
                 cl->next = NULL;
@@ -723,13 +736,15 @@ static ngx_int_t ngx_http_gzip_body_filt
 
                 } else {
                     if (!(b = ngx_create_temp_buf(r->pool, 8))) {
-                        return ngx_http_gzip_error(ctx);
+                        ngx_http_gzip_error(ctx);
+                        return NGX_ERROR;
                     }
 
                     b->last_buf = 1;
 
                     if (!(cl = ngx_alloc_chain_link(r->pool))) {
-                        return ngx_http_gzip_error(ctx);
+                        ngx_http_gzip_error(ctx);
+                        return NGX_ERROR;
                     }
                     cl->buf = b;
                     cl->next = NULL;
@@ -739,19 +754,21 @@ static ngx_int_t ngx_http_gzip_body_filt
                     b->last += 8;
                 }
 
-#if (NGX_HAVE_LITTLE_ENDIAN)
+#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
+
                 trailer->crc32 = ctx->crc32;
                 trailer->zlen = ctx->zin;
+
 #else
-                trailer->crc32[0] = ctx->crc32 & 0xff;
-                trailer->crc32[1] = (ctx->crc32 >> 8) & 0xff;
-                trailer->crc32[2] = (ctx->crc32 >> 16) & 0xff;
-                trailer->crc32[3] = (ctx->crc32 >> 24) & 0xff;
+                trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff);
+                trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff);
+                trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff);
+                trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff);
 
-                trailer->zlen[0] = ctx->zin & 0xff;
-                trailer->zlen[1] = (ctx->zin >> 8) & 0xff;
-                trailer->zlen[2] = (ctx->zin >> 16) & 0xff;
-                trailer->zlen[3] = (ctx->zin >> 24) & 0xff;
+                trailer->zlen[0] = (u_char) (ctx->zin & 0xff);
+                trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff);
+                trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff);
+                trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff);
 #endif
 
                 ctx->zstream.avail_in = 0;
@@ -764,7 +781,8 @@ static ngx_int_t ngx_http_gzip_body_filt
 
             if (conf->no_buffer && ctx->in == NULL) {
                 if (!(cl = ngx_alloc_chain_link(r->pool))) {
-                    return ngx_http_gzip_error(ctx);
+                    ngx_http_gzip_error(ctx);
+                    return NGX_ERROR;
                 }
                 cl->buf = ctx->out_buf;
                 cl->next = NULL;
@@ -791,7 +809,8 @@ static ngx_int_t ngx_http_gzip_body_filt
          */
 
         if (last == NGX_ERROR) {
-            return ngx_http_gzip_error(ctx);
+            ngx_http_gzip_error(ctx);
+            return NGX_ERROR;
         }
 
         ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out,
@@ -858,7 +877,7 @@ static void ngx_http_gzip_filter_free(vo
 
 
 static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf,
-                                       uintptr_t data)
+                                       ngx_http_log_op_t *op)
 {
     ngx_uint_t            zint, zfrac;
     ngx_http_gzip_ctx_t  *ctx;
@@ -889,7 +908,7 @@ static u_char *ngx_http_gzip_log_ratio(n
 }
 
 
-static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx)
+static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx)
 {
     deflateEnd(&ctx->zstream);
 
@@ -902,26 +921,24 @@ static int ngx_http_gzip_error(ngx_http_
 
     ctx->done = 1;
 
-    return NGX_ERROR;
+    return;
 }
 
 
-static ngx_int_t ngx_http_gzip_pre_conf(ngx_conf_t *cf)
+static ngx_int_t ngx_http_gzip_add_log_formats(ngx_conf_t *cf)
 {
     ngx_http_log_op_name_t  *op;
 
     for (op = ngx_http_gzip_log_fmt_ops; op->name.len; op++) { /* void */ }
-    op->op = NULL;
-
-    op = ngx_http_log_fmt_ops;
+    op->run = NULL;
 
-    for (op = ngx_http_log_fmt_ops; op->op; op++) {
+    for (op = ngx_http_log_fmt_ops; op->run; op++) {
         if (op->name.len == 0) {
-            op = (ngx_http_log_op_name_t *) op->op;
+            op = (ngx_http_log_op_name_t *) op->run;
         }
     }
 
-    op->op = (ngx_http_log_op_pt) ngx_http_gzip_log_fmt_ops;
+    op->run = (ngx_http_log_op_run_pt) ngx_http_gzip_log_fmt_ops;
 
     return NGX_OK;
 }
@@ -948,14 +965,11 @@ static void *ngx_http_gzip_create_conf(n
     }
 
     /*
-
-    set by ngx_pcalloc():
-
-    conf->bufs.num = 0;
-    conf->proxied = 0;
-
-    conf->types = NULL;
-
+     * set by ngx_pcalloc():
+     *
+     *     conf->bufs.num = 0;
+     *     conf->proxied = 0;
+     *     conf->types = NULL;
      */
 
     conf->enable = NGX_CONF_UNSET;
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -8,11 +8,15 @@
 #include <ngx_core.h>
 #include <ngx_http.h>
 
+#include <openssl/engine.h>
+
 
 #define NGX_DEFLAUT_CERTIFICATE      "cert.pem"
 #define NGX_DEFLAUT_CERTIFICATE_KEY  "cert.pem"
 
 
+static void *ngx_http_ssl_create_main_conf(ngx_conf_t *cf);
+static char *ngx_http_ssl_init_main_conf(ngx_conf_t *cf, void *conf);
 static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf);
 static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
                                          void *parent, void *child);
@@ -20,6 +24,13 @@ static char *ngx_http_ssl_merge_srv_conf
 
 static ngx_command_t  ngx_http_ssl_commands[] = {
 
+    { ngx_string("ssl_engine"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      offsetof(ngx_http_ssl_main_conf_t, engine),
+      NULL },
+
     { ngx_string("ssl"),
       NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -41,6 +52,13 @@ static ngx_command_t  ngx_http_ssl_comma
       offsetof(ngx_http_ssl_srv_conf_t, certificate_key),
       NULL },
 
+    { ngx_string("ssl_ciphers"),
+      NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_str_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_ssl_srv_conf_t, ciphers),
+      NULL },
+
       ngx_null_command
 };
 
@@ -48,8 +66,8 @@ static ngx_command_t  ngx_http_ssl_comma
 static ngx_http_module_t  ngx_http_ssl_module_ctx = {
     NULL,                                  /* pre conf */
 
-    NULL,                                  /* create main configuration */
-    NULL,                                  /* init main configuration */
+    ngx_http_ssl_create_main_conf,         /* create main configuration */
+    ngx_http_ssl_init_main_conf,           /* init main configuration */
 
     ngx_http_ssl_create_srv_conf,          /* create server configuration */
     ngx_http_ssl_merge_srv_conf,           /* merge server configuration */
@@ -69,6 +87,56 @@ ngx_module_t  ngx_http_ssl_module = {
 };
 
 
+static void *ngx_http_ssl_create_main_conf(ngx_conf_t *cf)
+{
+    ngx_http_ssl_main_conf_t  *mcf;
+
+    if (!(mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_main_conf_t)))) {
+        return NGX_CONF_ERROR;
+    }
+
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     mcf->engine.len = 0;
+     *     mcf->engine.data = NULL;
+     */
+
+    return mcf;
+}
+
+
+static char *ngx_http_ssl_init_main_conf(ngx_conf_t *cf, void *conf)
+{
+    ngx_http_ssl_main_conf_t *mcf = conf;
+
+    ENGINE  *engine;
+
+    if (mcf->engine.len == 0) {
+        return NGX_CONF_OK;
+    }
+
+    engine = ENGINE_by_id((const char *) mcf->engine.data);
+
+    if (engine == NULL) {
+        ngx_ssl_error(NGX_LOG_WARN, cf->log, 0,
+                      "ENGINE_by_id(\"%V\") failed", &mcf->engine);
+        return NGX_CONF_ERROR;
+    }
+
+    if (ENGINE_set_default(engine, ENGINE_METHOD_ALL) == 0) {
+        ngx_ssl_error(NGX_LOG_WARN, cf->log, 0,
+                      "ENGINE_set_default(\"%V\", ENGINE_METHOD_ALL) failed",
+                      &mcf->engine);
+        return NGX_CONF_ERROR;
+    }
+
+    ENGINE_free(engine);
+
+    return NGX_CONF_OK;
+}
+
+
 static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
 {
     ngx_http_ssl_srv_conf_t  *scf;
@@ -77,6 +145,17 @@ static void *ngx_http_ssl_create_srv_con
         return NGX_CONF_ERROR;
     }
 
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     scf->certificate.len = 0;
+     *     scf->certificate.data = NULL;
+     *     scf->certificate_key.len = 0;
+     *     scf->certificate_key.data = NULL;
+     *     scf->ciphers.len = 0;
+     *     scf->ciphers.data = NULL;
+     */
+
     scf->enable = NGX_CONF_UNSET;
 
     return scf;
@@ -101,6 +180,9 @@ static char *ngx_http_ssl_merge_srv_conf
     ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
                              NGX_DEFLAUT_CERTIFICATE_KEY);
 
+    ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, "");
+
+
     /* TODO: configure methods */
 
     conf->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
@@ -110,6 +192,16 @@ static char *ngx_http_ssl_merge_srv_conf
         return NGX_CONF_ERROR;
     }
 
+    if (conf->ciphers.len) {
+        if (SSL_CTX_set_cipher_list(conf->ssl_ctx,
+                                   (const char *) conf->ciphers.data) == 0)
+        {
+            ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
+                          "SSL_CTX_set_cipher_list(\"%V\") failed",
+                          &conf->ciphers);
+        }
+    }
+
     if (SSL_CTX_use_certificate_file(conf->ssl_ctx,
                                      (char *) conf->certificate.data,
                                      SSL_FILETYPE_PEM) == 0) {
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -14,10 +14,17 @@
 
 
 typedef struct {
+    ngx_str_t       engine;
+} ngx_http_ssl_main_conf_t;
+
+
+typedef struct {
     ngx_flag_t      enable;
     ngx_str_t       certificate;
     ngx_str_t       certificate_key;
 
+    ngx_str_t       ciphers;
+
     ngx_ssl_ctx_t  *ssl_ctx;
 } ngx_http_ssl_srv_conf_t;
 
--- a/src/http/modules/ngx_http_userid_filter.c
+++ b/src/http/modules/ngx_http_userid_filter.c
@@ -44,13 +44,17 @@ static ngx_int_t ngx_http_userid_set_uid
                                          ngx_http_userid_ctx_t *ctx,
                                          ngx_http_userid_conf_t *conf);
 
+static size_t ngx_http_userid_log_uid_got_getlen(ngx_http_request_t *r,
+                                                 uintptr_t data);
 static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf,
-                                           uintptr_t data);
+                                           ngx_http_log_op_t *op);
+static size_t ngx_http_userid_log_uid_set_getlen(ngx_http_request_t *r,
+                                                 uintptr_t data);
 static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf,
-                                           uintptr_t data);
+                                           ngx_http_log_op_t *op);
 
+static ngx_int_t ngx_http_userid_add_log_formats(ngx_conf_t *cf);
 static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle);
-static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf);
 static void *ngx_http_userid_create_conf(ngx_conf_t *cf);
 static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent,
                                         void *child);
@@ -142,7 +146,7 @@ static ngx_command_t  ngx_http_userid_co
 
 
 ngx_http_module_t  ngx_http_userid_filter_module_ctx = {
-    ngx_http_userid_pre_conf,              /* pre conf */
+    ngx_http_userid_add_log_formats,       /* pre conf */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -166,9 +170,13 @@ ngx_module_t  ngx_http_userid_filter_mod
 
 
 static ngx_http_log_op_name_t ngx_http_userid_log_fmt_ops[] = {
-    { ngx_string("uid_got"), 0, ngx_http_userid_log_uid_got },
-    { ngx_string("uid_set"), 0, ngx_http_userid_log_uid_set },
-    { ngx_null_string, 0, NULL }
+    { ngx_string("uid_got"), 0, NULL,
+                                ngx_http_userid_log_uid_got_getlen,
+                                ngx_http_userid_log_uid_got },
+    { ngx_string("uid_set"), 0, NULL,
+                                ngx_http_userid_log_uid_set_getlen,
+                                ngx_http_userid_log_uid_set },
+    { ngx_null_string, 0, NULL, NULL, NULL }
 };
 
 
@@ -298,7 +306,7 @@ static ngx_int_t ngx_http_userid_set_uid
     u_char              *cookie, *p;
     size_t               len;
     socklen_t            slen;
-    struct sockaddr_in   addr_in;
+    struct sockaddr_in   sin;
     ngx_str_t            src, dst;
     ngx_table_elt_t     *set_cookie, *p3p;
 
@@ -321,14 +329,13 @@ static ngx_int_t ngx_http_userid_set_uid
             if (r->in_addr == 0) {
                 slen = sizeof(struct sockaddr_in);
                 if (getsockname(r->connection->fd,
-                                (struct sockaddr *) &addr_in, &slen) == -1)
+                                (struct sockaddr *) &sin, &slen) == -1)
                 {
                     ngx_log_error(NGX_LOG_CRIT, r->connection->log,
-                                  ngx_socket_errno,
-                                  "getsockname() failed");
+                                  ngx_socket_errno, "getsockname() failed");
                 }
 
-                r->in_addr = addr_in.sin_addr.s_addr;
+                r->in_addr = sin.sin_addr.s_addr;
             }
 
             ctx->uid_set[0] = htonl(r->in_addr);
@@ -352,7 +359,7 @@ static ngx_int_t ngx_http_userid_set_uid
         len += sizeof(expires) - 1 + 2;
     }
 
-    if (conf->domain.len > 1) {
+    if (conf->domain.len) {
         len += conf->domain.len;
     }
 
@@ -379,7 +386,7 @@ static ngx_int_t ngx_http_userid_set_uid
         p = ngx_http_cookie_time(p, ngx_time() + conf->expires);
     }
 
-    if (conf->domain.len > 1) {
+    if (conf->domain.len) {
         p = ngx_cpymem(p, conf->domain.data, conf->domain.len);
     }
 
@@ -397,7 +404,7 @@ static ngx_int_t ngx_http_userid_set_uid
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "uid cookie: \"%V\"", &set_cookie->value);
 
-    if (conf->p3p.len == 1) {
+    if (conf->p3p.len == 0) {
         return NGX_OK;
     }
 
@@ -413,8 +420,8 @@ static ngx_int_t ngx_http_userid_set_uid
 }
 
 
-static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf,
-                                           uintptr_t data)
+static size_t ngx_http_userid_log_uid_got_getlen(ngx_http_request_t *r,
+                                                 uintptr_t data)
 {
     ngx_http_userid_ctx_t   *ctx;
     ngx_http_userid_conf_t  *conf;
@@ -422,20 +429,30 @@ static u_char *ngx_http_userid_log_uid_g
     ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module);
 
     if (ctx == NULL || ctx->uid_got[3] == 0) {
-        if (buf == NULL) {
-            return (u_char *) 1;
-        }
+        return 1;
+    }
+
+    conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
+
+    return conf->name.len + 1 + 32;
+}
+
 
+static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf,
+                                           ngx_http_log_op_t *op)
+{
+    ngx_http_userid_ctx_t   *ctx;
+    ngx_http_userid_conf_t  *conf;
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module);
+
+    if (ctx == NULL || ctx->uid_got[3] == 0) {
         *buf = '-';
         return buf + 1;
     }
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
 
-    if (buf == NULL) {
-        return (u_char *) (conf->name.len + 1 + 32);
-    }
-
     buf = ngx_cpymem(buf, conf->name.data, conf->name.len);
 
     *buf++ = '=';
@@ -446,8 +463,8 @@ static u_char *ngx_http_userid_log_uid_g
 }
 
 
-static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf,
-                                           uintptr_t data)
+static size_t ngx_http_userid_log_uid_set_getlen(ngx_http_request_t *r,
+                                                 uintptr_t data)
 {
     ngx_http_userid_ctx_t   *ctx;
     ngx_http_userid_conf_t  *conf;
@@ -455,20 +472,30 @@ static u_char *ngx_http_userid_log_uid_s
     ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module);
 
     if (ctx == NULL || ctx->uid_set[3] == 0) {
-        if (buf == NULL) {
-            return (u_char *) 1;
-        }
+        return 1;
+    }
+
+    conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
+
+    return conf->name.len + 1 + 32;
+}
+
 
+static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf,
+                                           ngx_http_log_op_t *op)
+{
+    ngx_http_userid_ctx_t   *ctx;
+    ngx_http_userid_conf_t  *conf;
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module);
+
+    if (ctx == NULL || ctx->uid_set[3] == 0) {
         *buf = '-';
         return buf + 1;
     }
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
 
-    if (buf == NULL) {
-        return (u_char *) (conf->name.len + 1 + 32);
-    }
-
     buf = ngx_cpymem(buf, conf->name.data, conf->name.len);
 
     *buf++ = '=';
@@ -479,31 +506,29 @@ static u_char *ngx_http_userid_log_uid_s
 }
 
 
-static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle)
+static ngx_int_t ngx_http_userid_add_log_formats(ngx_conf_t *cf)
 {
-    ngx_http_next_header_filter = ngx_http_top_header_filter;
-    ngx_http_top_header_filter = ngx_http_userid_filter;
+    ngx_http_log_op_name_t  *op;
+
+    for (op = ngx_http_userid_log_fmt_ops; op->name.len; op++) { /* void */ }
+    op->run = NULL;
+
+    for (op = ngx_http_log_fmt_ops; op->run; op++) {
+        if (op->name.len == 0) {
+            op = (ngx_http_log_op_name_t *) op->run;
+        }
+    }
+
+    op->run = (ngx_http_log_op_run_pt) ngx_http_userid_log_fmt_ops;
 
     return NGX_OK;
 }
 
 
-static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf)
+static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle)
 {
-    ngx_http_log_op_name_t  *op;
-
-    for (op = ngx_http_userid_log_fmt_ops; op->name.len; op++) { /* void */ }
-    op->op = NULL;
-
-    op = ngx_http_log_fmt_ops;
-
-    for (op = ngx_http_log_fmt_ops; op->op; op++) {
-        if (op->name.len == 0) {
-            op = (ngx_http_log_op_name_t *) op->op;
-        }
-    }
-
-    op->op = (ngx_http_log_op_pt) ngx_http_userid_log_fmt_ops;
+    ngx_http_next_header_filter = ngx_http_top_header_filter;
+    ngx_http_top_header_filter = ngx_http_userid_filter;
 
     return NGX_OK;
 }
@@ -517,18 +542,18 @@ static void *ngx_http_userid_create_conf
         return NGX_CONF_ERROR;
     }
 
-    /* set by ngx_pcalloc():
-
-    conf->name.len = 0;
-    conf->name.date = NULL;
-    conf->domain.len = 0;
-    conf->domain.date = NULL;
-    conf->path.len = 0;
-    conf->path.date = NULL;
-    conf->p3p.len = 0;
-    conf->p3p.date = NULL;
-
-    */
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     conf->name.len = 0;
+     *     conf->name.date = NULL;
+     *     conf->domain.len = 0;
+     *     conf->domain.date = NULL;
+     *     conf->path.len = 0;
+     *     conf->path.date = NULL;
+     *     conf->p3p.len = 0;
+     *     conf->p3p.date = NULL;
+     */
 
     conf->enable = NGX_CONF_UNSET;
     conf->service = NGX_CONF_UNSET;
@@ -547,9 +572,9 @@ static char *ngx_http_userid_merge_conf(
     ngx_conf_merge_value(conf->enable, prev->enable, NGX_HTTP_USERID_OFF);
 
     ngx_conf_merge_str_value(conf->name, prev->name, "uid");
-    ngx_conf_merge_str_value(conf->domain, prev->domain, ".");
+    ngx_conf_merge_str_value(conf->domain, prev->domain, "");
     ngx_conf_merge_str_value(conf->path, prev->path, "; path=/");
-    ngx_conf_merge_str_value(conf->p3p, prev->p3p, ".");
+    ngx_conf_merge_str_value(conf->p3p, prev->p3p, "");
 
     ngx_conf_merge_value(conf->service, prev->service, NGX_CONF_UNSET);
     ngx_conf_merge_sec_value(conf->expires, prev->expires, 0);
@@ -565,8 +590,8 @@ char *ngx_http_userid_domain(ngx_conf_t 
     u_char  *p, *new;
 
     if (domain->len == 4 && ngx_strcmp(domain->data, "none") == 0) {
-        domain->len = 1;
-        domain->data = (u_char *) ".";
+        domain->len = 0;
+        domain->data = (u_char *) "";
 
         return NGX_CONF_OK;
     }
@@ -645,8 +670,8 @@ char *ngx_http_userid_p3p(ngx_conf_t *cf
     ngx_str_t  *p3p = data;
 
     if (p3p->len == 4 && ngx_strcmp(p3p->data, "none") == 0) {
-        p3p->len = 1;
-        p3p->data = (u_char *) ".";
+        p3p->len = 0;
+        p3p->data = (u_char *) "";
     }
 
     return NGX_CONF_OK;
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -13,14 +13,20 @@
 static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r);
 static ngx_int_t ngx_http_proxy_cache_get(ngx_http_proxy_ctx_t *p);
 
+static size_t ngx_http_proxy_log_proxy_state_getlen(ngx_http_request_t *r,
+                                                    uintptr_t data);
 static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r,
-                                              u_char *buf, uintptr_t data);
+                                              u_char *buf,
+                                              ngx_http_log_op_t *op);
+
+#if 0
 static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r,
                                               u_char *buf, uintptr_t data);
 static u_char *ngx_http_proxy_log_reason(ngx_http_request_t *r, u_char *buf,
                                          uintptr_t data);
+#endif
 
-static ngx_int_t ngx_http_proxy_pre_conf(ngx_conf_t *cf);
+static ngx_int_t ngx_http_proxy_add_log_formats(ngx_conf_t *cf);
 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
                                            void *parent, void *child);
@@ -231,7 +237,6 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, default_expires),
       NULL },
 
-
     { ngx_string("proxy_next_upstream"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
       ngx_conf_set_bitmask_slot,
@@ -251,7 +256,7 @@ static ngx_command_t  ngx_http_proxy_com
 
 
 ngx_http_module_t  ngx_http_proxy_module_ctx = {
-    ngx_http_proxy_pre_conf,               /* pre conf */
+    ngx_http_proxy_add_log_formats,        /* pre conf */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -270,16 +275,22 @@ ngx_module_t  ngx_http_proxy_module = {
     ngx_http_proxy_commands,               /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
     NULL,                                  /* init module */
-    NULL                                   /* init child */
+    NULL                                   /* init process */
 };
 
 
 
 static ngx_http_log_op_name_t ngx_http_proxy_log_fmt_ops[] = {
-    { ngx_string("proxy"), 0, ngx_http_proxy_log_proxy_state },
+    { ngx_string("proxy"), 0, NULL,
+                              ngx_http_proxy_log_proxy_state_getlen,
+                              ngx_http_proxy_log_proxy_state },
+
+#if 0
     { 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 }
+#endif
+
+    { ngx_null_string, 0, NULL, NULL, NULL }
 };
 
 
@@ -301,8 +312,12 @@ ngx_http_header_t ngx_http_proxy_headers
                          offsetof(ngx_http_proxy_headers_in_t, content_type) },
     { ngx_string("Content-Length"),
                        offsetof(ngx_http_proxy_headers_in_t, content_length) },
+
+#if (NGX_HTTP_GZIP)
     { ngx_string("Content-Encoding"),
                      offsetof(ngx_http_proxy_headers_in_t, content_encoding) },
+#endif
+
     { ngx_string("Last-Modified"),
                         offsetof(ngx_http_proxy_headers_in_t, last_modified) },
     { ngx_string("Location"),
@@ -779,11 +794,12 @@ u_char *ngx_http_proxy_log_error(void *d
     peer = &ctx->proxy->upstream->peer;
 
     p = ngx_snprintf(buf, len,
-                     " while %s, client: %V, URL: %V, upstream: %V%V",
+                     " while %s, client: %V, URL: %V, upstream: http://%V%s%V",
                      ctx->proxy->action,
                      &r->connection->addr_text,
                      &r->unparsed_uri,
-                     &peer->peers->peers[peer->cur_peer].addr_port_text,
+                     &peer->peers->peer[peer->cur_peer].name,
+                     ctx->proxy->lcf->upstream->uri_separator,
                      &ctx->proxy->lcf->upstream->uri);
     len -= p - buf;
     buf = p;
@@ -835,8 +851,24 @@ u_char *ngx_http_proxy_log_error(void *d
 }
 
 
+static size_t ngx_http_proxy_log_proxy_state_getlen(ngx_http_request_t *r,
+                                                    uintptr_t data)
+{
+    ngx_http_proxy_ctx_t  *p;
+
+    p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
+
+    if (p == NULL) {
+        return 1;
+    }
+
+    return p->states.nelts * /* STUB */ 100;
+}
+
+
 static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r,
-                                              u_char *buf, uintptr_t data)
+                                              u_char *buf,
+                                              ngx_http_log_op_t *op)
 {
     ngx_uint_t               i;
     ngx_http_proxy_ctx_t    *p;
@@ -845,21 +877,10 @@ static u_char *ngx_http_proxy_log_proxy_
     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 (buf == NULL) {
-        /* find the request line length */
-        return (u_char *) (uintptr_t) (p->states.nelts * /* STUB */ 100);
-    }
-
-
     i = 0;
     state = p->states.elts;
 
@@ -935,6 +956,8 @@ static u_char *ngx_http_proxy_log_proxy_
 }
 
 
+#if 0
+
 static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r,
                                               u_char *buf, uintptr_t data)
 {
@@ -1014,23 +1037,23 @@ static u_char *ngx_http_proxy_log_reason
     }
 }
 
+#endif
 
-static ngx_int_t ngx_http_proxy_pre_conf(ngx_conf_t *cf)
+
+static ngx_int_t ngx_http_proxy_add_log_formats(ngx_conf_t *cf)
 {
     ngx_http_log_op_name_t  *op;
 
     for (op = ngx_http_proxy_log_fmt_ops; op->name.len; op++) { /* void */ }
-    op->op = NULL;
-
-    op = ngx_http_log_fmt_ops;
+    op->run = NULL;
 
-    for (op = ngx_http_log_fmt_ops; op->op; op++) {
+    for (op = ngx_http_log_fmt_ops; op->run; op++) {
         if (op->name.len == 0) {
-            op = (ngx_http_log_op_name_t *) op->op;
+            op = (ngx_http_log_op_name_t *) op->run;
         }
     }
 
-    op->op = (ngx_http_log_op_pt) ngx_http_proxy_log_fmt_ops;
+    op->run = (ngx_http_log_op_run_pt) ngx_http_proxy_log_fmt_ops;
 
     return NGX_OK;
 }
@@ -1044,24 +1067,19 @@ static void *ngx_http_proxy_create_loc_c
                   ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)),
                   NGX_CONF_ERROR);
 
-    /* set by ngx_pcalloc():
-
-    conf->bufs.num = 0;
-
-    conf->path = NULL;
-
-    conf->next_upstream = 0;
-    conf->use_stale = 0;
-
-    conf->upstreams = NULL;
-    conf->peers = NULL;
-
-    conf->cache_path = NULL;
-    conf->temp_path = NULL;
-
-    conf->busy_lock = NULL;
-
-    */
+    /*
+     * set by ngx_pcalloc():
+     *
+     *    conf->bufs.num = 0;
+     *    conf->path = NULL;
+     *    conf->next_upstream = 0;
+     *    conf->use_stale = 0;
+     *    conf->upstreams = NULL;
+     *    conf->peers = NULL;
+     *    conf->cache_path = NULL;
+     *    conf->temp_path = NULL;
+     *    conf->busy_lock = NULL;
+     */
 
     conf->connect_timeout = NGX_CONF_UNSET_MSEC;
     conf->send_timeout = NGX_CONF_UNSET_MSEC;
@@ -1210,11 +1228,15 @@ static char *ngx_http_proxy_merge_loc_co
     ngx_conf_merge_bitmask_value(conf->use_stale, prev->use_stale,
                                  NGX_CONF_BITMASK_SET);
 
+#if 0
     ngx_conf_merge_path_value(conf->cache_path, prev->cache_path,
-                              "cache", 1, 2, 0, cf->pool);
+                              NGX_HTTP_PROXY_CACHE_PATH, 1, 2, 0,
+                              ngx_garbage_collector_temp_handler, cf);
+#endif
 
     ngx_conf_merge_path_value(conf->temp_path, prev->temp_path,
-                              "temp", 1, 2, 0, cf->pool);
+                              NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,
+                              ngx_garbage_collector_temp_handler, cf);
 
     ngx_conf_merge_value(conf->cache, prev->cache, 0);
 
@@ -1256,24 +1278,23 @@ static char *ngx_http_proxy_merge_loc_co
 }
 
 
-
 static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
                                      void *conf)
 {
     ngx_http_proxy_loc_conf_t *lcf = conf;
 
-    ngx_uint_t                 i, len;
-    char                      *err;
-    u_char                    *host;
-    in_addr_t                  addr;
-    ngx_str_t                 *value;
-    struct hostent            *h;
-    ngx_http_core_loc_conf_t  *clcf;
-
+    ngx_str_t                   *value, *url;
+    ngx_inet_upstream_t          inet_upstream;
+    ngx_http_core_loc_conf_t    *clcf;
+#if (NGX_HAVE_UNIX_DOMAIN)
+    ngx_unix_domain_upstream_t   unix_upstream;
+#endif
 
     value = cf->args->elts;
 
-    if (ngx_strncasecmp(value[1].data, "http://", 7) != 0) {
+    url = &value[1];
+
+    if (ngx_strncasecmp(url->data, "http://", 7) != 0) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
         return NGX_CONF_ERROR;
     }
@@ -1284,121 +1305,52 @@ static char *ngx_http_proxy_set_pass(ngx
         return NGX_CONF_ERROR;
     }
 
-    lcf->upstream->url.len = value[1].len;
-    if (!(lcf->upstream->url.data = ngx_palloc(cf->pool, value[1].len + 1))) {
-        return NGX_CONF_ERROR;
-    }
-
-    ngx_cpystrn(lcf->upstream->url.data, value[1].data, value[1].len + 1);
-
-    value[1].data += 7;
-    value[1].len -= 7;
+    if (ngx_strncasecmp(url->data + 7, "unix:", 5) == 0) {
 
-    err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream);
+#if (NGX_HAVE_UNIX_DOMAIN)
 
-    if (err) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, err);
-        return NGX_CONF_ERROR;
-    }
-
-    if (!(host = ngx_palloc(cf->pool, lcf->upstream->host.len + 1))) {
-        return NGX_CONF_ERROR;
-    }
+        ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t));
 
-    ngx_cpystrn(host, lcf->upstream->host.data, lcf->upstream->host.len + 1);
-
-    /* AF_INET only */
-
-    addr = inet_addr((char *) host);
-
-    if (addr == INADDR_NONE) {
-        h = gethostbyname((char *) host);
+        unix_upstream.name = *url;
+        unix_upstream.url.len = url->len - 7;
+        unix_upstream.url.data = url->data + 7;
+        unix_upstream.uri_part = 1;
 
-        if (h == NULL || h->h_addr_list[0] == NULL) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "host %s not found", host);
-            return NGX_CONF_ERROR;
-        }
-
-        for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
-
-        /* MP: ngx_shared_palloc() */
-
-        lcf->peers = ngx_pcalloc(cf->pool,
-                           sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1));
-
-        if (lcf->peers == NULL) {
+        if (!(lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream))) {
             return NGX_CONF_ERROR;
         }
 
-        lcf->peers->number = i;
-
-        /* STUB */
-        lcf->peers->max_fails = 1;
-        lcf->peers->fail_timeout = 60;
-
-        for (i = 0; h->h_addr_list[i] != NULL; i++) {
-            lcf->peers->peers[i].host.data = host;
-            lcf->peers->peers[i].host.len = lcf->upstream->host.len;
-            lcf->peers->peers[i].addr = *(in_addr_t *)(h->h_addr_list[i]);
-            lcf->peers->peers[i].port = lcf->upstream->port;
-
-            len = INET_ADDRSTRLEN - 1 + 1 + lcf->upstream->port_text.len;
+        lcf->upstream->host_header.len = sizeof("localhost") - 1;
+        lcf->upstream->host_header.data = (u_char *) "localhost";
+        lcf->upstream->uri = unix_upstream.uri;
+        lcf->upstream->uri_separator = ":";
+        lcf->upstream->default_port = 1;
 
-            lcf->peers->peers[i].addr_port_text.data =
-                                                     ngx_palloc(cf->pool, len);
-            if (lcf->peers->peers[i].addr_port_text.data == NULL) {
-                return NGX_CONF_ERROR;
-            }
+#else
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "the unix domain sockets are not supported "
+                           "on this platform");
+        return NGX_CONF_ERROR;
 
-            len = ngx_inet_ntop(AF_INET,
-                                &lcf->peers->peers[i].addr,
-                                lcf->peers->peers[i].addr_port_text.data,
-                                len);
-
-            lcf->peers->peers[i].addr_port_text.data[len++] = ':';
-
-            ngx_memcpy(lcf->peers->peers[i].addr_port_text.data + len,
-                       lcf->upstream->port_text.data,
-                       lcf->upstream->port_text.len);
-
-            lcf->peers->peers[i].addr_port_text.len =
-                                            len + lcf->upstream->port_text.len;
-        }
+#endif
 
     } else {
+        ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t));
 
-        /* MP: ngx_shared_palloc() */
+        inet_upstream.name = *url;
+        inet_upstream.url.len = url->len - 7;
+        inet_upstream.url.data = url->data + 7;
+        inet_upstream.default_port_value = 80;
+        inet_upstream.uri_part = 1;
 
-        if (!(lcf->peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)))) {
+        if (!(lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream))) {
             return NGX_CONF_ERROR;
         }
 
-        lcf->peers->number = 1;
-
-        lcf->peers->peers[0].host.data = host;
-        lcf->peers->peers[0].host.len = lcf->upstream->host.len;
-        lcf->peers->peers[0].addr = addr;
-        lcf->peers->peers[0].port = lcf->upstream->port;
-
-        len = lcf->upstream->host.len + 1 + lcf->upstream->port_text.len;
-
-        lcf->peers->peers[0].addr_port_text.len = len;
-
-        lcf->peers->peers[0].addr_port_text.data = ngx_palloc(cf->pool, len);
-        if (lcf->peers->peers[0].addr_port_text.data == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        len = lcf->upstream->host.len;
-
-        ngx_memcpy(lcf->peers->peers[0].addr_port_text.data,
-                   lcf->upstream->host.data, len);
-
-        lcf->peers->peers[0].addr_port_text.data[len++] = ':';
-
-        ngx_memcpy(lcf->peers->peers[0].addr_port_text.data + len,
-                   lcf->upstream->port_text.data,
-                   lcf->upstream->port_text.len);
+        lcf->upstream->host_header = inet_upstream.host_header;
+        lcf->upstream->port_text = inet_upstream.port_text;
+        lcf->upstream->uri = inet_upstream.uri;
+        lcf->upstream->uri_separator = "";
     }
 
     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
@@ -1410,93 +1362,7 @@ static char *ngx_http_proxy_set_pass(ngx
         clcf->auto_redirect = 1;
     }
 
-    return NULL;
-}
-
-
-static char *ngx_http_proxy_parse_upstream(ngx_str_t *url,
-                                           ngx_http_proxy_upstream_conf_t *u)
-{
-    size_t  i;
-
-    if (url->data[0] == ':' || url->data[0] == '/') {
-        return "invalid upstream URL";
-    }
-
-    u->host.data = url->data;
-    u->host_header.data = url->data;
-
-    for (i = 1; i < url->len; i++) {
-        if (url->data[i] == ':') {
-            u->port_text.data = &url->data[i] + 1;
-            u->host.len = i;
-        }
-
-        if (url->data[i] == '/') {
-            u->uri.data = &url->data[i];
-            u->uri.len = url->len - i;
-            u->host_header.len = i;
-
-            if (u->host.len == 0) {
-                u->host.len = i;
-            }
-
-            if (u->port_text.data == NULL) {
-                u->default_port = 1;
-                u->port = htons(80);
-                u->port_text.len = 2;
-                u->port_text.data = (u_char *) "80";
-                return NULL;
-            }
-
-            u->port_text.len = &url->data[i] - u->port_text.data;
-
-            if (u->port_text.len > 0) {
-                u->port = (in_port_t) ngx_atoi(u->port_text.data,
-                                               u->port_text.len);
-                if (u->port > 0) {
-
-                    if (u->port == 80) {
-                        u->default_port = 1;
-                    }
-
-                    u->port = htons(u->port);
-                    return NULL;
-                }
-            }
-
-            return "invalid port in upstream URL";
-        }
-    }
-
-    if (u->host.len == 0) {
-        u->host.len = i;
-    }
-
-    u->host_header.len = i;
-
-    u->uri.data = (u_char *) "/";
-    u->uri.len = 1;
-
-    if (u->port_text.data == NULL) {
-        u->default_port = 1;
-        u->port = htons(80);
-        u->port_text.len = 2;
-        u->port_text.data = (u_char *) "80";
-        return NULL;
-    }
-
-    u->port_text.len = &url->data[i] - u->port_text.data;
-
-    if (u->port_text.len > 0) {
-        u->port = (in_port_t) ngx_atoi(u->port_text.data, u->port_text.len);
-        if (u->port > 0) {
-            u->port = htons(u->port);
-            return NULL;
-        }
-    }
-
-    return "invalid port in upstream URL";
+    return NGX_CONF_OK;
 }
 
 
--- a/src/http/modules/proxy/ngx_http_proxy_handler.h
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.h
@@ -47,6 +47,8 @@ typedef struct {
     ngx_str_t                        port_text;
     ngx_str_t                       *location;
 
+    char                            *uri_separator;
+
     in_port_t                        port;
 
     unsigned                         default_port:1;
@@ -131,7 +133,11 @@ typedef struct {
     ngx_table_elt_t                 *connection;
     ngx_table_elt_t                 *content_type;
     ngx_table_elt_t                 *content_length;
+
+#if (NGX_HTTP_GZIP)
     ngx_table_elt_t                 *content_encoding;
+#endif
+
     ngx_table_elt_t                 *last_modified;
     ngx_table_elt_t                 *location;
     ngx_table_elt_t                 *accept_ranges;
--- a/src/http/modules/proxy/ngx_http_proxy_header.c
+++ b/src/http/modules/proxy/ngx_http_proxy_header.c
@@ -26,12 +26,7 @@ int ngx_http_proxy_copy_header(ngx_http_
     part = &headers_in->headers.part;
     h = part->elts;
 
-#if 0
-    h = headers_in->headers.elts;
-    for (i = 0; i < headers_in->headers.nelts; i++) {
-#endif
-
-    for (i = 0 ; /* void */; i++) {
+    for (i = 0; /* void */; i++) {
   
         if (i >= part->nelts) {
             if (part->next == NULL) {
@@ -113,10 +108,12 @@ int ngx_http_proxy_copy_header(ngx_http_
             continue;
         }
 
+#if (NGX_HTTP_GZIP)
         if (&h[i] == headers_in->content_encoding) {
             r->headers_out.content_encoding = ho;
             continue;
         }
+#endif
 
         if (&h[i] == headers_in->last_modified) {
             r->headers_out.last_modified = ho;
@@ -169,7 +166,8 @@ static int ngx_http_proxy_rewrite_locati
         return NGX_ERROR;
     }
 
-    if (uc->url.len > loc->value.len
+    if (p->lcf->preserve_host
+        || uc->url.len > loc->value.len
         || ngx_rstrncmp(loc->value.data, uc->url.data, uc->url.len) != 0)
     {
 
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c
@@ -14,7 +14,7 @@
 
 
 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p);
-static void ngx_http_proxy_init_upstream(void *data);
+static void ngx_http_proxy_init_upstream(ngx_http_request_t *r);
 static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p);
 static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p);
 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p);
@@ -53,9 +53,7 @@ static char  connection_close_header[] =
 int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p)
 {
     int                         rc;
-    ngx_temp_file_t            *tf;
     ngx_http_request_t         *r;
-    ngx_http_request_body_t    *rb;
     ngx_http_proxy_upstream_t  *u;
 
     r = p->request;
@@ -75,36 +73,7 @@ int ngx_http_proxy_request_upstream(ngx_
 
     u->method = r->method;
 
-    if (!(rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)))) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-    r->request_body = rb;
-
-    if (r->headers_in.content_length_n <= 0) {
-        ngx_http_proxy_init_upstream(p);
-        return NGX_DONE;
-    }
-
-    if (!(tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    tf->file.fd = NGX_INVALID_FILE;
-    tf->file.log = r->connection->log;
-    tf->path = p->lcf->temp_path;
-    tf->pool = r->pool;
-    tf->warn = "a client request body is buffered to a temporary file";
-    /* tf->persistent = 0; */
-
-    rb->handler = ngx_http_proxy_init_upstream;
-    rb->data = p;
-    /* rb->bufs = NULL; */
-    /* rb->buf = NULL; */
-    /* rb->rest = 0; */
-
-    rb->temp_file = tf;
-
-    rc = ngx_http_read_client_request_body(r);
+    rc = ngx_http_read_client_request_body(r, ngx_http_proxy_init_upstream);
 
     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
         return rc;
@@ -428,17 +397,16 @@ static ngx_chain_t *ngx_http_proxy_creat
 }
 
 
-static void ngx_http_proxy_init_upstream(void *data)
+static void ngx_http_proxy_init_upstream(ngx_http_request_t *r)
 {
-    ngx_http_proxy_ctx_t *p = data;
 
     ngx_chain_t               *cl;
-    ngx_http_request_t        *r;
+    ngx_http_proxy_ctx_t      *p;
     ngx_output_chain_ctx_t    *output;
     ngx_chain_writer_ctx_t    *writer;
     ngx_http_proxy_log_ctx_t  *ctx;
 
-    r = p->request;
+    p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http proxy init upstream, client timer: %d",
@@ -502,7 +470,7 @@ static void ngx_http_proxy_init_upstream
     output->pool = r->pool;
     output->bufs.num = 1;
     output->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
-    output->output_filter = (ngx_output_chain_filter_pt) ngx_chain_writer;
+    output->output_filter = ngx_chain_writer;
 
     if (!(writer = ngx_palloc(r->pool, sizeof(ngx_chain_writer_ctx_t)))) {
         ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -700,7 +668,7 @@ static void ngx_http_proxy_connect(ngx_h
     }
 
     p->state->peer =
-     &p->upstream->peer.peers->peers[p->upstream->peer.cur_peer].addr_port_text;
+               &p->upstream->peer.peers->peer[p->upstream->peer.cur_peer].name;
 
     if (rc == NGX_CONNECT_ERROR) {
         ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
@@ -733,7 +701,7 @@ static void ngx_http_proxy_connect(ngx_h
     }
 
     if (r->request_body->buf) {
-        if (r->request_body->temp_file->file.fd != NGX_INVALID_FILE) {
+        if (r->request_body->temp_file) {
 
             if (!(output->free = ngx_alloc_chain_link(r->pool))) {
                 ngx_http_proxy_finalize_request(p,
@@ -1347,6 +1315,7 @@ static void ngx_http_proxy_send_response
     }
     ep->preread_bufs->buf = p->header_in;
     ep->preread_bufs->next = NULL;
+    p->header_in->recycled = 1;
 
     ep->preread_size = p->header_in->last - p->header_in->pos;
 
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -13,6 +13,7 @@
 #include <ngx_garbage_collector.h>
 
 typedef struct ngx_http_request_s  ngx_http_request_t;
+typedef struct ngx_http_log_ctx_s  ngx_http_log_ctx_t;
 typedef struct ngx_http_cleanup_s  ngx_http_cleanup_t;
 typedef struct ngx_http_in_addr_s  ngx_http_in_addr_t;
 
@@ -22,6 +23,7 @@ typedef struct ngx_http_in_addr_s  ngx_h
 /* STUB */
 #include <ngx_http_cache.h>
 
+#include <ngx_http_upstream.h>
 #include <ngx_http_request.h>
 #include <ngx_http_config.h>
 #include <ngx_http_busy_lock.h>
@@ -33,8 +35,8 @@ typedef struct ngx_http_in_addr_s  ngx_h
 #endif
 
 
-typedef struct {
-    u_int              connection;
+struct ngx_http_log_ctx_s {
+    ngx_uint_t         connection;
 
     /*
      * we declare "action" as "char *" because the actions are usually
@@ -45,18 +47,23 @@ typedef struct {
     char                *action;
     ngx_str_t           *client;
     ngx_http_request_t  *request;
-} ngx_http_log_ctx_t;
+};
 
 
 #define ngx_http_get_module_ctx(r, module)       r->ctx[module.ctx_index]
 #define ngx_http_get_module_err_ctx(r, module)                                \
          (r->err_ctx ? r->err_ctx[module.ctx_index] : r->ctx[module.ctx_index])
 
+/* STUB */
 #define ngx_http_create_ctx(r, cx, module, size, error)                       \
             do {                                                              \
                 ngx_test_null(cx, ngx_pcalloc(r->pool, size), error);         \
                 r->ctx[module.ctx_index] = cx;                                \
             } while (0)
+/**/
+
+#define ngx_http_set_ctx(r, c, module)                                        \
+            r->ctx[module.ctx_index] = c;
 
 #define ngx_http_delete_ctx(r, module)                                        \
             r->ctx[module.ctx_index] = NULL;
@@ -80,7 +87,8 @@ void ngx_http_close_request(ngx_http_req
 void ngx_http_close_connection(ngx_connection_t *c);
 
 
-ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r);
+ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r,
+                                 ngx_http_client_body_handler_pt post_handler);
 
 ngx_int_t ngx_http_send_header(ngx_http_request_t *r);
 ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, int error);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -205,6 +205,13 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_loc_conf_t, client_body_timeout),
       NULL },
 
+    { ngx_string("client_body_temp_path"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
+      ngx_conf_set_path_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, client_body_temp_path),
+      (void *) ngx_garbage_collector_temp_handler },
+
     { ngx_string("sendfile"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -1288,15 +1295,11 @@ static void *ngx_http_core_create_srv_co
     ngx_test_null(cscf,
                   ngx_pcalloc(cf->pool, sizeof(ngx_http_core_srv_conf_t)),
                   NGX_CONF_ERROR);
-
     /*
-
-    set by ngx_pcalloc():
-
-    conf->client_large_buffers.num = 0;
-
-    */
-
+     *
+     * set by ngx_pcalloc():
+     *     conf->client_large_buffers.num = 0;
+     */
 
     ngx_init_array(cscf->locations, cf->pool,
                    5, sizeof(void *), NGX_CONF_ERROR);
@@ -1398,22 +1401,22 @@ static void *ngx_http_core_create_loc_co
                   ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)),
                   NGX_CONF_ERROR);
 
-    /* set by ngx_pcalloc():
-
-    lcf->root.len = 0;
-    lcf->root.data = NULL;
-    lcf->types = NULL;
-    lcf->default_type.len = 0;
-    lcf->default_type.data = NULL;
-    lcf->err_log = NULL;
-    lcf->error_pages = NULL;
-
-    lcf->regex = NULL;
-    lcf->exact_match = 0;
-    lcf->auto_redirect = 0;
-    lcf->alias = 0;
-
-    */
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     lcf->root.len = 0;
+     *     lcf->root.data = NULL;
+     *     lcf->types = NULL;
+     *     lcf->default_type.len = 0;
+     *     lcf->default_type.data = NULL;
+     *     lcf->err_log = NULL;
+     *     lcf->error_pages = NULL;
+     *     lcf->client_body_path = NULL;
+     *     lcf->regex = NULL;
+     *     lcf->exact_match = 0;
+     *     lcf->auto_redirect = 0;
+     *     lcf->alias = 0;
+     */
 
     lcf->client_max_body_size = NGX_CONF_UNSET_SIZE;
     lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
@@ -1526,6 +1529,11 @@ static char *ngx_http_core_merge_loc_con
     ngx_conf_merge_msec_value(conf->lingering_timeout,
                               prev->lingering_timeout, 5000);
 
+    ngx_conf_merge_path_value(conf->client_body_temp_path,
+                              prev->client_body_temp_path,
+                              NGX_HTTP_CLIENT_TEMP_PATH, 0, 0, 0,
+                              ngx_garbage_collector_temp_handler, cf);
+
     ngx_conf_merge_value(conf->reset_timedout_connection,
                          prev->reset_timedout_connection, 0);
     ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1);
@@ -1746,7 +1754,7 @@ static char *ngx_set_error_page(ngx_conf
 
         if (overwrite == NGX_ERROR) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid value \"%V\"", value[i]);
+                               "invalid value \"%V\"", &value[i]);
             return NGX_CONF_ERROR;
         }
 
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -199,6 +199,8 @@ struct ngx_http_core_loc_conf_s {
 
     ngx_array_t  *error_pages;             /* error_page */
 
+    ngx_path_t   *client_body_temp_path;   /* client_body_temp_path */
+
     ngx_http_cache_hash_t  *open_files;
 
     ngx_log_t    *err_log;
--- a/src/http/ngx_http_log_handler.c
+++ b/src/http/ngx_http_log_handler.c
@@ -11,40 +11,64 @@
 
 
 static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf,
-                                 uintptr_t data);
+                                 ngx_http_log_op_t *op);
 static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
-                                       uintptr_t data);
+                                       ngx_http_log_op_t *op);
 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
-                                 uintptr_t data);
+                                 ngx_http_log_op_t *op);
 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
-                                 uintptr_t data);
+                                 ngx_http_log_op_t *op);
 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
-                                 uintptr_t data);
-static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf,
-                                    uintptr_t data);
+                                 ngx_http_log_op_t *op);
 static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
-                                   uintptr_t data);
+                                   ngx_http_log_op_t *op);
 static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf,
-                                   uintptr_t data);
+                                   ngx_http_log_op_t *op);
 static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf,
-                                          uintptr_t data);
+                                          ngx_http_log_op_t *op);
 static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
-                                           uintptr_t data);
+                                           ngx_http_log_op_t *op);
+
+static size_t ngx_http_log_request_getlen(ngx_http_request_t *r,
+                                          uintptr_t data);
+static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf,
+                                    ngx_http_log_op_t *op);
+
+static ngx_int_t ngx_http_log_header_in_compile(ngx_http_log_op_t *op,
+                                                ngx_str_t *value);
+static size_t ngx_http_log_header_in_getlen(ngx_http_request_t *r,
+                                            uintptr_t data);
 static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf,
-                                      uintptr_t data);
+                                      ngx_http_log_op_t *op);
+static size_t ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r,
+                                                    uintptr_t data);
+static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r,
+                                              u_char *buf,
+                                              ngx_http_log_op_t *op);
+
+static ngx_int_t ngx_http_log_header_out_compile(ngx_http_log_op_t *op,
+                                                 ngx_str_t *value);
+static size_t ngx_http_log_header_out_getlen(ngx_http_request_t *r,
+                                             uintptr_t data);
+static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf,
+                                       ngx_http_log_op_t *op);
+static size_t ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r,
+                                                     uintptr_t data);
+static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r,
+                                               u_char *buf,
+                                               ngx_http_log_op_t *op);
+
 static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r,
-                                                  u_char *buf, uintptr_t data);
+                                                  u_char *buf,
+                                                  ngx_http_log_op_t *op);
 static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r,
                                                          u_char *buf,
-                                                         uintptr_t data);
-static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r,
-                                              u_char *buf, uintptr_t data);
-static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf,
-                                       uintptr_t data);
-static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, u_char *buf,
-                                               uintptr_t data);
+                                                         ngx_http_log_op_t *op);
 
-static ngx_int_t ngx_http_log_pre_conf(ngx_conf_t *cf);
+static ngx_table_elt_t *ngx_http_log_unknown_header(ngx_list_t *headers,
+                                                    ngx_str_t *value);
+
+static ngx_int_t ngx_http_log_set_formats(ngx_conf_t *cf);
 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
 static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
@@ -78,7 +102,7 @@ static ngx_command_t  ngx_http_log_comma
 
 
 ngx_http_module_t  ngx_http_log_module_ctx = {
-    ngx_http_log_pre_conf,                 /* pre conf */
+    ngx_http_log_set_formats,              /* pre conf */
 
     ngx_http_log_create_main_conf,         /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -110,28 +134,38 @@ static ngx_str_t ngx_http_combined_fmt =
 
 
 ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = {
-    { ngx_string("addr"), INET_ADDRSTRLEN - 1, ngx_http_log_addr },
-    { ngx_string("conn"), NGX_INT32_LEN, ngx_http_log_connection },
-    { ngx_string("pipe"), 1, ngx_http_log_pipe },
+    { ngx_string("addr"), INET_ADDRSTRLEN - 1, NULL, NULL, ngx_http_log_addr },
+    { ngx_string("conn"), NGX_INT32_LEN, NULL, NULL, ngx_http_log_connection },
+    { ngx_string("pipe"), 1, NULL, NULL, ngx_http_log_pipe },
     { ngx_string("time"), sizeof("28/Sep/1970:12:00:00") - 1,
-                          ngx_http_log_time },
-    { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
-    { ngx_string("request"), 0, ngx_http_log_request },
-    { ngx_string("status"), 3, ngx_http_log_status },
-    { ngx_string("length"), NGX_OFF_T_LEN, ngx_http_log_length },
-    { ngx_string("apache_length"), NGX_OFF_T_LEN, ngx_http_log_apache_length },
+                          NULL, NULL, ngx_http_log_time },
+    { ngx_string("msec"), NGX_TIME_T_LEN + 4, NULL, NULL, ngx_http_log_msec },
+    { ngx_string("status"), 3, NULL, NULL, ngx_http_log_status },
+    { ngx_string("length"), NGX_OFF_T_LEN, NULL, NULL, ngx_http_log_length },
+    { ngx_string("apache_length"), NGX_OFF_T_LEN,
+                                   NULL, NULL, ngx_http_log_apache_length },
     { ngx_string("request_length"), NGX_SIZE_T_LEN,
-                                    ngx_http_log_request_length },
-    { ngx_string("i"), NGX_HTTP_LOG_ARG, ngx_http_log_header_in },
-    { ngx_string("o"), NGX_HTTP_LOG_ARG, ngx_http_log_header_out },
-    { ngx_null_string, 0, NULL }
+                                    NULL, NULL, ngx_http_log_request_length },
+
+    { ngx_string("request"), 0, NULL,
+                                ngx_http_log_request_getlen,
+                                ngx_http_log_request },
+
+    { ngx_string("i"), 0, ngx_http_log_header_in_compile,
+                          ngx_http_log_header_in_getlen,
+                          ngx_http_log_header_in },
+
+    { ngx_string("o"), 0, ngx_http_log_header_out_compile,
+                          ngx_http_log_header_out_getlen,
+                          ngx_http_log_header_out },
+
+    { ngx_null_string, 0, NULL, NULL, NULL }
 };
 
 
 ngx_int_t ngx_http_log_handler(ngx_http_request_t *r)
 {
     ngx_uint_t                i, l;
-    uintptr_t                 data;
     u_char                   *line, *p;
     size_t                    len;
     ngx_http_log_t           *log;
@@ -157,7 +191,7 @@ ngx_int_t ngx_http_log_handler(ngx_http_
         op = log[l].ops->elts;
         for (i = 0; i < log[l].ops->nelts; i++) {
             if (op[i].len == 0) {
-                len += (size_t) op[i].op(r, NULL, op[i].data);
+                len += op[i].getlen(r, op[i].data);
 
             } else {
                 len += op[i].len;
@@ -177,20 +211,7 @@ ngx_int_t ngx_http_log_handler(ngx_http_
         p = line;
 
         for (i = 0; i < log[l].ops->nelts; i++) {
-            if (op[i].op == NGX_HTTP_LOG_COPY_SHORT) {
-                len = op[i].len;
-                data = op[i].data;
-                while (len--) {
-                    *p++ = (char) (data & 0xff);
-                    data >>= 8;
-                }
-
-            } else if (op[i].op == NGX_HTTP_LOG_COPY_LONG) {
-                p = ngx_cpymem(p, (void *) op[i].data, op[i].len);
-
-            } else {
-                p = op[i].op(r, p, op[i].data);
-            }
+            p = op[i].run(r, p, &op[i]);
         }
 
 #if (NGX_WIN32)
@@ -206,8 +227,33 @@ ngx_int_t ngx_http_log_handler(ngx_http_
 }
 
 
+static u_char *ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
+                                       ngx_http_log_op_t *op)
+{
+    size_t     len;
+    uintptr_t  data;
+
+    len = op->len;
+    data = op->data;
+
+    while (len--) {
+        *buf++ = (u_char) (data & 0xff);
+        data >>= 8;
+    }
+
+    return buf;
+}
+
+
+static u_char *ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
+                                      ngx_http_log_op_t *op)
+{
+    return ngx_cpymem(buf, (u_char *) op->data, op->len);
+}
+
+
 static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf,
-                                 uintptr_t data)
+                                 ngx_http_log_op_t *op)
 {
     return ngx_cpymem(buf, r->connection->addr_text.data,
                       r->connection->addr_text.len);
@@ -215,14 +261,14 @@ static u_char *ngx_http_log_addr(ngx_htt
 
 
 static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
-                                     uintptr_t data)
+                                       ngx_http_log_op_t *op)
 {
     return ngx_sprintf(buf, "%ui", r->connection->number);
 }
 
 
 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
-                                 uintptr_t data)
+                                 ngx_http_log_op_t *op)
 {
     if (r->pipeline) {
         *buf = 'p';
@@ -235,7 +281,7 @@ static u_char *ngx_http_log_pipe(ngx_htt
 
 
 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
-                                 uintptr_t data)
+                                 ngx_http_log_op_t *op)
 {
     return ngx_cpymem(buf, ngx_cached_http_log_time.data,
                       ngx_cached_http_log_time.len);
@@ -243,7 +289,7 @@ static u_char *ngx_http_log_time(ngx_htt
 
 
 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
-                                 uintptr_t data)
+                                 ngx_http_log_op_t *op)
 {
     struct timeval  tv;
 
@@ -253,20 +299,22 @@ static u_char *ngx_http_log_msec(ngx_htt
 }
 
 
-static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf,
-                                    uintptr_t data)
+static size_t ngx_http_log_request_getlen(ngx_http_request_t *r,
+                                          uintptr_t data)
 {
-    if (buf == NULL) {
-        /* find the request line length */
-        return (u_char *) r->request_line.len;
-    }
+    return r->request_line.len;
+}
+
 
+static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf,
+                                    ngx_http_log_op_t *op)
+{
     return ngx_cpymem(buf, r->request_line.data, r->request_line.len);
 }
 
 
 static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
-                                   uintptr_t data)
+                                   ngx_http_log_op_t *op)
 {
     return ngx_sprintf(buf, "%ui",
                        r->err_status ? r->err_status : r->headers_out.status);
@@ -274,95 +322,320 @@ static u_char *ngx_http_log_status(ngx_h
 
 
 static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf,
-                                   uintptr_t data)
+                                   ngx_http_log_op_t *op)
 {
     return ngx_sprintf(buf, "%O", r->connection->sent);
 }
 
 
 static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf,
-                                          uintptr_t data)
+                                          ngx_http_log_op_t *op)
 {
     return ngx_sprintf(buf, "%O", r->connection->sent - r->header_size);
 }
 
 
 static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
-                                           uintptr_t data)
+                                           ngx_http_log_op_t *op)
 {
     return ngx_sprintf(buf, "%z", r->request_length);
 }
 
 
+static ngx_int_t ngx_http_log_header_in_compile(ngx_http_log_op_t *op,
+                                                ngx_str_t *value)
+{
+    ngx_uint_t  i;
+
+    op->len = 0;
+
+    for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) {
+
+        if (ngx_http_headers_in[i].name.len != value->len) {
+            continue;
+        }
+
+        if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, value->data,
+                                                              value->len) == 0)
+        {
+            op->getlen = ngx_http_log_header_in_getlen;
+            op->run = ngx_http_log_header_in;
+            op->data = ngx_http_headers_in[i].offset;
+
+            return NGX_OK;
+        }
+    }
+
+    op->getlen = ngx_http_log_unknown_header_in_getlen;
+    op->run = ngx_http_log_unknown_header_in;
+    op->data = (uintptr_t) value;
+
+    return NGX_OK;
+}
+
+
+static size_t ngx_http_log_header_in_getlen(ngx_http_request_t *r,
+                                            uintptr_t data)
+{
+    ngx_table_elt_t  *h;
+
+    h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data);
+
+    if (h) {
+        return h->value.len;
+    }
+
+    return 1;
+}
+
+
 static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf,
-                                      uintptr_t data)
+                                      ngx_http_log_op_t *op)
 {
-    ngx_uint_t          i;
-    ngx_str_t          *s;
-    ngx_table_elt_t    *h;
-    ngx_http_log_op_t  *op;
+    ngx_table_elt_t  *h;
+
+    h = *(ngx_table_elt_t **) ((char *) &r->headers_in + op->data);
+
+    if (h) {
+        return ngx_cpymem(buf, h->value.data, h->value.len);
+    }
+
+    *buf = '-';
+
+    return buf + 1;
+}
+
+
+static size_t ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r,
+                                                    uintptr_t data)
+{
+    ngx_table_elt_t  *h;
+
+    h = ngx_http_log_unknown_header(&r->headers_in.headers, (ngx_str_t *) data);
+
+    if (h) {
+        return h->value.len;
+    }
+
+    return 1;
+}
+
+
+static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r,
+                                              u_char *buf,
+                                              ngx_http_log_op_t *op)
+{
+    ngx_table_elt_t  *h;
+
+    h = ngx_http_log_unknown_header(&r->headers_in.headers,
+                                    (ngx_str_t *) op->data);
+
+    if (h) {
+        return ngx_cpymem(buf, h->value.data, h->value.len);
+    }
+
+    *buf = '-';
+
+    return buf + 1;
+}
+
+
+static ngx_int_t ngx_http_log_header_out_compile(ngx_http_log_op_t *op,
+                                                 ngx_str_t *value)
+{
+    ngx_uint_t  i;
+
+    op->len = 0;
+
+    for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) {
+
+        if (ngx_http_headers_out[i].name.len != value->len) {
+            continue;
+        }
 
-    if (r) {
-        h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data);
+        if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, value->data,
+                                                              value->len) == 0)
+        {
+            op->getlen = ngx_http_log_header_out_getlen;
+            op->run = ngx_http_log_header_out;
+            op->data = ngx_http_headers_out[i].offset;
+
+            return NGX_OK;
+        }
+    }
+
+    if (value->len == sizeof("Connection") - 1
+        && ngx_strncasecmp(value->data, "Connection", value->len) == 0)
+    {
+        op->len = sizeof("keep-alive") - 1;
+        op->getlen = NULL;
+        op->run = ngx_http_log_connection_header_out;
+        op->data = 0;
+        return NGX_OK;
+    }
 
-        if (h == NULL) {
+    if (value->len == sizeof("Transfer-Encoding") - 1
+        && ngx_strncasecmp(value->data, "Transfer-Encoding", value->len) == 0)
+    {
+        op->len = sizeof("chunked") - 1;
+        op->getlen = NULL;
+        op->run = ngx_http_log_transfer_encoding_header_out;
+        op->data = 0;
+        return NGX_OK;
+    }
+
+    op->getlen = ngx_http_log_unknown_header_out_getlen;
+    op->run = ngx_http_log_unknown_header_out;
+    op->data = (uintptr_t) value;
+
+    return NGX_OK;
+}
+
+
+static size_t ngx_http_log_header_out_getlen(ngx_http_request_t *r,
+                                             uintptr_t data)
+{
+    ngx_table_elt_t  *h;
+
+    h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data);
+
+    if (h) {
+        return h->value.len;
+    }
+
+    /*
+     * No header pointer was found.
+     * However, some headers: "Date", "Server", "Content-Length",
+     * and "Last-Modified" have a special handling in the header filter
+     * but we do not set up their pointers in the filter because
+     * they are too seldom needed to be logged.
+     */
 
-            /* no header */
+    if (data == offsetof(ngx_http_headers_out_t, date)) {
+        return ngx_cached_http_time.len;
+    }
+
+    if (data == offsetof(ngx_http_headers_out_t, server)) {
+        return (sizeof(NGINX_VER) - 1);
+    }
+
+    if (data == offsetof(ngx_http_headers_out_t, content_length)) {
+        if (r->headers_out.content_length_n == -1) {
+            return 1;
+        }
+
+        return NGX_OFF_T_LEN;
+    }
+
+    if (data == offsetof(ngx_http_headers_out_t, last_modified)) {
+        if (r->headers_out.last_modified_time == -1) {
+            return 1;
+        }
+
+        return sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
+    }
+
+    return 1;
+}
+
 
-            if (buf) {
-                *buf = '-';
-            }
+static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf,
+                                       ngx_http_log_op_t *op)
+{
+    ngx_table_elt_t  *h;
+
+    h = *(ngx_table_elt_t **) ((char *) &r->headers_out + op->data);
+
+    if (h) {
+        return ngx_cpymem(buf, h->value.data, h->value.len);
+    }
+
+    /*
+     * No header pointer was found.
+     * However, some headers: "Date", "Server", "Content-Length",
+     * and "Last-Modified" have a special handling in the header filter
+     * but we do not set up their pointers in the filter because
+     * they are too seldom needed to be logged.
+     */
+
+    if (op->data == offsetof(ngx_http_headers_out_t, date)) {
+        return ngx_cpymem(buf, ngx_cached_http_time.data,
+                          ngx_cached_http_time.len);
+    }
+
+    if (op->data == offsetof(ngx_http_headers_out_t, server)) {
+        return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1);
+    }
+
+    if (op->data == offsetof(ngx_http_headers_out_t, content_length)) {
+        if (r->headers_out.content_length_n == -1) {
+            *buf = '-';
 
             return buf + 1;
         }
 
-        if (buf == NULL) {
-            /* find the header length */
-            return (u_char *) h->value.len;
+        return ngx_sprintf(buf, "%O", r->headers_out.content_length_n);
+    }
+
+    if (op->data == offsetof(ngx_http_headers_out_t, last_modified)) {
+        if (r->headers_out.last_modified_time == -1) {
+            *buf = '-';
+
+            return buf + 1;
         }
 
+        return ngx_http_time(buf, r->headers_out.last_modified_time);
+    }
+
+    *buf = '-';
+
+    return buf + 1;
+}
+
+
+static size_t ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r,
+                                                     uintptr_t data)
+{
+    ngx_table_elt_t  *h;
+
+    h = ngx_http_log_unknown_header(&r->headers_out.headers,
+                                    (ngx_str_t *) data);
+
+    if (h) {
+        return h->value.len;
+    }
+
+    return 1;
+}
+
+
+static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r,
+                                               u_char *buf,
+                                               ngx_http_log_op_t *op)
+{
+    ngx_table_elt_t  *h;
+
+    h = ngx_http_log_unknown_header(&r->headers_out.headers,
+                                    (ngx_str_t *) op->data);
+
+    if (h) {
         return ngx_cpymem(buf, h->value.data, h->value.len);
     }
 
-    /* find an offset while a format string compilation */
-
-    op = (ngx_http_log_op_t *) buf;
-    s = (ngx_str_t *) data;
-
-    op->len = 0;
-
-    for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) {
-        if (ngx_http_headers_in[i].name.len != s->len) {
-            continue;
-        }
+    *buf = '-';
 
-        if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, s->data, s->len)
-                                                                          == 0)
-        {
-            op->op = ngx_http_log_header_in;
-            op->data = ngx_http_headers_in[i].offset;
-            return NULL;
-        }
-    }
-
-    op->op = ngx_http_log_unknown_header_in;
-    op->data = (uintptr_t) s;
-
-    return NULL;
+    return buf + 1;
 }
 
 
-static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r,
-                                              u_char *buf, uintptr_t data)
+static ngx_table_elt_t *ngx_http_log_unknown_header(ngx_list_t *headers,
+                                                    ngx_str_t *value)
 {
     ngx_uint_t        i;
-    ngx_str_t        *s;
     ngx_list_part_t  *part;
     ngx_table_elt_t  *h;
 
-    s = (ngx_str_t *) data;
-
-    part = &r->headers_in.headers.part;
+    part = &headers->part;
     h = part->elts;
 
     for (i = 0; /* void */; i++) {
@@ -377,172 +650,23 @@ static u_char *ngx_http_log_unknown_head
             i = 0;
         }
 
-        if (h[i].key.len != s->len) {
+        if (h[i].key.len != value->len) {
             continue;
         }
 
-        if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) {
-            if (buf == NULL) {
-                /* find the header length */
-                return (u_char *) h[i].value.len;
-            }
-
-            return ngx_cpymem(buf, h[i].value.data, h[i].value.len);
+        if (ngx_strncasecmp(h[i].key.data, value->data, value->len) == 0) {
+            return &h[i];
         }
     }
 
-    /* no header */
-
-    if (buf) {
-        *buf = '-';
-    }
-
-    return buf + 1;
-}
-
-
-static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf,
-                                       uintptr_t data)
-{
-    ngx_uint_t          i;
-    ngx_str_t          *s;
-    ngx_table_elt_t    *h;
-    ngx_http_log_op_t  *op;
-
-    if (r) {
-
-        /* run-time execution */
-
-        if (r->http_version < NGX_HTTP_VERSION_10) {
-            if (buf) {
-                *buf = '-';
-            }
-
-            return buf + 1;
-        }
-
-        h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data);
-
-        if (h == NULL) {
-
-            /*
-             * No header pointer was found.
-             * However, some headers: "Date", "Server", "Content-Length",
-             * and "Last-Modified" have a special handling in the header filter
-             * but we do not set up their pointers in the filter because
-             * they are too seldom needed to be logged.
-             */
-
-            if (data == offsetof(ngx_http_headers_out_t, date)) {
-                if (buf == NULL) {
-                    return (u_char *) ngx_cached_http_time.len;
-                }
-                return ngx_cpymem(buf, ngx_cached_http_time.data,
-                                  ngx_cached_http_time.len);
-            }
-
-            if (data == offsetof(ngx_http_headers_out_t, server)) {
-                if (buf == NULL) {
-                    return (u_char *) (sizeof(NGINX_VER) - 1);
-                }
-                return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1);
-            }
-
-            if (data == offsetof(ngx_http_headers_out_t, content_length)) {
-                if (r->headers_out.content_length_n == -1) {
-                    if (buf) {
-                        *buf = '-';
-                    }
-                    return buf + 1;
-                }
-
-                if (buf == NULL) {
-                    return (u_char *) NGX_OFF_T_LEN;
-                }
-                return ngx_sprintf(buf, "%O", r->headers_out.content_length_n);
-            }
-
-            if (data == offsetof(ngx_http_headers_out_t, last_modified)) {
-                if (r->headers_out.last_modified_time == -1) {
-                    if (buf) {
-                        *buf = '-';
-                    }
-                    return buf + 1;
-                }
-
-                if (buf == NULL) {
-                    return (u_char *)
-                                   sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
-                }
-                return ngx_http_time(buf, r->headers_out.last_modified_time);
-            }
-
-            if (buf) {
-                *buf = '-';
-            }
-
-            return buf + 1;
-        }
-
-        if (buf == NULL) {
-            /* find the header length */
-            return (u_char *) h->value.len;
-        }
-
-        return ngx_cpymem(buf, h->value.data, h->value.len);
-    }
-
-    /* find an offset while a format string compilation */
-
-    op = (ngx_http_log_op_t *) buf;
-    s = (ngx_str_t *) data;
-
-    op->len = 0;
-
-    for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) {
-        if (ngx_http_headers_out[i].name.len != s->len) {
-            continue;
-        }
-
-        if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, s->data, s->len)
-                                                                          == 0)
-        {
-            op->op = ngx_http_log_header_out;
-            op->data = ngx_http_headers_out[i].offset;
-            return NULL;
-        }
-    }
-
-    if (s->len == sizeof("Connection") - 1
-        && ngx_strncasecmp(s->data, "Connection", s->len) == 0)
-    {
-        op->op = ngx_http_log_connection_header_out;
-        op->data = (uintptr_t) NULL;
-        return NULL;
-    }
-
-    if (s->len == sizeof("Transfer-Encoding") - 1
-        && ngx_strncasecmp(s->data, "Transfer-Encoding", s->len) == 0) {
-        op->op = ngx_http_log_transfer_encoding_header_out;
-        op->data = (uintptr_t) NULL;
-        return NULL;
-    }
-
-    op->op = ngx_http_log_unknown_header_out;
-    op->data = (uintptr_t) s;
-
     return NULL;
 }
 
 
 static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r,
-                                                  u_char *buf, uintptr_t data)
+                                                  u_char *buf,
+                                                  ngx_http_log_op_t *op)
 {
-    if (buf == NULL) {
-        return (u_char *) ((r->keepalive) ? sizeof("keep-alive") - 1:
-                                            sizeof("close") - 1);
-    }
-
     if (r->keepalive) {
         return ngx_cpymem(buf, "keep-alive", sizeof("keep-alive") - 1);
 
@@ -554,12 +678,8 @@ static u_char *ngx_http_log_connection_h
 
 static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r,
                                                          u_char *buf,
-                                                         uintptr_t data)
+                                                         ngx_http_log_op_t *op)
 {
-    if (buf == NULL) {
-        return (u_char *) ((r->chunked) ? sizeof("chunked") - 1 : 1);
-    }
-
     if (r->chunked) {
         return ngx_cpymem(buf, "chunked", sizeof("chunked") - 1);
     }
@@ -570,62 +690,12 @@ static u_char *ngx_http_log_transfer_enc
 }
 
 
-static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r,
-                                               u_char *buf,
-                                               uintptr_t data)
-{
-    ngx_uint_t        i;
-    ngx_str_t        *s;
-    ngx_list_part_t  *part;
-    ngx_table_elt_t  *h;
-
-    s = (ngx_str_t *) data;
-
-    part = &r->headers_out.headers.part;
-    h = part->elts;
-
-    for (i = 0; /* void */; i++) {
-
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
-            }
-
-            part = part->next;
-            h = part->elts;
-            i = 0;
-        }
-
-        if (h[i].key.len != s->len) {
-            continue;
-        }
-
-        if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) {
-            if (buf == NULL) {
-                /* find the header length */
-                return (u_char *) h[i].value.len;
-            }
-
-            return ngx_cpymem(buf, h[i].value.data, h[i].value.len);
-        }
-    }
-
-    /* no header */
-
-    if (buf) {
-        *buf = '-';
-    }
-
-    return buf + 1;
-}
-
-
-static ngx_int_t ngx_http_log_pre_conf(ngx_conf_t *cf)
+static ngx_int_t ngx_http_log_set_formats(ngx_conf_t *cf)
 {
     ngx_http_log_op_name_t  *op;
 
     for (op = ngx_http_log_fmt_ops; op->name.len; op++) { /* void */ }
-    op->op = NULL;
+    op->run = NULL;
 
     return NGX_OK;
 }
@@ -889,15 +959,15 @@ static char *ngx_http_log_set_format(ngx
                     break;
                 }
 
-                for (name = ngx_http_log_fmt_ops; name->op; name++) {
+                for (name = ngx_http_log_fmt_ops; name->run; name++) {
                     if (name->name.len == 0) {
-                        name = (ngx_http_log_op_name_t *) name->op;
+                        name = (ngx_http_log_op_name_t *) name->run;
                     }
 
                     if (name->name.len == fname_len
                         && ngx_strncmp(name->name.data, fname, fname_len) == 0)
                     {
-                        if (name->len != NGX_HTTP_LOG_ARG) {
+                        if (name->compile == NULL) {
                             if (arg.len) {
                                 fname[fname_len] = '\0';
                                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -907,7 +977,8 @@ static char *ngx_http_log_set_format(ngx
                             }
 
                             op->len = name->len;
-                            op->op = name->op;
+                            op->getlen = name->getlen;
+                            op->run = name->run;
                             op->data = 0;
 
                             break;
@@ -926,7 +997,9 @@ static char *ngx_http_log_set_format(ngx
                         }
 
                         *a = arg;
-                        name->op(NULL, (u_char *) op, (uintptr_t) a);
+                        if (name->compile(op, a) == NGX_ERROR) {
+                            return NGX_CONF_ERROR;
+                        }
 
                         break;
                     }
@@ -949,9 +1022,10 @@ static char *ngx_http_log_set_format(ngx
                 if (len) {
 
                     op->len = len;
+                    op->getlen = NULL;
 
                     if (len <= sizeof(uintptr_t)) {
-                        op->op = NGX_HTTP_LOG_COPY_SHORT;
+                        op->run = ngx_http_log_copy_short;
                         op->data = 0;
 
                         while (len--) {
@@ -960,7 +1034,7 @@ static char *ngx_http_log_set_format(ngx
                         }
 
                     } else {
-                        op->op = NGX_HTTP_LOG_COPY_LONG;
+                        op->run = ngx_http_log_copy_long;
 
                         if (!(p = ngx_palloc(cf->pool, len))) {
                             return NGX_CONF_ERROR;
--- a/src/http/ngx_http_log_handler.h
+++ b/src/http/ngx_http_log_handler.h
@@ -13,49 +13,54 @@
 #include <ngx_http.h>
 
 
-typedef u_char *(*ngx_http_log_op_pt) (ngx_http_request_t *r, u_char *buf,
-                                       uintptr_t data);
+typedef struct ngx_http_log_op_s  ngx_http_log_op_t;
+
+typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
+                                           ngx_http_log_op_t *op);
+
+typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
+                                             uintptr_t data);
 
-#define NGX_HTTP_LOG_COPY_SHORT  (ngx_http_log_op_pt) 0
-#define NGX_HTTP_LOG_COPY_LONG   (ngx_http_log_op_pt) -1
+typedef ngx_int_t (*ngx_http_log_op_compile_pt) (ngx_http_log_op_t *op,
+                                                 ngx_str_t *value);
 
-#define NGX_HTTP_LOG_ARG         (u_int) -1
+struct ngx_http_log_op_s {
+    size_t                      len;
+    ngx_http_log_op_getlen_pt   getlen;
+    ngx_http_log_op_run_pt      run;
+    uintptr_t                   data;
+};
 
 
 typedef struct {
-    size_t               len;
-    ngx_http_log_op_pt   op;
-    uintptr_t            data;
-} ngx_http_log_op_t;
-
-
-typedef struct {
-    ngx_str_t            name;
-    ngx_array_t         *ops;        /* array of ngx_http_log_op_t */
+    ngx_str_t                   name;
+    ngx_array_t                *ops;        /* array of ngx_http_log_op_t */
 } ngx_http_log_fmt_t;
 
 
 typedef struct {
-    ngx_str_t            name;
-    size_t               len;
-    ngx_http_log_op_pt   op;
+    ngx_str_t                   name;
+    size_t                      len;
+    ngx_http_log_op_compile_pt  compile;
+    ngx_http_log_op_getlen_pt   getlen;
+    ngx_http_log_op_run_pt      run;
 } ngx_http_log_op_name_t;
 
 
 typedef struct {
-    ngx_array_t          formats;    /* array of ngx_http_log_fmt_t */
+    ngx_array_t                 formats;    /* array of ngx_http_log_fmt_t */
 } ngx_http_log_main_conf_t;
 
 
 typedef struct {
-    ngx_open_file_t     *file;
-    ngx_array_t         *ops;        /* array of ngx_http_log_op_t */
+    ngx_open_file_t            *file;
+    ngx_array_t                *ops;        /* array of ngx_http_log_op_t */
 } ngx_http_log_t;
 
 
 typedef struct {
-    ngx_array_t         *logs;       /* array of ngx_http_log_t */
-    ngx_uint_t           off;        /* unsigned  off:1 */
+    ngx_array_t                *logs;       /* array of ngx_http_log_t */
+    ngx_uint_t                  off;        /* unsigned  off:1 */
 } ngx_http_log_loc_conf_t;
 
 
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -34,15 +34,13 @@ ngx_int_t ngx_http_parse_request_line(ng
         sw_major_digit,
         sw_first_minor_digit,
         sw_minor_digit,
-        sw_almost_done,
-        sw_done
+        sw_almost_done
     } state;
 
     state = r->state;
-    p = b->pos;
 
-    while (p < b->last && state < sw_done) {
-        ch = *p++;
+    for (p = b->pos; p < b->last; p++) {
+        ch = *p;
 
         /* gcc 2.95.2 and msvc 6.0 compile this switch as an jump table */
 
@@ -50,7 +48,7 @@ ngx_int_t ngx_http_parse_request_line(ng
 
         /* HTTP methods: GET, HEAD, POST */
         case sw_start:
-            r->request_start = p - 1;
+            r->request_start = p;
 
             if (ch == CR || ch == LF) {
                 break;
@@ -65,19 +63,19 @@ ngx_int_t ngx_http_parse_request_line(ng
 
         case sw_method:
             if (ch == ' ') {
-                r->method_end = p - 1;
+                r->method_end = p;
                 m = r->request_start;
 
-                if (r->method_end - m == 3) {
+                if (p - m == 3) {
 
                     if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') {
                         r->method = NGX_HTTP_GET;
                     }
 
-                } else if (r->method_end - m == 4) {
+                } else if (p - m == 4) {
 
                     if (m[0] == 'P' && m[1] == 'O'
-                        && m[2] == 'T' && m[3] == 'T')
+                        && m[2] == 'S' && m[3] == 'T')
                     {
                         r->method = NGX_HTTP_POST;
 
@@ -113,14 +111,14 @@ ngx_int_t ngx_http_parse_request_line(ng
         case sw_spaces_before_uri:
             switch (ch) {
             case '/':
-                r->uri_start = p - 1;
+                r->uri_start = p;
                 state = sw_after_slash_in_uri;
                 break;
             case ' ':
                 break;
             default:
                 if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
-                    r->schema_start = p - 1;
+                    r->schema_start = p;
                     state = sw_schema;
                     break;
                 }
@@ -131,7 +129,7 @@ ngx_int_t ngx_http_parse_request_line(ng
         case sw_schema:
             switch (ch) {
             case ':':
-                r->schema_end = p - 1;
+                r->schema_end = p;
                 state = sw_schema_slash;
                 break;
             default:
@@ -155,7 +153,7 @@ ngx_int_t ngx_http_parse_request_line(ng
         case sw_schema_slash_slash:
             switch (ch) {
             case '/':
-                r->host_start = p - 1;
+                r->host_start = p;
                 state = sw_host;
                 break;
             default:
@@ -166,12 +164,12 @@ ngx_int_t ngx_http_parse_request_line(ng
         case sw_host:
             switch (ch) {
             case ':':
-                r->host_end = p - 1;
+                r->host_end = p;
                 state = sw_port;
                 break;
             case '/':
-                r->host_end = p - 1;
-                r->uri_start = p - 1;
+                r->host_end = p;
+                r->uri_start = p;
                 state = sw_after_slash_in_uri;
                 break;
             default:
@@ -187,8 +185,8 @@ ngx_int_t ngx_http_parse_request_line(ng
         case sw_port:
             switch (ch) {
             case '/':
-                r->port_end = p - 1;
-                r->uri_start = p - 1;
+                r->port_end = p;
+                r->uri_start = p;
                 state = sw_after_slash_in_uri;
                 break;
             default:
@@ -203,17 +201,16 @@ ngx_int_t ngx_http_parse_request_line(ng
         case sw_after_slash_in_uri:
             switch (ch) {
             case CR:
-                r->uri_end = p - 1;
+                r->uri_end = p;
                 r->http_minor = 9;
                 state = sw_almost_done;
                 break;
             case LF:
-                r->uri_end = p - 1;
+                r->uri_end = p;
                 r->http_minor = 9;
-                state = sw_done;
-                break;
+                goto done;
             case ' ':
-                r->uri_end = p - 1;
+                r->uri_end = p;
                 state = sw_http_09;
                 break;
             case '.':
@@ -233,7 +230,7 @@ ngx_int_t ngx_http_parse_request_line(ng
                 r->complex_uri = 1;
                 break;
             case '?':
-                r->args_start = p;
+                r->args_start = p + 1;
                 state = sw_uri;
                 break;
             default:
@@ -246,21 +243,20 @@ ngx_int_t ngx_http_parse_request_line(ng
         case sw_check_uri:
             switch (ch) {
             case CR:
-                r->uri_end = p - 1;
+                r->uri_end = p;
                 r->http_minor = 9;
                 state = sw_almost_done;
                 break;
             case LF:
-                r->uri_end = p - 1;
+                r->uri_end = p;
                 r->http_minor = 9;
-                state = sw_done;
-                break;
+                goto done;
             case ' ':
-                r->uri_end = p - 1;
+                r->uri_end = p;
                 state = sw_http_09;
                 break;
             case '.':
-                r->uri_ext = p;
+                r->uri_ext = p + 1;
                 break;
 #if (NGX_WIN32)
             case '\\':
@@ -277,7 +273,7 @@ ngx_int_t ngx_http_parse_request_line(ng
                 state = sw_uri;
                 break;
             case '?':
-                r->args_start = p;
+                r->args_start = p + 1;
                 state = sw_uri;
                 break;
             }
@@ -287,17 +283,16 @@ ngx_int_t ngx_http_parse_request_line(ng
         case sw_uri:
             switch (ch) {
             case CR:
-                r->uri_end = p - 1;
+                r->uri_end = p;
                 r->http_minor = 9;
                 state = sw_almost_done;
                 break;
             case LF:
-                r->uri_end = p - 1;
+                r->uri_end = p;
                 r->http_minor = 9;
-                state = sw_done;
-                break;
+                goto done;
             case ' ':
-                r->uri_end = p - 1;
+                r->uri_end = p;
                 state = sw_http_09;
                 break;
             }
@@ -314,9 +309,9 @@ ngx_int_t ngx_http_parse_request_line(ng
                 break;
             case LF:
                 r->http_minor = 9;
-                state = sw_done;
-                break;
+                goto done;
             case 'H':
+                r->http_protocol.data = p;
                 state = sw_http_H;
                 break;
             default:
@@ -406,8 +401,7 @@ ngx_int_t ngx_http_parse_request_line(ng
             }
 
             if (ch == LF) {
-                state = sw_done;
-                break;
+                goto done;
             }
 
             if (ch < '0' || ch > '9') {
@@ -419,42 +413,38 @@ ngx_int_t ngx_http_parse_request_line(ng
 
         /* end of request line */
         case sw_almost_done:
-            r->request_end = p - 2;
+            r->request_end = p - 1;
             switch (ch) {
             case LF:
-                state = sw_done;
-                break;
+                goto done;
             default:
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
             break;
-
-        /* suppress warning */
-        case sw_done:
-            break;
         }
     }
 
     b->pos = p;
+    r->state = state;
 
-    if (state == sw_done) {
-        if (r->request_end == NULL) {
-            r->request_end = p - 1;
-        }
+    return NGX_AGAIN;
 
-        r->http_version = r->http_major * 1000 + r->http_minor;
-        r->state = sw_start;
+done:
+
+    b->pos = p + 1;
 
-        if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
-            return NGX_HTTP_PARSE_INVALID_09_METHOD;
-        }
+    if (r->request_end == NULL) {
+        r->request_end = p;
+    }
 
-        return NGX_OK;
+    r->http_version = r->http_major * 1000 + r->http_minor;
+    r->state = sw_start;
 
-    } else {
-        r->state = state;
-        return NGX_AGAIN;
+    if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
+        return NGX_HTTP_PARSE_INVALID_09_METHOD;
     }
+
+    return NGX_OK;
 }
 
 
@@ -469,16 +459,13 @@ ngx_int_t ngx_http_parse_header_line(ngx
         sw_space_after_value,
         sw_almost_done,
         sw_header_almost_done,
-        sw_ignore_line,
-        sw_done,
-        sw_header_done
+        sw_ignore_line
     } state;
 
     state = r->state;
-    p = b->pos;
 
-    while (p < b->last && state < sw_done) {
-        ch = *p++;
+    for (p = b->pos; p < b->last; p++) {
+        ch = *p;
 
         switch (state) {
 
@@ -486,16 +473,15 @@ ngx_int_t ngx_http_parse_header_line(ngx
         case sw_start:
             switch (ch) {
             case CR:
-                r->header_end = p - 1;
+                r->header_end = p;
                 state = sw_header_almost_done;
                 break;
             case LF:
-                r->header_end = p - 1;
-                state = sw_header_done;
-                break;
+                r->header_end = p;
+                goto header_done;
             default:
                 state = sw_name;
-                r->header_name_start = p - 1;
+                r->header_name_start = p;
 
                 c = (u_char) (ch | 0x20);
                 if (c >= 'a' && c <= 'z') {
@@ -523,7 +509,7 @@ ngx_int_t ngx_http_parse_header_line(ngx
             }
 
             if (ch == ':') {
-                r->header_name_end = p - 1;
+                r->header_name_end = p;
                 state = sw_space_before_value;
                 break;
             }
@@ -539,7 +525,7 @@ ngx_int_t ngx_http_parse_header_line(ngx
             /* IIS may send the duplicate "HTTP/1.1 ..." lines */
             if (ch == '/'
                 && r->proxy
-                && p - r->header_start == 5
+                && p - r->header_start == 4
                 && ngx_strncmp(r->header_start, "HTTP", 4) == 0)
             {
                 state = sw_ignore_line;
@@ -554,15 +540,14 @@ ngx_int_t ngx_http_parse_header_line(ngx
             case ' ':
                 break;
             case CR:
-                r->header_start = r->header_end = p - 1;
+                r->header_start = r->header_end = p;
                 state = sw_almost_done;
                 break;
             case LF:
-                r->header_start = r->header_end = p - 1;
-                state = sw_done;
-                break;
+                r->header_start = r->header_end = p;
+                goto done;
             default:
-                r->header_start = p - 1;
+                r->header_start = p;
                 state = sw_value;
                 break;
             }
@@ -572,17 +557,16 @@ ngx_int_t ngx_http_parse_header_line(ngx
         case sw_value:
             switch (ch) {
             case ' ':
-                r->header_end = p - 1;
+                r->header_end = p;
                 state = sw_space_after_value;
                 break;
             case CR:
-                r->header_end = p - 1;
+                r->header_end = p;
                 state = sw_almost_done;
                 break;
             case LF:
-                r->header_end = p - 1;
-                state = sw_done;
-                break;
+                r->header_end = p;
+                goto done;
             }
             break;
 
@@ -595,8 +579,7 @@ ngx_int_t ngx_http_parse_header_line(ngx
                 state = sw_almost_done;
                 break;
             case LF:
-                state = sw_done;
-                break;
+                goto done;
             default:
                 state = sw_value;
                 break;
@@ -618,8 +601,7 @@ ngx_int_t ngx_http_parse_header_line(ngx
         case sw_almost_done:
             switch (ch) {
             case LF:
-                state = sw_done;
-                break;
+                goto done;
             default:
                 return NGX_HTTP_PARSE_INVALID_HEADER;
             }
@@ -629,34 +611,32 @@ ngx_int_t ngx_http_parse_header_line(ngx
         case sw_header_almost_done:
             switch (ch) {
             case LF:
-                state = sw_header_done;
-                break;
+                goto header_done;
             default:
                 return NGX_HTTP_PARSE_INVALID_HEADER;
             }
             break;
-
-        /* suppress warning */
-        case sw_done:
-        case sw_header_done:
-            break;
         }
     }
 
     b->pos = p;
+    r->state = state;
 
-    if (state == sw_done) {
-        r->state = sw_start;
-        return NGX_OK;
+    return NGX_AGAIN;
+
+done:
+
+    b->pos = p + 1;
+    r->state = sw_start;
 
-    } else if (state == sw_header_done) {
-        r->state = sw_start;
-        return NGX_HTTP_PARSE_HEADER_DONE;
+    return NGX_OK;
+
+header_done:
 
-    } else {
-        r->state = state;
-        return NGX_AGAIN;
-    }
+    b->pos = p + 1;
+    r->state = sw_start;
+
+    return NGX_HTTP_PARSE_HEADER_DONE;
 }
 
 
@@ -677,8 +657,10 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
         sw_quoted_second
     } state, quoted_state;
 
+#if (NGX_SUPPRESS_WARN)
     decoded = '\0';
     quoted_state = sw_usual;
+#endif
 
     state = sw_usual;
     p = r->uri_start;
@@ -688,10 +670,10 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
 
     ch = *p++;
 
-    while (p <= r->uri_end && r->args_start == NULL) {
+    while (p <= r->uri_end) {
 
         /*
-         * we use "ch = *p++" inside the cycle but this operation is safe
+         * we use "ch = *p++" inside the cycle, but this operation is safe,
          * because after the URI there is always at least one charcter:
          * the line feed
          */
@@ -731,7 +713,7 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
                 break;
             case '?':
                 r->args_start = p;
-                break;
+                goto done;
             case ':':
                 state = sw_colon;
                 *u++ = ch;
@@ -766,6 +748,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
                 quoted_state = state;
                 state = sw_quoted;
                 break;
+            case '?':
+                r->args_start = p;
+                goto done;
             default:
                 state = sw_usual;
                 *u++ = ch;
@@ -794,6 +779,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
                 quoted_state = state;
                 state = sw_quoted;
                 break;
+            case '?':
+                r->args_start = p;
+                goto done;
             default:
                 state = sw_usual;
                 *u++ = ch;
@@ -818,6 +806,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
                 quoted_state = state;
                 state = sw_quoted;
                 break;
+            case '?':
+                r->args_start = p;
+                goto done;
             default:
                 state = sw_usual;
                 *u++ = ch;
@@ -844,6 +835,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
                 quoted_state = state;
                 state = sw_quoted;
                 break;
+            case '?':
+                r->args_start = p;
+                goto done;
             default:
                 state = sw_usual;
                 *u++ = ch;
@@ -872,6 +866,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
                 quoted_state = state;
                 state = sw_quoted;
                 break;
+            case '?':
+                r->args_start = p;
+                goto done;
 #if (NGX_WIN32)
             case '.':
                 state = sw_dot_dot_dot;
@@ -953,11 +950,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
             c = (u_char) (ch | 0x20);
             if (c >= 'a' && c <= 'f') {
                 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
-                if (ch == '%') {
-                    state = sw_usual;
+                if (ch == '?') {
                     *u++ = ch;
                     ch = *p++;
-                    break;
                 }
                 state = quoted_state;
                 break;
@@ -967,6 +962,8 @@ ngx_int_t ngx_http_parse_complex_uri(ngx
         }
     }
 
+done:
+
     r->uri.len = u - r->uri.data;
     r->uri.data[r->uri.len] = '\0';
 
--- a/src/http/ngx_http_parse_time.c
+++ b/src/http/ngx_http_parse_time.c
@@ -216,10 +216,6 @@ time_t ngx_http_parse_time(u_char *value
                + (*(p + 2) - '0') * 10 + *(p + 3) - '0';
     }
 
-#if 0
-    printf("%d.%d.%d %d:%d:%d\n", day, month + 1, year, hour, min, sec);
-#endif
-
     if (hour > 23 || min > 59 || sec > 59) {
          return NGX_ERROR;
     }
@@ -239,7 +235,7 @@ time_t ngx_http_parse_time(u_char *value
 
     /*
      * shift new year to March 1 and start months from 1 (not 0),
-     * it's needed for Gauss's formula
+     * it is needed for Gauss's formula
      */
 
     if (--month <= 0) {
@@ -247,41 +243,16 @@ time_t ngx_http_parse_time(u_char *value
        year -= 1;
     }
 
-           /* Gauss's formula for Grigorian days from 1 March 1 BC */
+    /* Gauss's formula for Grigorian days from 1 March 1 BC */
 
     return (365 * year + year / 4 - year / 100 + year / 400
             + 367 * month / 12 - 31
             + day
 
-           /*
-            * 719527 days were between March 1, 1 BC and March 1, 1970,
-            * 31 and 28 days in January and February 1970
-            */
+            /*
+             * 719527 days were between March 1, 1 BC and March 1, 1970,
+             * 31 and 28 days in January and February 1970
+             */
 
             - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;
 }
-
-#if 0
-char zero[] = "Sun, 01 Jan 1970 08:49:30";
-char one[]  = "Sunday, 11-Dec-02 08:49:30";
-char two[]  = "Sun Mar 1 08:49:37 2000";
-char thr[]  = "Sun Dec 11 08:49:37 2002";
-
-main()
-{
-    int rc;
-
-    rc = ngx_http_parse_time(zero, sizeof(zero) - 1);
-    printf("rc: %d\n", rc);
-
-    rc = ngx_http_parse_time(one, sizeof(one) - 1);
-    printf("rc: %d\n", rc);
-
-    rc = ngx_http_parse_time(two, sizeof(two) - 1);
-    printf("rc: %d\n", rc);
-
-    rc = ngx_http_parse_time(thr, sizeof(thr) - 1);
-    printf("rc: %d\n", rc);
-}
-
-#endif
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -63,6 +63,8 @@ ngx_http_header_t  ngx_http_headers_in[]
     { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer) },
     { ngx_string("Content-Length"),
                             offsetof(ngx_http_headers_in_t, content_length) },
+    { ngx_string("Content-Type"),
+                              offsetof(ngx_http_headers_in_t, content_type) },
 
     { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range) },
 #if 0
@@ -86,7 +88,7 @@ ngx_http_header_t  ngx_http_headers_in[]
     { ngx_string("X-Real-IP"), offsetof(ngx_http_headers_in_t, x_real_ip) },
     { ngx_string("X-URL"), offsetof(ngx_http_headers_in_t, x_url) },
 #endif
-    
+
     { ngx_null_string, 0 }
 };
 
@@ -175,7 +177,7 @@ static void ngx_http_init_request(ngx_ev
 {
     ngx_uint_t                 i;
     socklen_t                  len;
-    struct sockaddr_in         addr_in;
+    struct sockaddr_in         sin;
     ngx_connection_t          *c;
     ngx_http_request_t        *r;
     ngx_http_in_port_t        *in_port;
@@ -283,21 +285,19 @@ static void ngx_http_init_request(ngx_ev
             r->in_addr =
                    ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr;
 
-        } else {
+        } else
 #endif
+        {
             len = sizeof(struct sockaddr_in);
-            if (getsockname(c->fd, (struct sockaddr *) &addr_in, &len) == -1) {
+            if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) {
                 ngx_connection_error(c, ngx_socket_errno,
                                      "getsockname() failed");
                 ngx_http_close_connection(c);
                 return;
             }
 
-            r->in_addr = addr_in.sin_addr.s_addr;
-
-#if (NGX_WIN32)
+            r->in_addr = sin.sin_addr.s_addr;
         }
-#endif
 
         /* the last in_port->addrs address is "*" */
 
@@ -573,6 +573,11 @@ static void ngx_http_process_request_lin
             }
 
 
+            if (r->http_protocol.data) {
+                r->http_protocol.len = r->request_end - r->http_protocol.data;
+            }
+
+
             if (r->uri_ext) {
                 if (r->args_start) {
                     r->exten.len = r->args_start - 1 - r->uri_ext;
@@ -2173,6 +2178,8 @@ void ngx_ssl_close_handler(ngx_event_t *
 
 void ngx_http_close_connection(ngx_connection_t *c)
 {
+    ngx_pool_t  *pool;
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "close http connection: %d", c->fd);
 
@@ -2192,7 +2199,11 @@ void ngx_http_close_connection(ngx_conne
     (*ngx_stat_active)--;
 #endif
 
+    pool = c->pool;
+
     ngx_close_connection(c);
+
+    ngx_destroy_pool(c->pool);
 }
 
 
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -133,6 +133,7 @@ typedef struct {
     ngx_table_elt_t  *user_agent;
     ngx_table_elt_t  *referer;
     ngx_table_elt_t  *content_length;
+    ngx_table_elt_t  *content_type;
 
     ngx_table_elt_t  *range;
 
@@ -201,13 +202,14 @@ typedef struct {
 } ngx_http_headers_out_t;
 
 
+typedef void (*ngx_http_client_body_handler_pt)(ngx_http_request_t *r);
+
 typedef struct {
-    ngx_temp_file_t   *temp_file;
-    ngx_chain_t       *bufs;
-    ngx_buf_t         *buf;
-    size_t             rest;
-    void             (*handler) (void *data); 
-    void              *data;
+    ngx_temp_file_t                  *temp_file;
+    ngx_chain_t                      *bufs;
+    ngx_buf_t                        *buf;
+    size_t                            rest;
+    ngx_http_client_body_handler_pt   post_handler;
 } ngx_http_request_body_t;
 
 
@@ -256,6 +258,8 @@ struct ngx_http_request_s {
 
     ngx_http_cache_t         *cache;
 
+    ngx_http_upstream_t      *upstream;
+
     ngx_file_t                file;
 
     ngx_pool_t               *pool;
@@ -280,6 +284,7 @@ struct ngx_http_request_s {
     ngx_str_t            unparsed_uri;
 
     ngx_str_t            method_name;
+    ngx_str_t            http_protocol;
 
     ngx_http_request_t  *main;
 
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -11,31 +11,67 @@
 
 
 static void ngx_http_read_client_request_body_handler(ngx_event_t *rev);
-static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
+static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r,
+                                                      ngx_connection_t *c);
 
+/*
+ * on completion ngx_http_read_client_request_body() adds to
+ * r->request_body->bufs one or two bufs:
+ *    *) one memory buf that was preread in r->header_in;
+ *    *) one memory or file buf that contains the rest of the body
+ */
 
-ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r)
+ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r,
+                                  ngx_http_client_body_handler_pt post_handler)
+
 {
     ssize_t                    size;
     ngx_buf_t                 *b;
     ngx_chain_t               *cl;
+    ngx_http_request_body_t   *rb;
     ngx_http_core_loc_conf_t  *clcf;
 
+    if (!(rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    r->request_body = rb;
+
+    if (r->headers_in.content_length_n <= 0) {
+        post_handler(r);
+        return NGX_OK;
+    }
+
+    rb->post_handler = post_handler;
+
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     rb->bufs = NULL;
+     *     rb->buf = NULL;
+     *     rb->rest = 0;
+     */
+
     size = r->header_in->last - r->header_in->pos;
 
     if (size) {
 
         /* there is the pre-read part of the request body */
 
-        ngx_test_null(b, ngx_calloc_buf(r->pool),
-                      NGX_HTTP_INTERNAL_SERVER_ERROR);
+        if (!(b = ngx_calloc_buf(r->pool))) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
 
         b->temporary = 1;
         b->start = b->pos = r->header_in->pos;
         b->end = b->last = r->header_in->last;
 
-        ngx_alloc_link_and_set_buf(r->request_body->bufs, b, r->pool,
-                                    NGX_HTTP_INTERNAL_SERVER_ERROR);
+        if (!(rb->bufs = ngx_alloc_chain_link(r->pool))) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        rb->bufs->buf = b;
+        rb->bufs->next = NULL;
 
         if (size >= r->headers_in.content_length_n) {
 
@@ -44,7 +80,7 @@ ngx_int_t ngx_http_read_client_request_b
             r->header_in->pos += r->headers_in.content_length_n;
             r->request_length += r->headers_in.content_length_n;
 
-            r->request_body->handler(r->request_body->data);
+            post_handler(r);
 
             return NGX_OK;
         }
@@ -56,35 +92,39 @@ ngx_int_t ngx_http_read_client_request_b
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    r->request_body->rest = r->headers_in.content_length_n - size;
+    rb->rest = r->headers_in.content_length_n - size;
 
-    if (r->request_body->rest
-                             < clcf->client_body_buffer_size
+    if (rb->rest < clcf->client_body_buffer_size
                                         + (clcf->client_body_buffer_size >> 2))
     {
-        size = r->request_body->rest;
+        size = rb->rest;
 
     } else {
         size = clcf->client_body_buffer_size;
     }
 
-    ngx_test_null(r->request_body->buf, ngx_create_temp_buf(r->pool, size),
-                  NGX_HTTP_INTERNAL_SERVER_ERROR);
+    if (!(rb->buf = ngx_create_temp_buf(r->pool, size))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
-    ngx_alloc_link_and_set_buf(cl, r->request_body->buf, r->pool,
-                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+    if (!(cl = ngx_alloc_chain_link(r->pool))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
-    if (r->request_body->bufs) {
-        r->request_body->bufs->next = cl;
+    cl->buf = rb->buf;
+    cl->next = NULL;
+
+    if (rb->bufs) {
+        rb->bufs->next = cl;
 
     } else {
-        r->request_body->bufs = cl;
+        rb->bufs = cl;
     }
 
     r->connection->read->event_handler =
                                      ngx_http_read_client_request_body_handler;
 
-    return ngx_http_do_read_client_request_body(r);
+    return ngx_http_do_read_client_request_body(r, r->connection);
 }
 
 
@@ -102,7 +142,7 @@ static void ngx_http_read_client_request
         return;
     }
 
-    rc = ngx_http_do_read_client_request_body(r);
+    rc = ngx_http_do_read_client_request_body(r, c);
 
     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
         ngx_http_finalize_request(r, rc);
@@ -110,24 +150,45 @@ static void ngx_http_read_client_request
 }
 
 
-static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r)
+static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r,
+                                                      ngx_connection_t *c)
 {
     size_t                     size;
     ssize_t                    n;
     ngx_buf_t                 *b;
-    ngx_connection_t          *c;
+    ngx_temp_file_t           *tf;
+    ngx_http_request_body_t   *rb;
     ngx_http_core_loc_conf_t  *clcf;
 
-    c = r->connection;
+    rb = r->request_body;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http read client request body");
 
     for ( ;; ) {
-        if (r->request_body->buf->last == r->request_body->buf->end) {
-            n = ngx_write_chain_to_temp_file(r->request_body->temp_file,
-                     r->request_body->bufs->next ? r->request_body->bufs->next:
-                                                   r->request_body->bufs);
+        if (rb->buf->last == rb->buf->end) {
+
+            if (rb->temp_file == NULL) {
+                if (!(tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
+                    return NGX_ERROR;
+                }
+
+                clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+                tf->file.fd = NGX_INVALID_FILE;
+                tf->file.log = r->connection->log;
+                tf->path = clcf->client_body_temp_path;
+                tf->pool = r->pool;
+                tf->warn = "a client request body is buffered "
+                           "to a temporary file";
+
+                rb->temp_file = tf;
+
+            }
+
+            n = ngx_write_chain_to_temp_file(rb->temp_file,
+                                             rb->bufs->next ? rb->bufs->next:
+                                                              rb->bufs);
 
             /* TODO: n == 0 or not complete and level event */
 
@@ -135,19 +196,19 @@ static ngx_int_t ngx_http_do_read_client
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
             }
 
-            r->request_body->temp_file->offset += n;
+            rb->temp_file->offset += n;
 
-            r->request_body->buf->pos = r->request_body->buf->start;
-            r->request_body->buf->last = r->request_body->buf->start;
+            rb->buf->pos = rb->buf->start;
+            rb->buf->last = rb->buf->start;
         }
 
-        size = r->request_body->buf->end - r->request_body->buf->last;
+        size = rb->buf->end - rb->buf->last;
 
-        if (size > r->request_body->rest) {
-            size = r->request_body->rest;
+        if (size > rb->rest) {
+            size = rb->rest;
         }
 
-        n = c->recv(c, r->request_body->buf->last, size);
+        n = c->recv(c, rb->buf->last, size);
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                        "http client request body recv %z", n);
@@ -173,33 +234,33 @@ static ngx_int_t ngx_http_do_read_client
             return NGX_HTTP_BAD_REQUEST;
         }
 
-        r->request_body->buf->last += n;
-        r->request_body->rest -= n;
+        rb->buf->last += n;
+        rb->rest -= n;
         r->request_length += n;
 
-        if (r->request_body->rest == 0) {
+        if (rb->rest == 0) {
             break;
         }
 
-        if (r->request_body->buf->last < r->request_body->buf->end) {
+        if (rb->buf->last < rb->buf->end) {
             break;
         }
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http client request body rest %uz",
-                   r->request_body->rest);
+                   "http client request body rest %uz", rb->rest);
 
-    if (r->request_body->rest) {
+    if (rb->rest) {
         return NGX_AGAIN;
     }
 
-    if (r->request_body->temp_file->file.fd != NGX_INVALID_FILE) {
+    if (rb->temp_file) {
 
         /* save the last part */
-        n = ngx_write_chain_to_temp_file(r->request_body->temp_file,
-                     r->request_body->bufs->next ? r->request_body->bufs->next:
-                                                   r->request_body->bufs);
+
+        n = ngx_write_chain_to_temp_file(rb->temp_file,
+                                         rb->bufs->next ? rb->bufs->next:
+                                                          rb->bufs);
 
         /* TODO: n == 0 or not complete and level event */
 
@@ -213,18 +274,18 @@ static ngx_int_t ngx_http_do_read_client
 
         b->in_file = 1;
         b->file_pos = 0;
-        b->file_last = r->request_body->temp_file->file.offset;
-        b->file = &r->request_body->temp_file->file;
+        b->file_last = rb->temp_file->file.offset;
+        b->file = &rb->temp_file->file;
 
-        if (r->request_body->bufs->next) {
-            r->request_body->bufs->next->buf = b;
+        if (rb->bufs->next) {
+            rb->bufs->next->buf = b;
 
         } else {
-            r->request_body->bufs->buf = b;
+            rb->bufs->buf = b;
         }
     }
 
-    r->request_body->handler(r->request_body->data);
+    rb->post_handler(r);
 
     return NGX_OK;
 }
new file mode 100644
--- /dev/null
+++ b/src/http/ngx_http_upstream.c
@@ -0,0 +1,1204 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+#include <ngx_event_connect.h>
+
+
+static void ngx_http_upstream_check_broken_connection(ngx_event_t *ev);
+static void ngx_http_upstream_connect(ngx_http_request_t *r,
+                                      ngx_http_upstream_t *u);
+static void ngx_http_upstream_reinit(ngx_http_request_t *r,
+                                     ngx_http_upstream_t *u);
+static void ngx_http_upstream_send_request(ngx_http_request_t *r,
+                                           ngx_http_upstream_t *u);
+static void ngx_http_upstream_send_request_handler(ngx_event_t *wev);
+static void ngx_http_upstream_process_header(ngx_event_t *rev);
+static void ngx_http_upstream_send_response(ngx_http_request_t *r,
+                                            ngx_http_upstream_t *u);
+static void ngx_http_upstream_process_body(ngx_event_t *ev);
+static void ngx_http_upstream_dummy_handler(ngx_event_t *wev);
+static void ngx_http_upstream_next(ngx_http_request_t *r,
+                                   ngx_http_upstream_t *u,
+                                   ngx_uint_t ft_type);
+static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
+                                               ngx_http_upstream_t *u,
+                                               ngx_int_t rc);
+
+static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r,
+                                                  uintptr_t data);
+static u_char *ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf,
+                                            ngx_http_log_op_t *op);
+
+
+static ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf);
+
+
+ngx_http_module_t  ngx_http_upstream_module_ctx = {
+    ngx_http_upstream_add_log_formats,     /* pre conf */
+    
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    NULL,                                  /* create location configuration */
+    NULL                                   /* merge location configuration */
+};
+    
+
+ngx_module_t  ngx_http_upstream_module = {
+    NGX_MODULE,
+    &ngx_http_upstream_module_ctx,         /* module context */
+    NULL,                                  /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init module */
+    NULL                                   /* init process */
+};
+
+
+static ngx_http_log_op_name_t ngx_http_upstream_log_fmt_ops[] = {
+    { ngx_string("upstream_status"), 0, NULL,
+                                        ngx_http_upstream_log_status_getlen,
+                                        ngx_http_upstream_log_status },
+    { ngx_null_string, 0, NULL, NULL, NULL }
+};
+
+
+char *ngx_http_upstream_header_errors[] = {
+    "upstream sent invalid header",
+    "upstream sent too long header line"
+};
+
+
+void ngx_http_upstream_init(ngx_http_request_t *r)
+{
+    ngx_connection_t     *c;
+    ngx_http_upstream_t  *u;
+
+    c = r->connection;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http init upstream, client timer: %d", c->read->timer_set);
+
+    if (c->read->timer_set) {
+        ngx_del_timer(c->read);
+    }
+
+    c->read->event_handler = ngx_http_upstream_check_broken_connection;
+    
+    if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
+    
+        c->write->event_handler = ngx_http_upstream_check_broken_connection;
+
+        if (!c->write->active) {
+            if (ngx_add_event(c->write, NGX_WRITE_EVENT,
+                                                NGX_CLEAR_EVENT) == NGX_ERROR)
+            {
+                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+                return;
+            }
+        }
+    }
+
+    u = r->upstream;
+
+    u->method = r->method;
+
+    if (u->create_request(r) == NGX_ERROR) {
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    u->peer.log = r->connection->log;
+    u->saved_ctx = r->connection->log->data;
+    u->saved_handler = r->connection->log->handler;
+    r->connection->log->data = u->log_ctx;
+    r->connection->log->handler = u->log_handler;
+
+    u->output.sendfile = r->connection->sendfile;
+    u->output.pool = r->pool;
+    u->output.bufs.num = 1;
+    u->output.output_filter = ngx_chain_writer;
+    u->output.filter_ctx = &u->writer;
+
+    u->writer.pool = r->pool;
+
+    if (ngx_array_init(&u->states, r->pool, u->peer.peers->number,
+                               sizeof(ngx_http_upstream_state_t)) == NGX_ERROR)
+    {
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    if (!(u->state = ngx_push_array(&u->states))) {
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
+
+    ngx_http_upstream_connect(r, u);
+}
+
+
+static void ngx_http_upstream_check_broken_connection(ngx_event_t *ev)
+{
+    int                  n;
+    char                 buf[1];
+    ngx_err_t            err; 
+    ngx_connection_t     *c;
+    ngx_http_request_t   *r;
+    ngx_http_upstream_t  *u;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+                   "http upstream check client, write event:%d", ev->write);
+
+#if (NGX_HAVE_KQUEUE)
+
+    if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
+
+        if (!ev->pending_eof) {
+            return;
+        }
+
+        ev->eof = 1;
+
+        if (ev->kq_errno) {
+            ev->error = 1;
+        }
+
+        c = ev->data;
+        r = c->data;
+        u = r->upstream;
+
+        if (!u->cachable && u->peer.connection) {
+            ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
+                          "kevent() reported that client closed "
+                          "prematurely connection, "
+                          "so upstream connection is closed too");
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_CLIENT_CLOSED_REQUEST);
+            return;
+        }
+
+        ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
+                      "kevent() reported that client closed "
+                      "prematurely connection");
+
+        if (u->peer.connection == NULL) {
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_CLIENT_CLOSED_REQUEST);
+            return;
+        }
+
+        return;
+    }
+
+#endif
+
+    c = ev->data;
+
+    n = recv(c->fd, buf, 1, MSG_PEEK);
+
+    err = ngx_socket_errno;
+
+    /*
+     * we do not need to disable the write event because
+     * that event has NGX_USE_CLEAR_EVENT type
+     */
+
+    if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
+        return;
+    }
+
+    r = c->data;
+    u = r->upstream;
+
+    if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
+        if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
+    }
+
+    if (n > 0) {
+        return;
+    }
+
+    ev->eof = 1;
+
+    if (n == -1) {
+        if (err == NGX_EAGAIN) {
+            return;
+        }
+
+        ev->error = 1;
+
+    } else {
+        /* n == 0 */
+        err = 0;
+    }
+
+    if (!u->cachable && u->peer.connection) {
+        ngx_log_error(NGX_LOG_INFO, ev->log, err,
+                      "client closed prematurely connection, "
+                      "so upstream connection is closed too");
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_CLIENT_CLOSED_REQUEST);
+        return;
+    }
+
+    ngx_log_error(NGX_LOG_INFO, ev->log, err,
+                  "client closed prematurely connection");
+
+    if (u->peer.connection == NULL) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_CLIENT_CLOSED_REQUEST);
+        return;
+    }
+}
+
+
+static void ngx_http_upstream_connect(ngx_http_request_t *r,
+                                      ngx_http_upstream_t *u)
+{
+    ngx_int_t            rc;
+    ngx_connection_t    *c;
+    ngx_http_log_ctx_t  *ctx;
+
+    ctx = r->connection->log->data;
+    ctx->action = "connecting to upstream";
+
+    r->connection->single_connection = 0;
+
+    rc = ngx_event_connect_peer(&u->peer);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http upstream connect: %i", rc);
+
+    if (rc == NGX_ERROR) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    u->state->peer = &u->peer.peers->peer[u->peer.cur_peer].name;
+
+    if (rc == NGX_CONNECT_ERROR) {
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+        return;
+    }
+
+    c = u->peer.connection;
+
+    c->data = r;
+    c->write->event_handler = ngx_http_upstream_send_request_handler;
+    c->read->event_handler = ngx_http_upstream_process_header;
+
+    c->sendfile = r->connection->sendfile;
+
+    c->pool = r->pool;
+    c->read->log = c->write->log = c->log = r->connection->log;
+
+    /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
+
+    u->writer.out = NULL;
+    u->writer.last = &u->writer.out;
+    u->writer.connection = c;
+    u->writer.limit = 0;
+
+    if (u->request_sent) {
+        ngx_http_upstream_reinit(r, u);
+    }
+
+    if (r->request_body->buf) {
+        if (r->request_body->temp_file) {
+
+            if (!(u->output.free = ngx_alloc_chain_link(r->pool))) {
+                ngx_http_upstream_finalize_request(r, u,
+                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
+                return;
+            }
+
+            u->output.free->buf = r->request_body->buf;
+            u->output.free->next = NULL;
+            u->output.allocated = 1;
+
+            r->request_body->buf->pos = r->request_body->buf->start;
+            r->request_body->buf->last = r->request_body->buf->start;
+            r->request_body->buf->tag = u->output.tag;
+
+        } else {
+            r->request_body->buf->pos = r->request_body->buf->start;
+        }
+    }
+
+    u->request_sent = 0;
+
+    if (rc == NGX_AGAIN) {
+        ngx_add_timer(c->write, u->conf->connect_timeout);
+        return;
+    }
+
+    /* rc == NGX_OK */
+
+    ngx_http_upstream_send_request(r, u);
+}
+
+
+static void ngx_http_upstream_reinit(ngx_http_request_t *r,
+                                     ngx_http_upstream_t *u)
+{
+    ngx_chain_t  *cl;
+
+    if (u->reinit_request(r) == NGX_ERROR) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    /* reinit the request chain */
+    
+    for (cl = r->request_body->bufs; cl; cl = cl->next) {
+        cl->buf->pos = cl->buf->start;
+        cl->buf->file_pos = 0;
+    }
+
+    /* reinit the ngx_output_chain() context */
+
+    u->output.buf = NULL;
+    u->output.in = NULL;
+    u->output.free = NULL;
+    u->output.busy = NULL;
+    
+    /* reinit u->header_in buffer */
+    
+#if 0
+    if (u->cache) {
+        u->header_in.pos = u->header_in.start + u->cache->ctx.header_size;
+        u->header_in.last = u->header_in.pos;
+
+    } else {
+        u->header_in.pos = u->header_in.start;
+        u->header_in.last = u->header_in.start;
+    }
+#else
+        u->header_in.pos = u->header_in.start;
+        u->header_in.last = u->header_in.start;
+#endif
+
+    /* add one more state */
+
+    if (!(u->state = ngx_push_array(&u->states))) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
+
+    u->status = 0;
+    u->status_count = 0;
+}
+
+
+static void ngx_http_upstream_send_request(ngx_http_request_t *r,
+                                           ngx_http_upstream_t *u)
+{
+    int                  rc;
+    ngx_connection_t    *c;
+    ngx_http_log_ctx_t  *ctx;
+    
+    c = u->peer.connection;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http upstream send request");
+
+#if (NGX_HAVE_KQUEUE)
+
+    if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT)
+        && !u->request_sent
+        && c->write->pending_eof)
+    {
+        ngx_log_error(NGX_LOG_ERR, c->log, c->write->kq_errno,
+                      "connect() failed");
+
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+        return;
+    }
+
+#endif
+
+    ctx = c->log->data;
+    ctx->action = "sending request to upstream";
+
+    rc = ngx_output_chain(&u->output,
+                          u->request_sent ? NULL : r->request_body->bufs);
+
+    u->request_sent = 1;
+
+    if (rc == NGX_ERROR) {
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+        return;
+    }
+
+    if (c->write->timer_set) {
+        ngx_del_timer(c->write);
+    }
+
+    if (rc == NGX_AGAIN) {
+        ngx_add_timer(c->write, u->conf->send_timeout);
+
+        if (ngx_handle_write_event(c->write, u->conf->send_lowat) == NGX_ERROR)
+        {
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
+
+        return;
+    }
+
+    /* rc == NGX_OK */
+
+    if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
+        if (ngx_tcp_push(c->fd) == NGX_ERROR) {
+            ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
+                          ngx_tcp_push_n " failed");
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return; 
+        }
+
+        c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
+        return;
+    }
+    
+    ngx_add_timer(c->read, u->conf->read_timeout);
+
+#if 1
+    if (c->read->ready) {
+    
+        /* post aio operation */
+
+        /*
+         * TODO comment
+         * although we can post aio operation just in the end
+         * of ngx_http_upstream_connect() CHECK IT !!!
+         * it's better to do here because we postpone header buffer allocation
+         */
+
+        ngx_http_upstream_process_header(c->read);
+        return;
+    }
+#endif
+
+    c->write->event_handler = ngx_http_upstream_dummy_handler;
+
+    if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+}
+
+
+static void ngx_http_upstream_send_request_handler(ngx_event_t *wev)
+{
+    ngx_connection_t     *c;
+    ngx_http_request_t   *r;
+    ngx_http_log_ctx_t   *ctx;
+    ngx_http_upstream_t  *u;
+
+    c = wev->data;
+    r = c->data;
+    u = r->upstream;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
+                   "http upstream send request handler");
+
+    if (wev->timedout) {
+        ctx = c->log->data;
+        ctx->action = "sending request to upstream";
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
+        return;
+    }
+
+    if (r->connection->write->eof && (!u->cachable || !u->request_sent)) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    ngx_http_upstream_send_request(r, u);
+}
+
+
+static void ngx_http_upstream_process_header(ngx_event_t *rev)
+{
+    ssize_t               n;
+    ngx_int_t             rc;
+    ngx_connection_t     *c;
+    ngx_http_request_t   *r;
+    ngx_http_log_ctx_t   *ctx;
+    ngx_http_upstream_t  *u;
+
+    c = rev->data;
+    r = c->data;
+    u = r->upstream;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
+                   "http upstream process handler");
+
+    ctx = c->log->data;
+    ctx->action = "reading response header from upstream";
+
+    if (rev->timedout) {
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
+        return;
+    }
+    
+    if (u->header_in.start == NULL) {
+        u->header_in.start = ngx_palloc(r->pool, u->conf->header_buffer_size);
+        if (u->header_in.start == NULL) {
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
+
+        u->header_in.pos = u->header_in.start;
+        u->header_in.last = u->header_in.start;
+        u->header_in.end = u->header_in.last + u->conf->header_buffer_size;
+        u->header_in.temporary = 1;
+
+        u->header_in.tag = u->output.tag;
+
+#if 0
+        if (u->cache) {
+            u->header_in.pos += u->cache->ctx.header_size;
+            u->header_in.last = u->header_in.pos;
+        }
+#endif
+    }
+
+    n = ngx_recv(u->peer.connection, u->header_in.last,
+                 u->header_in.end - u->header_in.last);
+
+    if (n == NGX_AGAIN) {
+#if 0
+        ngx_add_timer(rev, u->read_timeout);
+#endif
+
+        if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
+
+        return;
+    }
+
+    if (n == 0) {
+        ngx_log_error(NGX_LOG_ERR, rev->log, 0,
+                      "upstream prematurely closed connection");
+    }
+
+    if (n == NGX_ERROR || n == 0) {
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+        return;
+    }
+
+    if (n == NGX_HTTP_INTERNAL_SERVER_ERROR) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    u->header_in.last += n;
+
+#if 0
+    u->valid_header_in = 0;
+
+    u->peer.cached = 0;
+#endif
+
+    rc = u->process_header(r);
+
+    if (rc == NGX_AGAIN) {
+#if 0
+        ngx_add_timer(rev, u->read_timeout);
+#endif
+
+        if (u->header_in.last == u->header_in.end) {
+            ngx_log_error(NGX_LOG_ERR, rev->log, 0,
+                          "upstream sent too big header");
+
+            ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
+            return;
+        }
+
+        if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
+
+        return;
+    }
+
+    if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
+        return;
+    }
+
+    if (rc == NGX_ERROR || rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    /* rc == NGX_OK */
+
+    ngx_http_upstream_send_response(r, u);
+}
+
+
+static void ngx_http_upstream_send_response(ngx_http_request_t *r,
+                                            ngx_http_upstream_t *u)
+{
+    ngx_event_pipe_t          *p;
+    ngx_http_core_loc_conf_t  *clcf;
+
+
+    if (u->send_header(r) == NGX_HTTP_INTERNAL_SERVER_ERROR) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
+    u->header_sent = 1;
+
+    /* TODO: preallocate event_pipe bufs, look "Content-Length" */
+
+#if 0
+
+    if (u->cache && u->cache->ctx.file.fd != NGX_INVALID_FILE) {
+        if (ngx_close_file(u->cache->ctx.file.fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed",
+                          u->cache->ctx.file.name.data);
+        }
+    }
+
+    if (u->cachable) {
+        header = (ngx_http_cache_header_t *) u->header_in->start;
+
+        header->expires = u->cache->ctx.expires;
+        header->last_modified = u->cache->ctx.last_modified;
+        header->date = u->cache->ctx.date;
+        header->length = r->headers_out.content_length_n;
+        u->cache->ctx.length = r->headers_out.content_length_n;
+
+        header->key_len = u->cache->ctx.key0.len;
+        ngx_memcpy(&header->key, u->cache->ctx.key0.data, header->key_len);
+        header->key[header->key_len] = LF;
+    }
+
+#endif
+
+    p = &u->pipe;
+
+    p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter;
+    p->output_ctx = r;
+    p->tag = u->output.tag;
+    p->bufs = u->conf->bufs;     
+    p->busy_size = u->conf->busy_buffers_size;
+    p->upstream = u->peer.connection;
+    p->downstream = r->connection;
+    p->pool = r->pool;
+    p->log = r->connection->log;
+    
+    p->cachable = u->cachable;
+
+    if (!(p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
+        ngx_http_upstream_finalize_request(r, u, 0);
+        return;
+    }
+
+    p->temp_file->file.fd = NGX_INVALID_FILE;
+    p->temp_file->file.log = r->connection->log;
+    p->temp_file->path = u->conf->temp_path;
+    p->temp_file->pool = r->pool;
+    
+    if (u->cachable) {
+        p->temp_file->persistent = 1;
+    } else {
+        p->temp_file->warn = "an upstream response is buffered "
+                             "to a temporary file";
+    }
+
+    p->max_temp_file_size = u->conf->max_temp_file_size;
+    p->temp_file_write_size = u->conf->temp_file_write_size;
+
+    if (!(p->preread_bufs = ngx_alloc_chain_link(r->pool))) {
+        ngx_http_upstream_finalize_request(r, u, 0);
+        return;
+    }
+    p->preread_bufs->buf = &u->header_in;
+    p->preread_bufs->next = NULL;
+    u->header_in.recycled = 1;
+
+    p->preread_size = u->header_in.last - u->header_in.pos;
+
+    if (u->cachable) {
+        p->buf_to_file = ngx_calloc_buf(r->pool);
+        if (p->buf_to_file == NULL) {
+            ngx_http_upstream_finalize_request(r, u, 0);
+            return;
+        }
+        p->buf_to_file->pos = u->header_in.start;
+        p->buf_to_file->last = u->header_in.pos;
+        p->buf_to_file->temporary = 1;
+    }
+
+    if (ngx_event_flags & NGX_USE_AIO_EVENT) {
+        /* the posted aio operation may currupt a shadow buffer */
+        p->single_buf = 1;
+    }
+
+    /* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */
+    p->free_bufs = 1;
+
+    /*
+     * event_pipe would do u->header_in.last += p->preread_size
+     * as though these bytes were read
+     */
+    u->header_in.last = u->header_in.pos;
+
+    if (u->conf->cyclic_temp_file) {
+
+        /*
+         * we need to disable the use of sendfile() if we use cyclic temp file
+         * because the writing a new data may interfere with sendfile()
+         * that uses the same kernel file pages (at least on FreeBSD)
+         */
+
+        p->cyclic_temp_file = 1;
+        r->connection->sendfile = 0;
+
+    } else {
+        p->cyclic_temp_file = 0;
+    }
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    p->read_timeout = u->conf->read_timeout;
+    p->send_timeout = clcf->send_timeout;
+    p->send_lowat = clcf->send_lowat;
+
+    u->peer.connection->read->event_handler = ngx_http_upstream_process_body;
+    r->connection->write->event_handler = ngx_http_upstream_process_body;
+
+    ngx_http_upstream_process_body(u->peer.connection->read);
+}
+
+
+static void ngx_http_upstream_process_body(ngx_event_t *ev)
+{
+    ngx_connection_t     *c;
+    ngx_http_request_t   *r;
+    ngx_http_log_ctx_t   *ctx;
+    ngx_http_upstream_t  *u;
+    ngx_event_pipe_t     *p;
+
+    c = ev->data;
+    r = c->data;
+    u = r->upstream;
+
+    ctx = ev->log->data;
+
+    if (ev->write) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+                       "http proxy process downstream");
+        ctx->action = "sending to client";
+    
+    } else {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+                       "http proxy process upstream");
+        ctx->action = "reading upstream body";
+    }
+    
+    p = &u->pipe;
+
+    if (ev->timedout) {
+        if (ev->write) {
+            p->downstream_error = 1;
+            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
+                          "client timed out");
+
+        } else {
+            p->upstream_error = 1; 
+            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
+                          "upstream timed out");
+        }
+
+    } else {
+        if (ngx_event_pipe(p, ev->write) == NGX_ABORT) {
+            ngx_http_upstream_finalize_request(r, u, 0);
+            return;
+        }
+    }
+    
+    if (u->peer.connection) {
+
+#if (NGX_HTTP_FILE_CACHE)
+
+        if (p->upstream_done && u->cachable) {
+            if (ngx_http_cache_update(r) == NGX_ERROR) {
+                ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
+                ngx_http_upstream_finalize_request(r, u, 0);
+                return;
+            }
+
+        } else if (p->upstream_eof && u->cachable) {
+
+            /* TODO: check length & update cache */
+
+            if (ngx_http_cache_update(r) == NGX_ERROR) {
+                ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
+                ngx_http_upstream_finalize_request(r, u, 0);
+                return;
+            }
+        }
+
+#endif
+
+        if (p->upstream_done || p->upstream_eof || p->upstream_error) {
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+                           "http proxy upstream exit: %p", p->out);
+#if 0
+            ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
+#endif
+            ngx_http_upstream_finalize_request(r, u, 0);
+            return;
+        }
+    }
+
+    if (p->downstream_error) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+                       "http proxy downstream error");
+
+        if (!u->cachable && u->peer.connection) {
+            ngx_http_upstream_finalize_request(r, u, 0);
+        }
+    }
+}
+
+
+static void ngx_http_upstream_dummy_handler(ngx_event_t *wev)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
+                   "http upstream dummy handler");
+}
+
+
+static void ngx_http_upstream_next(ngx_http_request_t *r,
+                                   ngx_http_upstream_t *u,
+                                   ngx_uint_t ft_type)
+{
+    ngx_uint_t  status;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http next upstream, %xD", ft_type);
+
+#if 0
+    ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
+#endif
+
+    if (ft_type != NGX_HTTP_UPSTREAM_FT_HTTP_404) {
+        ngx_event_connect_peer_failed(&u->peer);
+    }
+    
+    if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
+                      "upstream timed out");
+    }
+    
+    if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
+        status = 0;
+
+    } else {
+        switch(ft_type) {
+
+        case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
+            status = NGX_HTTP_GATEWAY_TIME_OUT;
+            break;
+
+        case NGX_HTTP_UPSTREAM_FT_HTTP_500:
+            status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+            break;
+
+        case NGX_HTTP_UPSTREAM_FT_HTTP_404:
+            status = NGX_HTTP_NOT_FOUND;
+            break;
+
+        /*
+         * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
+         * never reach here
+         */
+
+        default:
+            status = NGX_HTTP_BAD_GATEWAY;
+        }
+    }
+
+    if (r->connection->write->eof) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_CLIENT_CLOSED_REQUEST);
+        return;
+    }
+
+    if (status) {
+        u->state->status = status;
+
+        if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type))
+        {
+
+#if (NGX_HTTP_CACHE)
+
+            if (u->stale && (u->conf->use_stale & ft_type)) {
+                ngx_http_upstream_finalize_request(r, u,
+                                       ngx_http_proxy_send_cached_response(r));
+                return;
+            }
+
+#endif
+
+            ngx_http_upstream_finalize_request(r, u, status);
+            return;
+        }
+    }
+
+    if (u->peer.connection) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "close http upstream connection: %d",
+                       u->peer.connection->fd);
+
+        ngx_close_connection(u->peer.connection);
+    }
+
+#if 0
+    if (u->conf->busy_lock && !u->busy_locked) {
+        ngx_http_upstream_busy_lock(p);
+        return;
+    }
+#endif
+
+    ngx_http_upstream_connect(r, u);
+}
+
+
+static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
+                                               ngx_http_upstream_t *u,
+                                               ngx_int_t rc)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "finalize http upstream request");
+
+    u->finalize_request(r, rc);
+
+    if (u->peer.connection) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "close http upstream connection: %d",
+                       u->peer.connection->fd);
+
+        ngx_close_connection(u->peer.connection);
+    }
+
+    if (u->header_sent
+        && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
+    {
+        rc = 0;
+    }
+
+    if (u->saved_ctx) {
+        r->connection->log->data = u->saved_ctx;
+        r->connection->log->handler = u->saved_handler;
+    }
+
+    if (u->pipe.temp_file->file.fd) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http upstream temp fd: %d",
+                       u->pipe.temp_file->file.fd);
+    }
+
+#if 0
+    if (u->cache) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http proxy cache fd: %d",
+                       u->cache->ctx.file.fd);
+    }
+#endif
+
+    if (u->pipe.temp_file->file.fd) {
+        r->file.fd = u->pipe.temp_file->file.fd;
+
+#if 0
+    } else if (u->cache) {
+        r->file.fd = u->cache->ctx.file.fd;
+#endif
+    }
+
+    if (rc == 0 && r->main == NULL) {
+        rc = ngx_http_send_last(r);
+    }
+
+    ngx_http_finalize_request(r, rc);
+}
+
+
+static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r,
+                                                  uintptr_t data)
+{
+    if (r->upstream) {
+        return r->upstream->states.nelts * (3 + 2);
+    }
+
+    return 1;
+}
+
+
+static u_char *ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf,
+                                            ngx_http_log_op_t *op)
+{
+    ngx_uint_t                  i;
+    ngx_http_upstream_t        *u;
+    ngx_http_upstream_state_t  *state;
+
+    u = r->upstream;
+
+    if (u == NULL) {
+        *buf = '-';
+        return buf + 1;
+    }
+
+    i = 0;
+    state = u->states.elts;
+
+    for ( ;; ) {
+        if (state[i].status == 0) {
+            *buf++ = '-';
+
+        } else {
+            buf = ngx_sprintf(buf, "%ui", state[i].status);
+        }
+
+        if (++i == u->states.nelts) {
+            return buf;
+        }
+
+        *buf++ = ',';
+        *buf++ = ' ';
+    }
+}
+
+
+u_char *ngx_http_upstream_log_error(void *data, u_char *buf, size_t len)
+{
+    ngx_http_log_ctx_t *ctx = data;
+    
+    u_char                 *p;
+    ngx_int_t               escape;
+    ngx_str_t               uri;
+    ngx_http_request_t     *r;
+    ngx_http_upstream_t    *u;
+    ngx_peer_connection_t  *peer;
+
+    r = ctx->request;
+    u = r->upstream;
+    peer = &u->peer;
+
+    p = ngx_snprintf(buf, len,
+                     " while %s, client: %V, URL: %V, upstream: %V%V%s%V",
+                     ctx->action,
+                     &r->connection->addr_text,
+                     &r->unparsed_uri,
+                     &u->schema,
+                     &peer->peers->peer[peer->cur_peer].name,
+                     peer->peers->peer[peer->cur_peer].uri_separator,
+                     &u->uri);
+    len -= p - buf;
+    buf = p;
+
+    if (r->quoted_uri) {
+        escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location->len,
+                                    r->uri.len - u->location->len,
+                                    NGX_ESCAPE_URI);
+    } else {
+        escape = 0;
+    }
+
+    if (escape) {
+        if (len >= r->uri.len - u->location->len + escape) {
+
+            ngx_escape_uri(buf, r->uri.data + u->location->len,
+                           r->uri.len - u->location->len, NGX_ESCAPE_URI);
+
+            buf += r->uri.len - u->location->len + escape;
+
+            if (r->args.len == 0) {
+                return buf;
+            }
+
+            len -= r->uri.len - u->location->len + escape;
+
+            return ngx_snprintf(buf, len, "?%V", &r->args);
+        }
+
+        p = ngx_palloc(r->pool, r->uri.len - u->location->len + escape);
+        if (p == NULL) {
+            return buf;
+        }
+
+        ngx_escape_uri(p, r->uri.data + u->location->len,
+                       r->uri.len - u->location->len, NGX_ESCAPE_URI);
+
+        uri.len = r->uri.len - u->location->len + escape;
+        uri.data = p;
+
+    } else {
+        uri.len = r->uri.len - u->location->len;
+        uri.data = r->uri.data + u->location->len;
+
+    }
+
+    return ngx_snprintf(buf, len, "%V%s%V", 
+                        &uri, r->args.len ? "?" : "", &r->args);
+}
+
+
+static ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf)
+{
+    ngx_http_log_op_name_t  *op;
+
+    for (op = ngx_http_upstream_log_fmt_ops; op->name.len; op++) { /* void */ }
+    op->run = NULL;
+
+    for (op = ngx_http_log_fmt_ops; op->run; op++) {
+        if (op->name.len == 0) {
+            op = (ngx_http_log_op_name_t *) op->run;
+        }
+    }
+
+    op->run = (ngx_http_log_op_run_pt) ngx_http_upstream_log_fmt_ops;
+
+    return NGX_OK;
+}
new file mode 100644
--- /dev/null
+++ b/src/http/ngx_http_upstream.h
@@ -0,0 +1,122 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_HTTP_UPSTREAM_H_INCLUDED_
+#define _NGX_HTTP_UPSTREAM_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_event_connect.h>
+#include <ngx_event_pipe.h>
+#include <ngx_http.h>
+
+
+#define NGX_HTTP_UPSTREAM_FT_ERROR           0x02
+#define NGX_HTTP_UPSTREAM_FT_TIMEOUT         0x04
+#define NGX_HTTP_UPSTREAM_FT_INVALID_HEADER  0x08
+#define NGX_HTTP_UPSTREAM_FT_HTTP_500        0x10
+#define NGX_HTTP_UPSTREAM_FT_HTTP_404        0x20
+#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK       0x40
+#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING     0x80
+
+
+#define NGX_HTTP_UPSTREAM_INVALID_HEADER     40
+
+
+typedef struct {
+    time_t                      bl_time;
+    ngx_uint_t                  bl_state;
+
+    ngx_uint_t                  status;
+    time_t                      time;
+    
+    ngx_str_t                  *peer;
+} ngx_http_upstream_state_t;
+
+
+typedef struct {
+    ngx_msec_t                  connect_timeout;
+    ngx_msec_t                  send_timeout;
+    ngx_msec_t                  read_timeout;
+
+    size_t                      send_lowat;
+    size_t                      header_buffer_size;
+    size_t                      busy_buffers_size;
+    size_t                      max_temp_file_size;
+    size_t                      temp_file_write_size;
+
+    ngx_uint_t                  next_upstream;
+
+    ngx_bufs_t                  bufs;
+
+    ngx_flag_t                  x_powered_by;
+    ngx_flag_t                  cyclic_temp_file;
+
+    ngx_path_t                 *temp_path;
+} ngx_http_upstream_conf_t;
+
+
+typedef struct ngx_http_upstream_s  ngx_http_upstream_t;
+
+struct ngx_http_upstream_s {
+    ngx_http_request_t         *request;
+
+    ngx_peer_connection_t       peer;
+
+    ngx_event_pipe_t            pipe;
+
+    ngx_output_chain_ctx_t      output;
+    ngx_chain_writer_ctx_t      writer;
+
+    ngx_http_upstream_conf_t   *conf;
+
+    ngx_buf_t                   header_in;
+
+    ngx_int_t                 (*create_request)(ngx_http_request_t *r);
+    ngx_int_t                 (*reinit_request)(ngx_http_request_t *r);
+    ngx_int_t                 (*process_header)(ngx_http_request_t *r);
+    ngx_int_t                 (*send_header)(ngx_http_request_t *r);
+    void                      (*abort_request)(ngx_http_request_t *r);
+    void                      (*finalize_request)(ngx_http_request_t *r,
+                                                  ngx_int_t rc);
+    ngx_uint_t                  method;
+
+    ngx_str_t                   schema;
+    ngx_str_t                   uri;
+    ngx_str_t                  *location;
+
+    ngx_http_log_ctx_t         *log_ctx;
+    ngx_log_handler_pt          log_handler;
+    ngx_http_log_ctx_t         *saved_ctx;
+    ngx_log_handler_pt          saved_handler;
+
+    /* used to parse an upstream HTTP header */
+    ngx_uint_t                  status;
+    u_char                     *status_start;
+    u_char                     *status_end;
+    ngx_uint_t                  status_count;
+    ngx_uint_t                  parse_state;
+
+    ngx_http_upstream_state_t  *state;
+    ngx_array_t                 states;    /* of ngx_http_upstream_state_t */
+
+    unsigned                    cachable:1;
+
+    unsigned                    request_sent:1;
+    unsigned                    header_sent:1;
+};
+
+
+void ngx_http_upstream_init(ngx_http_request_t *r);
+u_char *ngx_http_upstream_log_error(void *data, u_char *buf, size_t len);
+
+
+extern char *ngx_http_upstream_header_errors[];
+
+
+#endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */
--- a/src/http/ngx_http_write_filter.c
+++ b/src/http/ngx_http_write_filter.c
@@ -69,8 +69,19 @@ ngx_int_t ngx_http_write_filter(ngx_http
     for (cl = ctx->out; cl; cl = cl->next) {
         ll = &cl->next;
 
+        ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
+                       "write old buf t:%d f:%d %p, pos %p, size: %z "
+                       "file: %O, size: %z",
+                       cl->buf->temporary, cl->buf->in_file,
+                       cl->buf->start, cl->buf->pos,
+                       cl->buf->last - cl->buf->pos,
+                       cl->buf->file_pos,
+                       cl->buf->file_last - cl->buf->file_pos);
+
 #if 1
         if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
+            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                              "zero size buf in writer");
             ngx_debug_point();
         }
 #endif
@@ -97,8 +108,19 @@ ngx_int_t ngx_http_write_filter(ngx_http
         *ll = cl;
         ll = &cl->next;
 
+        ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
+                       "write new buf t:%d f:%d %p, pos %p, size: %z "
+                       "file: %O, size: %z",
+                       cl->buf->temporary, cl->buf->in_file,
+                       cl->buf->start, cl->buf->pos,
+                       cl->buf->last - cl->buf->pos,
+                       cl->buf->file_pos,
+                       cl->buf->file_last - cl->buf->file_pos);
+
 #if 1
         if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
+            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                              "zero size buf in writer");
             ngx_debug_point();
         }
 #endif
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -37,6 +37,7 @@
 #include <netinet/tcp.h>        /* TCP_NODELAY, TCP_NOPUSH */
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <sys/un.h>
 
 #include <libutil.h>            /* setproctitle() before 4.1 */
 #include <osreldate.h>
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -10,16 +10,16 @@
 
 
 /*
- * Although FreeBSD sendfile() allows to pass a header and a trailer
+ * Although FreeBSD sendfile() allows to pass a header and a trailer,
  * it can not send a header with a part of the file in one packet until
- * FreeBSD 5.3.  Besides over the fast ethernet connection sendfile()
+ * FreeBSD 5.3.  Besides, over the fast ethernet connection sendfile()
  * may send the partially filled packets, i.e. the 8 file pages may be sent
  * as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet,
  * and then again the 11 full 1460-bytes packets.
  *
- * So we use the TCP_NOPUSH option (similar to Linux's TCP_CORK)
- * to postpone the sending - it not only sends a header and the first part
- * of the file in one packet but also sends the file pages in the full packets.
+ * Threfore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK)
+ * to postpone the sending - it not only sends a header and the first part of
+ * the file in one packet, but also sends the file pages in the full packets.
  *
  * But until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush a pending
  * data that less than MSS so that data may be sent with 5 second delay.
@@ -220,7 +220,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
                     err = ngx_errno;
 
                     /*
-                     * there is a tiny chance to be interrupted, however
+                     * there is a tiny chance to be interrupted, however,
                      * we continue a processing without the TCP_NOPUSH
                      */
 
@@ -249,7 +249,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
              * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771
              */
 
-            if (ngx_freebsd_sendfile_nbytes_bug == 0) {
+            if (!ngx_freebsd_sendfile_nbytes_bug) {
                 header_size = 0;
             }
 
@@ -282,7 +282,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             if (rc == 0 && sent == 0) {
 
                 /*
-                 * rc and sent are equals to zero when someone has truncated
+                 * rc and sent equal to zero when someone has truncated
                  * the file, so the offset became beyond the end of the file
                  */
 
@@ -370,8 +370,8 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
         if (eagain) {
 
             /*
-             * sendfile() can return EAGAIN even if it has sent
-             * a whole file part but the successive sendfile() call would
+             * sendfile() may return EAGAIN, even if it has sent a whole file
+             * part, it indicates that the successive sendfile() call would
              * return EAGAIN right away and would not send anything.
              * We use it as a hint.
              */
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -42,6 +42,7 @@
 #include <netinet/tcp.h>        /* TCP_NODELAY, TCP_CORK */
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <sys/un.h>
 
 #include <time.h>               /* tzset() */
 #include <malloc.h>             /* memalign() */
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -11,9 +11,10 @@
 
 /*
  * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit
- * offsets only and the including <sys/sendfile.h> breaks the compiling
- * if off_t is 64 bit wide.  So we use own sendfile() definition where offset
- * parameter is int32_t and use sendfile() for the file parts below 2G only.
+ * offsets only, and the including <sys/sendfile.h> breaks the compiling,
+ * if off_t is 64 bit wide.  So we use own sendfile() definition, where offset
+ * parameter is int32_t, and use sendfile() for the file parts below 2G only,
+ * see src/os/unix/ngx_linux_config.h
  *
  * Linux 2.4.21 has a new sendfile64() syscall #239.
  */
@@ -85,6 +86,14 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
                 continue;
             }
 
+#if 1
+            if (!ngx_buf_in_memory(cl->buf) && !cl->buf->in_file) {
+                ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+                              "zero size buf in sendfile");
+                ngx_debug_point();
+            }
+#endif
+
             if (!ngx_buf_in_memory_only(cl->buf)) {
                 break;
             }
@@ -118,7 +127,6 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
             && cl
             && cl->buf->in_file)
         {
-
             /* the TCP_CORK and TCP_NODELAY are mutually exclusive */
 
             if (c->tcp_nodelay) {
@@ -131,7 +139,7 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
                     err = ngx_errno;
 
                     /*
-                     * there is a tiny chance to be interrupted, however
+                     * there is a tiny chance to be interrupted, however,
                      * we continue a processing with the TCP_NODELAY
                      * and without the TCP_CORK
                      */
@@ -157,7 +165,7 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng
                     err = ngx_errno;
 
                     /*
-                     * there is a tiny chance to be interrupted, however
+                     * there is a tiny chance to be interrupted, however,
                      * we continue a processing without the TCP_CORK
                      */
 
--- a/src/os/unix/ngx_posix_config.h
+++ b/src/os/unix/ngx_posix_config.h
@@ -57,6 +57,7 @@
 #include <netinet/tcp.h>        /* TCP_NODELAY */
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <sys/un.h>
 
 #if (NGX_HAVE_LIMITS_H)
 #include <limits.h>             /* IOV_MAX */
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -1113,7 +1113,7 @@ static void ngx_garbage_collector_cycle(
         for (i = 0; i < cycle->pathes.nelts; i++) {
             ctx.path = path[i];
             ctx.log = cycle->log;
-            ctx.handler = path[i]->gc_handler;
+            ctx.handler = path[i]->cleaner;
 
             ngx_collect_garbage(&ctx, &path[i]->name, 0);
         }
--- a/src/os/unix/ngx_solaris_config.h
+++ b/src/os/unix/ngx_solaris_config.h
@@ -41,6 +41,7 @@
 #include <netinet/tcp.h>        /* TCP_NODELAY */
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <sys/un.h>
 
 #include <sys/systeminfo.h>
 #include <limits.h>             /* IOV_MAX */