changeset 509:9b8c906f6e63 release-0.1.29

nginx-0.1.29-RELEASE import *) Feature: the ngx_http_ssi_module supports "include virtual" command. *) Feature: the ngx_http_ssi_module supports the condition command like 'if expr="$NAME"' and "else" and "endif" commands. Only one nested level is supported. *) Feature: the ngx_http_ssi_module supports the DATE_LOCAL and DATE_GMT variables and "config timefmt" command. *) Feature: the "ssi_ignore_recycled_buffers" directive. *) Bugfix: the "echo" command did not show the default value for the empty QUERY_STRING variable. *) Change: the ngx_http_proxy_module was rewritten. *) Feature: the "proxy_redirect", "proxy_pass_request_headers", "proxy_pass_request_body", and "proxy_method" directives. *) Feature: the "proxy_set_header" directive. The "proxy_x_var" was canceled and must be replaced with the proxy_set_header directive. *) Change: the "proxy_preserve_host" is canceled and must be replaced with the "proxy_set_header Host $host" and the "proxy_redirect off" directives, the "proxy_set_header Host $host:$proxy_port" directive and the appropriate proxy_redirect directives. *) Change: the "proxy_set_x_real_ip" is canceled and must be replaced with the "proxy_set_header X-Real-IP $remote_addr" directive. *) Change: the "proxy_add_x_forwarded_for" is canceled and must be replaced with the "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for" directive. *) Change: the "proxy_set_x_url" is canceled and must be replaced with the "proxy_set_header X-URL http://$host:$server_port$request_uri" directive. *) Feature: the "fastcgi_param" directive. *) Change: the "fastcgi_root", "fastcgi_set_var" and "fastcgi_params" directive are canceled and must be replaced with the fastcgi_param directives. *) Feature: the "index" directive can use the variables. *) Feature: the "index" directive can be used at http and server levels. *) Change: the last index only in the "index" directive can be absolute. *) Feature: the "rewrite" directive can use the variables. *) Feature: the "internal" directive. *) Feature: the CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR, SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME, REQUEST_METHOD, REQUEST_URI, and REMOTE_USER variables. *) Change: nginx now passes the invalid lines in a client request headers or a backend response header. *) Bugfix: if the backend did not transfer response for a long time and the "send_timeout" was less than "proxy_read_timeout", then nginx returned the 408 response. *) Bugfix: the segmentation fault was occurred if the backend sent an invalid line in response header; the bug had appeared in 0.1.26. *) Bugfix: the segmentation fault may occurred in FastCGI fault tolerance configuration. *) Bugfix: the "expires" directive did not remove the previous "Expires" and "Cache-Control" headers. *) Bugfix: nginx did not take into account trailing dot in "Host" header line. *) Bugfix: the ngx_http_auth_module did not work under Linux. *) Bugfix: the rewrite directive worked incorrectly, if the arguments were in a request. *) Bugfix: nginx could not be built on MacOS X.
author Igor Sysoev <igor@sysoev.ru>
date Thu, 12 May 2005 14:58:06 +0000
parents ca1020ce99ba
children 3e9296472a39
files auto/cc/gcc auto/cc/msvc auto/have_headers auto/include auto/modules auto/options auto/os/conf auto/os/freebsd auto/os/linux auto/os/solaris auto/os/win32 auto/sources auto/unix conf/mime.types docs/xml/nginx/changes.xml src/core/nginx.c src/core/nginx.h src/core/ngx_array.h src/core/ngx_buf.c src/core/ngx_buf.h src/core/ngx_conf_file.c src/core/ngx_conf_file.h src/core/ngx_cycle.c src/core/ngx_file.c src/core/ngx_hash.c src/core/ngx_hash.h src/core/ngx_inet.c src/core/ngx_log.c src/core/ngx_output_chain.c src/core/ngx_palloc.c src/core/ngx_palloc.h src/core/ngx_times.c src/core/ngx_times.h src/core/ngx_unix_domain.c src/event/modules/ngx_aio_module.c src/event/modules/ngx_devpoll_module.c src/event/modules/ngx_epoll_module.c src/event/modules/ngx_iocp_module.c src/event/modules/ngx_kqueue_module.c src/event/modules/ngx_poll_module.c src/event/modules/ngx_rtsig_module.c src/event/modules/ngx_select_module.c src/event/ngx_event.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_acceptex.c src/event/ngx_event_busy_lock.c src/event/ngx_event_connect.c src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/event/ngx_event_pipe.c src/event/ngx_event_posted.c src/event/ngx_event_timer.c src/http/modules/ngx_http_access_module.c src/http/modules/ngx_http_auth_basic_module.c src/http/modules/ngx_http_autoindex_module.c src/http/modules/ngx_http_charset_filter_module.c src/http/modules/ngx_http_chunked_filter_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_geo_module.c src/http/modules/ngx_http_gzip_filter_module.c src/http/modules/ngx_http_headers_filter_module.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_not_modified_filter_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_range_filter_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/ngx_http_static_module.c src/http/modules/ngx_http_stub_status_module.c src/http/modules/ngx_http_userid_filter_module.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_upstream.c src/http/ngx_http.c src/http/ngx_http.h src/http/ngx_http_busy_lock.c src/http/ngx_http_config.h src/http/ngx_http_copy_filter_module.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_header_filter_module.c src/http/ngx_http_log_module.c src/http/ngx_http_parse.c src/http/ngx_http_postpone_filter_module.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_request_body.c src/http/ngx_http_script.c src/http/ngx_http_script.h src/http/ngx_http_special_response.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h src/http/ngx_http_variables.c src/http/ngx_http_variables.h src/http/ngx_http_write_filter_module.c src/imap/ngx_imap.c src/imap/ngx_imap_handler.c src/imap/ngx_imap_proxy.c src/os/unix/ngx_channel.c src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_linux_config.h src/os/unix/ngx_linux_init.c src/os/unix/ngx_posix_config.h src/os/unix/ngx_posix_init.c src/os/unix/ngx_process.h src/os/unix/ngx_process_cycle.c src/os/unix/ngx_send.c src/os/unix/ngx_setproctitle.c src/os/unix/ngx_setproctitle.h src/os/unix/ngx_solaris_config.h src/os/unix/ngx_solaris_init.c src/os/unix/ngx_time.c src/os/unix/ngx_time.h src/os/unix/ngx_user.c src/os/win32/ngx_gui.c src/os/win32/ngx_process_cycle.c src/os/win32/ngx_time.c src/os/win32/ngx_time.h src/os/win32/ngx_win32_config.h
diffstat 121 files changed, 7096 insertions(+), 4541 deletions(-) [+]
line wrap: on
line diff
--- a/auto/cc/gcc
+++ b/auto/cc/gcc
@@ -57,6 +57,11 @@ case $CPU in
         CPU_OPT="-march=pentium4"
     ;;
 
+    opteron)
+        # optimize for Opteron, gcc 3.x
+        CPU_OPT="-march=opteron"
+    ;;
+
     sparc64)
         # build 64-bit UltraSparc binary
         CPU_OPT="-m64"
--- a/auto/cc/msvc
+++ b/auto/cc/msvc
@@ -6,18 +6,31 @@
 
 # optimizations
 
-# maximize speed
+# maximize speed, equivalent to -Og -Oi -Ot -Oy -Ob2 -Gs -GF -Gy
 CFLAGS="$CFLAGS -O2"
+
 # enable global optimization
-CFLAGS="$CFLAGS -Og"
+#CFLAGS="$CFLAGS -Og"
 # enable intrinsic functions
-CFLAGS="$CFLAGS -Oi"
-# inline expansion
-CFLAGS="$CFLAGS -Ob1"
+#CFLAGS="$CFLAGS -Oi"
+
+# disable inline expansion
+#CFLAGS="$CFLAGS -Ob0"
+# explicit inline expansion
+#CFLAGS="$CFLAGS -Ob1"
+# explicit and implicit inline expansion
+#CFLAGS="$CFLAGS -Ob2"
+
 # enable frame pointer omission
-CFLAGS="$CFLAGS -Oy"
+#CFLAGS="$CFLAGS -Oy"
 # disable stack checking calls
-CFLAGS="$CFLAGS -Gs"
+#CFLAGS="$CFLAGS -Gs"
+
+# pools strings as read/write
+#CFLAGS="$CFLAGS -Gf"
+# pools strings as read-only
+#CFLAGS="$CFLAGS -GF"
+
 
 case $CPU in
     pentium)
new file mode 100644
--- /dev/null
+++ b/auto/have_headers
@@ -0,0 +1,11 @@
+
+# Copyright (C) Igor Sysoev
+
+
+cat << END >> $NGX_AUTO_HEADERS_H
+
+#ifndef $have
+#define $have  1
+#endif
+
+END
--- a/auto/include
+++ b/auto/include
@@ -39,14 +39,7 @@ if [ -x $NGX_AUTOTEST ]; then
                   |  tr '[a-z]' '[A-Z]'`
 
 
-    cat << END >> $NGX_AUTO_HEADERS_H
-
-#ifndef NGX_HAVE_$ngx_name
-#define NGX_HAVE_$ngx_name  1
-#endif
-
-END
-
+    have=NGX_HAVE_$ngx_name . auto/have_headers
 
     eval "NGX_INCLUDE_$ngx_name='#include <$ngx_include>'"
 
--- a/auto/modules
+++ b/auto/modules
@@ -51,6 +51,10 @@ if [ $NGX_TEST_BUILD_SOLARIS_SENDFILEV =
 fi
 
 
+if [ $HTTP_SSI = YES ]; then
+    HTTP_POSTPONE=YES
+fi
+
 # the filter order is important
 #     ngx_http_write_filter
 #     ngx_http_header_filter
@@ -58,6 +62,7 @@ fi
 #     ngx_http_range_header_filter
 #     ngx_http_ssl_filter
 #     ngx_http_gzip_filter
+#     ngx_http_postpone_filter
 #     ngx_http_charset_filter
 #     ngx_http_ssi_filter
 #     ngx_http_headers_filter
@@ -77,6 +82,11 @@ if [ $HTTP_GZIP = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_GZIP_SRCS"
 fi
 
+if [ $HTTP_POSTPONE = YES ]; then
+    HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_POSTPONE_FILTER_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTPP_POSTPONE_FILTER_SRCS"
+fi
+
 if [ $HTTP_CHARSET = YES ]; then
     have=NGX_HTTP_CHARSET . auto/have
     HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_CHARSET_FILTER_MODULE"
--- a/auto/options
+++ b/auto/options
@@ -49,6 +49,7 @@ HTTP_CHARSET=YES
 HTTP_GZIP=YES
 HTTP_SSL=NO
 HTTP_SSI=YES
+HTTP_POSTPONE=NO
 HTTP_ACCESS=YES
 HTTP_AUTH_BASIC=YES
 HTTP_USERID=YES
--- a/auto/os/conf
+++ b/auto/os/conf
@@ -23,6 +23,15 @@ case "$NGX_PLATFORM" in
         . auto/os/freebsd
     ;;
 
+    Darwin:*)
+        have=NGX_DARWIN . auto/have_headers
+        have=NGX_HAVE_INHERITED_NONBLOCK . auto/have
+        CORE_INCS="$UNIX_INCS"
+        CORE_DEPS="$UNIX_DEPS $POSIX_DEPS"
+        CORE_SRCS="$UNIX_SRCS"
+        CRYPT_LIB=
+    ;;
+
     Linux:*)
         . auto/os/linux
     ;;
@@ -47,16 +56,16 @@ esac
 
 case "$NGX_MACHINE" in
 
-     i386|i686|i86pc|amd64)
-         have=NGX_HAVE_NONALIGNED . auto/have
-     ;;
+    i386|i686|i86pc|amd64)
+        have=NGX_HAVE_NONALIGNED . auto/have
+    ;;
 
 esac
 
 
 if [ "$NGX_PLATFORM" != win32 ]; then
 
-     NGX_USER=${NGX_USER:-nobody}
+    NGX_USER=${NGX_USER:-nobody}
 
     if [ -z "$NGX_GROUP" -a $NGX_USER = nobody ] ; then
        if grep nobody /etc/group 2>&1 >/dev/null; then
--- a/auto/os/freebsd
+++ b/auto/os/freebsd
@@ -2,14 +2,7 @@
 # Copyright (C) Igor Sysoev
 
 
-cat << END >> $NGX_AUTO_HEADERS_H
-
-#ifndef NGX_FREEBSD
-#define NGX_FREEBSD  1
-#endif
-
-END
-
+have=NGX_FREEBSD . auto/have_headers
 
 CORE_INCS="$UNIX_INCS"
 CORE_DEPS="$UNIX_DEPS $FREEBSD_DEPS"
@@ -39,6 +32,7 @@ then
     echo " + setproctitle() in libutil"
 
     CORE_LIBS="$CORE_LIBS -lutil"
+    NGX_SETPROCTITLE_LIB="-lutil"
 fi
 
 # sendfile
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -2,13 +2,7 @@
 # Copyright (C) Igor Sysoev
 
 
-cat << END >> $NGX_AUTO_HEADERS_H
-
-#ifndef NGX_LINUX
-#define NGX_LINUX  1
-#endif
-
-END
+have=NGX_LINUX . auto/have_headers
 
 CORE_INCS="$UNIX_INCS"
 CORE_DEPS="$UNIX_DEPS $LINUX_DEPS"
--- a/auto/os/solaris
+++ b/auto/os/solaris
@@ -2,13 +2,7 @@
 # Copyright (C) Igor Sysoev
 
 
-cat << END >> $NGX_AUTO_HEADERS_H
-
-#ifndef NGX_SOLARIS
-#define NGX_SOLARIS  1
-#endif
-
-END
+have=NGX_SOLARIS . auto/have_headers
 
 CORE_INCS="$UNIX_INCS"
 CORE_DEPS="$UNIX_DEPS $SOLARIS_DEPS"
--- a/auto/os/win32
+++ b/auto/os/win32
@@ -2,14 +2,7 @@
 # Copyright (C) Igor Sysoev
 
 
-cat << END >> $NGX_AUTO_HEADERS_H
-
-#ifndef NGX_WIN32
-#define NGX_WIN32  1
-#endif
-
-END
-
+have=NGX_WIN32 . auto/have_headers
 
 CORE_INCS="$WIN32_INCS"
 CORE_DEPS="$WIN32_DEPS"
--- a/auto/sources
+++ b/auto/sources
@@ -120,6 +120,7 @@ UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \
             src/os/unix/ngx_channel.h \
             src/os/unix/ngx_shared.h \
             src/os/unix/ngx_process.h \
+            src/os/unix/ngx_setproctitle.h \
             src/os/unix/ngx_atomic.h \
             src/os/unix/ngx_thread.h \
             src/os/unix/ngx_socket.h \
@@ -224,9 +225,11 @@ HTTP_CACHE_MODULE=ngx_http_cache_module
 HTTP_WRITE_FILTER_MODULE="ngx_http_write_filter_module"
 HTTP_HEADER_FILTER_MODULE="ngx_http_header_filter_module"
 
+HTTP_POSTPONE_FILTER_MODULE=ngx_http_postpone_filter_module
+HTTP_COPY_FILTER_MODULE=ngx_http_copy_filter_module
+
 HTTP_CHUNKED_FILTER_MODULE=ngx_http_chunked_filter_module
 HTTP_HEADERS_FILTER_MODULE=ngx_http_headers_filter_module
-HTTP_COPY_FILTER_MODULE=ngx_http_copy_filter_module
 
 HTTP_RANGE_HEADER_FILTER_MODULE=ngx_http_range_header_filter_module
 HTTP_RANGE_BODY_FILTER_MODULE=ngx_http_range_body_filter_module
@@ -273,6 +276,8 @@ HTTP_SRCS="src/http/ngx_http.c \
 # STUB
 HTTP_SRCS="$HTTP_SRCS src/http/ngx_http_busy_lock.c"
 
+HTPP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c
+
 HTPP_CACHE_SRCS=src/http/ngx_http_cache.c
 HTPP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c
 
@@ -323,17 +328,7 @@ HTTP_SSL_SRCS=src/http/modules/ngx_http_
 
 
 HTTP_PROXY_MODULE=ngx_http_proxy_module
-#HTTP_PROXY_SRCS=src/http/modules/ngx_http_proxy_module.c
-
-HTTP_PROXY_INCS="src/http/modules/proxy"
-HTTP_PROXY_DEPS=src/http/modules/proxy/ngx_http_proxy_handler.h
-HTTP_PROXY_SRCS="src/http/modules/proxy/ngx_http_proxy_handler.c \
-                 src/http/modules/proxy/ngx_http_proxy_upstream.c \
-                 src/http/modules/proxy/ngx_http_proxy_parse.c \
-                 src/http/modules/proxy/ngx_http_proxy_header.c"
-
-# STUB
-#                 src/http/modules/proxy/ngx_http_proxy_cache.c \
+HTTP_PROXY_SRCS=src/http/modules/ngx_http_proxy_module.c
 
 
 HTTP_FASTCGI_MODULE=ngx_http_fastcgi_module
--- a/auto/unix
+++ b/auto/unix
@@ -64,7 +64,7 @@ ngx_feature="setproctitle()"
 ngx_feature_name="NGX_HAVE_SETPROCTITLE"
 ngx_feature_run=no
 ngx_feature_incs=
-ngx_feature_libs=
+ngx_feature_libs=$NGX_SETPROCTITLE_LIB
 ngx_feature_test="setproctitle(\"test\");"
 . auto/feature
 
--- a/conf/mime.types
+++ b/conf/mime.types
@@ -17,6 +17,7 @@ types {
     application/x-javascript       js;
     application/x-rar-compressed   rar;
     application/x-xpinstall        xpi;
+    application/x-x509-ca-cert     der pem crt;
 
     audio/mpeg                     mp3;
     audio/x-realaudio              ra;
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -9,6 +9,319 @@
 <title lang="en">nginx changelog</title>
 
 
+<changes ver="0.1.29" date="12.05.2005">
+
+<change type="feature">
+<para lang="ru">
+ÍÏÄÕÌØ ngx_http_ssi_module ÐÏÄÄÅÒÖÉ×ÁÅÔ ËÏÍÁÎÄÕ include virtual.
+</para>
+<para lang="en">
+the ngx_http_ssi_module supports "include virtual" command.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÍÏÄÕÌØ ngx_http_ssi_module ÐÏÄÄÅÒÖÉ×ÁÅÔ ÕÓÌÏ×ÎÕÀ ËÏÍÁÎÄÕ ×ÉÄÁ
+'if expr="$NAME"' É ËÏÍÁÎÄÙ else É endif.
+äÏÐÕÓËÁÅÔÓÑ ÔÏÌØËÏ ÏÄÉÎ ÕÒÏ×ÅÎØ ×ÌÏÖÅÎÎÏÓÔÉ.
+</para>
+<para lang="en">
+the ngx_http_ssi_module supports the condition command like
+'if expr="$NAME"' and "else" and "endif" commands.
+Only one nested level is supported.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÍÏÄÕÌØ ngx_http_ssi_module ÐÏÄÄÅÒÖÉ×ÁÅÔ Ä×Å ÐÅÒÅÍÅÎÎÙÅ DATE_LOCAL É DATE_GMT
+É ËÏÍÁÎÄÕ config timefmt.
+</para>
+<para lang="en">
+the ngx_http_ssi_module supports the DATE_LOCAL and DATE_GMT variables
+and "config timefmt" command.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á ssi_ignore_recycled_buffers.
+</para>
+<para lang="en">
+the "ssi_ignore_recycled_buffers" directive.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÅÓÌÉ ÐÅÒÅÍÅÎÎÁÑ QUERY_STRING ÎÅ ÂÙÌÁ ÏÐÒÅÄÅÌÅÎÁ, ÔÏ × ËÏÍÁÎÄÅ echo
+ÎÅ ÓÔÁ×ÉÌÏÓØ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ.
+</para>
+<para lang="en">
+the "echo" command did not show the default value for the empty QUERY_STRING
+variable.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+ÍÏÄÕÌØ ngx_http_proxy_module ÐÏÌÎÏÓÔØÀ ÐÅÒÅÐÉÓÁÎ.
+</para>
+<para lang="en">
+the ngx_http_proxy_module was rewritten.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Ù proxy_redirect, proxy_pass_request_headers,
+proxy_pass_request_body É proxy_method.
+</para>
+<para lang="en">
+the "proxy_redirect", "proxy_pass_request_headers",
+"proxy_pass_request_body", and "proxy_method" directives.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á proxy_set_header.
+äÉÒÅËÔÉ×Á proxy_x_var ÕÐÒÁÚÄÎÅÎÁ É ÄÏÌÖÎÁ ÂÙÔØ ÚÁÍÅÎÅÎÁ ÄÉÒÅËÔÉ×ÏÊ
+proxy_set_header.
+</para>
+<para lang="en">
+the "proxy_set_header" directive.
+The "proxy_x_var" is canceled and must be replaced with the proxy_set_header
+directive.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á proxy_preserve_host ÕÐÒÁÚÄÎÅÎÁ É ÄÏÌÖÎÁ ÂÙÔØ ÚÁÍÅÎÅÎÁ ÄÉÒÅËÔÉ×ÁÍÉ
+"proxy_set_header Host $host" É "proxy_redirect off"
+ÉÌÉ ÄÉÒÅËÔÉ×ÏÊ <nobr>"proxy_set_header Host $host:$proxy_port"</nobr>
+É ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÍÉ ÅÊ ÄÉÒÅËÔÉ×ÁÍÉ proxy_redirect.
+</para>
+<para lang="en">
+the "proxy_preserve_host" is canceled and must be replaced with
+the "proxy_set_header Host $host" and the "proxy_redirect off" directives,
+the <nobr>"proxy_set_header Host $host:$proxy_port" directive</nobr>
+and the appropriate proxy_redirect directives.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á proxy_set_x_real_ip ÕÐÒÁÚÄÎÅÎÁ É ÄÏÌÖÎÁ ÂÙÔØ ÚÁÍÅÎÅÎÁ ÄÉÒÅËÔÉ×ÏÊ
+"proxy_set_header X-Real-IP $remote_addr".
+</para>
+<para lang="en">
+the "proxy_set_x_real_ip" is canceled and must be replaced with
+the "proxy_set_header X-Real-IP $remote_addr" directive.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á proxy_add_x_forwarded_for ÕÐÒÁÚÄÎÅÎÁ É ÄÏÌÖÎÁ ÂÙÔØ ÚÁÍÅÎÅÎÁ
+ÄÉÒÅËÔÉ×ÏÊ
+<nobr>"proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for".</nobr>
+</para>
+<para lang="en">
+the "proxy_add_x_forwarded_for" is canceled and must be replaced with
+<nobr>the "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for"</nobr>
+directive.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á proxy_set_x_url ÕÐÒÁÚÄÎÅÎÁ É ÄÏÌÖÎÁ ÂÙÔØ ÚÁÍÅÎÅÎÁ ÄÉÒÅËÔÉ×ÏÊ
+<nobr>"proxy_set_header X-URL http://$host:$server_port$request_uri".</nobr>
+</para>
+<para lang="en">
+the "proxy_set_x_url" is canceled and must be replaced with
+the "proxy_set_header X-URL http://$host:$server_port$request_uri"
+directive.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á fastcgi_param.
+</para>
+<para lang="en">
+the "fastcgi_param" directive.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Ù fastcgi_set_var É fastcgi_params ÕÐÒÁÚÄÎÅÎÙ É ÄÏÌÖÎÙ ÂÙÔØ
+ÚÁÍÅÎÙ ÄÉÒÅËÔÉ×ÁÍÉ fastcgi_param.
+</para>
+<para lang="en">
+the "fastcgi_set_var" and "fastcgi_params" directive are canceled and
+must be replaced with the fastcgi_param directives.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á index ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÐÅÒÅÍÅÎÎÙÅ.
+</para>
+<para lang="en">
+the "index" directive can use the variables.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á index ÍÏÖÅÔ ÂÙÔØ ÕËÁÚÁÎÁ ÎÁ ÕÒÏ×ÎÅ http É server.
+</para>
+<para lang="en">
+the "index" directive can be used at http and server levels.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+ÔÏÌØËÏ ÐÏÓÌÅÄÎÉÊ ÐÁÒÁÍÅÔÒ × ÄÉÒÅËÔÉ×Å index ÍÏÖÅÔ ÂÙÔØ ÁÂÓÏÌÀÔÎÙÍ.
+</para>
+<para lang="en">
+the last index only in the "index" directive can be absolute.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+× ÄÉÒÅËÔÉ×Å rewrite ÍÏÇÕÔ ÉÓÐÏÌØÚÏ×ÁÔØÓÑ ÐÅÒÅÍÅÎÎÙÅ.
+</para>
+<para lang="en">
+the "rewrite" directive can use the variables.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á internal.
+</para>
+<para lang="en">
+the "internal" directive.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÐÅÒÅÍÅÎÎÙÅ CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR,
+SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME,
+REQUEST_METHOD, REQUEST_URI É REMOTE_USER.
+</para>
+<para lang="en">
+the CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR,
+SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME,
+REQUEST_METHOD, REQUEST_URI, and REMOTE_USER variables.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+nginx ÔÅÐÅÒØ ÐÅÒÅÄÁ£Ô ÎÅ×ÅÒÎÙÅ ÓÔÒÏËÉ × ÚÁÇÏÌÏ×ËÁÈ ÚÁÐÒÏÓÁ ËÌÉÅÎÔÁ É
+ÏÔ×ÅÔÁ ÂÜËÅÎÄÁ.
+</para>
+<para lang="en">
+nginx now passes the invalid lines in a client request headers
+or a backend response header.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÅÓÌÉ ÂÜËÅÎÄ ÄÏÌÇÏ ÎÅ ÐÅÒÅÄÁ×ÁÌ ÏÔ×ÅÔ É send_timeout ÂÙÌ ÍÅÎØÛÅ, ÞÅÍ
+proxy_read_timeout, ÔÏ ËÌÉÅÎÔÕ ×ÏÚ×ÒÁÝÁÌÓÑ ÏÔ×ÅÔ 408.
+</para>
+<para lang="en">
+if the backend did not transfer response for a long time and
+the "send_timeout" was less than "proxy_read_timeout", then nginx
+returned the 408 response.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÅÓÌÉ ÂÜËÅÎÄ ÐÅÒÅÄÁ×ÁÌ ÎÅ×ÅÒÎÕÀ ÓÔÒÏËÕ × ÚÁÇÏÌÏ×ËÅ ÏÔ×ÅÔÁ, ÔÏ ÐÒÏÉÓÈÏÄÉÌ
+segmentation fault;
+ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.1.26.
+</para>
+<para lang="en">
+the segmentation fault was occurred if the backend sent an invalid line
+in response header;
+bug appeared in 0.1.26.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÏÔËÁÚÏÕÓÔÏÊÞÉ×ÏÊ ËÏÎÆÉÇÕÒÁÃÉÉ × FastCGI ÍÏÇ
+ÐÒÏÉÓÈÏÄÉÔØ segmentation fault.
+</para>
+<para lang="en">
+the segmentation fault may occurred in FastCGI fault tolerance configuration.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á expires ÎÅ ÕÄÁÌÑÌÁ ÕÖÅ ÕÓÔÁÎÏ×ÌÅÎÎÙÅ ÓÔÒÏËÉ ÚÁÇÏÌÏ×ËÁ
+"Expires" É "Cache-Control".
+</para>
+<para lang="en">
+the "expires" directive did not remove the previous "Expires" and
+"Cache-Control" headers.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx ÎÅ ÕÞÉÔÙ×ÁÌ ÚÁ×ÅÒÛÁÀÝÕÀ ÔÏÞËÕ × ÓÔÒÏËÅ ÚÁÇÏÌÏ×ËÁ ÚÁÐÒÏÓÁ "Host".
+</para>
+<para lang="en">
+nginx did not take into account trailing dot in "Host" header line.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÍÏÄÕÌØ ngx_http_auth_module ÎÅ ÒÁÂÏÔÁÌ ÎÁ Linux.
+</para>
+<para lang="en">
+the ngx_http_auth_module did not work under Linux.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Á rewrite ÎÅ×ÅÒÎÏ ÒÁÂÏÔÁÌÁ, ÅÓÌÉ × ÚÁÐÒÏÓÅ ÐÒÉÓÕÔÓÔ×Ï×ÁÌÉ ÁÒÇÕÍÅÎÔÙ.
+</para>
+<para lang="en">
+the rewrite directive worked incorrectly, if the arguments were in a request.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÎÁ MacOS X.
+</para>
+<para lang="en">
+nginx could not be built on MacOS X.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="0.1.28" date="08.04.2005">
 
 <change type="bugfix">
@@ -586,7 +899,7 @@ the rewrite/location cycle and sets the 
 
 <changes ver="0.1.17" date="03.02.2005">
 
-<change type="feature">
+<change type="change">
 <para lang="ru">
 ÍÏÄÕÌØ ngx_http_rewrite_module ÐÏÌÎÏÓÔØÀ ÐÅÒÅÐÉÓÁÎ.
 ôÅÐÅÒØ ÍÏÖÎÏ ÄÅÌÁÔØ ÒÅÄÉÒÅËÔÙ, ×ÏÚ×ÒÁÝÁÔØ ËÏÄÙ ÏÛÉÂÏË
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -107,7 +107,7 @@ static ngx_core_module_t  ngx_core_modul
 
 
 ngx_module_t  ngx_core_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_core_module_ctx,                  /* module context */
     ngx_core_commands,                     /* module directives */
     NGX_CORE_MODULE,                       /* module type */
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.1.28"
+#define NGINX_VER          "nginx/0.1.29"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_NEWPID_EXT     ".newbin"
--- a/src/core/ngx_array.h
+++ b/src/core/ngx_array.h
@@ -30,16 +30,21 @@ void *ngx_array_push_n(ngx_array_t *a, n
 static ngx_inline ngx_int_t
 ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
 {
-    array->elts = ngx_palloc(pool, n * size);
-    if (array->elts == NULL) {
-        return NGX_ERROR;
-    }
+    /*
+     * set "array->nelts" before "array->elts", otherwise MSVC thinks
+     * that "array->nelts" may be used without having been initialized
+     */
 
     array->nelts = 0;
     array->size = size;
     array->nalloc = n;
     array->pool = pool;
 
+    array->elts = ngx_palloc(pool, n * size);
+    if (array->elts == NULL) {
+        return NGX_ERROR;
+    }
+
     return NGX_OK;
 }
 
--- a/src/core/ngx_buf.c
+++ b/src/core/ngx_buf.c
@@ -31,7 +31,7 @@ ngx_create_temp_buf(ngx_pool_t *pool, si
      *     b->file = NULL;
      *     b->shadow = NULL;
      *     b->tag = 0;
-     *
+     *     and flags
      */
 
     b->pos = b->start;
@@ -94,6 +94,7 @@ ngx_create_chain_of_bufs(ngx_pool_t *poo
          *     b->file = NULL;
          *     b->shadow = NULL;
          *     b->tag = 0;
+         *     and flags
          *
          */
 
--- a/src/core/ngx_buf.h
+++ b/src/core/ngx_buf.h
@@ -44,7 +44,9 @@ struct ngx_buf_s {
     unsigned         recycled:1;
     unsigned         in_file:1;
     unsigned         flush:1;
+    unsigned         sync:1;
     unsigned         last_buf:1;
+    unsigned         last_in_chain:1;
 
     unsigned         last_shadow:1;
     unsigned         temp_file:1;
@@ -104,7 +106,8 @@ typedef struct {
 #define ngx_buf_in_memory(b)        (b->temporary || b->memory || b->mmap)
 #define ngx_buf_in_memory_only(b)   (ngx_buf_in_memory(b) && !b->in_file)
 #define ngx_buf_special(b)                                                   \
-    ((b->flush || b->last_buf) && !ngx_buf_in_memory(b) && !b->in_file)
+    ((b->flush || b->last_buf || b->sync)                                    \
+     && !ngx_buf_in_memory(b) && !b->in_file)
 
 #define ngx_buf_size(b)                                                      \
     (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos):                      \
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -27,7 +27,7 @@ static ngx_command_t  ngx_conf_commands[
 
 
 ngx_module_t  ngx_conf_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     NULL,                                  /* module context */
     ngx_conf_commands,                     /* module directives */
     NGX_CONF_MODULE,                       /* module type */
@@ -336,7 +336,7 @@ ngx_conf_read_token(ngx_conf_t *cf)
 {
     u_char      *start, ch, *src, *dst;
     int          len;
-    int          found, need_space, last_space, sharp_comment;
+    int          found, need_space, last_space, sharp_comment, variable;
     int          quoted, s_quoted, d_quoted;
     ssize_t      n;
     ngx_str_t   *word;
@@ -346,6 +346,7 @@ ngx_conf_read_token(ngx_conf_t *cf)
     need_space = 0;
     last_space = 1;
     sharp_comment = 0;
+    variable = 0;
     quoted = s_quoted = d_quoted = 0;
 
     cf->args->nelts = 0;
@@ -492,11 +493,22 @@ ngx_conf_read_token(ngx_conf_t *cf)
             }
 
         } else {
+            if (ch == '{' && variable) {
+                continue;
+            }
+
+            variable = 0;
+
             if (ch == '\\') {
                 quoted = 1;
                 continue;
             }
 
+            if (ch == '$') {
+                variable = 1;
+                continue;
+            }
+
             if (d_quoted) {
                 if (ch == '"') {
                     d_quoted = 0;
@@ -802,6 +814,45 @@ ngx_conf_set_str_slot(ngx_conf_t *cf, ng
 
 
 char *
+ngx_conf_set_table_elt_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char  *p = conf;
+
+    ngx_str_t         *value;
+    ngx_array_t      **a;
+    ngx_table_elt_t   *elt;
+    ngx_conf_post_t   *post;
+
+    a = (ngx_array_t **) (p + cmd->offset);
+
+    if (*a == NULL) {
+        *a = ngx_array_create(cf->pool, 4, sizeof(ngx_table_elt_t));
+        if (*a == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    elt = ngx_array_push(*a);
+    if (elt == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    elt->hash = 0;
+    elt->key = value[1];
+    elt->value = value[2];
+
+    if (cmd->post) {
+        post = cmd->post;
+        return post->post_handler(cf, post, elt);
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+char *
 ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char  *p = conf;
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -63,7 +63,7 @@
 #define NGX_CONF_BLOCK_DONE  2
 #define NGX_CONF_FILE_DONE   3
 
-#define NGX_MODULE           0, 0
+#define NGX_MODULE_V1        0, 0, 1, 0, 0
 
 #define NGX_CORE_MODULE      0x45524F43  /* "CORE" */
 #define NGX_CONF_MODULE      0x464E4F43  /* "CONF" */
@@ -100,6 +100,10 @@ struct ngx_open_file_s {
 struct ngx_module_s {
     ngx_uint_t            ctx_index;
     ngx_uint_t            index;
+    ngx_uint_t            version;
+    ngx_uint_t            spare0;
+    ngx_uint_t            spare1;
+
     void                 *ctx;
     ngx_command_t        *commands;
     ngx_uint_t            type;
@@ -280,6 +284,8 @@ void ngx_cdecl ngx_conf_log_error(ngx_ui
 
 char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_table_elt_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 char *ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -517,7 +517,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t 
         ngx_old_cycles.nalloc = n;
         ngx_old_cycles.pool = ngx_temp_pool;
 
-        ngx_cleaner_event.event_handler = ngx_clean_old_cycles;
+        ngx_cleaner_event.handler = ngx_clean_old_cycles;
         ngx_cleaner_event.log = cycle->log;
         ngx_cleaner_event.data = &dumb;
         dumb.fd = (ngx_socket_t) -1;
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -38,8 +38,10 @@ ngx_int_t
 ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
     int persistent)
 {
-    ngx_err_t           err;
-    ngx_atomic_uint_t   n;
+    ngx_err_t                 err;
+    ngx_atomic_uint_t         n;
+    ngx_pool_cleanup_file_t  *cln;
+
 
     file->name.len = path->name.len + 1 + path->len + NGX_ATOMIC_T_LEN;
 
@@ -74,6 +76,20 @@ ngx_create_temp_file(ngx_file_t *file, n
                        "temp fd:%d", file->fd);
 
         if (file->fd != NGX_INVALID_FILE) {
+            cln = ngx_palloc(pool, sizeof(ngx_pool_cleanup_file_t));
+            if (cln == NULL) {
+                return NGX_ERROR; 
+            }
+
+            cln->fd = file->fd;
+            cln->name = file->name.data;
+            cln->log = pool->log;
+
+            if (ngx_pool_cleanup_add(pool, ngx_pool_cleanup_file, cln) == NULL)
+            {
+                return NGX_ERROR;
+            }
+
             return NGX_OK;
         }
 
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -9,11 +9,20 @@
 
 
 ngx_int_t
-ngx_hash_init(ngx_hash_t *hash, ngx_pool_t *pool, void *names)
+ngx_hash_init(ngx_hash_t *hash, ngx_pool_t *pool, void *names, ngx_uint_t nelts)
 {
     u_char      *p;
-    ngx_str_t   *n, *bucket;
-    ngx_uint_t   i, key, size, best, *test, buckets, min_buckets;
+    ngx_str_t   *name, *bucket;
+    ngx_uint_t   i, n, key, size, best, *test, buckets, min_buckets;
+
+    if (nelts == 0) {
+        for (name = (ngx_str_t *) names;
+             name->len;
+             name = (ngx_str_t *) ((char *) name + hash->bucket_size))
+        {
+            nelts++;
+        }
+    }
 
     test = ngx_alloc(hash->max_size * sizeof(ngx_uint_t), pool->log);
     if (test == NULL) {
@@ -34,14 +43,14 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool
             test[i] = 0;
         }
 
-        for (n = (ngx_str_t *) names;
-             n->len;
-             n = (ngx_str_t *) ((char *) n + hash->bucket_size))
+        for (n = 0, name = (ngx_str_t *) names;
+             n < nelts;
+             n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
         {
             key = 0;
 
-            for (i = 0; i < n->len; i++) {
-                key += ngx_tolower(n->data[i]);
+            for (i = 0; i < name->len; i++) {
+                key += ngx_tolower(name->data[i]);
             }
 
             key %= size;
@@ -57,7 +66,7 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool
             }
         }
 
-        if (n->len == 0) {
+        if (n == nelts) {
             if (min_buckets > buckets) {
                 min_buckets = buckets;
                 best = size;
@@ -91,14 +100,14 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool
             test[i] = 0;
         }
 
-        for (n = (ngx_str_t *) names;
-             n->len;
-             n = (ngx_str_t *) ((char *) n + hash->bucket_size))
+        for (n = 0, name = (ngx_str_t *) names;
+             n < nelts;
+             n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
         {
             key = 0;
 
-            for (i = 0; i < n->len; i++) {
-                key += ngx_tolower(n->data[i]);
+            for (i = 0; i < name->len; i++) {
+                key += ngx_tolower(name->data[i]);
             }
 
             key %= best;
@@ -122,21 +131,21 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool
         }
     }
 
-    for (n = (ngx_str_t *) names;
-         n->len;
-         n = (ngx_str_t *) ((char *) n + hash->bucket_size))
+    for (n = 0, name = (ngx_str_t *) names;
+         n < nelts;
+         n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
     {
         key = 0;
 
-        for (i = 0; i < n->len; i++) {
-            key += ngx_tolower(n->data[i]);
+        for (i = 0; i < name->len; i++) {
+            key += ngx_tolower(name->data[i]);
         }
 
         key %= best;
 
         if (hash->bucket_limit == 1) {
             p = (u_char *) hash->buckets + key * hash->bucket_size;
-            ngx_memcpy(p, n, hash->bucket_size);
+            ngx_memcpy(p, name, hash->bucket_size);
             continue;
         }
 
@@ -147,7 +156,7 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool
             bucket->len &= 0x7fffffff;
         }
 
-        ngx_memcpy(bucket, n, hash->bucket_size);
+        ngx_memcpy(bucket, name, hash->bucket_size);
         bucket->len |= 0x80000000;
     }
 
--- a/src/core/ngx_hash.h
+++ b/src/core/ngx_hash.h
@@ -31,7 +31,8 @@ typedef struct {
 } ngx_table_elt_t;
 
 
-ngx_int_t ngx_hash_init(ngx_hash_t *hash, ngx_pool_t *pool, void *names);
+ngx_int_t ngx_hash_init(ngx_hash_t *hash, ngx_pool_t *pool, void *names,
+    ngx_uint_t nelts);
 
 
 #endif /* _NGX_HASH_H_INCLUDED_ */
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -21,7 +21,8 @@
  */
 
 
-static ngx_inline size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len)
+static
+ngx_inline size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len)
 {
     size_t      n;
     ngx_uint_t  c1, c2;
@@ -65,8 +66,8 @@ static ngx_inline size_t ngx_sprint_ucha
 
 /* AF_INET only */
 
-size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text,
-                     size_t len)
+size_t
+ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len)
 {
     u_char              *p;
     size_t               n;
@@ -119,7 +120,8 @@ size_t ngx_sock_ntop(int family, struct 
     return n;
 }
 
-size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len)
+size_t
+ngx_inet_ntop(int family, void *addr, u_char *text, size_t len)
 {
     u_char      *p;
     size_t       n;
@@ -173,7 +175,8 @@ size_t ngx_inet_ntop(int family, void *a
 
 /* AF_INET only */
 
-ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr)
+ngx_int_t
+ngx_ptocidr(ngx_str_t *text, void *cidr)
 {
     ngx_int_t         m;
     ngx_uint_t        i;
@@ -217,7 +220,8 @@ ngx_int_t ngx_ptocidr(ngx_str_t *text, v
 }
 
 
-ngx_peers_t *ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u)
+ngx_peers_t *
+ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u)
 {
     char                *err;
     u_char              *host;
@@ -392,7 +396,8 @@ ngx_peers_t *ngx_inet_upstream_parse(ngx
 }
 
 
-char *ngx_inet_parse_host_port(ngx_inet_upstream_t *u)
+char *
+ngx_inet_parse_host_port(ngx_inet_upstream_t *u)
 {
     size_t      i;
     ngx_int_t   port;
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -33,7 +33,7 @@ static ngx_core_module_t  ngx_errlog_mod
 
 
 ngx_module_t  ngx_errlog_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_errlog_module_ctx,                /* module context */
     ngx_errlog_commands,                   /* module directives */
     NGX_CORE_MODULE,                       /* module type */
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -49,7 +49,7 @@ ngx_output_chain(ngx_output_chain_ctx_t 
 #if (NGX_SENDFILE_LIMIT)
             && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT)
 #endif
-            && (!ngx_output_chain_need_to_copy(ctx, in->buf)))
+            && !ngx_output_chain_need_to_copy(ctx, in->buf))
         {
             return ctx->output_filter(ctx->filter_ctx, in);
         }
@@ -132,7 +132,7 @@ ngx_output_chain(ngx_output_chain_ctx_t 
 
                     size = ctx->bufs.size;
 
-                    if (ctx->in->buf->last_buf) {
+                    if (ctx->in->buf->last_in_chain) {
 
                         if (bsize < (off_t) ctx->bufs.size) {
 
@@ -202,6 +202,11 @@ ngx_output_chain(ngx_output_chain_ctx_t 
         }
 
         if (out == NULL && last != NGX_NONE) {
+
+            if (ctx->in) {
+                return NGX_AGAIN;
+            }
+
             return last;
         }
 
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -23,6 +23,7 @@ ngx_create_pool(size_t size, ngx_log_t *
     p->next = NULL;
     p->large = NULL;
     p->chain = NULL;
+    p->cleanup = NULL;
     p->log = log;
 
     return p;
@@ -32,8 +33,15 @@ ngx_create_pool(size_t size, ngx_log_t *
 void
 ngx_destroy_pool(ngx_pool_t *pool)
 {
-    ngx_pool_t        *p, *n;
-    ngx_pool_large_t  *l;
+    ngx_pool_t          *p, *n;
+    ngx_pool_large_t    *l;
+    ngx_pool_cleanup_t  *c;
+
+    for (c = pool->cleanup; c; c = c->next) {
+        if (c->handler) {
+            c->handler(c->data);
+        }
+    }
 
     for (l = pool->large; l; l = l->next) {
 
@@ -197,6 +205,39 @@ ngx_pcalloc(ngx_pool_t *pool, size_t siz
     return p;
 }
 
+
+ngx_pool_cleanup_t *
+ngx_pool_cleanup_add(ngx_pool_t *p, ngx_pool_cleanup_pt handler, void *data)
+{
+    ngx_pool_cleanup_t  *c;
+
+    c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
+    if (c == NULL) {
+        return NULL;
+    }
+
+    c->handler = handler;
+    c->data = data;
+    c->next = p->cleanup;
+
+    p->cleanup = c;
+
+    return c;
+}
+
+
+void
+ngx_pool_cleanup_file(void *data)
+{
+    ngx_pool_cleanup_file_t  *c = data;
+
+    if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
+                      ngx_close_file_n " \"%s\" failed", c->name);
+    }
+}
+
+
 #if 0
 
 static void *
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -22,24 +22,44 @@
 #define NGX_DEFAULT_POOL_SIZE   (16 * 1024)
 
 
+typedef void (*ngx_pool_cleanup_pt)(void *data);
+
+typedef struct ngx_pool_cleanup_s  ngx_pool_cleanup_t;
+
+struct ngx_pool_cleanup_s {
+    ngx_pool_cleanup_pt   handler;
+    void                 *data;
+    ngx_pool_cleanup_t   *next;
+};
+
+
 typedef struct ngx_pool_large_s  ngx_pool_large_t;
 
 struct ngx_pool_large_s {
-    ngx_pool_large_t  *next;
-    void              *alloc;
+    ngx_pool_large_t     *next;
+    void                 *alloc;
 };
 
 
 struct ngx_pool_s {
-    u_char            *last;
-    u_char            *end;
-    ngx_chain_t       *chain;
-    ngx_pool_t        *next;
-    ngx_pool_large_t  *large;
-    ngx_log_t         *log;
+    u_char               *last;
+    u_char               *end;
+    ngx_chain_t          *chain;
+    ngx_pool_t           *next;
+    ngx_pool_large_t     *large;
+    ngx_pool_cleanup_t   *cleanup;
+    ngx_log_t            *log;
 };
 
 
+typedef struct {
+    ngx_fd_t              fd;
+    u_char               *name;
+    ngx_log_t            *log;
+} ngx_pool_cleanup_file_t;
+
+
+
 void *ngx_alloc(size_t size, ngx_log_t *log);
 void *ngx_calloc(size_t size, ngx_log_t *log);
 
@@ -51,4 +71,9 @@ void *ngx_pcalloc(ngx_pool_t *pool, size
 ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);
 
 
+ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p,
+    ngx_pool_cleanup_pt handler, void *data);
+void ngx_pool_cleanup_file(void *data);
+
+
 #endif /* _NGX_PALLOC_H_INCLUDED_ */
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -12,8 +12,9 @@ ngx_epoch_msec_t  ngx_elapsed_msec;
 ngx_epoch_msec_t  ngx_old_elapsed_msec;
 ngx_epoch_msec_t  ngx_start_msec;
 
+ngx_int_t  ngx_gmtoff;
+
 static ngx_tm_t   ngx_cached_gmtime;
-static ngx_int_t  ngx_gmtoff;
 
 
 /*
--- a/src/core/ngx_times.h
+++ b/src/core/ngx_times.h
@@ -53,6 +53,7 @@ extern ngx_epoch_msec_t  ngx_elapsed_mse
  */
 extern ngx_epoch_msec_t  ngx_old_elapsed_msec;
 
+extern ngx_int_t         ngx_gmtoff;
 
 
 #endif /* _NGX_TIMES_H_INCLUDED_ */
--- a/src/core/ngx_unix_domain.c
+++ b/src/core/ngx_unix_domain.c
@@ -14,8 +14,8 @@
 #undef sun
 
 
-ngx_peers_t *ngx_unix_upstream_parse(ngx_conf_t *cf,
-                                     ngx_unix_domain_upstream_t *u)
+ngx_peers_t *
+ngx_unix_upstream_parse(ngx_conf_t *cf, ngx_unix_domain_upstream_t *u)
 {
     size_t               len;
     ngx_uint_t           i;
--- a/src/event/modules/ngx_aio_module.c
+++ b/src/event/modules/ngx_aio_module.c
@@ -54,7 +54,7 @@ ngx_event_module_t  ngx_aio_module_ctx =
 };
 
 ngx_module_t  ngx_aio_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_aio_module_ctx,                   /* module context */
     NULL,                                  /* module directives */
     NGX_EVENT_MODULE,                      /* module type */
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -91,7 +91,7 @@ ngx_event_module_t  ngx_devpoll_module_c
 };
 
 ngx_module_t  ngx_devpoll_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_devpoll_module_ctx,               /* module context */
     ngx_devpoll_commands,                  /* module directives */
     NGX_EVENT_MODULE,                      /* module type */
@@ -511,7 +511,7 @@ ngx_devpoll_process_events(ngx_cycle_t *
             wev->ready = 1;
 
             if (!ngx_threaded && !ngx_accept_mutex_held) {
-                wev->event_handler(wev);
+                wev->handler(wev);
 
             } else {
                 ngx_post_event(wev);
@@ -530,7 +530,7 @@ ngx_devpoll_process_events(ngx_cycle_t *
             rev->ready = 1;
 
             if (!ngx_threaded && !ngx_accept_mutex_held) {
-                rev->event_handler(rev);
+                rev->handler(rev);
 
             } else if (!rev->accept) {
                 ngx_post_event(rev);
@@ -538,7 +538,7 @@ ngx_devpoll_process_events(ngx_cycle_t *
             } else if (ngx_accept_disabled <= 0) {
                 ngx_mutex_unlock(ngx_posted_events_mutex);
 
-                c->read->event_handler(rev);
+                c->read->handler(rev);
 
                 if (ngx_accept_disabled > 0) { 
                     ngx_accept_mutex_unlock();
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -121,7 +121,7 @@ ngx_event_module_t  ngx_epoll_module_ctx
 };
 
 ngx_module_t  ngx_epoll_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_epoll_module_ctx,               /* module context */
     ngx_epoll_commands,                  /* module directives */
     NGX_EVENT_MODULE,                    /* module type */
@@ -573,7 +573,7 @@ ngx_epoll_process_events(ngx_cycle_t *cy
                 wev->ready = 1;
 
                 if (!ngx_accept_mutex_held) {
-                    wev->event_handler(wev);
+                    wev->handler(wev);
 
                 } else {
                     ngx_post_event(wev);
@@ -600,7 +600,7 @@ ngx_epoll_process_events(ngx_cycle_t *cy
             rev->ready = 1;
 
             if (!ngx_threaded && !ngx_accept_mutex_held) {
-                rev->event_handler(rev);
+                rev->handler(rev);
 
             } else if (!rev->accept) {
                 ngx_post_event(rev);
@@ -609,7 +609,7 @@ ngx_epoll_process_events(ngx_cycle_t *cy
 
                 ngx_mutex_unlock(ngx_posted_events_mutex);
 
-                rev->event_handler(rev);
+                rev->handler(rev);
 
                 if (ngx_accept_disabled > 0) {
                     ngx_accept_mutex_unlock();
--- a/src/event/modules/ngx_iocp_module.c
+++ b/src/event/modules/ngx_iocp_module.c
@@ -69,7 +69,7 @@ ngx_event_module_t  ngx_iocp_module_ctx 
 };
 
 ngx_module_t  ngx_iocp_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_iocp_module_ctx,                  /* module context */
     ngx_iocp_commands,                     /* module directives */
     NGX_EVENT_MODULE,                      /* module type */
@@ -294,9 +294,9 @@ ngx_int_t ngx_iocp_process_events(ngx_cy
     ev->available = bytes;
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
-                   "iocp event handler: %p", ev->event_handler);
+                   "iocp event handler: %p", ev->handler);
 
-    ev->event_handler(ev);
+    ev->handler(ev);
 
     if (timer != INFINITE && delta) {
         ngx_event_expire_timers((ngx_msec_t) delta);
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -94,7 +94,7 @@ ngx_event_module_t  ngx_kqueue_module_ct
 };
 
 ngx_module_t  ngx_kqueue_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_kqueue_module_ctx,                /* module context */
     ngx_kqueue_commands,                   /* module directives */
     NGX_EVENT_MODULE,                      /* module type */
@@ -192,11 +192,13 @@ ngx_kqueue_init(ngx_cycle_t *cycle)
     ngx_event_actions = ngx_kqueue_module_ctx.actions;
 
     ngx_event_flags = NGX_USE_ONESHOT_EVENT
+#if 1
 #if (NGX_HAVE_CLEAR_EVENT)
                      |NGX_USE_CLEAR_EVENT
 #else
                      |NGX_USE_LEVEL_EVENT
 #endif
+#endif
 #if (NGX_HAVE_LOWAT_EVENT)
                      |NGX_USE_LOWAT_EVENT
 #endif
@@ -615,6 +617,10 @@ ngx_kqueue_process_events(ngx_cycle_t *c
                 ngx_kqueue_dump_event(ev->log, &event_list[i]);
             }
 
+            if (ev->oneshot) {
+                ev->active = 0;
+            }
+
 #if (NGX_THREADS)
 
             if (ngx_threaded && !ev->accept) {
@@ -663,7 +669,7 @@ ngx_kqueue_process_events(ngx_cycle_t *c
         }
 
         if (!ngx_threaded && !ngx_accept_mutex_held) {
-            ev->event_handler(ev);
+            ev->handler(ev);
             continue;
         }
 
@@ -678,7 +684,7 @@ ngx_kqueue_process_events(ngx_cycle_t *c
 
         ngx_mutex_unlock(ngx_posted_events_mutex);
 
-        ev->event_handler(ev);
+        ev->handler(ev);
 
         if (ngx_accept_disabled > 0) {
             ngx_accept_mutex_unlock();
--- a/src/event/modules/ngx_poll_module.c
+++ b/src/event/modules/ngx_poll_module.c
@@ -50,7 +50,7 @@ ngx_event_module_t  ngx_poll_module_ctx 
 };
 
 ngx_module_t  ngx_poll_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_poll_module_ctx,                  /* module context */
     NULL,                                  /* module directives */
     NGX_EVENT_MODULE,                      /* module type */
@@ -536,7 +536,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc
             }
         }
 
-        ev->event_handler(ev);
+        ev->handler(ev);
     }
 #endif
 
@@ -553,7 +553,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc
 
         ngx_mutex_unlock(ngx_posted_events_mutex);
 
-        ev->event_handler(ev);
+        ev->handler(ev);
 
         if (ngx_accept_disabled > 0) {
             lock = 0;
--- a/src/event/modules/ngx_rtsig_module.c
+++ b/src/event/modules/ngx_rtsig_module.c
@@ -118,7 +118,7 @@ ngx_event_module_t  ngx_rtsig_module_ctx
 };
 
 ngx_module_t  ngx_rtsig_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_rtsig_module_ctx,               /* module context */
     ngx_rtsig_commands,                  /* module directives */
     NGX_EVENT_MODULE,                    /* module type */
@@ -461,11 +461,11 @@ ngx_rtsig_process_events(ngx_cycle_t *cy
                     rev->ready = 1;
 
                     if (!ngx_threaded && !ngx_accept_mutex_held) {
-                        rev->event_handler(rev);
+                        rev->handler(rev);
 
                     } else if (rev->accept) {
                         if (ngx_accept_disabled <= 0) {
-                            rev->event_handler(rev);
+                            rev->handler(rev);
                         }
 
                     } else {
@@ -495,7 +495,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy
                     wev->ready = 1;
 
                     if (!ngx_threaded && !ngx_accept_mutex_held) {
-                        wev->event_handler(wev);
+                        wev->handler(wev);
 
                     } else {
                         ngx_post_event(wev);
@@ -598,11 +598,11 @@ ngx_rtsig_process_overflow(ngx_cycle_t *
 
             events = 0;
 
-            if (c->read->active && c->read->event_handler) {
+            if (c->read->active && c->read->handler) {
                 events |= POLLIN;
             }
 
-            if (c->write->active && c->write->event_handler) {
+            if (c->write->active && c->write->handler) {
                 events |= POLLOUT;
             }
 
@@ -652,7 +652,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t *
 
             if (rev->active
                 && !rev->closed
-                && rev->event_handler
+                && rev->handler
                 && (overflow_list[i].revents
                                           & (POLLIN|POLLERR|POLLHUP|POLLNVAL)))
             {
@@ -664,7 +664,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t *
 
                 } else {
                     rev->ready = 1;
-                    rev->event_handler(rev); 
+                    rev->handler(rev); 
                 }
             }
 
@@ -672,7 +672,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t *
 
             if (wev->active
                 && !wev->closed
-                && wev->event_handler
+                && wev->handler
                 && (overflow_list[i].revents
                                          & (POLLOUT|POLLERR|POLLHUP|POLLNVAL)))
             {
@@ -684,7 +684,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t *
 
                 } else {
                     wev->ready = 1;
-                    wev->event_handler(wev); 
+                    wev->handler(wev); 
                 }
             }
         }
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -63,7 +63,7 @@ ngx_event_module_t  ngx_select_module_ct
 };
 
 ngx_module_t  ngx_select_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_select_module_ctx,                /* module context */
     NULL,                                  /* module directives */
     NGX_EVENT_MODULE,                      /* module type */
@@ -540,7 +540,7 @@ ngx_select_process_events(ngx_cycle_t *c
             }
         }
 
-        ev->event_handler(ev);
+        ev->handler(ev);
     }
 #endif
 
@@ -557,7 +557,7 @@ ngx_select_process_events(ngx_cycle_t *c
 
         ngx_mutex_unlock(ngx_posted_events_mutex);
 
-        ev->event_handler(ev);
+        ev->handler(ev);
 
         if (ngx_accept_disabled > 0) {
             lock = 0;
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -24,10 +24,10 @@ static ngx_int_t ngx_event_process_init(
 static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 static char *ngx_event_connections(ngx_conf_t *cf, ngx_command_t *cmd,
-                                   void *conf);
+    void *conf);
 static char *ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd,
-                                        void *conf);
+    void *conf);
 
 static void *ngx_event_create_conf(ngx_cycle_t *cycle);
 static char *ngx_event_init_conf(ngx_cycle_t *cycle, void *conf);
@@ -91,7 +91,7 @@ static ngx_core_module_t  ngx_events_mod
 
 
 ngx_module_t  ngx_events_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_events_module_ctx,                /* module context */
     ngx_events_commands,                   /* module directives */
     NGX_CORE_MODULE,                       /* module type */
@@ -163,7 +163,7 @@ ngx_event_module_t  ngx_event_core_modul
 
 
 ngx_module_t  ngx_event_core_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_event_core_module_ctx,            /* module context */
     ngx_event_core_commands,               /* module directives */
     NGX_EVENT_MODULE,                      /* module type */
@@ -172,7 +172,143 @@ ngx_module_t  ngx_event_core_module = {
 };
 
 
-static ngx_int_t ngx_event_module_init(ngx_cycle_t *cycle)
+ngx_int_t
+ngx_handle_read_event(ngx_event_t *rev, u_int flags)
+{
+    if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
+    
+        /* kqueue, epoll */
+
+        if (!rev->active && !rev->ready) {
+            if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT)
+                == NGX_ERROR)
+            {
+                return NGX_ERROR;
+            }
+        }
+    
+        return NGX_OK;
+
+    } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
+
+        /* select, poll, /dev/poll */
+
+        if (!rev->active && !rev->ready) {
+            if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT)
+                == NGX_ERROR)
+            {
+                return NGX_ERROR;
+            }
+
+            return NGX_OK;
+        }
+
+        if (rev->active && (rev->ready || (flags & NGX_CLOSE_EVENT))) {
+            if (ngx_del_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT | flags)
+                == NGX_ERROR)
+            {
+                return NGX_ERROR;
+            }
+
+            return NGX_OK;
+        }
+
+    } else if (ngx_event_flags & NGX_USE_ONESHOT_EVENT) {
+
+        /* event ports */
+
+        if (!rev->active) {
+            if (ngx_add_event(rev, NGX_READ_EVENT, NGX_ONESHOT_EVENT)
+                == NGX_ERROR)
+            {
+                return NGX_ERROR;
+            }
+        }
+    
+        return NGX_OK;
+    }
+
+    /* aio, iocp, rtsig */
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_handle_write_event(ngx_event_t *wev, size_t lowat)
+{
+    ngx_connection_t  *c;
+
+    if (lowat) {
+        c = (ngx_connection_t *) wev->data;
+
+        if (ngx_send_lowat(c, lowat) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+    }
+
+    if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
+
+        /* kqueue, epoll */
+
+        if (!wev->active && !wev->ready) {
+            if (ngx_add_event(wev, NGX_WRITE_EVENT,
+                              NGX_CLEAR_EVENT | (lowat ? NGX_LOWAT_EVENT : 0))
+                == NGX_ERROR)
+            {
+                return NGX_ERROR;
+            }
+        }
+
+        return NGX_OK;
+
+    } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
+
+        /* select, poll, /dev/poll */
+
+        if (!wev->active && !wev->ready) {
+            if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT)
+                == NGX_ERROR)
+            {
+                return NGX_ERROR;
+            }
+
+            return NGX_OK;
+        }
+
+        if (wev->active && wev->ready) {
+            if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT)
+                == NGX_ERROR)
+            {
+                return NGX_ERROR;
+            }
+
+            return NGX_OK;
+        }
+
+    } else if (ngx_event_flags & NGX_USE_ONESHOT_EVENT) {
+
+        /* event ports */
+
+        if (!wev->active) {
+            if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_ONESHOT_EVENT)
+                == NGX_ERROR)
+            {
+                return NGX_ERROR;
+            }
+        }
+    
+        return NGX_OK;
+    }
+
+    /* aio, iocp, rtsig */
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_event_module_init(ngx_cycle_t *cycle)
 {
 #if !(NGX_WIN32)
 
@@ -248,7 +384,8 @@ static ngx_int_t ngx_event_module_init(n
 }
 
 
-static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle)
+static ngx_int_t
+ngx_event_process_init(ngx_cycle_t *cycle)
 {
     ngx_uint_t           m, i;
     ngx_socket_t         fd;
@@ -417,7 +554,7 @@ static ngx_int_t ngx_event_process_init(
 #if (NGX_WIN32)
 
         if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
-            rev->event_handler = ngx_event_acceptex;
+            rev->handler = ngx_event_acceptex;
 
             if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) {
                 return NGX_ERROR;
@@ -431,7 +568,7 @@ static ngx_int_t ngx_event_process_init(
             }
 
         } else {
-            rev->event_handler = ngx_event_accept;
+            rev->handler = ngx_event_accept;
 
             if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
                 return NGX_ERROR;
@@ -440,7 +577,7 @@ static ngx_int_t ngx_event_process_init(
 
 #else
 
-        rev->event_handler = ngx_event_accept;
+        rev->handler = ngx_event_accept;
 
         if (ngx_accept_mutex) {
             continue;
@@ -464,7 +601,8 @@ static ngx_int_t ngx_event_process_init(
 }
 
 
-ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat)
+ngx_int_t
+ngx_send_lowat(ngx_connection_t *c, size_t lowat)
 {
     int  sndlowat;
 
@@ -497,7 +635,8 @@ ngx_int_t ngx_send_lowat(ngx_connection_
 }
 
 
-static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+static char *
+ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char                 *rv;
     void               ***ctx;
@@ -574,8 +713,8 @@ static char *ngx_events_block(ngx_conf_t
 }
 
 
-static char *ngx_event_connections(ngx_conf_t *cf, ngx_command_t *cmd,
-                                   void *conf)
+static char *
+ngx_event_connections(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_event_conf_t  *ecf = conf;
 
@@ -600,7 +739,8 @@ static char *ngx_event_connections(ngx_c
 }
 
 
-static char *ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+static char *
+ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_event_conf_t  *ecf = conf;
 
@@ -662,8 +802,8 @@ static char *ngx_event_use(ngx_conf_t *c
 }
 
 
-static char *ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd,
-                                        void *conf)
+static char *
+ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
 #if (NGX_DEBUG)
     ngx_event_conf_t  *ecf = conf;
@@ -709,7 +849,8 @@ static char *ngx_event_debug_connection(
 }
 
 
-static void *ngx_event_create_conf(ngx_cycle_t *cycle)
+static void *
+ngx_event_create_conf(ngx_cycle_t *cycle)
 {
     ngx_event_conf_t  *ecf;
 
@@ -739,7 +880,8 @@ static void *ngx_event_create_conf(ngx_c
 }
 
 
-static char *ngx_event_init_conf(ngx_cycle_t *cycle, void *conf)
+static char *
+ngx_event_init_conf(ngx_cycle_t *cycle, void *conf)
 {
     ngx_event_conf_t  *ecf = conf;
 
@@ -874,7 +1016,8 @@ static char *ngx_event_init_conf(ngx_cyc
 }
 
 
-static char *ngx_accept_mutex_check(ngx_conf_t *cf, void *post, void *data)
+static char *
+ngx_accept_mutex_check(ngx_conf_t *cf, void *post, void *data)
 {
 #if !(NGX_HAVE_ATOMIC_OPS)
 
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -113,8 +113,7 @@ struct ngx_event_s {
     unsigned         available:1;
 #endif
 
-    /* TODO rename to handler */
-    ngx_event_handler_pt  event_handler;
+    ngx_event_handler_pt  handler;
 
 
 #if (NGX_HAVE_AIO)
@@ -474,6 +473,10 @@ ngx_int_t ngx_disable_accept_events(ngx_
 ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle);
 
 
+ngx_int_t ngx_handle_read_event(ngx_event_t *rev, u_int flags);
+ngx_int_t ngx_handle_write_event(ngx_event_t *wev, size_t lowat);
+
+
 #if (NGX_WIN32)
 void ngx_event_acceptex(ngx_event_t *ev);
 int ngx_event_post_acceptex(ngx_listening_t *ls, int n);
@@ -496,158 +499,4 @@ ngx_int_t ngx_send_lowat(ngx_connection_
 #endif
 
 
-
-static ngx_inline ngx_int_t ngx_handle_read_event(ngx_event_t *rev, u_int flags)
-{
-    if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
-
-        /* kqueue, epoll */
-
-        if (!rev->active && !rev->ready) {
-            if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT)
-                                                                == NGX_ERROR) {
-                return NGX_ERROR;
-            }
-        }
-
-        return NGX_OK;
-
-    } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
-
-        /* select, poll, /dev/poll */
-
-        if (!rev->active && !rev->ready) {
-            if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT)
-                                                                  == NGX_ERROR)
-            {
-                return NGX_ERROR;
-            }
-
-            return NGX_OK;
-        }
-
-        if (rev->active && (rev->ready || (flags & NGX_CLOSE_EVENT))) {
-            if (ngx_del_event(rev, NGX_READ_EVENT, flags) == NGX_ERROR) {
-                return NGX_ERROR;
-            }
-
-            return NGX_OK;
-        }
-    }
-
-    /* aio, iocp, rtsig */
-
-    return NGX_OK;
-}
-
-
-static ngx_inline ngx_int_t ngx_handle_level_read_event(ngx_event_t *rev)
-{
-    if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
-        if (!rev->active && !rev->ready) {
-            if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT)
-                                                                  == NGX_ERROR)
-            {
-                return NGX_ERROR;
-            }
-
-            return NGX_OK;
-        }
-
-        if (rev->active && rev->ready) {
-            if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
-                return NGX_ERROR;
-            }
-
-            return NGX_OK;
-        }
-    }
-
-    return NGX_OK;
-}
-
-
-static ngx_inline ngx_int_t ngx_handle_write_event(ngx_event_t *wev,
-                                                   size_t lowat)
-{
-    ngx_connection_t  *c;
-
-    if (lowat) {
-        c = (ngx_connection_t *) wev->data;
-
-        if (ngx_send_lowat(c, lowat) == NGX_ERROR) {
-            return NGX_ERROR;
-        }
-    }
-
-    if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
-
-        /* kqueue, epoll */
-
-        if (!wev->active && !wev->ready) {
-            if (ngx_add_event(wev, NGX_WRITE_EVENT,
-                              NGX_CLEAR_EVENT | (lowat ? NGX_LOWAT_EVENT : 0))
-                                                                  == NGX_ERROR)
-            {
-                return NGX_ERROR;
-            }
-        }
-
-        return NGX_OK;
-
-    } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
-
-        /* select, poll, /dev/poll */
-
-        if (!wev->active && !wev->ready) {
-            if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT)
-                                                                  == NGX_ERROR)
-            {
-                return NGX_ERROR;
-            }
-
-            return NGX_OK;
-        }
-
-        if (wev->active && wev->ready) {
-            if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
-                return NGX_ERROR;
-            }
-
-            return NGX_OK;
-        }
-    }
-
-    /* aio, iocp, rtsig */
-
-    return NGX_OK;
-}
-
-
-static ngx_inline ngx_int_t ngx_handle_level_write_event(ngx_event_t *wev)
-{
-    if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
-        if (!wev->active && !wev->ready) {
-            if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT)
-                                                                  == NGX_ERROR)
-            {
-                return NGX_ERROR;
-            }
-
-            return NGX_OK;
-        }
-
-        if (wev->active && wev->ready) {
-            if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
-                return NGX_ERROR;
-            }
-
-            return NGX_OK;
-        }
-    }
-
-    return NGX_OK;
-}
-
-
 #endif /* _NGX_EVENT_H_INCLUDED_ */
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -106,7 +106,9 @@ ngx_event_accept(ngx_event_t *ev)
                 return;
             }
 
-            ngx_log_error(NGX_LOG_ALERT, ev->log, err,
+            ngx_log_error((err == NGX_ECONNABORTED) ? NGX_LOG_CRIT:
+                                                      NGX_LOG_ALERT,
+                          ev->log, err,
                           "accept() on %V failed", &ls->listening->addr_text);
 
             if (err == NGX_ECONNABORTED) {
--- a/src/event/ngx_event_acceptex.c
+++ b/src/event/ngx_event_acceptex.c
@@ -132,7 +132,7 @@ int ngx_event_post_acceptex(ngx_listenin
 
         rev->ovlp.event = rev;
         wev->ovlp.event = wev;
-        rev->event_handler = ngx_event_acceptex;
+        rev->handler = ngx_event_acceptex;
 
         rev->data = c;
         wev->data = c;
--- a/src/event/ngx_event_busy_lock.c
+++ b/src/event/ngx_event_busy_lock.c
@@ -43,7 +43,7 @@ ngx_int_t ngx_event_busy_lock(ngx_event_
     } else if (ctx->timer && bl->waiting < bl->max_waiting) {
         bl->waiting++;
         ngx_add_timer(ctx->event, ctx->timer);
-        ctx->event->event_handler = ngx_event_busy_lock_handler;
+        ctx->event->handler = ngx_event_busy_lock_handler;
 
         if (bl->events) {
             bl->last->next = ctx;
@@ -92,7 +92,7 @@ ngx_int_t ngx_event_busy_lock_cachable(n
         if (ctx->timer && bl->waiting < bl->max_waiting) {
             bl->waiting++;
             ngx_add_timer(ctx->event, ctx->timer);
-            ctx->event->event_handler = ngx_event_busy_lock_handler;
+            ctx->event->handler = ngx_event_busy_lock_handler;
 
             if (bl->events == NULL) {
                 bl->events = ctx;
@@ -296,7 +296,7 @@ static void ngx_event_busy_lock_handler(
 
     ngx_mutex_unlock(ngx_posted_events_mutex);
 
-    ev->event_handler = ngx_event_busy_lock_posted_handler;
+    ev->handler = ngx_event_busy_lock_posted_handler;
 }
 
 
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -114,6 +114,9 @@ ngx_event_connect_peer(ngx_peer_connecti
 
     s = ngx_socket(peer->sockaddr->sa_family, SOCK_STREAM, 0);
 
+    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0,
+                   "socket %d", s);
+
     if (s == -1) {
         ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
                       ngx_socket_n " failed");
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -170,7 +170,7 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
 
         if (c->ssl->saved_write_handler) {
 
-            c->write->event_handler = c->ssl->saved_write_handler;
+            c->write->handler = c->ssl->saved_write_handler;
             c->ssl->saved_write_handler = NULL;
             c->write->ready = 1;
 
@@ -223,8 +223,8 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
          */
 
         if (c->ssl->saved_write_handler == NULL) {
-            c->ssl->saved_write_handler = c->write->event_handler;
-            c->write->event_handler = ngx_ssl_write_handler;
+            c->ssl->saved_write_handler = c->write->handler;
+            c->write->handler = ngx_ssl_write_handler;
         }
 
         return NGX_AGAIN;
@@ -253,7 +253,7 @@ ngx_ssl_write_handler(ngx_event_t *wev)
     ngx_connection_t  *c;
 
     c = wev->data;
-    c->read->event_handler(c->read);
+    c->read->handler(c->read);
 }
 
 
@@ -405,7 +405,7 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
     if (n > 0) {
         if (c->ssl->saved_read_handler) {
 
-            c->read->event_handler = c->ssl->saved_read_handler;
+            c->read->handler = c->ssl->saved_read_handler;
             c->ssl->saved_read_handler = NULL;
             c->read->ready = 1;
 
@@ -460,8 +460,8 @@ ngx_ssl_write(ngx_connection_t *c, u_cha
          */
 
         if (c->ssl->saved_read_handler == NULL) {
-            c->ssl->saved_read_handler = c->read->event_handler;
-            c->read->event_handler = ngx_ssl_read_handler;
+            c->ssl->saved_read_handler = c->read->handler;
+            c->read->handler = ngx_ssl_read_handler;
         }
 
         return NGX_AGAIN;
@@ -482,7 +482,7 @@ ngx_ssl_read_handler(ngx_event_t *rev)
     ngx_connection_t  *c;
 
     c = rev->data;
-    c->write->event_handler(c->write);
+    c->write->handler(c->write);
 }
 
 
@@ -592,3 +592,12 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_
 
     ngx_log_error(level, log, err, "%s)", errstr);
 }
+
+
+void
+ngx_ssl_cleanup_ctx(void *data)
+{
+   SSL_CTX  *ctx = data;
+
+   SSL_CTX_free(ctx);
+}
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -54,6 +54,7 @@ ngx_chain_t *ngx_ssl_send_chain(ngx_conn
 ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c);
 void ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
     char *fmt, ...);
+void ngx_ssl_cleanup_ctx(void *data);
 
 
 #endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -64,13 +64,13 @@ ngx_int_t ngx_event_pipe(ngx_event_pipe_
         }
     }
 
-    if (p->downstream->fd != -1) {
+    if (p->downstream->fd != -1 && p->downstream->data == p->output_ctx) {
         wev = p->downstream->write;
         if (ngx_handle_write_event(wev, p->send_lowat) == NGX_ERROR) {
             return NGX_ABORT;
         }
 
-        if (wev->active) {
+        if (wev->active && !wev->ready && !wev->delayed) {
             ngx_add_timer(wev, p->send_timeout);
         }
     }
@@ -180,8 +180,10 @@ static ngx_int_t ngx_event_pipe_read_ups
                 chain->buf = b;
                 chain->next = NULL;
 
-            } else if (!p->cachable && p->downstream->write->ready) {
-
+            } else if (!p->cachable
+                       && p->downstream->data == p->output_ctx
+                       && p->downstream->write->ready)
+            {
                 /*
                  * if the bufs are not needed to be saved in a cache and
                  * a downstream is ready then write the bufs to a downstream
@@ -409,10 +411,18 @@ static ngx_int_t ngx_event_pipe_write_to
 
             /* pass the p->out and p->in chains to the output filter */
 
+            for (cl = p->busy; cl; cl = cl->next) {
+                cl->buf->recycled = 0;
+            }
+
             if (p->out) {
                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
                                "pipe write downstream flush out");
 
+                for (cl = p->out; cl; cl = cl->next) {
+                    cl->buf->recycled = 0;
+                }
+
                 if (p->output_filter(p->output_ctx, p->out) == NGX_ERROR) {
                     p->downstream_error = 1;
                     return ngx_event_pipe_drain_chains(p);
@@ -425,6 +435,10 @@ static ngx_int_t ngx_event_pipe_write_to
                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
                                "pipe write downstream flush in");
 
+                for (cl = p->in; cl; cl = cl->next) {
+                    cl->buf->recycled = 0;
+                }
+
                 if (p->output_filter(p->output_ctx, p->in) == NGX_ERROR) {
                     p->downstream_error = 1;
                     return ngx_event_pipe_drain_chains(p);
@@ -442,7 +456,9 @@ static ngx_int_t ngx_event_pipe_write_to
             break;
         }
 
-        if (!p->downstream->write->ready) {
+        if (p->downstream->data != p->output_ctx
+            || !p->downstream->write->ready)
+        {
             break;
         }
 
--- a/src/event/ngx_event_posted.c
+++ b/src/event/ngx_event_posted.c
@@ -33,7 +33,7 @@ void ngx_event_process_posted(ngx_cycle_
 
         ngx_delete_posted_event(ev);
 
-        ev->event_handler(ev);
+        ev->handler(ev);
     }
 }
 
@@ -137,7 +137,7 @@ ngx_int_t ngx_event_thread_process_poste
 
             ngx_mutex_unlock(ngx_posted_events_mutex);
 
-            ev->event_handler(ev);
+            ev->handler(ev);
 
             if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
                 return NGX_ERROR;
--- a/src/event/ngx_event_timer.c
+++ b/src/event/ngx_event_timer.c
@@ -156,7 +156,7 @@ ngx_event_expire_timers(ngx_msec_t timer
 
             ev->timedout = 1;
 
-            ev->event_handler(ev);
+            ev->handler(ev);
 
             continue;
         }
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -54,7 +54,8 @@ static ngx_command_t  ngx_http_access_co
 
 
 ngx_http_module_t  ngx_http_access_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -68,7 +69,7 @@ ngx_http_module_t  ngx_http_access_modul
 
 
 ngx_module_t  ngx_http_access_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_access_module_ctx,           /* module context */
     ngx_http_access_commands,              /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -60,7 +60,8 @@ static ngx_command_t  ngx_http_auth_basi
 
 
 ngx_http_module_t  ngx_http_auth_basic_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -74,7 +75,7 @@ ngx_http_module_t  ngx_http_auth_basic_m
 
 
 ngx_module_t  ngx_http_auth_basic_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_auth_basic_module_ctx,       /* module context */
     ngx_http_auth_basic_commands,          /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -327,6 +328,7 @@ ngx_http_auth_basic_set_realm(ngx_http_r
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    r->headers_out.www_authenticate->hash = 1;
     r->headers_out.www_authenticate->key.len = sizeof("WWW-Authenticate") - 1;
     r->headers_out.www_authenticate->key.data = (u_char *) "WWW-Authenticate";
     r->headers_out.www_authenticate->value = *realm;
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -63,7 +63,8 @@ static ngx_command_t  ngx_http_autoindex
 
 
 ngx_http_module_t  ngx_http_autoindex_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -77,7 +78,7 @@ ngx_http_module_t  ngx_http_autoindex_mo
 
 
 ngx_module_t  ngx_http_autoindex_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_autoindex_module_ctx,        /* module context */ 
     ngx_http_autoindex_commands,           /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -419,16 +420,8 @@ ngx_http_autoindex_handler(ngx_http_requ
 
     r->headers_out.status = NGX_HTTP_OK;
     r->headers_out.content_length_n = b->last - b->pos;
-
-    r->headers_out.content_type = ngx_list_push(&r->headers_out.headers);
-    if (r->headers_out.content_type == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    r->headers_out.content_type->key.len = 0;
-    r->headers_out.content_type->key.data = NULL;
-    r->headers_out.content_type->value.len = sizeof("text/html") - 1;
-    r->headers_out.content_type->value.data = (u_char *) "text/html";
+    r->headers_out.content_type.len = sizeof("text/html") - 1;
+    r->headers_out.content_type.data = (u_char *) "text/html";
 
     rc = ngx_http_send_header(r);
 
@@ -436,10 +429,12 @@ ngx_http_autoindex_handler(ngx_http_requ
         return rc;
     }
 
-    if (!r->main) {
+    if (r->main == NULL) {
         b->last_buf = 1;
     }
 
+    b->last_in_chain = 1;
+
     out.buf = b;
     out.next = NULL;
 
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -106,7 +106,8 @@ static ngx_command_t  ngx_http_charset_f
 
 
 static ngx_http_module_t  ngx_http_charset_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     ngx_http_charset_create_main_conf,     /* create main configuration */
     ngx_http_charset_init_main_conf,       /* init main configuration */
@@ -120,7 +121,7 @@ static ngx_http_module_t  ngx_http_chars
 
 
 ngx_module_t  ngx_http_charset_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_charset_filter_module_ctx,   /* module context */
     ngx_http_charset_filter_commands,      /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -148,19 +149,18 @@ ngx_http_charset_header_filter(ngx_http_
         return ngx_http_next_header_filter(r);
     }
 
-    if (r->headers_out.content_type == NULL) {
+    if (r->headers_out.content_type.len == 0) {
         return ngx_http_next_header_filter(r);
     }
 
-    if (ngx_strncasecmp(r->headers_out.content_type->value.data,
-                                                              "text/", 5) != 0
-        && ngx_strncasecmp(r->headers_out.content_type->value.data,
-                                          "application/x-javascript", 24) != 0)
+    if (ngx_strncasecmp(r->headers_out.content_type.data, "text/", 5) != 0
+        && ngx_strncasecmp(r->headers_out.content_type.data,
+                           "application/x-javascript", 24) != 0)
     {
         return ngx_http_next_header_filter(r);
     }
 
-    if (ngx_strstr(r->headers_out.content_type->value.data, "charset") != NULL)
+    if (ngx_strstr(r->headers_out.content_type.data, "charset") != NULL)
     {
         return ngx_http_next_header_filter(r);
     }
--- a/src/http/modules/ngx_http_chunked_filter_module.c
+++ b/src/http/modules/ngx_http_chunked_filter_module.c
@@ -13,7 +13,8 @@ static ngx_int_t ngx_http_chunked_filter
 
 
 static ngx_http_module_t  ngx_http_chunked_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -27,7 +28,7 @@ static ngx_http_module_t  ngx_http_chunk
 
 
 ngx_module_t  ngx_http_chunked_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_chunked_filter_module_ctx,   /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -43,7 +44,7 @@ static ngx_http_output_body_filter_pt   
 static ngx_int_t
 ngx_http_chunked_header_filter(ngx_http_request_t *r)
 {
-    if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) {
+    if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED || r->main) {
         return ngx_http_next_header_filter(r);
     }
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -15,37 +15,14 @@ typedef struct {
 
     ngx_peers_t                    *peers;
 
-    ngx_uint_t                      params;
-
-    ngx_str_t                       root;
     ngx_str_t                       index;
 
-    ngx_array_t                    *vars;
-
-    ngx_str_t                      *location;
+    ngx_array_t                    *params_len;
+    ngx_array_t                    *params;
+    ngx_array_t                    *params_source;
 } 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,
@@ -69,28 +46,9 @@ typedef struct {
     size_t                        padding;
 
     ngx_uint_t                    header;
-
-    ngx_http_fastcgi_upstream_t  *upstream;
 } ngx_http_fastcgi_ctx_t;
 
 
-#define NGX_HTTP_FASTCGI_REMOTE_ADDR          0x00000002
-#define NGX_HTTP_FASTCGI_REMOTE_USER          0x00000004
-#define NGX_HTTP_FASTCGI_SERVER_NAME          0x00000008
-#define NGX_HTTP_FASTCGI_SERVER_ADDR          0x00000010
-#define NGX_HTTP_FASTCGI_SERVER_PORT          0x00000020
-#define NGX_HTTP_FASTCGI_SCRIPT_NAME          0x00000040
-#define NGX_HTTP_FASTCGI_AUTH_TYPE            0x00000080
-#define NGX_HTTP_FASTCGI_SERVER_PROTOCOL      0x00000100
-#define NGX_HTTP_FASTCGI_SERVER_SOFTWARE      0x00000200
-#define NGX_HTTP_FASTCGI_GATEWAY_INTERFACE    0x00000400
-#define NGX_HTTP_FASTCGI_REQUEST_URI          0x00000800
-#define NGX_HTTP_FASTCGI_REDIRECT_STATUS      0x00001000
-#define NGX_HTTP_FASTCGI_DOCUMENT_ROOT        0x00002000
-#define NGX_HTTP_FASTCGI_SCRIPT_FILENAME      0x00004000
-#define NGX_HTTP_FASTCGI_REMOTE_PORT          0x00008000
-
-
 #define NGX_HTTP_FASTCGI_RESPONDER      1
 
 #define NGX_HTTP_FASTCGI_BEGIN_REQUEST  1
@@ -123,10 +81,24 @@ typedef struct {
 } ngx_http_fastcgi_begin_request_t;
 
 
+typedef struct {
+    u_char  version;
+    u_char  type;
+    u_char  request_id_hi;
+    u_char  request_id_lo;
+} ngx_http_fastcgi_header_small_t;
+
+
+typedef struct {
+    ngx_http_fastcgi_header_t         h0;
+    ngx_http_fastcgi_begin_request_t  br;
+    ngx_http_fastcgi_header_small_t   h1;
+} ngx_http_fastcgi_request_start_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,
@@ -135,22 +107,54 @@ static void ngx_http_fastcgi_abort_reque
 static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r,
     ngx_int_t rc);
 
+static ngx_int_t ngx_http_fastcgi_add_variables(ngx_conf_t *cf);
+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_http_variable_value_t *
+    ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
+    uintptr_t data);
+
 static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
-static char *ngx_http_fastcgi_set_var(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_http_fastcgi_request_start_t  ngx_http_fastcgi_request_start = {
+    { 1,                                               /* version */
+      NGX_HTTP_FASTCGI_BEGIN_REQUEST,                  /* type */
+      0,                                               /* request_id_hi */
+      1,                                               /* request_id_lo */
+      0,                                               /* content_length_hi */
+      sizeof(ngx_http_fastcgi_begin_request_t),        /* content_length_lo */
+      0,                                               /* padding_length */
+      0 },                                             /* reserved */
+
+    { 0,                                               /* role_hi */
+      NGX_HTTP_FASTCGI_RESPONDER,                      /* role_lo */
+      0, /* NGX_HTTP_FASTCGI_KEEP_CONN */              /* flags */
+      { 0, 0, 0, 0, 0 } },                             /* reserved[5] */
+
+    { 1,                                               /* version */
+      NGX_HTTP_FASTCGI_PARAMS,                         /* type */
+      0,                                               /* request_id_hi */
+      1 },                                             /* request_id_lo */
+
+};
+
+
+#if 0
 static ngx_str_t ngx_http_fastcgi_methods[] = {
     ngx_string("GET"),
     ngx_string("HEAD"),
     ngx_string("POST")
 };
+#endif
+
+
+static ngx_str_t  ngx_http_fastcgi_script_name =
+    ngx_string("fastcgi_script_name");
 
 
 #if (NGX_PCRE)
@@ -158,30 +162,14 @@ static ngx_str_t ngx_http_fastcgi_uri = 
 #endif
 
 
-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) },
+static ngx_conf_post_t  ngx_http_fastcgi_lowat_post =
+    { ngx_http_fastcgi_lowat_check };
 
-    { 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
-
+static ngx_conf_enum_t  ngx_http_fastcgi_set_methods[] = {
+    { ngx_string("get"), NGX_HTTP_GET },
     { 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 },
@@ -192,28 +180,6 @@ static ngx_conf_bitmask_t  ngx_http_fast
 };
 
 
-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_string("document_root"), NGX_HTTP_FASTCGI_DOCUMENT_ROOT },
-    { ngx_string("script_filename"), NGX_HTTP_FASTCGI_SCRIPT_FILENAME },
-    { ngx_string("remote_port"), NGX_HTTP_FASTCGI_REMOTE_PORT },
-
-    { ngx_null_string, 0 }
-};
-
-
 static ngx_command_t  ngx_http_fastcgi_commands[] = {
 
     { ngx_string("fastcgi_pass"),
@@ -223,13 +189,6 @@ static ngx_command_t  ngx_http_fastcgi_c
       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,
@@ -265,6 +224,27 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.header_buffer_size),
       NULL },
 
+    { ngx_string("fastcgi_method"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.method),
+      ngx_http_fastcgi_set_methods },
+
+    { ngx_string("fastcgi_pass_request_headers"),
+      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.pass_request_headers),
+      NULL },
+
+    { ngx_string("fastcgi_pass_request_body"),
+      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.pass_request_body),
+      NULL },
+
     { ngx_string("fastcgi_redirect_errors"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -276,7 +256,7 @@ static ngx_command_t  ngx_http_fastcgi_c
       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),
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_x_powered_by),
       NULL },
 
     { ngx_string("fastcgi_read_timeout"),
@@ -328,26 +308,20 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
       &ngx_http_fastcgi_next_upstream_masks },
 
-    { ngx_string("fastcgi_set_var"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_fastcgi_set_var,
+    { ngx_string("fastcgi_param"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_table_elt_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      0,
+      offsetof(ngx_http_fastcgi_loc_conf_t, params_source),
       NULL },
 
-    { 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 */
+    ngx_http_fastcgi_add_variables,        /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -361,7 +335,7 @@ ngx_http_module_t  ngx_http_fastcgi_modu
 
 
 ngx_module_t  ngx_http_fastcgi_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_fastcgi_module_ctx,          /* module context */
     ngx_http_fastcgi_commands,             /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -396,26 +370,15 @@ ngx_http_fastcgi_handler(ngx_http_reques
 
     u->conf = &flcf->upstream;
 
-    u->location0 = 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->schema0.len = sizeof("fastcgi://") - 1;
-    u->schema0.data = (u_char *) "fastcgi://";
-    u->uri0.len = sizeof("/") - 1;
-    u->uri0.data = (u_char *) "/";
-
     r->upstream = u;
 
     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
@@ -431,206 +394,67 @@ ngx_http_fastcgi_handler(ngx_http_reques
 static ngx_int_t
 ngx_http_fastcgi_create_request(ngx_http_request_t *r)
 {
-    u_char                             ch, *pos, addr_text[INET_ADDRSTRLEN],
-                                       port_text[sizeof("65535") - 1];
-    size_t                             size, len, index, padding,
-                                       addr_len, port_len;
-    off_t                              file_pos;
-    ngx_buf_t                         *b;
-    socklen_t                          slen;
-    ngx_chain_t                       *cl, *body;
-    ngx_uint_t                         i, n, next, *vindex, port;
-    ngx_list_part_t                   *part;
-    ngx_table_elt_t                   *header;
-    struct sockaddr_in                 sin, *sinp;
-    ngx_http_variable_t               *var;
-    ngx_http_variable_value_t         *value;
-    ngx_http_core_loc_conf_t          *clcf;
-    ngx_http_core_main_conf_t         *cmcf;
-    ngx_http_fastcgi_header_t         *h;
-    ngx_http_fastcgi_loc_conf_t       *flcf;
-    ngx_http_fastcgi_begin_request_t  *br;
+    off_t                         file_pos;
+    u_char                        ch, *pos;
+    size_t                        size, len, key_len, val_len, padding;
+    ngx_uint_t                    i, n, next;
+    ngx_buf_t                    *b;
+    ngx_chain_t                  *cl, *body;
+    ngx_list_part_t              *part;
+    ngx_table_elt_t              *header;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e, le;
+    ngx_http_fastcgi_header_t    *h;
+    ngx_http_fastcgi_loc_conf_t  *flcf;
+    ngx_http_script_len_code_pt   lcode;
 
+    len = 0;
 
     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 (NGX_SUPPRESS_WARN)
-    clcf = NULL;
-    var = NULL;
-    vindex = NULL;
-#endif
-
-
-    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;
-    }
-
+    if (flcf->params_len) {
+        ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
 
-    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;
-    }
-
+        le.ip = flcf->params_len->elts;
+        le.request = r;
 
-    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->unparsed_uri.len > 127) ? 4 : 1)
-            + sizeof("REQUEST_URI") - 1 + r->unparsed_uri.len;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_DOCUMENT_ROOT) {
-        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-        len += 1 + ((clcf->root.len > 127) ? 4 : 1)
-            + sizeof("DOCUMENT_ROOT") - 1 + clcf->root.len;
-    }
+        while (*(uintptr_t *) le.ip) {
 
-    if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_FILENAME) {
-        len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1)
-            + sizeof("SCRIPT_FILENAME") - 1
-            + flcf->root.len + r->uri.len + index;
-    }
-
-    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;
-    }
-
-    port_len = 0;
-
-    if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_PORT) {
-
-        /* AF_INET only */
-
-        if (r->connection->sockaddr->sa_family == AF_INET) {
-            sinp = (struct sockaddr_in *) r->connection->sockaddr;
-
-            port = ntohs(sinp->sin_port);
-
-            if (port > 0 && port < 65536) {
-                port_len = ngx_sprintf(port_text, "%ui", port) - port_text;
-            }
-
-            len += 1 + 1 + sizeof("REMOTE_PORT") - 1 + port_len;
-        }
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) {
-        len += 1 + 1 + sizeof("SERVER_NAME") - 1 + r->server_name.len;
-    }
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            key_len = lcode(&le);
 
-    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;
-    }
+            for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
+                lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            }
+            le.ip += sizeof(uintptr_t);
 
-    if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) {
-        len += 1 + 1 + sizeof("GATEWAY_INTERFACE") - 1 + sizeof("CGI/1.1") - 1;
-    }
-
-
-    if (flcf->vars) {
-        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-
-        var = cmcf->variables.elts;
-        vindex = flcf->vars->elts;
-
-        for (i = 0; i < flcf->vars->nelts; i++) {
-
-            value = ngx_http_get_indexed_variable(r, vindex[i]);
-            if (value == NULL) {
-                continue;
-            }
-
-            if (value->text.len) {
-                len += 1 + 1 + var[vindex[i]].name.len + value->text.len;
+            if (val_len) {
+                len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
             }
         }
     }
 
+    if (flcf->upstream.pass_request_headers) {
 
-    part = &r->headers_in.headers.part;
-    header = part->elts;
+        part = &r->headers_in.headers.part;
+        header = part->elts;
+
+        for (i = 0; /* void */; i++) {
 
-    for (i = 0; /* void */; i++) {
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
 
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
+                part = part->next;
+                header = part->elts;
+                i = 0;
             }
 
-            part = part->next;
-            header = part->elts;
-            i = 0;
+            len += ((sizeof("HTTP_") - 1 + header[i].key.len > 127) ? 4 : 1)
+                + ((header[i].value.len > 127) ? 4 : 1)
+                + sizeof("HTTP_") - 1 + header[i].key.len + header[i].value.len;
         }
-
-        len += ((header[i].key.len > 127) ? 4 : 1)
-            + ((header[i].value.len > 127) ? 4 : 1)
-            + 5 + header[i].key.len + header[i].value.len;
     }
 
 
@@ -667,36 +491,13 @@ ngx_http_fastcgi_create_request(ngx_http
 
     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;
+    ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
+               sizeof(ngx_http_fastcgi_request_start_t));
 
     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;
@@ -707,376 +508,109 @@ ngx_http_fastcgi_create_request(ngx_http
                      + sizeof(ngx_http_fastcgi_header_t);
 
 
-    *b->last++ = sizeof("PATH_TRANSLATED") - 1;
+    if (flcf->params_len) {
+        ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
 
-    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);
+        e.ip = flcf->params->elts;
+        e.pos = b->last;
+        e.request = r;
 
-    } else {
-        *b->last++ = (u_char) len;
-    }
+        le.ip = flcf->params_len->elts;
 
-    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);
+        while (*(uintptr_t *) le.ip) {
 
-    if (index) {
-        b->last = ngx_cpymem(b->last, flcf->index.data, index);
-    }
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            key_len = (u_char) lcode(&le);
 
-
-    *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);
+            for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
+                lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            }
+            le.ip += sizeof(uintptr_t);
 
-        b->last = ngx_cpymem(b->last,
-                        ngx_http_fastcgi_methods[r->upstream->method - 1].data,
-                        ngx_http_fastcgi_methods[r->upstream->method - 1].len);
+            if (val_len) {
+                *e.pos++ = (u_char) key_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;
-        }
+                if (val_len > 127) {
+                    *e.pos++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
+                    *e.pos++ = (u_char) ((val_len >> 16) & 0xff);
+                    *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
+                    *e.pos++ = (u_char) (val_len & 0xff);
 
-        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;
+                } else {
+                    *e.pos++ = (u_char) val_len;
+                }
+            }
 
-        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);
+            e.skip = val_len ? 0 : 1;
 
-        } else {
-            *b->last++ = (u_char) len;
+            while (*(uintptr_t *) e.ip) {
+                code = *(ngx_http_script_code_pt *) e.ip;
+                code((ngx_http_script_engine_t *) &e);
+            }
+            e.ip += sizeof(uintptr_t);
         }
 
-        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->unparsed_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->unparsed_uri.data, len);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_DOCUMENT_ROOT) {
-        *b->last++ = sizeof("DOCUMENT_ROOT") - 1;
-
-        len = clcf->root.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, "DOCUMENT_ROOT",
-                             sizeof("DOCUMENT_ROOT") - 1);
-        b->last = ngx_cpymem(b->last, clcf->root.data, len);
+        b->last = e.pos;
     }
 
 
-    if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_FILENAME) {
-        *b->last++ = sizeof("SCRIPT_FILENAME") - 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, "SCRIPT_FILENAME",
-                             sizeof("SCRIPT_FILENAME") - 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);
-        }
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) {
-        *b->last++ = sizeof("SCRIPT_NAME") - 1;
+    if (flcf->upstream.pass_request_headers) {
 
-        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);
+        part = &r->headers_in.headers.part;
+        header = part->elts;
 
-        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 (port_len) {
-        *b->last++ = sizeof("REMOTE_PORT") - 1;
-        *b->last++ = (u_char) port_len;
-        b->last = ngx_cpymem(b->last, "REMOTE_PORT", sizeof("REMOTE_PORT") - 1);
-        b->last = ngx_cpymem(b->last, port_text, port_len);
-    }
-
+        for (i = 0; /* void */; i++) {
 
-    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;
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break; 
+                }
+    
+                part = part->next;
+                header = part->elts;
+                i = 0;
+            }
 
-        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);
-    }
-
-
-    if (flcf->vars) {
-        for (i = 0; i < flcf->vars->nelts; i++) {
-
-            value = ngx_http_get_indexed_variable(r, vindex[i]);
-            if (value == NULL) {
-                continue;
+            len = sizeof("HTTP_") - 1 + 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;
             }
 
-            if (value->text.len == 0) {
-                continue;
-            }
-
-            *b->last++ = (u_char) var[vindex[i]].name.len;
-            *b->last++ = (u_char) value->text.len;
-
-            b->last = ngx_cpymem(b->last, var[vindex[i]].name.data,
-                                 var[vindex[i]].name.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);
 
-            b->last = ngx_cpymem(b->last, value->text.data, value->text.len);
-        }
-    }
-
-
-    part = &r->headers_in.headers.part;
-    header = part->elts;
-
-    for (i = 0; /* void */; i++) {
-
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
+            } else {
+                *b->last++ = (u_char) len;
             }
 
-            part = part->next;
-            header = part->elts;
-            i = 0;
-        }
+            b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
 
-        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;
-        }
+            for (n = 0; n < header[i].key.len; n++) {
+                ch = header[i].key.data[n];
 
-        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;
-        }
+                if (ch >= 'a' && ch <= 'z') {
+                    ch &= ~0x20;
 
-        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];
+                } else if (ch == '-') {
+                    ch = '_';
+                }
 
-            if (ch >= 'a' && ch <= 'z') {
-                ch &= ~0x20;
-
-            } else if (ch == '-') {
-                ch = '_';
+                *b->last++ = ch;
             }
 
-            *b->last++ = ch;
+            b->last = ngx_cpymem(b->last, header[i].value.data,
+                                 header[i].value.len);
         }
-
-        b->last = ngx_cpymem(b->last, header[i].value.data,
-                             header[i].value.len);
     }
 
 
@@ -1101,103 +635,109 @@ ngx_http_fastcgi_create_request(ngx_http
     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 (flcf->upstream.pass_request_body) {
+        body = r->upstream->request_bufs;
+        r->upstream->request_bufs = cl;
 
 #if (NGX_SUPPRESS_WARN)
-    file_pos = 0;
-    pos = NULL;
+        file_pos = 0;
+        pos = NULL;
 #endif
 
-    while (body) {
-
-        if (body->buf->in_file) {
-            file_pos = body->buf->file_pos;
+        while (body) {
 
-        } else {
-            pos = body->buf->pos;
-        }
+            if (body->buf->in_file) {
+                file_pos = body->buf->file_pos;
 
-        next = 0;
-
-        do {
-            b = ngx_alloc_buf(r->pool);
-            if (b == NULL) {
-                return NGX_ERROR;
+            } else {
+                pos = body->buf->pos;
             }
 
-            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;
-                }
+            next = 0;
 
-                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;
+            do {
+                b = ngx_alloc_buf(r->pool);
+                if (b == NULL) {
+                    return NGX_ERROR;
                 }
 
-                b->last = pos;
-                len = (ngx_uint_t) (pos - b->pos);
-            }
+                ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
+
+                if (body->buf->in_file) {
+                    b->file_pos = file_pos;
+                    file_pos += 32 * 1024;
 
-            padding = 8 - len % 8;
-            padding = (padding == 8) ? 0 : padding;
+                    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;
 
-            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 (pos > body->buf->last) {
+                        pos = body->buf->last;
+                        next = 1;
+                    }
+
+                    b->last = pos;
+                    len = (ngx_uint_t) (pos - b->pos);
+                }
 
-            cl->next = ngx_alloc_chain_link(r->pool);
-            if (cl->next == NULL) {
-                return NGX_ERROR;
-            }
+                padding = 8 - len % 8;
+                padding = (padding == 8) ? 0 : padding;
 
-            cl = cl->next;
-            cl->buf = b;
+                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;
 
-            b = ngx_create_temp_buf(r->pool, sizeof(ngx_http_fastcgi_header_t)
-                                             + padding);
-            if (b == NULL) {
-                return NGX_ERROR;
-            }
+                cl->next = ngx_alloc_chain_link(r->pool);
+                if (cl->next == NULL) {
+                    return NGX_ERROR;
+                }
 
-            if (padding) {
-                ngx_memzero(b->last, padding);
-                b->last += padding;
-            }
+                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;
+                }
 
-            h = (ngx_http_fastcgi_header_t *) b->last;
-            b->last += sizeof(ngx_http_fastcgi_header_t);
+                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);
 
-            cl->next = ngx_alloc_chain_link(r->pool);
-            if (cl->next == NULL) {
-                return NGX_ERROR;
-            }
+                cl->next = ngx_alloc_chain_link(r->pool);
+                if (cl->next == NULL) {
+                    return NGX_ERROR;
+                }
+
+                cl = cl->next;
+                cl->buf = b;
 
-            cl = cl->next;
-            cl->buf = b;
+            } while (!next);
 
-        } while (!next);
+            body = body->next;
+        }
 
-        body = body->next;
+    } else {
+        r->upstream->request_bufs = cl;
     }
 
     h->version = 1;
@@ -1229,17 +769,6 @@ ngx_http_fastcgi_reinit_request(ngx_http
     f->state = ngx_http_fastcgi_st_version;
     f->header = 0;
 
-    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, 8,
-                                         sizeof(ngx_table_elt_t)) == NGX_ERROR)
-        {
-            return NGX_ERROR;
-        }
-    }
-
     return NGX_OK;
 }
 
@@ -1247,16 +776,21 @@ ngx_http_fastcgi_reinit_request(ngx_http
 static ngx_int_t
 ngx_http_fastcgi_process_header(ngx_http_request_t *r)
 {
-    u_char                  *start, *last;
-    ngx_str_t               *status_line, 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;
+    u_char                         *start, *last;
+    ngx_str_t                      *status_line, line;
+    ngx_int_t                       rc, status;
+    ngx_uint_t                      key;
+    ngx_table_elt_t                *h;
+    ngx_http_upstream_t            *u;
+    ngx_http_fastcgi_ctx_t         *f;
+    ngx_http_upstream_header_t     *hh;
+    ngx_http_upstream_main_conf_t  *umcf;
 
     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
 
+    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+    hh = (ngx_http_upstream_header_t *) umcf->headers_in_hash.buckets;
+
     if (f == NULL) {
         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
         if (f == NULL) {
@@ -1264,17 +798,6 @@ ngx_http_fastcgi_process_header(ngx_http
         }
 
         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, 8,
-                                         sizeof(ngx_table_elt_t)) == NGX_ERROR)
-        {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
     }
 
     u = r->upstream;
@@ -1424,11 +947,13 @@ ngx_http_fastcgi_process_header(ngx_http
 
                 /* a header line has been parsed successfully */
 
-                h = ngx_list_push(&f->upstream->headers_in.headers);
+                h = ngx_list_push(&u->headers_in.headers);
                 if (h == NULL) {
                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
                 }
 
+                h->hash = r->header_hash;
+
                 h->key.len = r->header_name_end - r->header_name_start;
                 h->value.len = r->header_end - r->header_start;
 
@@ -1443,18 +968,13 @@ ngx_http_fastcgi_process_header(ngx_http
                 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;
-                    }
+                key = h->hash % umcf->headers_in_hash.hash_size;
 
-                    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;
+                if (hh[key].name.len == h->key.len
+                    && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0)
+                {
+                    if (hh[key].handler(r, h, hh[key].offset) != NGX_OK) {
+                        return NGX_HTTP_INTERNAL_SERVER_ERROR;
                     }
                 }
 
@@ -1472,8 +992,8 @@ ngx_http_fastcgi_process_header(ngx_http
                 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;
+                if (u->headers_in.status) {
+                    status_line = &u->headers_in.status->value;
 
                     status = ngx_atoi(status_line->data, 3);
 
@@ -1541,84 +1061,6 @@ ngx_http_fastcgi_process_header(ngx_http
 
 
 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 */
-
-        ho = ngx_list_push(&r->headers_out.headers);
-        if (ho == NULL) {
-            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;
@@ -1937,7 +1379,6 @@ ngx_http_fastcgi_process_record(ngx_http
         }
     }
 
-    f->pos = p + 1;
     f->state = state;
 
     return NGX_AGAIN;
@@ -1964,140 +1405,19 @@ ngx_http_fastcgi_finalize_request(ngx_ht
 }
 
 
-static char *
-ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+static ngx_int_t
+ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
 {
-    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];
-
-        lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
-        if (lcf->peers == NULL) {
-            return NGX_CONF_ERROR;
-        }
+    ngx_http_variable_t  *var;
 
-#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];
-    
-        lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
-        if (lcf->peers == NULL) {
-            return NGX_CONF_ERROR;
-        }
-    }
-
-    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
-
-    clcf->handler = ngx_http_fastcgi_handler;
-
-#if (NGX_PCRE)
-    lcf->location = clcf->regex ? &ngx_http_fastcgi_uri : &clcf->name;
-#else
-    lcf->location = &clcf->name;
-#endif
-
-    if (clcf->name.data[clcf->name.len - 1] == '/') {
-        clcf->auto_redirect = 1;
+    var = ngx_http_add_variable(cf, &ngx_http_fastcgi_script_name, 0);
+    if (var == NULL) {
+        return NGX_ERROR;
     }
 
-    return NGX_CONF_OK;
-}
-
-
-static char *
-ngx_http_fastcgi_set_var(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_http_fastcgi_loc_conf_t *lcf = conf;
-
-    ngx_uint_t                  i, *index;
-    ngx_str_t                  *value;
-    ngx_http_variable_t        *var;
-    ngx_http_core_main_conf_t  *cmcf;
-
-    if (lcf->vars == NULL) {
-        lcf->vars = ngx_array_create(cf->pool, 4,
-                                     sizeof(ngx_http_variable_t *));
-        if (lcf->vars == NULL) {
-            return NGX_CONF_ERROR;
-        }
-    }
-
-    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
-
-    value = cf->args->elts;
-
-    var = cmcf->variables.elts;
-    for (i = 0; i < cmcf->variables.nelts; i++) {
-        if (ngx_strcasecmp(var[i].name.data, value[1].data) == 0) {
-
-            index = ngx_array_push(lcf->vars);
-            if (index == NULL) {
-                return NGX_CONF_ERROR;
-            }
+    var->handler = ngx_http_fastcgi_script_name_variable;
 
-            *index = var[i].index;
-            return NGX_CONF_OK;
-        }
-    }
-
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "unknown variable name \"%V\"", &value[1]);
-    return NGX_CONF_ERROR;
-}
-
-
-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;
+    return NGX_OK;
 }
 
 
@@ -2118,12 +1438,12 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
      *     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->upstream.schema = { 0, NULL };
+     *     conf->upstream.uri = { 0, NULL };
+     *     conf->upstream.location = NULL;
+     *
      *     conf->index.len = 0;
      *     conf->index.data = NULL;
-     *     conf->location = NULL;
      */
 
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
@@ -2135,14 +1455,23 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
     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.pass_unparsed_uri = NGX_CONF_UNSET;
+    conf->upstream.method = NGX_CONF_UNSET_UINT;
+    conf->upstream.pass_request_headers = NGX_CONF_UNSET;
+    conf->upstream.pass_request_body = NGX_CONF_UNSET;
+
     conf->upstream.redirect_errors = NGX_CONF_UNSET;
-    conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET;
-    conf->upstream.x_powered_by = NGX_CONF_UNSET;
 
     /* "fastcgi_cyclic_temp_file" is disabled */
     conf->upstream.cyclic_temp_file = 0;
 
+    conf->upstream.pass_x_powered_by = NGX_CONF_UNSET;
+
+    /* the hardcoded values */
+    conf->upstream.pass_server = 1;
+    conf->upstream.pass_date = 1;
+
     return conf;
 }
 
@@ -2153,7 +1482,13 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     ngx_http_fastcgi_loc_conf_t *prev = parent;
     ngx_http_fastcgi_loc_conf_t *conf = child;
 
-    size_t  size;
+    u_char                       *p;
+    size_t                        size;
+    uintptr_t                    *code;
+    ngx_uint_t                    i;
+    ngx_table_elt_t              *src;
+    ngx_http_script_compile_t     sc;
+    ngx_http_script_copy_code_t  *copy;
 
     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                               prev->upstream.connect_timeout, 60000);
@@ -2263,51 +1598,300 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
                               NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0,
                               ngx_garbage_collector_temp_handler, cf);
 
-
-    ngx_conf_merge_msec_value(conf->upstream.redirect_errors,
-                              prev->upstream.redirect_errors, 0);
-
     ngx_conf_merge_msec_value(conf->upstream.pass_unparsed_uri,
                               prev->upstream.pass_unparsed_uri, 0);
 
-    if (conf->upstream.pass_unparsed_uri && conf->location->len > 1) {
+    if (conf->upstream.pass_unparsed_uri && conf->upstream.location->len > 1) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                       "\"fastcgi_pass_unparsed_uri\" can be set for "
                       "location \"/\" or given by regular expression.");
         return NGX_CONF_ERROR;
     }
 
-    ngx_conf_merge_msec_value(conf->upstream.x_powered_by,
-                              prev->upstream.x_powered_by, 1);
+    if (conf->upstream.method == NGX_CONF_UNSET_UINT) {
+        conf->upstream.method = prev->upstream.method; 
+    }
+
+    ngx_conf_merge_value(conf->upstream.pass_request_headers,
+                              prev->upstream.pass_request_headers, 1);
+    ngx_conf_merge_value(conf->upstream.pass_request_body,
+                              prev->upstream.pass_request_body, 1);
+
+    ngx_conf_merge_msec_value(conf->upstream.redirect_errors,
+                              prev->upstream.redirect_errors, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.pass_x_powered_by,
+                              prev->upstream.pass_x_powered_by, 1);
 
 
-    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, "");
 
-    if (conf->vars == NULL) {
-        conf->vars = prev->vars;
-    }
-
     if (conf->peers == NULL) {
         conf->peers = prev->peers;
         conf->upstream = prev->upstream;
     }
 
+    if (conf->params_source == NULL) {
+        conf->params_source = prev->params_source;
+        conf->params_len = prev->params_len;
+        conf->params = prev->params;
+
+        if (conf->params_source == NULL) {
+            return NGX_CONF_OK;
+        }
+    }
+
+    conf->params_len = ngx_array_create(cf->pool, 64, 1);
+    if (conf->params_len == NULL) {
+        return NGX_CONF_ERROR;
+    }
+    
+    conf->params = ngx_array_create(cf->pool, 512, 1);
+    if (conf->params == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    src = conf->params_source->elts;
+    for (i = 0; i < conf->params_source->nelts; i++) {
+
+        if (ngx_http_script_variables_count(&src[i].value) == 0) {
+            copy = ngx_array_push_n(conf->params_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                  ngx_http_script_copy_len_code;
+            copy->len = src[i].key.len;
+
+
+            copy = ngx_array_push_n(conf->params_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                 ngx_http_script_copy_len_code;
+            copy->len = src[i].value.len;
+
+
+            size = (sizeof(ngx_http_script_copy_code_t)
+                       + src[i].key.len + src[i].value.len
+                       + sizeof(uintptr_t) - 1)
+                    & ~(sizeof(uintptr_t) - 1);
+
+            copy = ngx_array_push_n(conf->params, size);
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+    
+            copy->code = ngx_http_script_copy_code;
+            copy->len = src[i].key.len + src[i].value.len;
+
+            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+
+            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
+            ngx_memcpy(p, src[i].value.data, src[i].value.len);
+
+        } else {
+            copy = ngx_array_push_n(conf->params_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                 ngx_http_script_copy_len_code;
+            copy->len = src[i].key.len;
+
+
+            size = (sizeof(ngx_http_script_copy_code_t)
+                    + src[i].key.len + sizeof(uintptr_t) - 1)
+                    & ~(sizeof(uintptr_t) - 1);
+
+            copy = ngx_array_push_n(conf->params, size);
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+    
+            copy->code = ngx_http_script_copy_code;
+            copy->len = src[i].key.len;
+
+            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+            ngx_memcpy(p, src[i].key.data, src[i].key.len);
+
+
+            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+            sc.cf = cf;
+            sc.source = &src[i].value;
+            sc.lengths = &conf->params_len;
+            sc.values = &conf->params;
+
+            if (ngx_http_script_compile(&sc) != NGX_OK) {
+                return NGX_CONF_ERROR;
+            }
+        }
+
+        code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+
+
+        code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+    }
+
+    code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
+    if (code == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    *code = (uintptr_t) NULL;
+
     return NGX_CONF_OK;
 }
+
+
+static ngx_http_variable_value_t *
+ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, uintptr_t data)
+{
+    u_char                       *p;
+    ngx_http_variable_value_t    *vv;
+    ngx_http_fastcgi_loc_conf_t  *flcf;
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    vv->value = 0;
+
+    flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
+
+    if (r->uri.data[r->uri.len - 1] != '/') {
+        vv->text = r->uri;
+        return vv;
+    }
+
+    vv->text.len = r->uri.len + flcf->index.len;
+
+    vv->text.data = ngx_palloc(r->pool, vv->text.len);
+    if (vv->text.data == NULL) {
+        return NULL;
+    }
+
+    p = ngx_cpymem(vv->text.data, r->uri.data, r->uri.len);
+    ngx_memcpy(p, flcf->index.data, flcf->index.len);
+
+    return vv;
+}
+
+
+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];
+
+        lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
+        if (lcf->peers == 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;
+
+#endif
+
+    } else {
+        ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t));
+
+        inet_upstream.name = value[1];
+        inet_upstream.url = value[1];
+    
+        lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
+        if (lcf->peers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    lcf->upstream.schema.len = sizeof("fastcgi://") - 1;
+    lcf->upstream.schema.data = (u_char *) "fastcgi://";
+    lcf->upstream.uri.len = sizeof("/") - 1;
+    lcf->upstream.uri.data = (u_char *) "/";
+
+    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+
+    clcf->handler = ngx_http_fastcgi_handler;
+
+#if (NGX_PCRE)
+    lcf->upstream.location = clcf->regex ? &ngx_http_fastcgi_uri : &clcf->name;
+#else
+    lcf->upstream.location = &clcf->name;
+#endif
+
+    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;
+}
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -34,7 +34,8 @@ static ngx_command_t  ngx_http_geo_comma
 
 
 static ngx_http_module_t  ngx_http_geo_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -48,7 +49,7 @@ static ngx_http_module_t  ngx_http_geo_m
 
 
 ngx_module_t  ngx_http_geo_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_geo_module_ctx,              /* module context */
     ngx_http_geo_commands,                 /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -110,7 +111,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
         name.data++;
     }
 
-    var = ngx_http_add_variable(cf, &name, 1);
+    var = ngx_http_add_variable(cf, &name, 0);
     if (var == NULL) {
         return NGX_CONF_ERROR;
     }
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -207,7 +207,8 @@ static ngx_command_t  ngx_http_gzip_filt
 
 
 static ngx_http_module_t  ngx_http_gzip_filter_module_ctx = {
-    ngx_http_gzip_add_log_formats,         /* pre conf */
+    ngx_http_gzip_add_log_formats,         /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -221,7 +222,7 @@ static ngx_http_module_t  ngx_http_gzip_
 
 
 ngx_module_t  ngx_http_gzip_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_gzip_filter_module_ctx,      /* module context */
     ngx_http_gzip_filter_commands,         /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -257,6 +258,11 @@ struct gztrailer {
 #endif
 
 
+static ngx_str_t  ngx_http_gzip_no_cache = ngx_string("no-cache");
+static ngx_str_t  ngx_http_gzip_no_store = ngx_string("no-store");
+static ngx_str_t  ngx_http_gzip_private = ngx_string("private");
+
+
 static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
 static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
 
@@ -276,8 +282,9 @@ ngx_http_gzip_header_filter(ngx_http_req
             && r->headers_out.status != NGX_HTTP_FORBIDDEN
             && r->headers_out.status != NGX_HTTP_NOT_FOUND)
         || r->header_only
+        || r->main
         || r->http_version < conf->http_version
-        || r->headers_out.content_type == NULL
+        || r->headers_out.content_type.len == 0
         || (r->headers_out.content_encoding
             && r->headers_out.content_encoding->value.len)
         || r->headers_in.accept_encoding == NULL
@@ -294,8 +301,8 @@ ngx_http_gzip_header_filter(ngx_http_req
     type = conf->types->elts;
 
     for (i = 0; i < conf->types->nelts; i++) {
-        if (r->headers_out.content_type->value.len >= type[i].name.len
-            && ngx_strncasecmp(r->headers_out.content_type->value.data, 
+        if (r->headers_out.content_type.len >= type[i].name.len
+            && ngx_strncasecmp(r->headers_out.content_type.data, 
                                type[i].name.data, type[i].name.len) == 0)
         {
             found = 1;
@@ -346,6 +353,7 @@ ngx_http_gzip_header_filter(ngx_http_req
         return NGX_ERROR;
     }
 
+    r->headers_out.content_encoding->hash = 1;
     r->headers_out.content_encoding->key.len = sizeof("Content-Encoding") - 1;
     r->headers_out.content_encoding->key.data = (u_char *) "Content-Encoding";
     r->headers_out.content_encoding->value.len = sizeof("gzip") - 1;
@@ -353,10 +361,12 @@ ngx_http_gzip_header_filter(ngx_http_req
 
     ctx->length = r->headers_out.content_length_n;
     r->headers_out.content_length_n = -1;
+
     if (r->headers_out.content_length) {
-        r->headers_out.content_length->key.len = 0;
+        r->headers_out.content_length->hash = 0;
         r->headers_out.content_length = NULL;
     }
+
     r->filter_need_in_memory = 1;
 
     return ngx_http_next_header_filter(r);
@@ -404,22 +414,25 @@ ngx_http_gzip_proxied(ngx_http_request_t
         return NGX_DECLINED;
     }
 
-    if (r->headers_out.cache_control) {
+    if (r->headers_out.cache_control.elts) {
 
         if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_CACHE)
-            && ngx_strstr(r->headers_out.cache_control->value.data, "no-cache"))
+            && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control,
+                   &ngx_http_gzip_no_cache, NULL) >= 0)
         {
             return NGX_OK;
         }
 
         if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_STORE)
-            && ngx_strstr(r->headers_out.cache_control->value.data, "no-store"))
+            && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control,
+                   &ngx_http_gzip_no_store, NULL) >= 0)
         {
             return NGX_OK;
         }
 
         if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_PRIVATE)
-            && ngx_strstr(r->headers_out.cache_control->value.data, "private"))
+            && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control,
+                   &ngx_http_gzip_private, NULL) >= 0)
         {
             return NGX_OK;
         }
@@ -484,8 +497,8 @@ ngx_http_gzip_body_filter(ngx_http_reque
          * and do not wait while a whole response will be sent to a client.
          *
          * 8K is for zlib deflate_state, it takes
-         *  * 5816 bytes on x86 and sparc64 (32-bit mode)
-         *  * 5920 bytes on amd64 and sparc64
+         *  *) 5816 bytes on i386 and sparc64 (32-bit mode)
+         *  *) 5920 bytes on amd64 and sparc64
          */
 
         ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9));
@@ -696,7 +709,8 @@ ngx_http_gzip_body_filter(ngx_http_reque
 
             if (ctx->flush == Z_SYNC_FLUSH) {
 
-                ctx->out_buf->flush = 0;
+                ctx->zstream.avail_out = 0;
+                ctx->out_buf->flush = 1;
                 ctx->flush = Z_NO_FLUSH;
 
                 cl = ngx_alloc_chain_link(r->pool);
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -41,7 +41,8 @@ static ngx_command_t  ngx_http_headers_f
 
 
 static ngx_http_module_t  ngx_http_headers_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -55,7 +56,7 @@ static ngx_http_module_t  ngx_http_heade
 
 
 ngx_module_t  ngx_http_headers_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_headers_filter_module_ctx,   /* module context */
     ngx_http_headers_filter_commands,      /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -71,10 +72,11 @@ static ngx_int_t
 ngx_http_headers_filter(ngx_http_request_t *r)
 {
     size_t                    len;
+    ngx_uint_t                i;
     ngx_table_elt_t          *expires, *cc;
     ngx_http_headers_conf_t  *conf;
 
-    if (r->headers_out.status != NGX_HTTP_OK) {
+    if (r->headers_out.status != NGX_HTTP_OK || r->main) {
         return ngx_http_next_header_filter(r);
     }
 
@@ -82,28 +84,43 @@ ngx_http_headers_filter(ngx_http_request
 
     if (conf->expires != NGX_HTTP_EXPIRES_OFF) {
 
-        expires = ngx_list_push(&r->headers_out.headers);
+        expires = r->headers_out.expires;
+
         if (expires == NULL) {
-            return NGX_ERROR;
+
+            expires = ngx_list_push(&r->headers_out.headers);
+            if (expires == NULL) {
+                return NGX_ERROR;
+            }
+
+            r->headers_out.expires = expires;
+
+            expires->hash = 1;
+            expires->key.len = sizeof("Expires") - 1;
+            expires->key.data = (u_char *) "Expires";
         }
 
-        r->headers_out.expires = expires;
-
-        cc = ngx_list_push(&r->headers_out.headers);
-        if (cc == NULL) {
-            return NGX_ERROR;
-        }
-
-        r->headers_out.cache_control = cc;
-
         len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT");
-
-        expires->key.len = sizeof("Expires") - 1;
-        expires->key.data = (u_char *) "Expires";
         expires->value.len = len - 1;
 
-        cc->key.len = sizeof("Cache-Control") - 1;
-        cc->key.data = (u_char *) "Cache-Control";
+        cc = r->headers_out.cache_control.elts;
+
+        if (cc == NULL) {
+
+            cc = ngx_list_push(&r->headers_out.headers);
+            if (cc == NULL) {
+                return NGX_ERROR;
+            }
+
+            cc->hash = 1;
+            cc->key.len = sizeof("Cache-Control") - 1;
+            cc->key.data = (u_char *) "Cache-Control";
+
+        } else {
+            for (i = 1; i < r->headers_out.cache_control.nelts; i++) {
+                cc[i].hash = 0;
+            }
+        }
 
         if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) {
             expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT";
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -10,42 +10,52 @@
 
 
 typedef struct {
-    ngx_array_t              indices;
+    ngx_str_t                name;
+    ngx_array_t             *lengths;
+    ngx_array_t             *values;
+} ngx_http_index_t;
+
+
+typedef struct {
+    ngx_array_t             *indices;    /* array of ngx_http_index_t */
     size_t                   max_index_len;
-    ngx_http_cache_hash_t   *index_cache;
 } ngx_http_index_loc_conf_t;
 
 
 typedef struct {
-    ngx_uint_t               index;
-    u_char                  *last;
-    ngx_str_t                path;
-    ngx_str_t                redirect;
-    ngx_http_cache_entry_t  *cache;
-    ngx_uint_t               tested; /* unsigned  tested:1 */
+    ngx_uint_t               current;
+    size_t                   allocated;
+
+    u_char                  *path;
+    ngx_str_t                uri;
+    ngx_str_t                index;
+
+    ngx_uint_t               tested;     /* unsigned  tested:1 */
 } ngx_http_index_ctx_t;
 
 
 #define NGX_HTTP_DEFAULT_INDEX   "index.html"
 
 
+static ngx_int_t ngx_http_index_alloc(ngx_http_request_t *r, size_t size,
+    ngx_http_index_ctx_t *ctx, ngx_http_core_loc_conf_t *clcf);
 static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r,
-                                         ngx_http_index_ctx_t *ctx);
+    ngx_http_index_ctx_t *ctx);
 static ngx_int_t ngx_http_index_error(ngx_http_request_t *r,
-                                      ngx_http_index_ctx_t *ctx, ngx_err_t err);
+    ngx_http_index_ctx_t *ctx, ngx_err_t err);
 
 static ngx_int_t ngx_http_index_init(ngx_cycle_t *cycle);
 static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf,
-                                       void *parent, void *child);
+    void *parent, void *child);
 static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
-                                      void *conf);
+    void *conf);
 
 
 static ngx_command_t  ngx_http_index_commands[] = {
 
     { ngx_string("index"),
-      NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_http_index_set_index,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -67,7 +77,8 @@ static ngx_command_t  ngx_http_index_com
 
 
 ngx_http_module_t  ngx_http_index_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -81,7 +92,7 @@ ngx_http_module_t  ngx_http_index_module
 
 
 ngx_module_t  ngx_http_index_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_index_module_ctx,            /* module context */
     ngx_http_index_commands,               /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -100,21 +111,24 @@ ngx_module_t  ngx_http_index_module = {
  * that path contains the usual file in place of the directory.
  */
 
-static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r)
+static ngx_int_t
+ngx_http_index_handler(ngx_http_request_t *r)
 {
-    u_char                     *name;
-    ngx_fd_t                    fd;
-    ngx_int_t                   rc;
-    ngx_str_t                  *index;
-    ngx_err_t                   err;
-    ngx_log_t                  *log;
-    ngx_http_index_ctx_t       *ctx;
-    ngx_http_core_loc_conf_t   *clcf;
-    ngx_http_index_loc_conf_t  *ilcf;
-#if (NGX_HTTP_CACHE0)
-    /* crc must be in ctx !! */
-    uint32_t                    crc;
-#endif
+    u_char                       *name;
+    size_t                        len;
+    ngx_fd_t                      fd;
+    ngx_int_t                     rc;
+    ngx_err_t                     err;
+    ngx_log_t                    *log;
+    ngx_uint_t                    i;
+    ngx_http_index_t             *index;
+    ngx_http_index_ctx_t         *ctx;
+    ngx_pool_cleanup_file_t      *cln;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e;
+    ngx_http_core_loc_conf_t     *clcf;
+    ngx_http_index_loc_conf_t    *ilcf;
+    ngx_http_script_len_code_pt   lcode;
 
     if (r->uri.data[r->uri.len - 1] != '/') {
         return NGX_DECLINED;
@@ -128,8 +142,8 @@ static ngx_int_t ngx_http_index_handler(
     log = r->connection->log;
 
     /*
-     * we use context because the handler supports an async file opening
-     * and thus can be called several times
+     * we use context because the handler supports an async file opening,
+     * and may be called several times
      */
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -144,108 +158,63 @@ static ngx_int_t ngx_http_index_handler(
         }
 
         ngx_http_set_ctx(r, ctx, ngx_http_index_module);
+    }
 
-#if (NGX_HTTP_CACHE)
+    index = ilcf->indices->elts;
+    for (i = ctx->current; i < ilcf->indices->nelts; i++) {
+
+        if (index[i].lengths == NULL) {
 
-        if (ilcf->index_cache) {
-            ctx->cache = ngx_http_cache_get(ilcf->index_cache, NULL,
-                                            &r->uri, &crc);
+            if (index[i].name.data[0] == '/') {
+                return ngx_http_internal_redirect(r, &index[i].name, &r->args);
+            }
 
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                           "http index cache get: %p", ctx->cache);
+            len = ilcf->max_index_len;
+            ctx->index.len = index[i].name.len;
 
-            if (ctx->cache && !ctx->cache->expired) {
+        } else {
+            ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
 
-                ctx->cache->accessed = ngx_cached_time;
+            e.ip = index[i].lengths->elts;
+            e.request = r;
+
+            len = 1;
 
-                ctx->redirect.len = ctx->cache->data.value.len;
-                ctx->redirect.data = ngx_palloc(r->pool, ctx->redirect.len + 1);
-                if (ctx->redirect.data == NULL) {
-                    ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
-                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
-                }
+            while (*(uintptr_t *) e.ip) {
+                lcode = *(ngx_http_script_len_code_pt *) e.ip;
+                len += lcode(&e);
+            }
 
-                ngx_memcpy(ctx->redirect.data, ctx->cache->data.value.data,
-                           ctx->redirect.len + 1);
-                ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
+            ctx->index.len = len;
+        }
 
-                return ngx_http_internal_redirect(r, &ctx->redirect, NULL);
+        if (len > ctx->allocated) {
+            if (ngx_http_index_alloc(r, len, ctx, clcf) != NGX_OK) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
             }
         }
 
-#endif
-
-#if 0
-        ctx->path.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len
-                                             + ilcf->max_index_len
-                                             - clcf->alias * clcf->name.len);
-        if (ctx->path.data == NULL) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
+        if (index[i].values == NULL) {
+            ngx_memcpy(ctx->index.data, index[i].name.data, ctx->index.len);
 
-        ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->root.data,
-                                        clcf->root.len);
-#endif
+        } else {
+            e.ip = index[i].values->elts;
+            e.pos = ctx->index.data;
 
-        if (clcf->alias) {
-            ctx->path.data = ngx_palloc(r->pool, clcf->root.len
-                                              + r->uri.len + 1 - clcf->name.len
-                                              + ilcf->max_index_len);
-            if (ctx->path.data == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
-
-            ctx->redirect.data = ngx_palloc(r->pool, r->uri.len
-                                            + ilcf->max_index_len);
-            if (ctx->redirect.data == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            while (*(uintptr_t *) e.ip) {
+                code = *(ngx_http_script_code_pt *) e.ip;
+                code((ngx_http_script_engine_t *) &e);
             }
 
-            ngx_memcpy(ctx->path.data, clcf->root.data, clcf->root.len);
-
-            ctx->last = ngx_cpystrn(ctx->path.data + clcf->root.len,
-                                    r->uri.data + clcf->name.len,
-                                    r->uri.len + 1 - clcf->name.len);
-
-#if 0
-            /*
-             * aliases usually have trailling "/",
-             * set it in the start of the possible redirect
-             */
-
-            if (*ctx->redirect.data != '/') {
-                ctx->redirect.data--; 
-            }
-#endif
-
-        } else {
-            ctx->path.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len
-                                                 + ilcf->max_index_len);
-            if (ctx->path.data == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            if (*ctx->index.data == '/') {
+                ctx->index.len--;
+                return ngx_http_internal_redirect(r, &ctx->index, &r->args);
             }
 
-            ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->root.data,
-                                            clcf->root.len);
-
-            ctx->last = ngx_cpystrn(ctx->redirect.data, r->uri.data,
-                                    r->uri.len + 1);
+            *e.pos++ = '\0';
         }
-    }
-
-    ctx->path.len = ctx->last - ctx->path.data;
 
-    index = ilcf->indices.elts;
-    for (/* void */; ctx->index < ilcf->indices.nelts; ctx->index++) {
-
-        if (index[ctx->index].data[0] == '/') {
-            name = index[ctx->index].data;
-
-        } else {
-            ngx_memcpy(ctx->last, index[ctx->index].data,
-                       index[ctx->index].len + 1);
-            name = ctx->path.data;
-        }
+        name = ctx->path;
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                        "open index \"%s\"", name);
@@ -253,6 +222,7 @@ static ngx_int_t ngx_http_index_handler(
         fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN);
 
         if (fd == (ngx_fd_t) NGX_AGAIN) {
+            ctx->current = i;
             return NGX_AGAIN;
         }
 
@@ -290,131 +260,268 @@ static ngx_int_t ngx_http_index_handler(
         }
 
 
-        /* STUB: open file cache */
-
-        r->file.name.data = name;
-        r->file.fd = fd;
-
-        if (index[ctx->index].data[0] == '/') {
-            r->file.name.len = index[ctx->index].len;
-            ctx->redirect.len = index[ctx->index].len;
-            ctx->redirect.data = index[ctx->index].data;
-
-        } else {
-            if (clcf->alias) {
-                name = ngx_cpymem(ctx->redirect.data, r->uri.data, r->uri.len);
-                ngx_memcpy(name, index[ctx->index].data,
-                           index[ctx->index].len + 1);
-            }
-
-            ctx->redirect.len = r->uri.len + index[ctx->index].len;
-            r->file.name.len = clcf->root.len + r->uri.len
-                                                - clcf->alias * clcf->name.len
-                                                       + index[ctx->index].len;
+        cln = ngx_palloc(r->pool, sizeof(ngx_pool_cleanup_file_t));
+        if (cln == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR; 
         }
 
-        /**/
+        cln->fd = fd;
+        cln->name = name;
+        cln->log = r->pool->log;
+
+        if (ngx_pool_cleanup_add(r->pool, ngx_pool_cleanup_file, cln) == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
 
 
-#if (NGX_HTTP_CACHE)
-
-        if (ilcf->index_cache) {
-
-            if (ctx->cache) {
-                if (ctx->redirect.len == ctx->cache->data.value.len
-                    && ngx_memcmp(ctx->cache->data.value.data,
-                                  ctx->redirect.data, ctx->redirect.len) == 0)
-                {
-                    ctx->cache->accessed = ngx_cached_time;
-                    ctx->cache->updated = ngx_cached_time;
-                    ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
-
-                    return ngx_http_internal_redirect(r, &ctx->redirect, NULL);
-                }
-            }
-
-            ctx->redirect.len++;
-            ctx->cache = ngx_http_cache_alloc(ilcf->index_cache, ctx->cache,
-                                              NULL, &r->uri, crc,
-                                              &ctx->redirect, log);
-            ctx->redirect.len--;
-
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                           "http index cache alloc: %p", ctx->cache);
-
-            if (ctx->cache) {
-                ctx->cache->fd = NGX_INVALID_FILE;
-                ctx->cache->accessed = ngx_cached_time;
-                ctx->cache->last_modified = 0;
-                ctx->cache->updated = ngx_cached_time;
-                ctx->cache->memory = 1;
-                ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
-            }
+        if (clcf->alias) {
+            name = ngx_cpymem(ctx->uri.data, r->uri.data, r->uri.len);
+            ngx_memcpy(name, ctx->index.data, ctx->index.len - 1);
         }
 
-#endif
+        ctx->uri.len = r->uri.len + ctx->index.len - 1;
 
-        return ngx_http_internal_redirect(r, &ctx->redirect, NULL);
+        return ngx_http_internal_redirect(r, &ctx->uri, &r->args);
     }
 
     return NGX_DECLINED;
 }
 
 
-static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r,
-                                         ngx_http_index_ctx_t *ctx)
+static ngx_int_t
+ngx_http_index_alloc(ngx_http_request_t *r, size_t size,
+    ngx_http_index_ctx_t *ctx, ngx_http_core_loc_conf_t *clcf)
 {
-    ngx_err_t  err;
+    ctx->allocated = size;
+
+    if (!clcf->alias) {
+        ctx->path = ngx_palloc(r->pool, clcf->root.len + r->uri.len + size);
+        if (ctx->path == NULL) {
+            return NGX_ERROR;
+        }
+
+        ctx->uri.data = ngx_cpymem(ctx->path, clcf->root.data, clcf->root.len);
+
+        ctx->index.data = ngx_cpymem(ctx->uri.data, r->uri.data, r->uri.len);
+
+    } else {
+        ctx->path = ngx_palloc(r->pool,
+                          clcf->root.len + r->uri.len - clcf->name.len + size);
+        if (ctx->path == NULL) {
+            return NGX_ERROR;
+        }
 
-    ctx->path.data[ctx->path.len - 1] = '\0';
-    ctx->path.data[ctx->path.len] = '\0';
+        ctx->uri.data = ngx_palloc(r->pool, r->uri.len + size);
+        if (ctx->uri.data == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_memcpy(ctx->path, clcf->root.data, clcf->root.len);
+
+        ctx->index.data = ngx_cpymem(ctx->path + clcf->root.len,
+                                     r->uri.data + clcf->name.len,
+                                     r->uri.len - clcf->name.len);
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx)
+{
+    ngx_err_t        err;
+    ngx_file_info_t  fi;
+
+    *(ctx->index.data - 1) = '\0';
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http check dir: \"%s\"", ctx->path.data);
+                   "http index check dir: \"%s\"", ctx->path);
 
-    if (ngx_file_info(ctx->path.data, &r->file.info) == -1) {
+    if (ngx_file_info(ctx->path, &fi) == -1) {
 
         err = ngx_errno;
 
         if (err == NGX_ENOENT) {
-            ctx->path.data[ctx->path.len - 1] = '/';
+            *(ctx->index.data - 1) = '/';
             return ngx_http_index_error(r, ctx, err);
         }
 
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
-                      ngx_file_info_n " \"%s\" failed", ctx->path.data);
+                      ngx_file_info_n " \"%s\" failed", ctx->path);
 
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    ctx->path.data[ctx->path.len - 1] = '/';
+    *(ctx->index.data - 1) = '/';
 
-    if (ngx_is_dir(&r->file.info)) {
+    if (ngx_is_dir(&fi)) {
         return NGX_OK;
     }
 
-    /* THINK: not reached ??? */
-    return ngx_http_index_error(r, ctx, 0);
+    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                  "\"%s\" is not a directory", ctx->path);
+
+    return NGX_HTTP_INTERNAL_SERVER_ERROR;
 }
 
 
-static ngx_int_t ngx_http_index_error(ngx_http_request_t *r,
-                                      ngx_http_index_ctx_t *ctx, ngx_err_t err)
+static ngx_int_t
+ngx_http_index_error(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx,
+    ngx_err_t err)
 {
     if (err == NGX_EACCES) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
-                      "\"%s\" is forbidden", ctx->path.data);
+                      "\"%s\" is forbidden", ctx->path);
     
         return NGX_HTTP_FORBIDDEN;
     }
 
     ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
-                  "\"%s\" is not found", ctx->path.data);
+                  "\"%s\" is not found", ctx->path);
+
     return NGX_HTTP_NOT_FOUND;
 }
 
 
-static ngx_int_t ngx_http_index_init(ngx_cycle_t *cycle)
+static void *
+ngx_http_index_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_index_loc_conf_t  *conf;
+
+    conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t));
+    if (conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->indices = NULL;
+    conf->max_index_len = 1;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_index_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_index_loc_conf_t  *prev = parent;
+    ngx_http_index_loc_conf_t  *conf = child;
+
+    ngx_http_index_t  *index;
+
+    if (conf->indices == NULL) {
+        conf->indices = prev->indices;
+        conf->max_index_len = prev->max_index_len;
+    }
+
+    if (conf->indices == NULL) {
+        conf->indices = ngx_array_create(cf->pool, 1, sizeof(ngx_http_index_t));
+        if (conf->indices == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        index = ngx_array_push(conf->indices);
+        if (index == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        index->name.len = sizeof(NGX_HTTP_DEFAULT_INDEX);
+        index->name.data = (u_char *) NGX_HTTP_DEFAULT_INDEX;
+        index->lengths = NULL;
+        index->values = NULL;
+
+        conf->max_index_len = sizeof(NGX_HTTP_DEFAULT_INDEX);
+
+        return NGX_CONF_OK;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+/* TODO: warn about duplicate indices */
+
+static char *
+ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_index_loc_conf_t *ilcf = conf;
+
+    ngx_uint_t                  i, n;
+    ngx_str_t                  *value;
+    ngx_http_index_t           *index;
+    ngx_http_script_compile_t   sc;
+
+    if (ilcf->indices == NULL) {
+        ilcf->indices = ngx_array_create(cf->pool, 2, sizeof(ngx_http_index_t));
+        if (ilcf->indices == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    value = cf->args->elts;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+        if (value[i].data[0] == '/' && i != cf->args->nelts - 1) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "only the last index in \"index\" directive "
+                               "may be absolute");
+            return NGX_CONF_ERROR;
+        }
+
+        if (value[i].len == 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "index \"%V\" in \"index\" directive is invalid",
+                               &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+        index = ngx_array_push(ilcf->indices);
+        if (index == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        index->name.len = value[i].len;
+        index->name.data = value[i].data;
+        index->lengths = NULL;
+        index->values = NULL;
+
+        n = ngx_http_script_variables_count(&value[i]);
+
+        if (n == 0) {
+            index->name.len++;
+
+            if (ilcf->max_index_len != 0
+                && ilcf->max_index_len < index->name.len)
+            {
+                ilcf->max_index_len = index->name.len;
+            }
+
+            continue;
+        }
+
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+        sc.cf = cf;
+        sc.source = &value[i];
+        sc.lengths = &index->lengths;
+        sc.values = &index->values;
+        sc.variables = n;
+        sc.complete_lengths = 1;
+        sc.complete_values = 1;
+
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
+
+        ilcf->max_index_len = 0;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_index_init(ngx_cycle_t *cycle)
 {
     ngx_http_handler_pt        *h;
     ngx_http_core_main_conf_t  *cmcf;
@@ -430,129 +537,3 @@ static ngx_int_t ngx_http_index_init(ngx
 
     return NGX_OK;
 }
-
-
-static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf)
-{
-    ngx_http_index_loc_conf_t  *conf;
-
-    conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t));
-    if (conf == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    if (ngx_array_init(&conf->indices, cf->pool, 2, sizeof(ngx_str_t))
-                                                                  == NGX_ERROR)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->max_index_len = 0;
-
-    conf->index_cache = NULL;
-
-    return conf;
-}
-
-
-/* TODO: remove duplicate indices */
-
-static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf,
-                                           void *parent, void *child)
-{
-    ngx_http_index_loc_conf_t  *prev = parent;
-    ngx_http_index_loc_conf_t  *conf = child;
-
-    ngx_str_t  *index;
-
-    if (conf->max_index_len == 0) {
-        if (prev->max_index_len != 0) {
-            ngx_memcpy(conf, prev, sizeof(ngx_http_index_loc_conf_t));
-            return NGX_CONF_OK;
-        }
-
-        index = ngx_array_push(&conf->indices);
-        if (index == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        index->len = sizeof(NGX_HTTP_DEFAULT_INDEX) - 1;
-        index->data = (u_char *) NGX_HTTP_DEFAULT_INDEX;
-        conf->max_index_len = sizeof(NGX_HTTP_DEFAULT_INDEX);
-
-        return NGX_CONF_OK;
-    }
-
-#if 0
-
-    if (prev->max_index_len != 0) {
-
-        prev_index = prev->indices.elts;
-        for (i = 0; i < prev->indices.nelts; i++) {
-            index = ngx_array_push(&conf->indices);
-            if (index == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            index->len = prev_index[i].len;
-            index->data = prev_index[i].data;
-        }
-    }
-
-    if (conf->max_index_len < prev->max_index_len) {
-        conf->max_index_len = prev->max_index_len;
-    }
-
-#endif
-
-    if (conf->index_cache == NULL) {
-        conf->index_cache = prev->index_cache;
-    }
-
-    return NGX_CONF_OK;
-}
-
-
-/* TODO: warn about duplicate indices */
-
-static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
-                                      void *conf)
-{
-    ngx_http_index_loc_conf_t *ilcf = conf;
-
-    ngx_uint_t  i;
-    ngx_str_t  *index, *value;
-
-    value = cf->args->elts;
-
-    if (value[1].data[0] == '/' && ilcf->indices.nelts == 0) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "first index \"%V\" in \"%V\" directive "
-                           "must not be absolute",
-                           &value[1], &cmd->name);
-        return NGX_CONF_ERROR;
-    }
-
-    for (i = 1; i < cf->args->nelts; i++) {
-        if (value[i].len == 0) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "index \"%V\" in \"%V\" directive is invalid",
-                               &value[1], &cmd->name);
-            return NGX_CONF_ERROR;
-        }
-
-        index = ngx_array_push(&ilcf->indices);
-        if (index == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        index->len = value[i].len;
-        index->data = value[i].data;
-
-        if (ilcf->max_index_len < index->len + 1) {
-            ilcf->max_index_len = index->len + 1;
-        }
-    }
-
-    return NGX_CONF_OK;
-}
--- a/src/http/modules/ngx_http_not_modified_filter_module.c
+++ b/src/http/modules/ngx_http_not_modified_filter_module.c
@@ -14,7 +14,8 @@ static ngx_int_t ngx_http_not_modified_f
 
 
 static ngx_http_module_t  ngx_http_not_modified_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -28,7 +29,7 @@ static ngx_http_module_t  ngx_http_not_m
 
 
 ngx_module_t  ngx_http_not_modified_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_not_modified_filter_module_ctx, /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -45,6 +46,7 @@ static ngx_int_t ngx_http_not_modified_h
     time_t  ims;
 
     if (r->headers_out.status != NGX_HTTP_OK
+        || r->main
         || r->headers_in.if_modified_since == NULL
         || r->headers_out.last_modified_time == -1)
     {
@@ -63,12 +65,11 @@ static ngx_int_t ngx_http_not_modified_h
 
     if (ims != NGX_ERROR && ims == r->headers_out.last_modified_time) {
         r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
-        r->headers_out.content_type->key.len = 0;
-        r->headers_out.content_type = NULL;
+        r->headers_out.content_type.len = 0;
         r->headers_out.content_length_n = -1;
         r->headers_out.content_length = NULL;
 #if 0
-        r->headers_out.accept_ranges->key.len = 0;
+        r->headers_out.accept_ranges->hash = 0;
 #endif
     }
 
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -10,89 +10,100 @@
 #include <ngx_http.h>
 
 
-typedef struct {
-    ngx_http_upstream_conf_t   upstream;
+typedef struct ngx_http_proxy_redirect_s  ngx_http_proxy_redirect_t;
+
+typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r,
+    ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr);
 
-    ngx_peers_t               *peers;
+struct ngx_http_proxy_redirect_s {
+    ngx_http_proxy_redirect_pt   handler;
+    ngx_str_t                    redirect;
 
-    ngx_array_t               *headers_set_len;
-    ngx_array_t               *headers_set;
-    ngx_hash_t                *headers_set_hash;
+    union {
+        ngx_str_t                text;
+
+        struct {
+            void                *lengths;
+            void                *values;
+        } vars;
 
-    ngx_flag_t                 preserve_host;
-    ngx_flag_t                 set_x_url;
-    ngx_flag_t                 set_x_real_ip;
-    ngx_flag_t                 add_x_forwarded_for;
-    ngx_flag_t                 pass_server;
-    ngx_flag_t                 pass_x_accel_expires;
+        void                    *regex;
+    } replacement;
+};
+
+
+typedef struct {
+    ngx_http_upstream_conf_t     upstream;
+
+    ngx_peers_t                 *peers;
 
-    ngx_str_t                 *location0;
+    ngx_array_t                 *headers_set_len;
+    ngx_array_t                 *headers_set;
+    ngx_hash_t                  *headers_set_hash;
+
+    ngx_array_t                 *headers_source;
+    ngx_array_t                 *headers_names;
 
-    ngx_str_t                  host_header;
-    ngx_str_t                  uri0;
+    ngx_array_t                 *redirects;
 
-    ngx_array_t               *headers_sources;
-    ngx_array_t               *headers_names;
+    ngx_str_t                    host_header;
+    ngx_str_t                    port_text;
+
+    ngx_flag_t                   redirect;
 } ngx_http_proxy_loc_conf_t;
 
 
 typedef struct {
-    ngx_list_t                 headers;
-    
-    ngx_table_elt_t           *date;
-    ngx_table_elt_t           *server;
-
-    ngx_table_elt_t           *expires;
-    ngx_table_elt_t           *cache_control;
-    ngx_table_elt_t           *etag;
-    ngx_table_elt_t           *x_accel_expires;
+    ngx_uint_t                   status;
+    ngx_uint_t                   status_count;
+    u_char                      *status_start;
+    u_char                      *status_end;
+} ngx_http_proxy_ctx_t;
 
-    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;
-    ngx_table_elt_t           *x_pad;
 
-    off_t                      content_length_n;
-} ngx_http_proxy_headers_in_t;
+#define NGX_HTTP_PROXY_PARSE_NO_HEADER  20
 
 
 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
+static ngx_int_t ngx_http_proxy_parse_status_line(ngx_http_request_t *r,
+    ngx_http_proxy_ctx_t *p);
 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
-static ngx_int_t ngx_http_proxy_send_header(ngx_http_request_t *r);
 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
     ngx_int_t rc);
 
-static ngx_int_t ngx_http_proxy_compile_header_start(ngx_table_elt_t *h,
-    ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value);
-static ngx_int_t ngx_http_proxy_compile_header_end(ngx_array_t *lengths,
-    ngx_array_t *values);
+static ngx_http_variable_value_t *
+    ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data);
+static ngx_http_variable_value_t *
+    ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data);
+static ngx_http_variable_value_t *
+    ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
+    uintptr_t data);
+static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
+    ngx_table_elt_t *h, size_t prefix);
 
-static ngx_int_t ngx_http_proxy_init(ngx_cycle_t *cycle);
-static ngx_http_variable_value_t *ngx_http_proxy_host_variable
-    (ngx_http_request_t *r, uintptr_t data);
+static ngx_int_t ngx_http_proxy_add_variables(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);
 
 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 
-static char *ngx_http_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
 
+
 static ngx_conf_post_t  ngx_http_proxy_lowat_post =
-                                                { ngx_http_proxy_lowat_check };
+    { ngx_http_proxy_lowat_check };
+
+static ngx_conf_enum_t  ngx_http_proxy_set_methods[] = {
+    { ngx_string("get"), NGX_HTTP_GET },
+    { ngx_null_string, 0 }
+};
 
 static ngx_conf_bitmask_t  ngx_http_proxy_next_upstream_masks[] = {
     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
@@ -113,6 +124,13 @@ static ngx_command_t  ngx_http_proxy_com
       0,
       NULL },
 
+    { ngx_string("proxy_redirect"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+      ngx_http_proxy_redirect,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("proxy_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -134,6 +152,13 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
       &ngx_http_proxy_lowat_post },
 
+    { ngx_string("proxy_redirect_errors"),
+      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_proxy_loc_conf_t, upstream.redirect_errors),
+      NULL },
+
     { ngx_string("proxy_pass_unparsed_uri"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -141,39 +166,32 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_unparsed_uri),
       NULL },
 
-    { ngx_string("proxy_preserve_host"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
+    { ngx_string("proxy_set_header"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_table_elt_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, preserve_host),
+      offsetof(ngx_http_proxy_loc_conf_t, headers_source),
       NULL },
 
-    { ngx_string("proxy_set_x_url"),
+    { ngx_string("proxy_method"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.method),
+      ngx_http_proxy_set_methods },
+
+    { ngx_string("proxy_pass_request_headers"),
       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_proxy_loc_conf_t, set_x_url),
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
       NULL },
 
-    { ngx_string("proxy_set_x_real_ip"),
+    { ngx_string("proxy_pass_request_body"),
       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_proxy_loc_conf_t, set_x_real_ip),
-      NULL },
-
-    { ngx_string("proxy_set_x_var"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_proxy_set_x_var,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      0,
-      NULL },
-
-    { ngx_string("proxy_add_x_forwarded_for"),
-      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_proxy_loc_conf_t, add_x_forwarded_for),
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
       NULL },
 
     { ngx_string("proxy_header_buffer_size"),
@@ -232,18 +250,25 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
       &ngx_http_proxy_next_upstream_masks },
 
+    { ngx_string("proxy_pass_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_proxy_loc_conf_t, upstream.pass_x_powered_by),
+      NULL },
+
     { ngx_string("proxy_pass_server"),
       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_proxy_loc_conf_t, pass_server),
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_server),
       NULL },
 
     { ngx_string("proxy_pass_x_accel_expires"),
       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_proxy_loc_conf_t, pass_x_accel_expires),
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_x_accel_expires),
       NULL },
 
       ngx_null_command
@@ -251,7 +276,8 @@ static ngx_command_t  ngx_http_proxy_com
 
 
 ngx_http_module_t  ngx_http_proxy_module_ctx = {
-    NULL,                                  /* pre conf */
+    ngx_http_proxy_add_variables,          /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -265,25 +291,49 @@ ngx_http_module_t  ngx_http_proxy_module
 
 
 ngx_module_t  ngx_http_proxy_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_proxy_module_ctx,            /* module context */
     ngx_http_proxy_commands,               /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
-    ngx_http_proxy_init,                   /* init module */
+    NULL,                                  /* init module */
     NULL                                   /* init process */
 };
 
 
 static ngx_str_t ngx_http_proxy_methods[] = {
-    ngx_string("GET"),
-    ngx_string("HEAD"),
-    ngx_string("POST")
+    ngx_string("GET "),
+    ngx_string("HEAD "),
+    ngx_string("POST ")
 };
 
 
 static char  ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
 
-static ngx_str_t  ngx_http_proxy_host = ngx_string("PROXY_HOST");
+
+static ngx_table_elt_t  ngx_http_proxy_headers[] = {
+    { 0, ngx_string("Host"), ngx_string("$proxy_host"), },
+    { 0, ngx_string("Connection"), ngx_string("close"), },
+    { 0, ngx_null_string, ngx_null_string }
+};
+
+
+static ngx_http_variable_t  ngx_http_proxy_vars[] = {
+
+    { ngx_string("proxy_host"), ngx_http_proxy_host_variable, 0,
+      NGX_HTTP_VAR_CHANGABLE },
+
+    { ngx_string("proxy_port"), ngx_http_proxy_port_variable, 0,
+      NGX_HTTP_VAR_CHANGABLE },
+
+    { ngx_string("proxy_add_x_forwarded_for"),
+      ngx_http_proxy_add_x_forwarded_for_variable, 0, 0 },
+
+#if 0
+    { ngx_string("proxy_add_via"), NULL, 0, 0 },
+#endif
+
+    { ngx_null_string, NULL, 0, 0 }
+};
 
 
 #if (NGX_PCRE)
@@ -291,45 +341,6 @@ static ngx_str_t ngx_http_proxy_uri = ng
 #endif
 
 
-#if 0
-
-ngx_http_header_t ngx_http_proxy_headers_in[] = {
-    { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) },
-    { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) },
-
-    { ngx_string("Expires"), offsetof(ngx_http_proxy_headers_in_t, expires) },
-    { ngx_string("Cache-Control"),
-                 offsetof(ngx_http_proxy_headers_in_t, cache_control) },
-    { ngx_string("ETag"), offsetof(ngx_http_proxy_headers_in_t, etag) },
-    { ngx_string("X-Accel-Expires"),
-                 offsetof(ngx_http_proxy_headers_in_t, x_accel_expires) },
-
-    { ngx_string("Connection"),
-                 offsetof(ngx_http_proxy_headers_in_t, connection) },
-    { ngx_string("Content-Type"),
-                 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"),
-                 offsetof(ngx_http_proxy_headers_in_t, location) },
-    { ngx_string("Accept-Ranges"),
-                 offsetof(ngx_http_proxy_headers_in_t, accept_ranges) },
-    { ngx_string("X-Pad"), offsetof(ngx_http_proxy_headers_in_t, x_pad) },
-
-    { ngx_null_string, 0 }
-};
-
-#endif
-
-
 static ngx_int_t
 ngx_http_proxy_handler(ngx_http_request_t *r)
 {   
@@ -358,20 +369,17 @@ ngx_http_proxy_handler(ngx_http_request_
 
     u->create_request = ngx_http_proxy_create_request;
     u->reinit_request = ngx_http_proxy_reinit_request;
-    u->process_header = ngx_http_proxy_process_header;
-    u->send_header = ngx_http_proxy_send_header;
+    u->process_header = ngx_http_proxy_process_status_line;
     u->abort_request = ngx_http_proxy_abort_request;
     u->finalize_request = ngx_http_proxy_finalize_request;
 
+    if (plcf->redirects) {
+        u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
+    }
+
     u->pipe.input_filter = ngx_event_pipe_copy_input_filter;
 
-    u->log_ctx = r->connection->log->data;
-    u->log_handler = ngx_http_upstream_log_error;
-
-    u->schema0.len = sizeof("http://") - 1;
-    u->schema0.data = (u_char *) "http://";
-    u->uri0 = plcf->uri0;
-    u->location0 = plcf->location0;
+    u->accel = 1;
     
     r->upstream = u;
 
@@ -388,19 +396,19 @@ ngx_http_proxy_handler(ngx_http_request_
 static ngx_int_t
 ngx_http_proxy_create_request(ngx_http_request_t *r)
 {
-    size_t                          len;
-    ngx_uint_t                      i, key;
-    uintptr_t                       escape;
-    ngx_buf_t                      *b;
-    ngx_str_t                      *hh;
-    ngx_chain_t                    *cl;
-    ngx_list_part_t                *part;
-    ngx_table_elt_t                *header;
-    ngx_http_upstream_t            *u;
-    ngx_http_proxy_loc_conf_t      *plcf;
-    ngx_http_script_code_pt         code;
-    ngx_http_script_len_code_pt     lcode;
-    ngx_http_script_lite_engine_t   e;
+    size_t                        len, loc_len;
+    ngx_uint_t                    i, key;
+    uintptr_t                     escape;
+    ngx_buf_t                    *b;
+    ngx_str_t                    *hh;
+    ngx_chain_t                  *cl, *body;
+    ngx_list_part_t              *part;
+    ngx_table_elt_t              *header;
+    ngx_http_upstream_t          *u;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e, le;
+    ngx_http_proxy_loc_conf_t    *plcf;
+    ngx_http_script_len_code_pt   lcode;
 
     u = r->upstream;
 
@@ -409,64 +417,72 @@ ngx_http_proxy_create_request(ngx_http_r
     len = sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
 
     if (u->method) {
-        len += ngx_http_proxy_methods[u->method - 1].len + u->uri0.len;
+        len += ngx_http_proxy_methods[u->method - 1].len + u->conf->uri.len;
     } else {
-        len += r->method_name.len + u->uri0.len;
+        len += r->method_name.len + 1 + u->conf->uri.len;
     }
 
     escape = 0;
-    
+
+    loc_len = r->valid_location ? u->conf->location->len : 1;
+
     if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) {
         len += r->unparsed_uri.len - 1;
 
     } else {
         if (r->quoted_uri) {
-            escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location0->len,
-                                        r->uri.len - u->location0->len,
-                                        NGX_ESCAPE_URI);
+            escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
+                                        r->uri.len - loc_len, NGX_ESCAPE_URI);
         }
 
-        len += r->uri.len - u->location0->len + escape
-            + sizeof("?") - 1 + r->args.len;
+        len += r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len;
     }
 
+    ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
 
-    e.ip = plcf->headers_set_len->elts;
-    e.request = r;
+    le.ip = plcf->headers_set_len->elts;
+    le.request = r;
 
-    while (*(uintptr_t *) e.ip) {
-        lcode = *(ngx_http_script_len_code_pt *) e.ip;
-        len += lcode(&e);
+    while (*(uintptr_t *) le.ip) {
+        while (*(uintptr_t *) le.ip) {
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            len += lcode(&le);
+        }
+        le.ip += sizeof(uintptr_t);
     }
 
 
-    part = &r->headers_in.headers.part;
-    header = part->elts;
     hh = (ngx_str_t *) plcf->headers_set_hash->buckets;
 
-    for (i = 0; /* void */; i++) {
+    if (plcf->upstream.pass_request_headers) {
+        part = &r->headers_in.headers.part;
+        header = part->elts;
+
+        for (i = 0; /* void */; i++) {
 
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0; 
             }
 
-            part = part->next;
-            header = part->elts;
-            i = 0; 
-        }
-
-        key = header[i].hash % plcf->headers_set_hash->hash_size;
+            key = header[i].hash % plcf->headers_set_hash->hash_size;
 
-        if (hh[key].len == header[i].key.len
-            && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0)
-        {
-            continue;
+            if (hh[key].len == header[i].key.len
+                && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0)
+            {
+                continue;
+            }
+
+            len += header[i].key.len + sizeof(": ") - 1
+                + header[i].value.len + sizeof(CRLF) - 1;
         }
+    }
 
-        len += header[i].key.len + sizeof(": ") - 1
-            + header[i].value.len + sizeof(CRLF) - 1;
-    }
 
     b = ngx_create_temp_buf(r->pool, len);
     if (b == NULL) {
@@ -479,9 +495,6 @@ ngx_http_proxy_create_request(ngx_http_r
     }
 
     cl->buf = b;
-    cl->next = NULL;
-
-    r->request_body->bufs = cl;
 
 
     /* the request line */
@@ -491,23 +504,24 @@ ngx_http_proxy_create_request(ngx_http_r
                              ngx_http_proxy_methods[u->method - 1].data,
                              ngx_http_proxy_methods[u->method - 1].len);
     } else {
-        b->last = ngx_cpymem(b->last, r->method_name.data, r->method_name.len);
+        b->last = ngx_cpymem(b->last, r->method_name.data,
+                             r->method_name.len + 1);
     }
 
-    b->last = ngx_cpymem(b->last, u->uri0.data, u->uri0.len);
+    b->last = ngx_cpymem(b->last, u->conf->uri.data, u->conf->uri.len);
 
     if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) {
         b->last = ngx_cpymem(b->last, r->unparsed_uri.data + 1,
                              r->unparsed_uri.len - 1);
     } else {
         if (escape) {
-            ngx_escape_uri(b->last, r->uri.data + u->location0->len,
-                           r->uri.len - u->location0->len, NGX_ESCAPE_URI);
-            b->last += r->uri.len - u->location0->len + escape;
+            ngx_escape_uri(b->last, r->uri.data + loc_len,
+                           r->uri.len - loc_len, NGX_ESCAPE_URI);
+            b->last += r->uri.len - loc_len + escape;
 
         } else { 
-            b->last = ngx_cpymem(b->last, r->uri.data + u->location0->len,
-                                 r->uri.len - u->location0->len);
+            b->last = ngx_cpymem(b->last, r->uri.data + loc_len,
+                                 r->uri.len - loc_len);
         }
 
         if (r->args.len > 0) {
@@ -522,50 +536,76 @@ ngx_http_proxy_create_request(ngx_http_r
 
     e.ip = plcf->headers_set->elts;
     e.pos = b->last;
+    e.request = r;
 
-    while (*(uintptr_t *) e.ip) {
-        code = *(ngx_http_script_code_pt *) e.ip;
-        code((ngx_http_script_engine_t *) &e);
+    le.ip = plcf->headers_set_len->elts;
+
+    while (*(uintptr_t *) le.ip) {
+        lcode = *(ngx_http_script_len_code_pt *) le.ip;
+        lcode(&le);
+
+        if (*(ngx_http_script_len_code_pt *) le.ip) {
+
+            for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
+                lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            }
+
+            e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
+
+        } else {
+            e.skip = 0;
+        }
+
+        le.ip += sizeof(uintptr_t);
+
+        while (*(uintptr_t *) e.ip) {
+            code = *(ngx_http_script_code_pt *) e.ip;
+            code((ngx_http_script_engine_t *) &e);
+        } 
+        e.ip += sizeof(uintptr_t);
     }
 
     b->last = e.pos;
 
 
-    part = &r->headers_in.headers.part;
-    header = part->elts;
+    if (plcf->upstream.pass_request_headers) {
+        part = &r->headers_in.headers.part;
+        header = part->elts;
     
-    for (i = 0; /* void */; i++) {
+        for (i = 0; /* void */; i++) {
 
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0; 
             }
 
-            part = part->next;
-            header = part->elts;
-            i = 0; 
-        }
+            key = header[i].hash % plcf->headers_set_hash->hash_size;
 
-        key = header[i].hash % plcf->headers_set_hash->hash_size;
+            if (hh[key].len == header[i].key.len
+                && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0)
+            {
+                continue;
+            }
 
-        if (hh[key].len == header[i].key.len
-            && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0)
-        {
-            continue;
-        }
+            b->last = ngx_cpymem(b->last, header[i].key.data,
+                                 header[i].key.len);
 
-        b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len);
+            *b->last++ = ':'; *b->last++ = ' ';
 
-        *b->last++ = ':'; *b->last++ = ' ';
+            b->last = ngx_cpymem(b->last, header[i].value.data,
+                                 header[i].value.len);
 
-        b->last = ngx_cpymem(b->last, header[i].value.data,
-                             header[i].value.len);
+            *b->last++ = CR; *b->last++ = LF;
 
-        *b->last++ = CR; *b->last++ = LF;
-
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http proxy header: \"%V: %V\"",
-                       &header[i].key, &header[i].value);
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http proxy header: \"%V: %V\"",
+                           &header[i].key, &header[i].value);
+        }
     }
 
     /* add "\r\n" at the header end */
@@ -582,6 +622,36 @@ ngx_http_proxy_create_request(ngx_http_r
     }
 #endif
 
+    if (plcf->upstream.pass_request_body) {
+
+        body = u->request_bufs;
+        u->request_bufs = cl;
+
+        while (body) {
+            b = ngx_alloc_buf(r->pool);
+            if (b == NULL) {
+                return NGX_ERROR;
+            }
+
+            ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
+
+            cl->next = ngx_alloc_chain_link(r->pool);
+            if (cl->next == NULL) {
+                return NGX_ERROR;
+            }
+
+            cl = cl->next;
+            cl->buf = b;
+
+            body = body->next;
+        }
+
+    } else {
+        u->request_bufs = cl;
+    }
+
+    cl->next = NULL;
+
     return NGX_OK;
 }
 
@@ -589,6 +659,286 @@ ngx_http_proxy_create_request(ngx_http_r
 static ngx_int_t
 ngx_http_proxy_reinit_request(ngx_http_request_t *r)
 {
+    ngx_http_proxy_ctx_t  *p;
+
+    p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+    if (p == NULL) {
+        return NGX_OK;
+    }
+
+    p->status = 0;
+    p->status_count = 0;
+    p->status_start = NULL;
+    p->status_end = NULL;
+
+    r->upstream->process_header = ngx_http_proxy_process_status_line;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_process_status_line(ngx_http_request_t *r)
+{
+    ngx_int_t              rc;
+    ngx_http_upstream_t   *u;
+    ngx_http_proxy_ctx_t  *p;
+
+    p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+    if (p == NULL) {
+        p = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
+        if (p == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        ngx_http_set_ctx(r, p, ngx_http_proxy_module);
+    }
+
+    rc = ngx_http_proxy_parse_status_line(r, p);
+
+    if (rc == NGX_AGAIN) {
+        return rc;
+    }
+
+    u = r->upstream;
+
+    if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent no valid HTTP/1.0 header"); 
+
+        if (u->accel) {
+            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+        }
+
+        r->http_version = NGX_HTTP_VERSION_9;
+        p->status = NGX_HTTP_OK;
+    
+        return NGX_OK;
+    }
+
+    r->headers_out.status = p->status;
+    u->state->status = p->status;
+
+    r->headers_out.status_line.len = p->status_end - p->status_start;
+    r->headers_out.status_line.data = ngx_palloc(r->pool,
+                                                r->headers_out.status_line.len);
+    if (r->headers_out.status_line.data == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+    ngx_memcpy(r->headers_out.status_line.data, p->status_start,
+               r->headers_out.status_line.len);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http proxy status %ui \"%V\"",
+                   r->headers_out.status, &r->headers_out.status_line);
+
+    u->process_header = ngx_http_proxy_process_header;
+
+    return ngx_http_proxy_process_header(r);
+}
+
+
+static ngx_int_t
+ngx_http_proxy_parse_status_line(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p)
+{
+    u_char                ch;
+    u_char               *pos;
+    ngx_http_upstream_t  *u;
+    enum  {
+        sw_start = 0,
+        sw_H,
+        sw_HT,
+        sw_HTT,
+        sw_HTTP,
+        sw_first_major_digit,
+        sw_major_digit,
+        sw_first_minor_digit,
+        sw_minor_digit,
+        sw_status,
+        sw_space_after_status,
+        sw_status_text,
+        sw_almost_done
+    } state; 
+
+    u = r->upstream;
+
+    state = r->state;
+
+    for (pos = u->header_in.pos; pos < u->header_in.last; pos++) {
+        ch = *pos;
+
+        switch (state) {
+
+        /* "HTTP/" */
+        case sw_start:
+            switch (ch) {
+            case 'H': 
+                state = sw_H;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        case sw_H: 
+            switch (ch) {
+            case 'T': 
+                state = sw_HT;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        case sw_HT:
+            switch (ch) {
+            case 'T': 
+                state = sw_HTT;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        case sw_HTT:
+            switch (ch) {
+            case 'P': 
+                state = sw_HTTP;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        case sw_HTTP:
+            switch (ch) {
+            case '/': 
+                state = sw_first_major_digit;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        /* the first digit of major HTTP version */
+        case sw_first_major_digit:
+            if (ch < '1' || ch > '9') {
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+
+            state = sw_major_digit;
+            break;
+
+        /* the major HTTP version or dot */
+        case sw_major_digit:
+            if (ch == '.') {
+                state = sw_first_minor_digit;
+                break;
+            }
+
+            if (ch < '0' || ch > '9') {
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+
+            break;
+
+        /* the first digit of minor HTTP version */
+        case sw_first_minor_digit:
+            if (ch < '0' || ch > '9') {
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+
+            state = sw_minor_digit;
+            break;
+
+        /* the minor HTTP version or the end of the request line */
+        case sw_minor_digit:
+            if (ch == ' ') {
+                state = sw_status;
+                break;
+            }
+
+            if (ch < '0' || ch > '9') {
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+
+            break;
+
+        /* HTTP status code */
+        case sw_status:
+            if (ch < '0' || ch > '9') {
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+
+            p->status = p->status * 10 + ch - '0';
+
+            if (++p->status_count == 3) {
+                state = sw_space_after_status;
+                p->status_start = pos - 2;
+            }
+
+            break;
+
+         /* space or end of line */
+         case sw_space_after_status:
+            switch (ch) {
+            case ' ': 
+                state = sw_status_text;
+                break;
+            case '.':                    /* IIS may send 403.1, 403.2, etc */
+                state = sw_status_text;
+                break;
+            case CR:
+                state = sw_almost_done;
+                break;
+            case LF:
+                goto done;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        /* any text until end of line */
+        case sw_status_text:
+            switch (ch) {
+            case CR:
+                state = sw_almost_done;
+
+                break;
+            case LF:
+                goto done;
+            }
+            break;
+
+        /* end of request line */
+        case sw_almost_done:
+            p->status_end = pos - 1;
+            switch (ch) {
+            case LF:
+                goto done;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+        }
+    }
+
+    u->header_in.pos = pos + 1;
+    r->state = state;
+
+    return NGX_AGAIN;
+
+done:
+
+    u->header_in.pos = pos + 1;
+
+    if (p->status_end == NULL) {
+        p->status_end = pos;
+    }
+
+    r->state = sw_start;
+
     return NGX_OK;
 }
 
@@ -596,14 +946,79 @@ ngx_http_proxy_reinit_request(ngx_http_r
 static ngx_int_t
 ngx_http_proxy_process_header(ngx_http_request_t *r)
 {
-    return NGX_OK;
-}
+    ngx_int_t                       rc;
+    ngx_uint_t                      key;
+    ngx_table_elt_t                *h;
+    ngx_http_upstream_header_t     *hh;
+    ngx_http_upstream_main_conf_t  *umcf;
+
+    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+    hh = (ngx_http_upstream_header_t *) umcf->headers_in_hash.buckets;
+
+    for ( ;;  ) {
+
+        rc = ngx_http_parse_header_line(r, &r->upstream->header_in);
+
+        if (rc == NGX_OK) {
+
+            /* a header line has been parsed successfully */
 
+            h = ngx_list_push(&r->upstream->headers_in.headers);
+            if (h == NULL) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            h->hash = r->header_hash;
+
+            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;
 
-static ngx_int_t
-ngx_http_proxy_send_header(ngx_http_request_t *r)
-{
-    return NGX_OK;
+            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);
+
+            key = h->hash % umcf->headers_in_hash.hash_size;
+
+            if (hh[key].name.len == h->key.len
+                && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0)
+            {
+                if (hh[key].handler(r, h, hh[key].offset) != NGX_OK) {
+                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                }
+            }
+
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http proxy 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 proxy header done");
+
+            return NGX_OK;
+        }
+
+        /* 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;
+    }
 }
 
 
@@ -627,57 +1042,222 @@ ngx_http_proxy_finalize_request(ngx_http
 }
 
 
-static ngx_int_t
-ngx_http_proxy_init(ngx_cycle_t *cycle)
+static ngx_http_variable_value_t *
+ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data)
 {
-#if 0
-    ngx_http_variable_t  *var;
+    ngx_http_variable_value_t  *vv;
+    ngx_http_proxy_loc_conf_t  *plcf;
 
-    var = ngx_http_add_variable(cf, &ngx_http_proxy_host, 1);
-    if (var == NULL) {
-        return NGX_ERROR;
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
     }
 
-    var->handler = ngx_http_proxy_host_variable;
-#endif
-
-    return NGX_OK;
-
-#if 0
-    ngx_http_log_op_name_t  *op;
+    plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
 
-    for (op = ngx_http_proxy_log_fmt_ops; op->name.len; op++) { /* void */ }
-    op->run = NULL;
+    vv->value = 0;
+    vv->text = plcf->host_header;
 
-    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_proxy_log_fmt_ops;
-
-#endif
+    return vv;
 }
 
 
 static ngx_http_variable_value_t *
-ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data)
+ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data)
 {
-    ngx_http_variable_value_t  *var;
+    ngx_http_variable_value_t  *vv;
     ngx_http_proxy_loc_conf_t  *plcf;
 
-    var = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
-    if (var == NULL) {
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
         return NULL;
     }
 
     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
 
-    var->value = 0;
-    var->text = plcf->host_header;
+    vv->value = 0;
+    vv->text = plcf->port_text;
+
+    return vv;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
+    uintptr_t data)
+{
+    u_char                     *p;
+    ngx_http_variable_value_t  *vv;
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    vv->value = 0;
+
+    if (r->headers_in.x_forwarded_for == NULL) {
+        vv->text = r->connection->addr_text;
+        return vv;
+    }
+
+    vv->text.len = r->headers_in.x_forwarded_for->value.len
+                   + sizeof(", ") - 1 + r->connection->addr_text.len;
+
+    p = ngx_palloc(r->pool, vv->text.len);
+    if (p == NULL) {
+        return NULL;
+    }
+
+    vv->text.data = p;
+
+    p = ngx_cpymem(p, r->headers_in.x_forwarded_for->value.data,
+                   r->headers_in.x_forwarded_for->value.len);
+
+    *p++ = ','; *p++ = ' ';
+
+    ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
+
+    return vv;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
+    size_t prefix)
+{
+    ngx_int_t                   rc;
+    ngx_uint_t                  i;
+    ngx_http_proxy_loc_conf_t  *plcf;
+    ngx_http_proxy_redirect_t  *pr;
+
+    plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+    pr = plcf->redirects->elts;
+
+    if (pr == NULL) {
+        return NGX_DECLINED;
+    }
+
+    for (i = 0; i < plcf->redirects->nelts; i++) {
+        rc = pr->handler(r, h, prefix, pr);
+
+        if (rc != NGX_DECLINED) {
+            return rc;
+        }
+    }
+
+    return NGX_DECLINED;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h,
+    size_t prefix, ngx_http_proxy_redirect_t *pr)
+{
+    size_t   len;
+    u_char  *data, *p;
+
+    if (pr->redirect.len > h->value.len - prefix
+        || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
+                        pr->redirect.len) != 0)
+    {
+        return NGX_DECLINED;
+    }
+
+    len = prefix + pr->replacement.text.len + h->value.len - pr->redirect.len;
 
-    return var;
+    data = ngx_palloc(r->pool, len);
+    if (data == NULL) {
+        return NGX_ERROR;
+    }
+
+    p = data;
+
+    if (prefix) {
+        p = ngx_cpymem(p, h->value.data, prefix);
+    }
+
+    p = ngx_cpymem(p, pr->replacement.text.data, pr->replacement.text.len);
+
+    ngx_memcpy(p, h->value.data + prefix + pr->redirect.len,
+               h->value.len - pr->redirect.len - prefix);
+
+    h->value.len = len;
+    h->value.data = data;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t *r, ngx_table_elt_t *h,
+    size_t prefix, ngx_http_proxy_redirect_t *pr)
+{
+    size_t                        len;
+    u_char                       *data, *p;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e;
+    ngx_http_script_len_code_pt   lcode;
+
+    if (pr->redirect.len > h->value.len - prefix
+        || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
+                        pr->redirect.len) != 0)
+    {
+        return NGX_DECLINED;
+    }
+
+    ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+    e.ip = pr->replacement.vars.lengths;
+    e.request = r;
+
+    for (len = prefix; *(uintptr_t *) e.ip; len += lcode(&e)) {
+        lcode = *(ngx_http_script_len_code_pt *) e.ip;
+    }
+
+    data = ngx_palloc(r->pool, len);
+    if (data == NULL) {
+        return NGX_ERROR;
+    }
+
+    p = data;
+
+    if (prefix) {
+        p = ngx_cpymem(p, h->value.data, prefix);
+    }
+
+    e.ip = pr->replacement.vars.values;
+    e.pos = p;
+
+    while (*(uintptr_t *) e.ip) {
+        code = *(ngx_http_script_code_pt *) e.ip;
+        code(&e);
+    }
+
+    h->value.len = len;
+    h->value.data = data;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_add_variables(ngx_conf_t *cf)
+{
+    ngx_http_variable_t  *var, *v;
+
+    for (v = ngx_http_proxy_vars; v->name.len; v++) {
+        var = ngx_http_add_variable(cf, &v->name, v->flags);
+        if (var == NULL) {
+            return NGX_ERROR;
+        }
+
+        var->handler = v->handler;
+        var->data = v->data;
+    }
+
+    return NGX_OK;
 }
 
 
@@ -698,6 +1278,15 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
      *     conf->upstream.path = NULL;
      *     conf->upstream.next_upstream = 0;
      *     conf->upstream.temp_path = NULL;
+     *     conf->upstream.schema = { 0, NULL };
+     *     conf->upstream.uri = { 0, NULL };
+     *     conf->upstream.location = NULL;
+     *
+     *     conf->headers_source = NULL;
+     *     conf->headers_set_len = NULL;
+     *     conf->headers_set = NULL;
+     *     conf->headers_set_hash = NULL;
+     *     conf->rewrite_locations = NULL;
      */
     
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
@@ -709,21 +1298,23 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
     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.pass_unparsed_uri = NGX_CONF_UNSET;
+    conf->upstream.method = NGX_CONF_UNSET_UINT;
+    conf->upstream.pass_request_headers = NGX_CONF_UNSET;
+    conf->upstream.pass_request_body = NGX_CONF_UNSET;
     
     conf->upstream.redirect_errors = NGX_CONF_UNSET;
-    conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET;
-    conf->upstream.x_powered_by = NGX_CONF_UNSET;
 
     /* "proxy_cyclic_temp_file" is disabled */
     conf->upstream.cyclic_temp_file = 0;
 
-    conf->preserve_host = NGX_CONF_UNSET;
-    conf->set_x_url = NGX_CONF_UNSET;
-    conf->set_x_real_ip = NGX_CONF_UNSET;
-    conf->add_x_forwarded_for = NGX_CONF_UNSET;
+    conf->upstream.pass_x_powered_by = NGX_CONF_UNSET;
+    conf->upstream.pass_server = NGX_CONF_UNSET;
+    conf->upstream.pass_date = 0;
+    conf->upstream.pass_x_accel_expires = NGX_CONF_UNSET;
 
-    conf->pass_server = NGX_CONF_UNSET;
-    conf->pass_x_accel_expires = NGX_CONF_UNSET;
+    conf->redirect = NGX_CONF_UNSET;
 
     return conf;
 }
@@ -735,11 +1326,16 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
     ngx_http_proxy_loc_conf_t *prev = parent;
     ngx_http_proxy_loc_conf_t *conf = child;
 
-    size_t            size;
-    ngx_str_t        *name;
-    ngx_table_elt_t  *src;
-    ngx_http_variable_t  *var;
-    
+    u_char                       *p;
+    size_t                        size;
+    uintptr_t                    *code;
+    ngx_str_t                    *name;
+    ngx_uint_t                    i;
+    ngx_table_elt_t              *src, *s, *h;
+    ngx_http_proxy_redirect_t    *pr;
+    ngx_http_script_compile_t     sc;
+    ngx_http_script_copy_code_t  *copy;
+
     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                               prev->upstream.connect_timeout, 60000);
 
@@ -841,241 +1437,297 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
                                |NGX_HTTP_UPSTREAM_FT_ERROR
                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
 
-    ngx_conf_merge_msec_value(conf->upstream.redirect_errors,
-                              prev->upstream.redirect_errors, 0);
+    ngx_conf_merge_path_value(conf->upstream.temp_path,
+                              prev->upstream.temp_path,
+                              NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,
+                              ngx_garbage_collector_temp_handler, cf);
 
     ngx_conf_merge_msec_value(conf->upstream.pass_unparsed_uri,
                               prev->upstream.pass_unparsed_uri, 0);
 
-    if (conf->upstream.pass_unparsed_uri && conf->location0->len > 1) {
+    if (conf->upstream.pass_unparsed_uri && conf->upstream.location->len > 1) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                       "\"proxy_pass_unparsed_uri\" can be set for "
                       "location \"/\" or given by regular expression.");
         return NGX_CONF_ERROR;
     }
 
-    ngx_conf_merge_msec_value(conf->upstream.x_powered_by,
-                              prev->upstream.x_powered_by, 1);
+    if (conf->upstream.method == NGX_CONF_UNSET_UINT) {
+        conf->upstream.method = prev->upstream.method;
+    }
+
+    ngx_conf_merge_value(conf->upstream.pass_request_headers,
+                              prev->upstream.pass_request_headers, 1);
+    ngx_conf_merge_value(conf->upstream.pass_request_body,
+                              prev->upstream.pass_request_body, 1);
+
+    ngx_conf_merge_msec_value(conf->upstream.redirect_errors,
+                              prev->upstream.redirect_errors, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.pass_x_powered_by,
+                              prev->upstream.pass_x_powered_by, 1);
+    ngx_conf_merge_msec_value(conf->upstream.pass_server,
+                              prev->upstream.pass_server, 0);
+    ngx_conf_merge_msec_value(conf->upstream.pass_x_accel_expires,
+                              prev->upstream.pass_x_accel_expires, 0);
+
+
+    ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
+
+    if (conf->redirect) {
 
-    ngx_conf_merge_value(conf->preserve_host, prev->preserve_host, 0);
-    ngx_conf_merge_value(conf->set_x_url, prev->set_x_url, 0);
-    ngx_conf_merge_value(conf->set_x_real_ip, prev->set_x_real_ip, 0);
-    ngx_conf_merge_value(conf->add_x_forwarded_for,
-                              prev->add_x_forwarded_for, 0);
+        if (conf->redirects == NULL) {
+            conf->redirects = prev->redirects;
+        }
+
+        if (conf->redirects == NULL && conf->upstream.url.data) {
+
+            conf->redirects = ngx_array_create(cf->pool, 1,
+                                            sizeof(ngx_http_proxy_redirect_t));
+            if (conf->redirects == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            pr = ngx_array_push(conf->redirects);
+            if (pr == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            pr->handler = ngx_http_proxy_rewrite_redirect_text;
+            pr->redirect = conf->upstream.url;
+            pr->replacement.text = *conf->upstream.location;
+        }
+    }
+
 
     if (conf->peers == NULL) {
         conf->peers = prev->peers;
         conf->upstream = prev->upstream;
     }
 
-    if (conf->headers_set_hash == NULL) {
+    if (conf->headers_source == NULL) {
+        conf->headers_source = prev->headers_source;
         conf->headers_set_len = prev->headers_set_len;
         conf->headers_set = prev->headers_set;
         conf->headers_set_hash = prev->headers_set_hash;
     }
 
-    if (conf->headers_set_hash == NULL) {
+    if (conf->headers_set_hash) {
+        return NGX_CONF_OK;
+    }
+
+
+    conf->headers_names = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
+    if (conf->headers_names == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (conf->headers_source == NULL) {
+        conf->headers_source = ngx_array_create(cf->pool, 4,
+                                                sizeof(ngx_table_elt_t));
+        if (conf->headers_source == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
 
-        if (conf->headers_names == NULL) {
-            conf->headers_names = ngx_array_create(cf->pool, 4,
-                                                   sizeof(ngx_str_t));
-            if (conf->headers_names == NULL) {
-                return NGX_CONF_ERROR;
+    conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
+    if (conf->headers_set_len == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->headers_set = ngx_array_create(cf->pool, 512, 1);
+    if (conf->headers_set == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+
+    src = conf->headers_source->elts;
+
+    for (h = ngx_http_proxy_headers; h->key.len; h++) {
+
+        for (i = 0; i < conf->headers_source->nelts; i++) {
+            if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
+                goto next;
             }
         }
 
-        if (conf->headers_sources == NULL) {
-            conf->headers_sources = ngx_array_create(cf->pool, 4,
-                                                     sizeof(ngx_table_elt_t));
-            if (conf->headers_sources == NULL) {
-                return NGX_CONF_ERROR;
-            }
-        }
-
-        /* STUB */
-        var = ngx_http_add_variable(cf, &ngx_http_proxy_host, 0);
-        if (var == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        var->handler = ngx_http_proxy_host_variable;
-        /**/
-
-
-        name = ngx_array_push(conf->headers_names);
-        if (name == NULL) {
+        s = ngx_array_push(conf->headers_source);
+        if (s == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        name->len = sizeof("Host") - 1;
-        name->data = (u_char *) "Host";
+        *s = *h;
 
-        src = ngx_array_push(conf->headers_sources);
-        if (src == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        src->hash = 0;
-        src->key.len = sizeof("Host") - 1;
-        src->key.data = (u_char *) "Host";
-        src->value.len = sizeof("$PROXY_HOST") - 1;
-        src->value.data = (u_char *) "$PROXY_HOST";
-
+    next:
 
-        name = ngx_array_push(conf->headers_names);
-        if (name == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        name->len = sizeof("Connection") - 1;
-        name->data = (u_char *) "Connection";
+        continue;
+    }
 
-        src = ngx_array_push(conf->headers_sources);
-        if (src == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        src->hash = 0;
-        src->key.len = sizeof("Connection") - 1;
-        src->key.data = (u_char *) "Connection";
-        src->value.len = sizeof("close") - 1;
-        src->value.data = (u_char *) "close";
-
+    for (i = 0; i < conf->headers_source->nelts; i++) {
 
         name = ngx_array_push(conf->headers_names);
         if (name == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        name->len = 0;
-        name->data = NULL;
+        *name = src[i].key;
+
+        if (ngx_http_script_variables_count(&src[i].value) == 0) {
+            copy = ngx_array_push_n(conf->headers_set_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                 ngx_http_script_copy_len_code;
+            copy->len = src[i].key.len + sizeof(": ") - 1
+                        + src[i].value.len + sizeof(CRLF) - 1;
 
 
-        if (ngx_http_script_compile_lite(cf, conf->headers_sources,
-                &conf->headers_set_len, &conf->headers_set,
-                ngx_http_proxy_compile_header_start,
-                ngx_http_proxy_compile_header_end) != NGX_OK)
-        {
-            return NGX_CONF_ERROR;
-        }
+            size = (sizeof(ngx_http_script_copy_code_t)
+                       + src[i].key.len + sizeof(": ") - 1
+                       + src[i].value.len + sizeof(CRLF) - 1
+                       + sizeof(uintptr_t) - 1)
+                    & ~(sizeof(uintptr_t) - 1);
+
+            copy = ngx_array_push_n(conf->headers_set, size);
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = ngx_http_script_copy_code;
+            copy->len = src[i].key.len + sizeof(": ") - 1
+                        + src[i].value.len + sizeof(CRLF) - 1;
+
+            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+
+            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
+            *p++ = ':'; *p++ = ' ';
+            p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
+            *p++ = CR; *p = LF;
+
+        } else {
+            copy = ngx_array_push_n(conf->headers_set_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                 ngx_http_script_copy_len_code;
+            copy->len = src[i].key.len + sizeof(": ") - 1;
 
 
-        conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash_t));
-        if (conf->headers_set_hash == NULL) {
-            return NGX_CONF_ERROR;
+            size = (sizeof(ngx_http_script_copy_code_t)
+                    + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
+                    & ~(sizeof(uintptr_t) - 1);
+
+            copy = ngx_array_push_n(conf->headers_set, size);
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = ngx_http_script_copy_code;
+            copy->len = src[i].key.len + sizeof(": ") - 1;
+
+            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
+            *p++ = ':'; *p = ' ';
+
+
+            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+            sc.cf = cf;
+            sc.source = &src[i].value;
+            sc.lengths = &conf->headers_set_len;
+            sc.values = &conf->headers_set;
+
+            if (ngx_http_script_compile(&sc) != NGX_OK) {
+                return NGX_CONF_ERROR;
+            }
+
+
+            copy = ngx_array_push_n(conf->headers_set_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                 ngx_http_script_copy_len_code;
+            copy->len = sizeof(CRLF) - 1;
+
+
+            size = (sizeof(ngx_http_script_copy_code_t)
+                    + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
+                    & ~(sizeof(uintptr_t) - 1);
+
+            copy = ngx_array_push_n(conf->headers_set, size);
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = ngx_http_script_copy_code;
+            copy->len = sizeof(CRLF) - 1;
+
+            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+            *p++ = CR; *p = LF;
         }
 
-        conf->headers_set_hash->max_size = 100;
-        conf->headers_set_hash->bucket_limit = 1;
-        conf->headers_set_hash->bucket_size = sizeof(ngx_str_t);
-        conf->headers_set_hash->name = "proxy_headers";
-
-        if (ngx_hash_init(conf->headers_set_hash, cf->pool,
-                          conf->headers_names->elts) != NGX_OK)
-        {
+        code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
+        if (code == NULL) {
             return NGX_CONF_ERROR;
         }
 
-#if 0
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-#endif
-        ngx_log_error(NGX_LOG_NOTICE, cf->log, 0,
-                       "proxy_headers hash size: %ui, "
-                       "max buckets per entry: %ui",
-                       conf->headers_set_hash->hash_size,
-                       conf->headers_set_hash->min_buckets);
+        *code = (uintptr_t) NULL;
+
+        code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
     }
 
-    return NGX_CONF_OK;
-}
-
-
-static ngx_int_t
-ngx_http_proxy_compile_header_start(ngx_table_elt_t *h,
-    ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value)
-{
-    u_char                       *p;
-    size_t                        size;
-    ngx_http_script_copy_code_t  *copy;
-
-    copy = ngx_array_push_n(lengths, sizeof(ngx_http_script_copy_code_t));
-    if (copy == NULL) {
-        return NGX_ERROR;
-    }
-
-    copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len;
-    copy->len = h->key.len + sizeof(": ") - 1;
-
-    if (value) {
-        copy->len += h->value.len + sizeof(CRLF) - 1;
-    }
-
-    size = (copy->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
-
-    copy = ngx_array_push_n(values,
-                            sizeof(ngx_http_script_copy_code_t) + size);
-    if (copy == NULL) {
-        return NGX_ERROR;
+    code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
+    if (code == NULL) {
+        return NGX_CONF_ERROR;
     }
 
-    copy->code = ngx_http_script_copy;
-    copy->len = h->key.len + sizeof(": ") - 1;
-
-    if (value) {
-        copy->len += h->value.len + sizeof(CRLF) - 1;
-    }
-
-    p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
-
-    p = ngx_cpymem(p, h->key.data, h->key.len);
-    p = ngx_cpymem(p, ": ", sizeof(": ") - 1);
-
-    if (value) {
-        p = ngx_cpymem(p, h->value.data, h->value.len);
-        ngx_memcpy(p, CRLF, sizeof(CRLF) - 1);
-    }
-
-    return NGX_OK;
-}
+    *code = (uintptr_t) NULL;
 
 
-static ngx_int_t
-ngx_http_proxy_compile_header_end(ngx_array_t *lengths, ngx_array_t *values)
-{
-    size_t                        size;
-    ngx_http_script_copy_code_t  *copy;
-
-    copy = ngx_array_push_n(lengths, sizeof(ngx_http_script_copy_code_t));
-    if (copy == NULL) {
-        return NGX_ERROR;
+    conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash_t));
+    if (conf->headers_set_hash == NULL) {
+        return NGX_CONF_ERROR;
     }
 
-    copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len;
-    copy->len = sizeof(CRLF) - 1;
+    conf->headers_set_hash->max_size = 100;
+    conf->headers_set_hash->bucket_limit = 1;
+    conf->headers_set_hash->bucket_size = sizeof(ngx_str_t);
+    conf->headers_set_hash->name = "proxy_headers";
 
-    size = (sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
-            & ~(sizeof(uintptr_t) - 1);
-
-    copy = ngx_array_push_n(values,
-                            sizeof(ngx_http_script_copy_code_t) + size);
-    if (copy == NULL) {
-        return NGX_ERROR;
+    if (ngx_hash_init(conf->headers_set_hash, cf->pool,
+              conf->headers_names->elts, conf->headers_names->nelts) != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
     }
 
-    copy->code = ngx_http_script_copy;
-    copy->len = sizeof(CRLF) - 1;
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
+                   "proxy_headers hash size: %ui, "
+                   "max buckets per entry: %ui",
+                   conf->headers_set_hash->hash_size,
+                   conf->headers_set_hash->min_buckets);
 
-    ngx_memcpy((u_char *) copy + sizeof(ngx_http_script_copy_code_t),
-               CRLF, sizeof(CRLF) - 1);
-
-    return NGX_OK;
+    return NGX_CONF_OK;
 }
 
 
 static char *
 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_proxy_loc_conf_t *lcf = conf;
+    ngx_http_proxy_loc_conf_t *plcf = conf;
 
     ngx_uint_t                   i;
     ngx_str_t                   *value, *url;
@@ -1105,20 +1757,16 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
         unix_upstream.url.data = url->data + 7;
         unix_upstream.uri_part = 1;
 
-        lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
-        if (lcf->peers == NULL) {
+        plcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
+        if (plcf->peers == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        lcf->peers->peer[0].uri_separator = ":";
+        plcf->peers->peer[0].uri_separator = ":";
 
-        lcf->host_header.len = sizeof("localhost") - 1;
-        lcf->host_header.data = (u_char *) "localhost";
-        lcf->uri0 = unix_upstream.uri;
-#if 0
-	STUB
-        lcf->upstream->default_port = 1;
-#endif
+        plcf->host_header.len = sizeof("localhost") - 1;
+        plcf->host_header.data = (u_char *) "localhost";
+        plcf->upstream.uri = unix_upstream.uri;
 
 #else
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -1137,34 +1785,35 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
         inet_upstream.default_port_value = 80;
         inet_upstream.uri_part = 1;
 
-        lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
-        if (lcf->peers == NULL) {
+        plcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
+        if (plcf->peers == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        for (i = 0; i < lcf->peers->number; i++) {
-            lcf->peers->peer[i].uri_separator = ":";
+        for (i = 0; i < plcf->peers->number; i++) {
+            plcf->peers->peer[i].uri_separator = ":";
         }
 
-        lcf->host_header = inet_upstream.host_header;
-        lcf->uri0 = inet_upstream.uri;
-#if 0
-	STUB
-        lcf->port_text = inet_upstream.port_text;
-        lcf->upstream->default_port = inet_upstream.default_port;
-#endif
+        plcf->host_header = inet_upstream.host_header;
+        plcf->port_text = inet_upstream.port_text;
+        plcf->upstream.uri = inet_upstream.uri;
     }
 
+    plcf->upstream.schema.len = sizeof("http://") - 1;
+    plcf->upstream.schema.data = (u_char *) "http://";
+
     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
 
     clcf->handler = ngx_http_proxy_handler;
 
 #if (NGX_PCRE)
-    lcf->location0 = clcf->regex ? &ngx_http_proxy_uri : &clcf->name;
+    plcf->upstream.location = clcf->regex ? &ngx_http_proxy_uri : &clcf->name;
 #else
-    lcf->location0 = &clcf->name;
+    plcf->upstream.location = &clcf->name;
 #endif
 
+    plcf->upstream.url = *url;
+
     if (clcf->name.data[clcf->name.len - 1] == '/') {
         clcf->auto_redirect = 1;
     }
@@ -1174,8 +1823,84 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
 
 
 static char *
-ngx_http_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
+    ngx_http_proxy_loc_conf_t *plcf = conf;
+
+    ngx_str_t                  *value;
+    ngx_array_t                *vars_lengths, *vars_values;
+    ngx_http_script_compile_t   sc;
+    ngx_http_proxy_redirect_t  *pr;
+
+    if (plcf->redirect == 0) {
+        return NGX_CONF_OK;
+    }
+
+    value = cf->args->elts;
+
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        plcf->redirect = 0;
+        plcf->redirects = NULL;
+        return NGX_CONF_OK;
+    }
+
+    if (plcf->redirects == NULL) {
+        plcf->redirects = ngx_array_create(cf->pool, 1,
+                                           sizeof(ngx_http_proxy_redirect_t));
+        if (plcf->redirects == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    pr = ngx_array_push(plcf->redirects);
+    if (pr == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "default") == 0) {
+        if (plcf->upstream.url.data == NULL) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "\"proxy_rewrite_location default\" must go "
+                               "after the \"proxy_pass\" directive");
+            return NGX_CONF_ERROR;
+        }
+
+        pr->handler = ngx_http_proxy_rewrite_redirect_text;
+        pr->redirect = plcf->upstream.url;
+        pr->replacement.text = *plcf->upstream.location;
+
+        return NGX_CONF_OK;
+    }
+
+    if (ngx_http_script_variables_count(&value[2]) == 0) {
+        pr->handler = ngx_http_proxy_rewrite_redirect_text;
+        pr->redirect = value[1];
+        pr->replacement.text = value[2];
+
+        return NGX_CONF_OK;
+    }
+
+    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+    vars_lengths = NULL;
+    vars_values = NULL;
+
+    sc.cf = cf;
+    sc.source = &value[2];
+    sc.lengths = &vars_lengths;
+    sc.values = &vars_values;
+    sc.complete_lengths = 1;
+    sc.complete_values = 1;
+
+    if (ngx_http_script_compile(&sc) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    pr->handler = ngx_http_proxy_rewrite_redirect_vars;
+    pr->redirect = value[1];
+    pr->replacement.vars.lengths = vars_lengths->elts;
+    pr->replacement.vars.values = vars_values->elts;
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -54,7 +54,8 @@ static ngx_int_t ngx_http_range_body_fil
 
 
 static ngx_http_module_t  ngx_http_range_header_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -68,7 +69,7 @@ static ngx_http_module_t  ngx_http_range
 
 
 ngx_module_t  ngx_http_range_header_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_range_header_filter_module_ctx, /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -78,7 +79,8 @@ ngx_module_t  ngx_http_range_header_filt
 
 
 static ngx_http_module_t  ngx_http_range_body_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -92,7 +94,7 @@ static ngx_http_module_t  ngx_http_range
 
 
 ngx_module_t  ngx_http_range_body_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_range_body_filter_module_ctx, /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -120,6 +122,7 @@ ngx_http_range_header_filter(ngx_http_re
 
     if (r->http_version < NGX_HTTP_VERSION_10
         || r->headers_out.status != NGX_HTTP_OK
+        || r->main
         || r->headers_out.content_length_n == -1
         || !r->filter_allow_ranges)
     {
@@ -136,6 +139,7 @@ ngx_http_range_header_filter(ngx_http_re
             return NGX_ERROR;
         }
 
+        r->headers_out.accept_ranges->hash = 1;
         r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1;
         r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges";
         r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1;
@@ -269,6 +273,7 @@ ngx_http_range_header_filter(ngx_http_re
 
         r->headers_out.content_range = content_range;
 
+        content_range->hash = 1;
         content_range->key.len = sizeof("Content-Range") - 1;
         content_range->key.data = (u_char *) "Content-Range";
 
@@ -303,6 +308,7 @@ ngx_http_range_header_filter(ngx_http_re
 
         r->headers_out.content_range = content_range;
 
+        content_range->hash = 1;
         content_range->key.len = sizeof("Content-Range") - 1;
         content_range->key.data = (u_char *) "Content-Range";
 
@@ -338,7 +344,7 @@ ngx_http_range_header_filter(ngx_http_re
 
     len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
           + sizeof(CRLF "Content-Type: ") - 1
-          + r->headers_out.content_type->value.len
+          + r->headers_out.content_type.len
           + sizeof(CRLF "Content-Range: bytes ") - 1;
 
     if (r->headers_out.charset.len) {
@@ -366,7 +372,7 @@ ngx_http_range_header_filter(ngx_http_re
                                            "Content-Type: %V; charset=%V" CRLF
                                            "Content-Range: bytes ",
                                            boundary,
-                                           &r->headers_out.content_type->value,
+                                           &r->headers_out.content_type,
                                            &r->headers_out.charset)
                                    - ctx->boundary_header.data;
 
@@ -378,26 +384,26 @@ ngx_http_range_header_filter(ngx_http_re
                                            "Content-Type: %V" CRLF
                                            "Content-Range: bytes ",
                                            boundary,
-                                           &r->headers_out.content_type->value)
+                                           &r->headers_out.content_type)
                                    - ctx->boundary_header.data;
     }
 
-    r->headers_out.content_type->value.data =
-         ngx_palloc(r->pool,
-                    sizeof("Content-Type: multipart/byteranges; boundary=") - 1
-                    + NGX_ATOMIC_T_LEN);
+    r->headers_out.content_type.data =
+        ngx_palloc(r->pool,
+                   sizeof("Content-Type: multipart/byteranges; boundary=") - 1
+                   + NGX_ATOMIC_T_LEN);
 
-    if (r->headers_out.content_type->value.data == NULL) {
+    if (r->headers_out.content_type.data == NULL) {
         return NGX_ERROR;
     }
 
     /* "Content-Type: multipart/byteranges; boundary=0123456789" */
 
-    r->headers_out.content_type->value.len =
-                           ngx_sprintf(r->headers_out.content_type->value.data,
+    r->headers_out.content_type.len =
+                           ngx_sprintf(r->headers_out.content_type.data,
                                        "multipart/byteranges; boundary=%0muA",
                                        boundary)
-                           - r->headers_out.content_type->value.data;
+                           - r->headers_out.content_type.data;
 
 
     /* the size of the last boundary CRLF "--0123456789--" CRLF */
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -9,136 +9,36 @@
 #include <ngx_http.h>
 
 
-typedef struct ngx_http_rewrite_engine_s  ngx_http_rewrite_engine_t;
-
-typedef void (*ngx_http_rewrite_code_pt) (ngx_http_rewrite_engine_t *e);
-
-
 typedef struct {
-    ngx_str_t                     name;
-    ngx_uint_t                    wildcard;
+    ngx_str_t                   name;
+    ngx_uint_t                  wildcard;
 } ngx_http_rewrite_referer_t;
 
 
 typedef struct {
-    ngx_str_t                    *name;
-    ngx_http_variable_value_t    *value;
+    ngx_str_t                  *name;
+    ngx_http_variable_value_t  *value;
 } ngx_http_rewrite_variable_t;
 
 
 typedef struct {
-    ngx_array_t                  *codes;        /* uintptr_t */
-    ngx_array_t                  *referers;     /* ngx_http_rewrite_referer_t */
+    ngx_array_t                *codes;        /* uintptr_t */
+    ngx_array_t                *referers;     /* ngx_http_rewrite_referer_t */
 
-    ngx_uint_t                    max_captures;
-    ngx_uint_t                    stack_size;
+    ngx_uint_t                  max_captures;
+    ngx_uint_t                  stack_size;
 
-    ngx_flag_t                    log;
+    ngx_flag_t                  log;
 
-    ngx_flag_t                    no_referer;
-    ngx_flag_t                    blocked_referer;
+    ngx_flag_t                  no_referer;
+    ngx_flag_t                  blocked_referer;
 } ngx_http_rewrite_loc_conf_t;
 
 
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    ngx_regex_t                  *regex;
-    uintptr_t                     size;
-    uintptr_t                     ncaptures;
-    uintptr_t                     status;
-    uintptr_t                     next;
-
-    uintptr_t                     test:1;
-    uintptr_t                     uri:1;
-
-    /* add the r->args to the new arguments */
-    uintptr_t                     args:1;
-
-    uintptr_t                     redirect:1;
-    uintptr_t                     break_cycle:1;
-
-    ngx_str_t                     name;
-} ngx_http_rewrite_regex_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-
-    uintptr_t                     uri:1;
-
-    /* add the r->args to the new arguments */
-    uintptr_t                     args:1;
-
-    uintptr_t                     redirect:1;
-} ngx_http_rewrite_regex_end_code_t;
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     n;
-} ngx_http_rewrite_copy_capture_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     len;
-} ngx_http_rewrite_copy_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     status;
-    uintptr_t                     null;
-} ngx_http_rewrite_return_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     next;
-    void                        **loc_conf;
-} ngx_http_rewrite_if_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     value;
-    uintptr_t                     text_len;
-    uintptr_t                     text_data;
-} ngx_http_rewrite_value_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     index;
-} ngx_http_rewrite_var_code_t;
-
-
-struct ngx_http_rewrite_engine_s {
-    u_char                       *ip;
-    ngx_http_variable_value_t    *sp;
-
-    ngx_str_t                     buf;
-    ngx_str_t                    *line;
-
-    u_char                       *pos;
-
-    /* the start of the rewritten arguments */
-    u_char                       *args;
-
-    unsigned                      quote:1;
-
-    ngx_int_t                     status;
-
-    int                          *captures;
-
-    ngx_http_request_t           *request;
-    ngx_http_rewrite_loc_conf_t  *conf;
-};
-
-
-static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle);
 static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
     void *parent, void *child);
+static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle);
 static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
@@ -150,12 +50,8 @@ static char *ngx_http_rewrite_variable(n
     ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
 static char *ngx_http_rewrite_valid_referers(ngx_conf_t *cf,
     ngx_command_t *cmd, void *conf);
-static char * ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd,
+static char *ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
-static void *ngx_http_rewrite_start_code(ngx_pool_t *pool,
-    ngx_array_t **codes, size_t size);
-static void *ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size,
-    void *code);
 
 
 static ngx_command_t  ngx_http_rewrite_commands[] = {
@@ -211,7 +107,8 @@ static ngx_command_t  ngx_http_rewrite_c
 
 
 ngx_http_module_t  ngx_http_rewrite_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -225,7 +122,7 @@ ngx_http_module_t  ngx_http_rewrite_modu
 
 
 ngx_module_t  ngx_http_rewrite_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_rewrite_module_ctx,          /* module context */ 
     ngx_http_rewrite_commands,             /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -234,19 +131,15 @@ ngx_module_t  ngx_http_rewrite_module = 
 };
 
 
-#define ngx_http_rewrite_exit  (u_char *) &ngx_http_rewrite_exit_code
-
-uintptr_t ngx_http_rewrite_exit_code = (uintptr_t) NULL;
-
 static ngx_http_variable_value_t  ngx_http_rewrite_null_value =
-                                                        { 0, ngx_string("") };
+    { 0, ngx_string("") };
 
 
 static ngx_int_t
 ngx_http_rewrite_handler(ngx_http_request_t *r)
 {
-    ngx_http_rewrite_code_pt      code;
-    ngx_http_rewrite_engine_t    *e;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t     *e;
     ngx_http_rewrite_loc_conf_t  *cf;
 
     cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
@@ -255,13 +148,13 @@ ngx_http_rewrite_handler(ngx_http_reques
         return NGX_DECLINED;
     }
 
-    e = ngx_palloc(r->pool, sizeof(ngx_http_rewrite_engine_t));
+    e = ngx_pcalloc(r->pool, sizeof(ngx_http_script_engine_t));
     if (e == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    e->sp = ngx_palloc(r->pool,
-                       cf->stack_size * sizeof(ngx_http_variable_value_t));
+    e->sp = ngx_pcalloc(r->pool,
+                        cf->stack_size * sizeof(ngx_http_variable_value_t));
     if (e->sp == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -277,18 +170,13 @@ ngx_http_rewrite_handler(ngx_http_reques
     }
 
     e->ip = cf->codes->elts;
-    e->buf.len = 0;
-    e->buf.data = NULL;
-    e->line = NULL;
-    e->pos = NULL;
-    e->args = NULL;
+    e->request = r;
     e->quote = 1;
+    e->log = cf->log;
     e->status = NGX_DECLINED;
-    e->request = r;
-    e->conf = cf;
 
     while (*(uintptr_t *) e->ip) {
-        code = *(ngx_http_rewrite_code_pt *) e->ip;
+        code = *(ngx_http_script_code_pt *) e->ip;
         code(e);
     }
 
@@ -297,392 +185,7 @@ ngx_http_rewrite_handler(ngx_http_reques
 
 
 static void
-ngx_http_rewrite_regex_start_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_int_t                       rc;
-    ngx_uint_t                      n;
-    ngx_http_request_t             *r;
-    ngx_http_rewrite_regex_code_t  *code;
-
-    code = (ngx_http_rewrite_regex_code_t *) e->ip;
-
-    r = e->request;
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http rewrite regex: \"%V\"", &code->name);
-
-    if (code->uri) {
-        e->line = &r->uri;
-    } else {
-        e->sp--;
-        e->line = &e->sp->text;
-    }
-
-    rc = ngx_regex_exec(code->regex, e->line, e->captures, code->ncaptures);
-
-    if (rc == NGX_REGEX_NO_MATCHED) {
-        if (e->conf->log) {
-            ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                          "\"%V\" does not match \"%V\"", &code->name, e->line);
-        }
-
-        if (code->test) {
-            e->sp->value = 0;
-            e->sp->text.len = 0;
-            e->sp->text.data = (u_char *) "";
-            e->sp++;
-
-            e->ip += sizeof(ngx_http_rewrite_regex_code_t);
-            return;
-        }
-
-        e->ip += code->next;
-        return;
-    }
-
-    if (rc < 0) {
-        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                      ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
-                      rc, e->line, &code->name);
-
-        e->ip = ngx_http_rewrite_exit;
-        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-        return;
-    }
-
-    if (e->conf->log) {
-        ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                      "\"%V\" matches \"%V\"", &code->name, e->line);
-    }
-
-    if (code->test) {
-        e->sp->value = 1;
-        e->sp->text.len = 1;
-        e->sp->text.data = (u_char *) "1";
-        e->sp++;
-
-        e->ip += sizeof(ngx_http_rewrite_regex_code_t);
-        return;
-    }
-
-    if (code->status) {
-        e->status = code->status;
-
-        if (!code->redirect) {
-            e->ip = ngx_http_rewrite_exit;
-            return;
-        }
-    }
-
-    e->buf.len = code->size;
-
-    if (code->uri) {
-        if (!code->break_cycle) {
-            r->uri_changed = 1;
-            r->valid_unparsed_uri = 1;
-        }
-
-        if (rc && (r->quoted_uri || r->plus_in_uri)) {
-            e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
-                                             NGX_ESCAPE_ARGS);
-        }
-    }
-
-    for (n = 1; n < (ngx_uint_t) rc; n++) {
-        e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n];
-    }
-
-    if (code->args && r->args.len) {
-        e->buf.len += r->args.len + 1;
-    }
-
-    e->buf.data = ngx_palloc(r->pool, e->buf.len);
-    if (e->buf.data == NULL) {
-        e->ip = ngx_http_rewrite_exit;
-        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-        return;
-    }
-
-    e->quote = code->redirect;
-
-    e->pos = e->buf.data;
-
-    e->ip += sizeof(ngx_http_rewrite_regex_code_t);
-}
-
-
-static void
-ngx_http_rewrite_regex_end_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_request_t                 *r;
-    ngx_http_rewrite_regex_end_code_t  *code;
-
-    code = (ngx_http_rewrite_regex_end_code_t *) e->ip;
-
-    r = e->request;
-
-    e->quote = 0;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http rewrite regex end");
-
-    if (e->args) {
-        e->buf.len = e->args - e->buf.data;
-
-        if (code->args && r->args.len) {
-            *e->pos++ = '&';
-            e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len);
-        }
-
-        r->args.len = e->pos - e->args;
-        r->args.data = e->args;
-
-        e->args = NULL;
-
-    } else {
-        if (code->args && r->args.len) {
-            *e->pos++ = '?';
-            e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len);
-        }
-
-        e->buf.len = e->pos - e->buf.data;
-    }
-
-    if (!code->redirect) {
-        if (e->conf->log) {
-            ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                          "rewritten data: \"%V\", args: \"%V\"",
-                          &e->buf, &r->args);
-        }
-
-        if (code->uri) {
-            r->uri = e->buf;
-
-            if (ngx_http_set_exten(r) != NGX_OK) {
-                e->ip = ngx_http_rewrite_exit;
-                e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-                return;
-            }
-        }
-
-        e->ip += sizeof(ngx_http_rewrite_regex_end_code_t);
-        return;
-    }
-
-    ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                  "rewritten redirect: \"%V\"", &e->buf);
-
-    r->headers_out.location = ngx_list_push(&r->headers_out.headers);
-    if (r->headers_out.location == NULL) {
-        e->ip = ngx_http_rewrite_exit;
-        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-        return;
-    }
-
-    if (e->buf.data[0] != '/') {
-        r->headers_out.location->key.len = sizeof("Location") - 1;
-        r->headers_out.location->key.data = (u_char *) "Location";
-    }
-
-    r->headers_out.location->value = e->buf;
-
-    e->ip += sizeof(ngx_http_rewrite_regex_end_code_t);
-}
-
-
-static void
-ngx_http_rewrite_copy_capture_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_rewrite_copy_capture_code_t  *code;
-
-    code = (ngx_http_rewrite_copy_capture_code_t *) e->ip;
-
-    e->ip += sizeof(ngx_http_rewrite_copy_capture_code_t);
-
-    if ((e->args || e->quote)
-        && (e->request->quoted_uri || e->request->plus_in_uri))
-    {
-        e->pos = (u_char *) ngx_escape_uri(e->pos,
-                                &e->line->data[e->captures[code->n]],
-                                e->captures[code->n + 1] - e->captures[code->n],
-                                NGX_ESCAPE_ARGS);
-    } else {
-        e->pos = ngx_cpymem(e->pos, &e->line->data[e->captures[code->n]],
-                        e->captures[code->n + 1] - e->captures[code->n]);
-    }
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite capture: \"%V\"", &e->buf);
-}
-
-
-static void
-ngx_http_rewrite_copy_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_rewrite_copy_code_t  *code;
-
-    code = (ngx_http_rewrite_copy_code_t *) e->ip;
-
-    e->pos = ngx_cpymem(e->pos, e->ip + sizeof(ngx_http_rewrite_copy_code_t),
-                        code->len);
-
-    e->ip += sizeof(ngx_http_rewrite_copy_code_t)
-          + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite copy: \"%V\"", &e->buf);
-}
-
-
-static void
-ngx_http_rewrite_start_args_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite args");
-
-    e->args = e->pos;
-    e->ip += sizeof(uintptr_t);
-}
-
-
-static void
-ngx_http_rewrite_return_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_rewrite_return_code_t  *code;
-
-    code = (ngx_http_rewrite_return_code_t *) e->ip;
-
-    e->status = code->status;
-
-    e->ip += sizeof(ngx_http_rewrite_return_code_t) - sizeof(uintptr_t);
-}
-
-
-static void
-ngx_http_rewrite_if_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_rewrite_if_code_t  *code;
-
-    code = (ngx_http_rewrite_if_code_t *) e->ip;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite if");
-
-    e->sp--;
-
-    if (e->sp->value) {
-        if (code->loc_conf) {
-            e->request->loc_conf = code->loc_conf;
-        }
-
-        e->ip += sizeof(ngx_http_rewrite_if_code_t);
-        return;
-    }
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite if false");
-
-    e->ip += code->next;
-}
-
-
-static void
-ngx_http_rewrite_value_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_rewrite_value_code_t  *code;
-
-    code = (ngx_http_rewrite_value_code_t *) e->ip;
-
-    e->ip += sizeof(ngx_http_rewrite_value_code_t);
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite value");
-
-    e->sp->value = (ngx_uint_t) code->value;
-    e->sp->text.len = (size_t) code->text_len;
-    e->sp->text.data = (u_char *) code->text_data;
-    e->sp++;
-}
-
-
-static void
-ngx_http_rewrite_set_var_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_request_t           *r;
-    ngx_http_variable_value_t    *value;
-    ngx_http_core_main_conf_t    *cmcf;
-    ngx_http_rewrite_var_code_t  *code;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite set var");
-
-    code = (ngx_http_rewrite_var_code_t *) e->ip;
-
-    e->ip += sizeof(ngx_http_rewrite_var_code_t);
-
-    r = e->request;
-
-    if (r->variables == NULL) {
-        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-
-        r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts
-                                        * sizeof(ngx_http_variable_value_t *));
-        if (r->variables == NULL) {
-            e->ip = ngx_http_rewrite_exit;
-            e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-            return;
-        }
-    }
-
-    value = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
-    if (value == NULL) {
-        e->ip = ngx_http_rewrite_exit;
-        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-        return;
-    }
-
-    e->sp--;
-
-    *value = *e->sp;
-
-    r->variables[code->index] = value;
-}
-
-
-static void
-ngx_http_rewrite_var_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_variable_value_t    *value;
-    ngx_http_rewrite_var_code_t  *code;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite var");
-
-    code = (ngx_http_rewrite_var_code_t *) e->ip;
-
-    e->ip += sizeof(ngx_http_rewrite_var_code_t);
-
-    value = ngx_http_get_indexed_variable(e->request, code->index);
-
-    if (value == NULL || value == NGX_HTTP_VARIABLE_NOT_FOUND) {
-        e->sp->value = 0;
-        e->sp->text.len = 0;
-        e->sp->text.data = (u_char *) "";
-        e->sp++;
-
-        return;
-    }
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite var: %ui, \"%V\"", value->value, &value->text);
-
-    *e->sp = *value;
-    e->sp++;
-}
-
-
-static void
-ngx_http_rewrite_invalid_referer_code(ngx_http_rewrite_engine_t *e)
+ngx_http_rewrite_invalid_referer_code(ngx_http_script_engine_t *e)
 {
     u_char                       *ref;
     size_t                        len;
@@ -804,13 +307,6 @@ ngx_http_rewrite_invalid_referer_code(ng
 }
 
 
-static void
-ngx_http_rewrite_nop_code(ngx_http_rewrite_engine_t *e)
-{
-    e->ip += sizeof(uintptr_t);
-}
-
-
 static ngx_http_variable_value_t *
 ngx_http_rewrite_var(ngx_http_request_t *r, uintptr_t data)
 {
@@ -834,25 +330,6 @@ ngx_http_rewrite_var(ngx_http_request_t 
 }
 
 
-static ngx_int_t
-ngx_http_rewrite_init(ngx_cycle_t *cycle)
-{   
-    ngx_http_handler_pt        *h;
-    ngx_http_core_main_conf_t  *cmcf;
-    
-    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
-
-    h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
-    if (h == NULL) {
-        return NGX_ERROR;
-    }
-    
-    *h = ngx_http_rewrite_handler;
-    
-    return NGX_OK;
-}   
-
-
 static void *
 ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
 {
@@ -878,8 +355,7 @@ ngx_http_rewrite_merge_loc_conf(ngx_conf
     ngx_http_rewrite_loc_conf_t *prev = parent;
     ngx_http_rewrite_loc_conf_t *conf = child;
 
-    uintptr_t                      *code, *last;
-    ngx_http_rewrite_regex_code_t  *regex;
+    uintptr_t  *code;
 
     ngx_conf_merge_value(conf->log, prev->log, 0);
     ngx_conf_merge_unsigned_value(conf->stack_size, prev->stack_size, 10);
@@ -906,65 +382,6 @@ ngx_http_rewrite_merge_loc_conf(ngx_conf
         return NGX_CONF_OK;
     }
 
-    code = conf->codes->elts;
-    last = (uintptr_t *) ((u_char *) code + conf->codes->nelts);
-
-    while (code < last) {
-        if (*code == (uintptr_t) NULL) {
-            return NGX_CONF_OK;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_regex_start_code) {
-            regex = (ngx_http_rewrite_regex_code_t *) code;
-            if (conf->max_captures < regex->ncaptures) {
-                conf->max_captures = regex->ncaptures;
-            }
-            code = (uintptr_t *) ((u_char *) code + regex->next);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_if_code) {
-            code += sizeof(ngx_http_rewrite_if_code_t) / sizeof(uintptr_t);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_return_code) {
-            code += sizeof(ngx_http_rewrite_return_code_t) / sizeof(uintptr_t);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_set_var_code) {
-            code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_var_code) {
-            code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_value_code) {
-            code += sizeof(ngx_http_rewrite_value_code_t) / sizeof(uintptr_t);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_invalid_referer_code) {
-            code++;
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_nop_code) {
-            code++;
-            continue;
-        }
-
-#if (NGX_DEBUG)
-        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                      "unknown rewrite code: %p", *code);
-        return NGX_CONF_ERROR;
-#endif
-    }
-
     code = ngx_array_push_n(conf->codes, sizeof(uintptr_t));
     if (code == NULL) {
         return NGX_CONF_ERROR;
@@ -976,29 +393,47 @@ ngx_http_rewrite_merge_loc_conf(ngx_conf
 }
 
 
+static ngx_int_t
+ngx_http_rewrite_init(ngx_cycle_t *cycle)
+{   
+    ngx_http_handler_pt        *h;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
+
+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_rewrite_handler;
+
+    return NGX_OK;
+}   
+
+
 static char *
 ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_rewrite_loc_conf_t *lcf = conf;
     
-    u_char                                *data;
-    size_t                                 len, size;
-    ngx_str_t                             *value, err;
-    ngx_int_t                              n;
-    ngx_uint_t                             i, last;
-    ngx_http_rewrite_code_pt              *code;
-    ngx_http_rewrite_copy_code_t          *copy;
-    ngx_http_rewrite_regex_code_t         *regex;
-    ngx_http_rewrite_regex_end_code_t     *regex_end;
-    ngx_http_rewrite_copy_capture_code_t  *copy_capture;
-    u_char                                 errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_str_t                         *value, err;
+    ngx_int_t                          n;
+    ngx_uint_t                         last;
+    ngx_http_script_code_pt           *code;
+    ngx_http_script_compile_t          sc;
+    ngx_http_script_regex_code_t      *regex;
+    ngx_http_script_regex_end_code_t  *regex_end;
+    u_char                             errstr[NGX_MAX_CONF_ERRSTR];
 
-    regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                        sizeof(ngx_http_rewrite_regex_code_t));
+    regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                       sizeof(ngx_http_script_regex_code_t));
     if (regex == NULL) {
         return NGX_CONF_ERROR;
     }
 
+    ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
+
     value = cf->args->elts;
 
     err.len = NGX_MAX_CONF_ERRSTR;
@@ -1013,17 +448,19 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
         return NGX_CONF_ERROR;
     }
 
-    regex->code = ngx_http_rewrite_regex_start_code;
-    regex->size = 0;
-    regex->ncaptures = 0;
-    regex->status = 0;
-    regex->test = 0;
+    regex->code = ngx_http_script_regex_start_code;
     regex->uri = 1;
-    regex->args = 1;
-    regex->redirect = 0;
-    regex->break_cycle = 0;
     regex->name = value[1];
 
+    if (value[2].data[value[2].len - 1] == '?') {
+
+        /* the last "?" drops the original arguments */
+        value[2].len--;
+
+    } else {
+        regex->add_args = 1;
+    }
+
     last = 0;
 
     if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0) {
@@ -1057,113 +494,29 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
         }
     }
 
-    i = 0;
-
-    while (i < value[2].len) {
-
-        data = &value[2].data[i];
-
-        if (value[2].data[i] == '$' && i < value[2].len
-            && value[2].data[i + 1] >= '1' && value[2].data[i + 1] <= '9')
-        {
-
-            /* the "$1" - "$9" captures */
-
-            copy_capture = ngx_http_rewrite_add_code(lcf->codes,
-                                  sizeof(ngx_http_rewrite_copy_capture_code_t),
-                                  &regex);
-            if (copy_capture == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            i++;
-
-            copy_capture->code = ngx_http_rewrite_copy_capture_code;
-            copy_capture->n = value[2].data[i] - '0';
+    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
 
-            if (regex->ncaptures < copy_capture->n) {
-                regex->ncaptures = copy_capture->n;
-            }
-
-            copy_capture->n *= 2;
-
-            i++;
-
-            continue;
-        }
-
-        if (value[2].data[i] == '?') {
-
-            /* the arguments */
-
-            if (i == value[2].len - 1) {
-                /* the last "?" drops the original arguments */
-                regex->args = 0;
-                break;
-            }
-
-            if (!regex->redirect) {
-                code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t),
-                                                 &regex);
-                if (code == NULL) {
-                    return NGX_CONF_ERROR;
-                }
-
-                *code = ngx_http_rewrite_start_args_code;
+    sc.cf = cf;
+    sc.source = &value[2];
+    sc.lengths = &regex->lengths;
+    sc.values = &lcf->codes;
+    sc.variables = ngx_http_script_variables_count(&value[2]);
+    sc.main = regex;
+    sc.complete_lengths = 1;
+    sc.compile_args = !regex->redirect;
 
-                i++;
-
-                continue;
-            }
-        }
-
-        i++;
-
-        /* the substituion strings */
+    if (ngx_http_script_compile(&sc) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
 
-        while (i < value[2].len && value[2].data[i] != '$') {
-
-            if (value[2].data[i] == '?') {
-
-                if (i == value[2].len - 1) {
-                    /*
-                     * the last "?" drops the original arguments,
-                     * and it should not be copied to a substituion
-                     */
-                    regex->args = 0;
-                    break;
-                }
+    regex = sc.main;
 
-                if (!regex->redirect) {
-                    break;
-                }
-            }
-
-            i++;
-        }
-
-        len = &value[2].data[i] - data;
-
-        if (len == 0) {
-            continue;
-        }
+    regex->ncaptures = sc.ncaptures;
+    regex->size = sc.size;
+    regex->args = sc.args;
 
-        regex->size += len;
-
-        size = (len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
-
-        copy = ngx_http_rewrite_add_code(lcf->codes,
-                                   sizeof(ngx_http_rewrite_copy_code_t) + size,
-                                   &regex);
-        if (copy == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        copy->code = ngx_http_rewrite_copy_code;
-        copy->len = len;
-
-        ngx_memcpy((u_char *) copy + sizeof(ngx_http_rewrite_copy_code_t),
-                   data, len);
+    if (sc.variables == 0) {
+        regex->lengths = NULL;
     }
 
     n = ngx_regex_capture_count(regex->regex);
@@ -1191,21 +544,26 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
         regex->ncaptures = (regex->ncaptures + 1) * 3;
     }
 
-    regex_end = ngx_http_rewrite_add_code(lcf->codes,
-                                     sizeof(ngx_http_rewrite_regex_end_code_t),
-                                     &regex);
+    if (lcf->max_captures < regex->ncaptures) {
+        lcf->max_captures = regex->ncaptures;
+    }
+
+    regex_end = ngx_http_script_add_code(lcf->codes,
+                                      sizeof(ngx_http_script_regex_end_code_t),
+                                      &regex);
     if (regex_end == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    regex_end->code = ngx_http_rewrite_regex_end_code;
+    regex_end->code = ngx_http_script_regex_end_code;
     regex_end->uri = regex->uri;
     regex_end->args = regex->args;
+    regex_end->add_args = regex->add_args;
     regex_end->redirect = regex->redirect;
 
     if (last) {
-        code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t),
-                                         &regex);
+        code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t),
+                                        &regex);
         if (code == NULL) {
             return NGX_CONF_ERROR;
         }
@@ -1225,18 +583,18 @@ ngx_http_rewrite_return(ngx_conf_t *cf, 
 {
     ngx_http_rewrite_loc_conf_t *lcf = conf;
 
-    ngx_str_t                       *value;
-    ngx_http_rewrite_return_code_t  *ret;
+    ngx_str_t                      *value;
+    ngx_http_script_return_code_t  *ret;
 
-    ret = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                      sizeof(ngx_http_rewrite_return_code_t));
+    ret = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                     sizeof(ngx_http_script_return_code_t));
     if (ret == NULL) {
         return NGX_CONF_ERROR;
     }
 
     value = cf->args->elts;
 
-    ret->code = ngx_http_rewrite_return_code;
+    ret->code = ngx_http_script_return_code;
     ret->null = (uintptr_t) NULL;
 
     ret->status = ngx_atoi(value[1].data, value[1].len);
@@ -1262,7 +620,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_
     ngx_http_module_t            *module;
     ngx_http_conf_ctx_t          *ctx, *pctx;
     ngx_http_core_loc_conf_t     *clcf, *pclcf, **clcfp;
-    ngx_http_rewrite_if_code_t   *if_code;
+    ngx_http_script_if_code_t    *if_code;
     ngx_http_rewrite_loc_conf_t  *nlcf;
 
     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
@@ -1324,12 +682,12 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_
         return NGX_CONF_ERROR;
     }
 
-    if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_rewrite_if_code_t));
+    if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t));
     if (if_code == NULL) {
         return NULL;
     }
 
-    if_code->code = ngx_http_rewrite_if_code;
+    if_code->code = ngx_http_script_if_code;
 
     elts = lcf->codes->elts;
 
@@ -1362,7 +720,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_
 
 
     if (elts != lcf->codes->elts) {
-        if_code = (ngx_http_rewrite_if_code_t *)
+        if_code = (ngx_http_script_if_code_t *)
                    ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts));
     }
 
@@ -1376,10 +734,10 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_
 static char *
 ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf)
 {
-    ngx_str_t                      *value, err;
-    ngx_uint_t                      cur, last;
-    ngx_http_rewrite_regex_code_t  *regex;
-    u_char                          errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_str_t                     *value, err;
+    ngx_uint_t                     cur, last;
+    ngx_http_script_regex_code_t  *regex;
+    u_char                         errstr[NGX_MAX_CONF_ERRSTR];
 
     value = cf->args->elts;
     last = cf->args->nelts - 1;
@@ -1440,12 +798,14 @@ ngx_http_rewrite_if_condition(ngx_conf_t
             return NGX_CONF_ERROR;
         }
 
-        regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                        sizeof(ngx_http_rewrite_regex_code_t));
+        regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                         sizeof(ngx_http_script_regex_code_t));
         if (regex == NULL) {
             return NGX_CONF_ERROR;
         }
 
+        ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
+
         err.len = NGX_MAX_CONF_ERRSTR;
         err.data = errstr;
 
@@ -1458,16 +818,9 @@ ngx_http_rewrite_if_condition(ngx_conf_t
             return NGX_CONF_ERROR;
         }
 
-        regex->code = ngx_http_rewrite_regex_start_code;
-        regex->size = 0;
-        regex->ncaptures = 0;
-        regex->status = 0;
-        regex->next = sizeof(ngx_http_rewrite_regex_code_t);
+        regex->code = ngx_http_script_regex_start_code;
+        regex->next = sizeof(ngx_http_script_regex_code_t);
         regex->test = 1;
-        regex->uri = 0;
-        regex->args = 0;
-        regex->redirect = 0;
-        regex->break_cycle = 0;
         regex->name = value[last];
 
         return NGX_CONF_OK;
@@ -1484,9 +837,9 @@ static char *
 ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
     ngx_str_t *value)
 {
-    ngx_http_variable_t          *var;
-    ngx_http_rewrite_code_pt     *code;
-    ngx_http_rewrite_var_code_t  *var_code;
+    ngx_int_t                    index;
+    ngx_http_script_code_pt     *code;
+    ngx_http_script_var_code_t  *var_code;
 
     value->len--;
     value->data++;
@@ -1495,8 +848,8 @@ ngx_http_rewrite_variable(ngx_conf_t *cf
         && ngx_strncmp(value->data, "invalid_referer",
                        sizeof("invalid_referer") - 1) == 0)
     {
-        code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                           sizeof(ngx_http_rewrite_code_pt));
+        code = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                          sizeof(ngx_http_script_code_pt));
         if (code == NULL) {
             return NGX_CONF_ERROR;
         }
@@ -1504,20 +857,20 @@ ngx_http_rewrite_variable(ngx_conf_t *cf
         *code = ngx_http_rewrite_invalid_referer_code;
 
     } else {
-        var = ngx_http_add_variable(cf, value, 0);
+        index = ngx_http_get_variable_index(cf, value);
 
-        if (var == NULL) {
+        if (index == NGX_ERROR) {
             return NGX_CONF_ERROR;
         }
 
-        var_code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                           sizeof(ngx_http_rewrite_var_code_t));
+        var_code = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                           sizeof(ngx_http_script_var_code_t));
         if (var_code == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        var_code->code = ngx_http_rewrite_var_code;
-        var_code->index = var->index;
+        var_code->code = ngx_http_script_var_code;
+        var_code->index = index;
     }
 
     return NGX_CONF_OK;
@@ -1624,11 +977,11 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx
 {
     ngx_http_rewrite_loc_conf_t *lcf = conf;
 
-    ngx_int_t                       n;
-    ngx_str_t                      *value;
-    ngx_http_variable_t            *v;
-    ngx_http_rewrite_var_code_t    *var;
-    ngx_http_rewrite_value_code_t  *val;
+    ngx_int_t                      n, index;
+    ngx_str_t                     *value;
+    ngx_http_variable_t           *v;
+    ngx_http_script_var_code_t    *var;
+    ngx_http_script_value_code_t  *val;
 
     value = cf->args->elts;
 
@@ -1641,16 +994,21 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx
     value[1].len--;
     value[1].data++;
 
-    v = ngx_http_add_variable(cf, &value[1], 1);
+    v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGABLE);
     if (v == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    v->handler = ngx_http_rewrite_var;
-    v->data = v->index;
+    index = ngx_http_get_variable_index(cf, &value[1]);
+    if (index == NGX_ERROR) {
+        return NGX_CONF_ERROR;
+    }
 
-    val = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                      sizeof(ngx_http_rewrite_value_code_t));
+    v->handler = ngx_http_rewrite_var;
+    v->data = index;
+
+    val = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                     sizeof(ngx_http_script_value_code_t));
     if (val == NULL) {
         return NGX_CONF_ERROR;
     }
@@ -1661,55 +1019,19 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx
         n = 0;
     }
 
-    val->code = ngx_http_rewrite_value_code;
+    val->code = ngx_http_script_value_code;
     val->value = (uintptr_t) n;
     val->text_len = (uintptr_t) value[2].len;
     val->text_data = (uintptr_t) value[2].data;
 
-    var = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                      sizeof(ngx_http_rewrite_var_code_t));
+    var = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                     sizeof(ngx_http_script_var_code_t));
     if (var == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    var->code = ngx_http_rewrite_set_var_code;
-    var->index = (uintptr_t) v->index;
+    var->code = ngx_http_script_set_var_code;
+    var->index = (uintptr_t) index;
 
     return NGX_CONF_OK;
 }
-
-
-static void *
-ngx_http_rewrite_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size)
-{
-    if (*codes == NULL) {
-        *codes = ngx_array_create(pool, 256, 1);
-        if (*codes == NULL) {
-            return NULL;
-        }
-    }
-
-    return ngx_array_push_n(*codes, size);
-}
-
-
-static void *
-ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size, void *code)
-{
-    u_char  *elts, **p;
-    void    *new;
-
-    elts = codes->elts;
-
-    new = ngx_array_push_n(codes, size);
-    if (new == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    if (elts != codes->elts) {
-        p = code;
-        *p += (u_char *) codes->elts - elts;
-    }
-
-    return new;
-}
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -16,10 +16,13 @@
 
 #define NGX_HTTP_SSI_ERROR        1
 
+#define NGX_HTTP_SSI_DATE_LEN     2048
+
 
 typedef struct {
     ngx_flag_t        enable;
     ngx_flag_t        silent_errors;
+    ngx_flag_t        ignore_recycled_buffers;
 
     size_t            min_file_chunk;
     size_t            value_len;
@@ -50,6 +53,10 @@ typedef struct {
     size_t             looked;
 
     size_t             value_len;
+
+    ngx_uint_t         output;        /* unsigned  output:1; */
+
+    ngx_str_t          timefmt;
 } ngx_http_ssi_ctx_t;
 
 
@@ -70,7 +77,8 @@ typedef struct {
     ngx_http_ssi_command_pt   handler;
     ngx_http_ssi_param_t     *params;
 
-    ngx_uint_t                flush;    /* unsigned  flush:1; */
+    unsigned                  conditional:1;
+    unsigned                  flush:1;
 } ngx_http_ssi_command_t;
 
 
@@ -98,12 +106,28 @@ typedef enum {
 } ngx_http_ssi_state_e;
 
 
+static ngx_int_t ngx_http_ssi_output(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx);
 static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx);
 
 static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
+static ngx_int_t ngx_http_ssi_config(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
+static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
+static ngx_int_t ngx_http_ssi_if(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
+static ngx_int_t ngx_http_ssi_else(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
+static ngx_int_t ngx_http_ssi_endif(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
 
+static ngx_http_variable_value_t *
+    ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt);
+
+static ngx_int_t ngx_http_ssi_add_variables(ngx_conf_t *cf);
 static void *ngx_http_ssi_create_conf(ngx_conf_t *cf);
 static char *ngx_http_ssi_merge_conf(ngx_conf_t *cf,
     void *parent, void *child);
@@ -126,6 +150,13 @@ static ngx_command_t  ngx_http_ssi_filte
       offsetof(ngx_http_ssi_conf_t, silent_errors),
       NULL },
 
+    { ngx_string("ssi_ignore_recycled_buffers"),
+      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_ssi_conf_t, ignore_recycled_buffers),
+      NULL },
+
     { ngx_string("ssi_min_file_chunk"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_size_slot,
@@ -139,7 +170,8 @@ static ngx_command_t  ngx_http_ssi_filte
 
     
 static ngx_http_module_t  ngx_http_ssi_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    ngx_http_ssi_add_variables,            /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -153,7 +185,7 @@ static ngx_http_module_t  ngx_http_ssi_f
 
 
 ngx_module_t  ngx_http_ssi_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_ssi_filter_module_ctx,       /* module context */
     ngx_http_ssi_filter_commands,          /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -174,8 +206,16 @@ static u_char ngx_http_ssi_error_string[
 static ngx_str_t ngx_http_ssi_none = ngx_string("(none)");
 
 
-#define  NGX_HTTP_SSI_ECHO_VAR      0
-#define  NGX_HTTP_SSI_ECHO_DEFAULT  1
+#define  NGX_HTTP_SSI_ECHO_VAR         0
+#define  NGX_HTTP_SSI_ECHO_DEFAULT     1
+
+#define  NGX_HTTP_SSI_CONFIG_TIMEFMT   0
+
+#define  NGX_HTTP_SSI_INCLUDE_VIRTUAL  0
+#define  NGX_HTTP_SSI_INCLUDE_FILE     1
+
+#define  NGX_HTTP_SSI_IF_EXPR          0
+
 
 static ngx_http_ssi_param_t  ngx_http_ssi_echo_params[] = {
     { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1 },
@@ -183,13 +223,60 @@ static ngx_http_ssi_param_t  ngx_http_ss
     { ngx_null_string, 0, 0 }
 };
 
+static ngx_http_ssi_param_t  ngx_http_ssi_include_params[] = {
+    { ngx_string("virtual"), NGX_HTTP_SSI_INCLUDE_VIRTUAL, 0 },
+#if 0
+    { ngx_string("file"), NGX_HTTP_SSI_INCLUDE_FILE, 0 },
+#endif
+    { ngx_null_string, 0, 0 }
+};
+
+
+static ngx_http_ssi_param_t  ngx_http_ssi_config_params[] = {
+    { ngx_string("timefmt"), NGX_HTTP_SSI_CONFIG_TIMEFMT, 0 },
+    { ngx_null_string, 0, 0 }
+};
+
+
+static ngx_http_ssi_param_t  ngx_http_ssi_if_params[] = {
+    { ngx_string("expr"), NGX_HTTP_SSI_IF_EXPR, 0 },
+    { ngx_null_string, 0, 0 }
+};
+
+
+static ngx_http_ssi_param_t  ngx_http_ssi_no_params[] = {
+    { ngx_null_string, 0, 0 }
+};
+
 
 static ngx_http_ssi_command_t  ngx_http_ssi_commands[] = {
-    { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0 },
-    { ngx_null_string, NULL, NULL, 0 }
+    { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0, 0 },
+    { ngx_string("config"), ngx_http_ssi_config,
+                       ngx_http_ssi_config_params, 0, 0 },
+    { ngx_string("include"), ngx_http_ssi_include,
+                       ngx_http_ssi_include_params, 0, 1 },
+
+    { ngx_string("if"), ngx_http_ssi_if, ngx_http_ssi_if_params, 0, 0 },
+    { ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params, 1, 0 },
+    { ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params, 1, 0 },
+
+    { ngx_null_string, NULL, NULL, 0, 0 }
 };
 
 
+static ngx_http_variable_t  ngx_http_ssi_vars[] = {
+
+    { ngx_string("date_local"), ngx_http_ssi_date_gmt_local_variable, 0,
+      NGX_HTTP_VAR_NOCACHABLE },
+
+    { ngx_string("date_gmt"), ngx_http_ssi_date_gmt_local_variable, 1,
+      NGX_HTTP_VAR_NOCACHABLE },
+
+    { ngx_null_string, NULL, 0, 0 }
+};
+
+
+
 static ngx_int_t
 ngx_http_ssi_header_filter(ngx_http_request_t *r)
 {
@@ -204,9 +291,9 @@ ngx_http_ssi_header_filter(ngx_http_requ
 
     /* TODO: "text/html" -> custom types */
 
-    if (r->headers_out.content_type
-        && ngx_strncasecmp(r->headers_out.content_type->value.data,
-                                                          "text/html", 5) != 0)
+    if (r->headers_out.content_type.len == 0
+        || ngx_strncasecmp(r->headers_out.content_type.data, "text/html", 5)
+           != 0)
     {
         return ngx_http_next_header_filter(r);
     }
@@ -223,26 +310,33 @@ ngx_http_ssi_header_filter(ngx_http_requ
     ctx->value_len = conf->value_len;
     ctx->last_out = &ctx->out;
 
+    ctx->output = 1;
+
     ctx->params.elts = ctx->params_array;
     ctx->params.size = sizeof(ngx_table_elt_t);
     ctx->params.nalloc = NGX_HTTP_SSI_PARAMS_N;
     ctx->params.pool = r->pool;
 
-    r->headers_out.content_length_n = -1;
-    if (r->headers_out.content_length) {
-        r->headers_out.content_length->key.len = 0;
-        r->headers_out.content_length = NULL;
-    }
-
-    r->headers_out.last_modified_time = -1;
-    if (r->headers_out.last_modified) {
-        r->headers_out.last_modified->key.len = 0;
-        r->headers_out.last_modified = NULL;
-    }
+    ctx->timefmt.len = sizeof("%A, %d-%b-%Y %H:%M:%S %Z") - 1;
+    ctx->timefmt.data = (u_char *) "%A, %d-%b-%Y %H:%M:%S %Z";
 
     r->filter_need_in_memory = 1;
     r->filter_ssi_need_in_memory = 1;
 
+    if (r->main == NULL) {
+        r->headers_out.content_length_n = -1;
+        if (r->headers_out.content_length) {
+            r->headers_out.content_length->hash = 0;
+            r->headers_out.content_length = NULL;
+        }
+
+        r->headers_out.last_modified_time = -1;
+        if (r->headers_out.last_modified) {
+            r->headers_out.last_modified->hash = 0;
+            r->headers_out.last_modified = NULL;
+        }
+    }
+
     return ngx_http_next_header_filter(r);
 }
 
@@ -277,8 +371,8 @@ ngx_http_ssi_body_filter(ngx_http_reques
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module);
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http ssi filter");
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http ssi filter \"%V\"", &r->uri);
 
     while (ctx->in || ctx->buf) {
 
@@ -312,19 +406,50 @@ ngx_http_ssi_body_filter(ngx_http_reques
 
             if (ctx->copy_start != ctx->copy_end) {
 
-                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                               "saved: %d", ctx->saved);
+                if (ctx->output) {
+
+                    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                                   "saved: %d", ctx->saved);
+
+                    if (ctx->saved) {
+
+                        if (ctx->free) {
+                            cl = ctx->free;
+                            ctx->free = ctx->free->next;
+                            b = cl->buf;
+                            ngx_memzero(b, sizeof(ngx_buf_t));
 
-                if (ctx->saved) {
+                        } else {
+                            b = ngx_calloc_buf(r->pool);
+                            if (b == NULL) {
+                                return NGX_ERROR;
+                            }
+
+                            cl = ngx_alloc_chain_link(r->pool);
+                            if (cl == NULL) {
+                                return NGX_ERROR;
+                            }
+
+                            cl->buf = b;
+                        }
+
+                        b->memory = 1;
+                        b->pos = ngx_http_ssi_string;
+                        b->last = ngx_http_ssi_string + ctx->saved;
+
+                        *ctx->last_out = cl;
+                        ctx->last_out = &cl->next;
+
+                        ctx->saved = 0;
+                    }
 
                     if (ctx->free) {
                         cl = ctx->free;
                         ctx->free = ctx->free->next;
                         b = cl->buf;
-                        ngx_memzero(b, sizeof(ngx_buf_t));
 
                     } else {
-                        b = ngx_calloc_buf(r->pool);
+                        b = ngx_alloc_buf(r->pool);
                         if (b == NULL) {
                             return NGX_ERROR;
                         }
@@ -337,56 +462,31 @@ ngx_http_ssi_body_filter(ngx_http_reques
                         cl->buf = b;
                     }
 
-                    b->memory = 1;
-                    b->pos = ngx_http_ssi_string;
-                    b->last = ngx_http_ssi_string + ctx->saved;
+                    ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));
+
+                    b->last_buf = 0;
+                    b->recycled = 0;
+                    b->pos = ctx->copy_start;
+                    b->last = ctx->copy_end;
 
+                    if (b->in_file) {
+                        if (conf->min_file_chunk < (size_t) (b->last - b->pos))
+                        {
+                            b->file_last = b->file_pos + (b->last - b->start);
+                            b->file_pos += b->pos - b->start;
+
+                        } else {
+                            b->in_file = 0;
+                        }
+                    }
+
+                    cl->next = NULL;
                     *ctx->last_out = cl;
                     ctx->last_out = &cl->next;
 
+                } else {
                     ctx->saved = 0;
                 }
-
-                if (ctx->free) {
-                    cl = ctx->free;
-                    ctx->free = ctx->free->next;
-                    b = cl->buf;
-
-                } else {
-                    b = ngx_alloc_buf(r->pool);
-                    if (b == NULL) {
-                        return NGX_ERROR;
-                    }
-
-                    cl = ngx_alloc_chain_link(r->pool);
-                    if (cl == NULL) {
-                        return NGX_ERROR;
-                    }
-
-                    cl->buf = b;
-                }
-
-                ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));
-
-                b->last_buf = 0;
-                b->recycled = 0;
-                b->pos = ctx->copy_start;
-                b->last = ctx->copy_end;
-
-                if (b->in_file) {
-
-                    if (conf->min_file_chunk < (size_t) (b->last - b->pos)) {
-                        b->file_last = b->file_pos + (b->last - b->start);
-                        b->file_pos += b->pos - b->start;
-
-                    } else {
-                        b->in_file = 0;
-                    }
-                }
-
-                cl->next = NULL;
-                *ctx->last_out = cl;
-                ctx->last_out = &cl->next;
             }
 
             if (ctx->state == ssi_start_state) {
@@ -420,12 +520,16 @@ ngx_http_ssi_body_filter(ngx_http_reques
                     break;
                 }
 
-                if (cmd->name.len == 0) {
+                if (cmd->name.len == 0 && ctx->output) {
                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                   "invalid SSI command: \"%V\"", &ctx->command);
                     goto ssi_error;
                 }
 
+                if (!ctx->output && !cmd->conditional) {
+                    continue;
+                }
+
                 ngx_memzero(params,
                             NGX_HTTP_SSI_MAX_PARAMS * sizeof(ngx_str_t *));
 
@@ -479,6 +583,14 @@ ngx_http_ssi_body_filter(ngx_http_reques
                     }
                 }
 
+                if (cmd->flush && ctx->out) {
+                    rc = ngx_http_ssi_output(r, ctx);
+
+                    if (rc == NGX_ERROR) {
+                        return NGX_ERROR;
+                    }
+                }
+
                 if (cmd->handler(r, ctx, params) == NGX_OK) {
                     continue;
                 }
@@ -525,9 +637,9 @@ ngx_http_ssi_body_filter(ngx_http_reques
             continue;
         }
 
-        if (ctx->buf->recycled || ctx->buf->last_buf) {
+        if (ctx->buf->last_buf || ctx->buf->recycled) {
+
             if (b == NULL) {
-
                 if (ctx->free) {
                     cl = ctx->free;
                     ctx->free = ctx->free->next;
@@ -548,14 +660,19 @@ ngx_http_ssi_body_filter(ngx_http_reques
                     cl->buf = b;
                 }
 
+                b->sync = 1;
+
                 cl->next = NULL;
                 *ctx->last_out = cl;
                 ctx->last_out = &cl->next;
             }
 
             b->last_buf = ctx->buf->last_buf;
-            b->flush = ctx->buf->recycled;
             b->shadow = ctx->buf;
+
+            if (conf->ignore_recycled_buffers == 0)  {
+                b->recycled = ctx->buf->recycled;
+            }
         }
 
         ctx->buf = NULL;
@@ -567,6 +684,17 @@ ngx_http_ssi_body_filter(ngx_http_reques
         return NGX_OK;
     }
 
+    return ngx_http_ssi_output(r, ctx);
+}
+
+
+static ngx_int_t
+ngx_http_ssi_output(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx)
+{
+    ngx_int_t     rc;
+    ngx_buf_t    *b;
+    ngx_chain_t  *cl;
+
     rc = ngx_http_next_body_filter(r, ctx->out);
 
     if (ctx->busy == NULL) {
@@ -1154,7 +1282,7 @@ ngx_http_ssi_echo(ngx_http_request_t *r,
     var = params[NGX_HTTP_SSI_ECHO_VAR];
 
     for (i = 0; i < var->len; i++) {
-        var->data[i] = ngx_toupper(var->data[i]);
+        var->data[i] = ngx_tolower(var->data[i]);
     }
 
     vv = ngx_http_get_variable(r, var);
@@ -1163,7 +1291,7 @@ ngx_http_ssi_echo(ngx_http_request_t *r,
         return NGX_HTTP_SSI_ERROR;
     }
 
-    if (vv == NGX_HTTP_VARIABLE_NOT_FOUND) {
+    if (vv == NGX_HTTP_VAR_NOT_FOUND) {
         value = params[NGX_HTTP_SSI_ECHO_DEFAULT];
 
         if (value == NULL) {
@@ -1204,6 +1332,325 @@ ngx_http_ssi_echo(ngx_http_request_t *r,
 }
 
 
+static ngx_int_t
+ngx_http_ssi_config(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
+    ngx_str_t **params)
+{
+    ngx_str_t  *value;
+
+    value = params[NGX_HTTP_SSI_CONFIG_TIMEFMT];
+
+    if (value) {
+        ctx->timefmt = *value;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
+    ngx_str_t **params)
+{
+    u_char                      ch, *p, **value;
+    size_t                     *size, len;
+    ngx_uint_t                  i, j, n, bracket;
+    ngx_str_t                   uri, args, name;
+    ngx_array_t                 lengths, values;
+    ngx_http_variable_value_t  *vv;
+
+    /* TODO: file, virtual vs file */
+
+    uri = *params[NGX_HTTP_SSI_INCLUDE_VIRTUAL];
+    args.len = 0;
+    args.data = NULL;
+
+    n = ngx_http_script_variables_count(&uri);
+
+    if (n > 0) {
+
+        if (ngx_array_init(&lengths, r->pool, 8, sizeof(size_t *)) != NGX_OK) {
+            return NGX_HTTP_SSI_ERROR;
+        }
+
+        if (ngx_array_init(&values, r->pool, 8, sizeof(u_char *)) != NGX_OK) {
+            return NGX_HTTP_SSI_ERROR;
+        }
+
+        len = 0;
+
+        for (i = 0; i < uri.len; /* void */ ) {
+
+            name.len = 0;
+
+            if (uri.data[i] == '$') {
+
+                if (++i == uri.len) {
+                    goto invalid_variable;
+                }
+
+                if (uri.data[i] == '{') {
+                    bracket = 1;
+
+                    if (++i == uri.len) {
+                        goto invalid_variable;
+                    }
+
+                    name.data = &uri.data[i];
+
+                } else {
+                    bracket = 0;
+                    name.data = &uri.data[i];
+                }
+
+                for ( /* void */ ; i < uri.len; i++, name.len++) {
+                    ch = uri.data[i];
+
+                    if (ch == '}' && bracket) {
+                        i++;
+                        bracket = 0;
+                        break;
+                    }
+
+                    if ((ch >= 'A' && ch <= 'Z')
+                        || (ch >= 'a' && ch <= 'z')
+                        || (ch >= '0' && ch <= '9')
+                        || ch == '_')
+                    {
+                        continue;
+                    }
+
+                    break;
+                }
+
+                if (bracket) {
+                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                                  "the closing bracket in \"%V\" "
+                                  "variable is missing", &name);
+                    return NGX_HTTP_SSI_ERROR;
+                }
+
+                if (name.len == 0) {
+                    goto invalid_variable;
+                }
+
+                for (j = 0; j < name.len; j++) {
+                    name.data[j] = ngx_tolower(name.data[j]);
+                }
+
+                vv = ngx_http_get_variable(r, &name);
+
+                if (vv == NULL) {
+                    return NGX_HTTP_SSI_ERROR;
+                }
+
+                if (vv == NGX_HTTP_VAR_NOT_FOUND) {
+                    continue;
+                }
+
+                name = vv->text;
+
+            } else {
+                name.data = &uri.data[i];
+
+                while (i < uri.len && uri.data[i] != '$') {
+                    i++;
+                    name.len++;
+                }
+            }
+
+            len += name.len;
+
+            size = ngx_array_push(&lengths);
+            if (size == NULL) {
+                return NGX_HTTP_SSI_ERROR;
+            }
+
+            *size = name.len;
+
+            value = ngx_array_push(&values);
+            if (value == NULL) {
+                return NGX_HTTP_SSI_ERROR;
+            }
+
+            *value = name.data;
+        }
+
+        p = ngx_palloc(r->pool, len);
+        if (p == NULL) {
+            return NGX_HTTP_SSI_ERROR;
+        }
+
+        uri.len = len;
+        uri.data = p;
+
+        size = lengths.elts;
+        value = values.elts;
+
+        for (i = 0; i < values.nelts; i++) {
+            p = ngx_cpymem(p, value[i], size[i]);
+        }
+    }
+
+    for (i = 0; i < uri.len; i++) {
+        if (uri.data[i] == '?') {
+            args.len = uri.len - i - 1;
+            args.data = &uri.data[i + 1];
+            uri.len -= args.len + 1;
+
+            break;
+        }
+    }
+
+    if (ngx_http_subrequest(r, &uri, &args) != NGX_OK) {
+        return NGX_HTTP_SSI_ERROR;
+    }
+
+    return NGX_OK;
+
+invalid_variable:
+
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                  "invalid variable name in \"%V\"", &uri);
+
+    return NGX_ERROR;
+}
+
+
+static ngx_int_t
+ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
+    ngx_str_t **params)
+{
+    ngx_str_t                  *expr, var;
+    ngx_uint_t                  i;
+    ngx_http_variable_value_t  *vv;
+
+    expr = params[NGX_HTTP_SSI_IF_EXPR];
+
+    if (expr->data[0] != '$') {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "invalid variable name in \"%V\"", expr);
+        return NGX_HTTP_SSI_ERROR;
+    }
+
+    var.len = expr->len - 1;
+    var.data = expr->data + 1;
+
+    for (i = 0; i < var.len; i++) {
+        var.data[i] = ngx_tolower(var.data[i]);
+    }
+
+    vv = ngx_http_get_variable(r, &var);
+
+    if (vv == NULL) {
+        return NGX_HTTP_SSI_ERROR;
+    }
+
+    if (vv != NGX_HTTP_VAR_NOT_FOUND && vv->text.len != 0) {
+        ctx->output = 1;
+
+    } else {
+        ctx->output = 0;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_ssi_else(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
+    ngx_str_t **params)
+{
+    ctx->output = !ctx->output;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_ssi_endif(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
+    ngx_str_t **params)
+{
+    ctx->output = 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt)
+{
+    ngx_http_ssi_ctx_t         *ctx;
+    ngx_http_variable_value_t  *vv;
+    struct tm                   tm;
+    char                        buf[NGX_HTTP_SSI_DATE_LEN];
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module);
+
+    if (ctx->timefmt.len == sizeof("%s") - 1
+        && ctx->timefmt.data[0] == '%' && ctx->timefmt.data[1] == 's')
+    {
+        vv->value = ngx_time() + (gmt ? 0 : ngx_gmtoff);
+
+        vv->text.data = ngx_palloc(r->pool, NGX_TIME_T_LEN);
+        if (vv->text.data == NULL) {
+            return NULL;
+        }
+
+        vv->text.len = ngx_sprintf(vv->text.data, "%T", vv->value)
+                       - vv->text.data;
+        return vv;
+    }
+
+    if (gmt) {
+        ngx_libc_gmtime(&tm);
+    } else {
+        ngx_libc_localtime(&tm);
+    }
+
+    vv->value = ngx_time() + (gmt ? 0 : ngx_gmtoff);
+
+    vv->text.len = strftime(buf, NGX_HTTP_SSI_DATE_LEN,
+                            (char *) ctx->timefmt.data, &tm);
+    if (vv->text.len == 0) {
+        return NULL;
+    }
+
+    vv->text.data = ngx_palloc(r->pool, vv->text.len);
+    if (vv->text.data == NULL) {
+        return NULL;
+    }
+
+    ngx_memcpy(vv->text.data, buf, vv->text.len);
+
+    return vv;
+}
+
+
+static ngx_int_t
+ngx_http_ssi_add_variables(ngx_conf_t *cf)
+{
+    ngx_http_variable_t  *var, *v;
+
+    for (v = ngx_http_ssi_vars; v->name.len; v++) {
+        var = ngx_http_add_variable(cf, &v->name, v->flags);
+        if (var == NULL) {
+            return NGX_ERROR;
+        }
+
+        var->handler = v->handler;
+        var->data = v->data;
+    }
+
+    return NGX_OK; 
+}
+
+
 static void *
 ngx_http_ssi_create_conf(ngx_conf_t *cf)
 {
@@ -1216,6 +1663,7 @@ ngx_http_ssi_create_conf(ngx_conf_t *cf)
 
     conf->enable = NGX_CONF_UNSET;
     conf->silent_errors = NGX_CONF_UNSET;
+    conf->ignore_recycled_buffers = NGX_CONF_UNSET;
 
     conf->min_file_chunk = NGX_CONF_UNSET_SIZE;
     conf->value_len = NGX_CONF_UNSET_SIZE;
@@ -1232,6 +1680,8 @@ ngx_http_ssi_merge_conf(ngx_conf_t *cf, 
 
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
     ngx_conf_merge_value(conf->silent_errors, prev->silent_errors, 0);
+    ngx_conf_merge_value(conf->ignore_recycled_buffers,
+                         prev->ignore_recycled_buffers, 0);
 
     ngx_conf_merge_size_value(conf->min_file_chunk, prev->min_file_chunk, 1024);
     ngx_conf_merge_size_value(conf->value_len, prev->value_len, 256);
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -64,7 +64,8 @@ static ngx_command_t  ngx_http_ssl_comma
 
 
 static ngx_http_module_t  ngx_http_ssl_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     ngx_http_ssl_create_main_conf,         /* create main configuration */
     ngx_http_ssl_init_main_conf,           /* init main configuration */
@@ -78,7 +79,7 @@ static ngx_http_module_t  ngx_http_ssl_m
 
 
 ngx_module_t  ngx_http_ssl_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_ssl_module_ctx,              /* module context */
     ngx_http_ssl_commands,                 /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -197,6 +198,13 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
         return NGX_CONF_ERROR;
     }
 
+    if (ngx_pool_cleanup_add(cf->pool, ngx_ssl_cleanup_ctx, conf->ssl_ctx)
+        == NULL)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+
 #if 0
     SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL);
     SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_NO_SSLv3);
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -17,7 +17,7 @@ typedef struct {
 static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r);
 static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf,
-                                            void *parent, void *child);
+    void *parent, void *child);
 static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle);
 
 
@@ -38,9 +38,9 @@ static ngx_command_t  ngx_http_static_co
 };
 
 
-
 ngx_http_module_t  ngx_http_static_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -54,7 +54,7 @@ ngx_http_module_t  ngx_http_static_modul
 
 
 ngx_module_t  ngx_http_static_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_static_module_ctx,           /* module context */
     ngx_http_static_commands,              /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -63,7 +63,8 @@ ngx_module_t  ngx_http_static_module = {
 };
 
 
-static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r)
+static ngx_int_t
+ngx_http_static_handler(ngx_http_request_t *r)
 {
     u_char                      *last;
     ngx_fd_t                     fd;
@@ -75,16 +76,8 @@ static ngx_int_t ngx_http_static_handler
     ngx_buf_t                   *b;
     ngx_chain_t                  out;
     ngx_file_info_t              fi;
-    ngx_http_cleanup_t          *file_cleanup;
-#if (NGX_HTTP_CACHE)
-    ngx_http_cleanup_t          *redirect_cleanup;
-#endif
+    ngx_pool_cleanup_file_t     *cln;
     ngx_http_core_loc_conf_t    *clcf;
-#if (NGX_HTTP_CACHE)
-    ngx_http_static_loc_conf_t  *slcf;
-    uint32_t                     file_crc, redirect_crc;
-    ngx_http_cache_t            *file, *redirect;
-#endif
 
     if (r->uri.data[r->uri.len - 1] == '/') {
         return NGX_DECLINED;
@@ -105,19 +98,6 @@ static ngx_int_t ngx_http_static_handler
         return rc;
     }
 
-#if (NGX_HTTP_CACHE)
-
-    /*
-     * there is a valid cached open file, i.e by the index handler,
-     * and it should be already registered in r->cleanup
-     */
-
-    if (r->cache && !r->cache->expired) {
-        return ngx_http_send_cached(r);
-    }
-
-#endif
-
     log = r->connection->log;
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -127,7 +107,19 @@ static ngx_int_t ngx_http_static_handler
      * in a possible redirect and for the last '\0'
      */
 
-    if (clcf->alias) {
+    if (!clcf->alias) {
+        name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2);
+        if (name.data == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len);
+        last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);
+
+        name.len = last - name.data;
+        location.len = last - location.data + 1;
+
+    } else {
         name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2
                                         - clcf->name.len);
         if (name.data == NULL) {
@@ -147,119 +139,16 @@ static ngx_int_t ngx_http_static_handler
 
         last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);
 
-#if 0
-        /*
-         * aliases usually have trailling "/",
-         * set it in the start of the possible redirect
-         */
-
-        if (*location.data != '/') {
-            location.data--;
-        }
-#endif
-
-        location.len = last - location.data + 1;
-
-    } else {
-        name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2);
-        if (name.data == NULL) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len);
-        last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);
-
-        name.len = last - name.data;
         location.len = last - location.data + 1;
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                    "http filename: \"%s\"", name.data);
 
-
-    /* allocate cleanups */
-
-    file_cleanup = ngx_array_push(&r->cleanup);
-    if (file_cleanup == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-    file_cleanup->valid = 0;
-
-#if (NGX_HTTP_CACHE)
-
-    slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module);
-    if (slcf->redirect_cache) {
-        redirect_cleanup = ngx_array_push(&r->cleanup);
-        if (redirect_cleanup == NULL) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-        redirect_cleanup->valid = 0;
-
-    } else {
-        redirect_cleanup = NULL;
-    }
-
-    /* look up an open files cache */
-
-    if (clcf->open_files) {
-        file = ngx_http_cache_get(clcf->open_files, file_cleanup,
-                                  &name, &file_crc);
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                       "http open file cache get: %p", file);
-
-        if (file && !file->expired) {
-            r->cache = file;
-            return ngx_http_send_cached(r);
-        }
-
-    } else {
-        file = NULL;
-    }
-
-
-    /* look up an redirect cache */
-
-    if (slcf->redirect_cache) {
-        redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup,
-                                      &name, &redirect_crc);
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                       "http redirect cache get: %p", redirect);
-
-        if (redirect && !redirect->expired) {
-
-            /*
-             * We do not copy a cached value so the cache entry is locked
-             * until the end of the request.  In a single threaded model
-             * the redirected request should complete before other event
-             * will be processed.  In a multithreaded model this locking
-             * should keep more popular redirects in cache.
-             */
-
-            r->headers_out.location = ngx_http_add_header(&r->headers_out,
-                                                          ngx_http_headers_out);
-            if (r->headers_out.location == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
-
-            r->headers_out.location->value = redirect->data.value;
-
-            return NGX_HTTP_MOVED_PERMANENTLY;
-        }
-
-    } else {
-        redirect = NULL;
-    }
-
-#endif
-
     /* open file */
 
 #if (NGX_WIN9X)
 
-    /* TODO: redirect cache */
-
     if (ngx_win32_version < NGX_WIN_NT) {
 
         /*
@@ -285,9 +174,6 @@ static ngx_int_t ngx_http_static_handler
         }
 
         if (ngx_is_dir(&fi)) {
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                           "HTTP DIR: \"%s\"", name.data);
-
             r->headers_out.location = ngx_http_add_header(&r->headers_out,
                                                           ngx_http_headers_out);
             if (r->headers_out.location == NULL) {
@@ -356,59 +242,17 @@ static ngx_int_t ngx_http_static_handler
         *last++ = '/';
         *last = '\0';
 
-        r->headers_out.location = ngx_list_push(&r->headers_out.headers);
+        r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
         if (r->headers_out.location == NULL) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        r->headers_out.location->value = location;
-
-#if (NGX_HTTP_CACHE)
-
-        if (slcf->redirect_cache) {
-            if (redirect) {
-                if (location.len == redirect->data.value.len
-                    && ngx_memcmp(redirect->data.value.data, location.data,
-                                                            location.len) == 0)
-                {
-                    redirect->accessed = ngx_cached_time;
-                    redirect->updated = ngx_cached_time;
-
-                    /*
-                     * we can unlock the cache entry because
-                     * we have the local copy anyway
-                     */
-
-                    ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
-                    redirect_cleanup->valid = 0;
+        /*
+         * we do not need to set the r->headers_out.location->hash and
+         * r->headers_out.location->key fields
+         */
 
-                    return NGX_HTTP_MOVED_PERMANENTLY;
-                }
-            }
-
-            location.len++;
-            redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect,
-                                            redirect_cleanup,
-                                            &name, redirect_crc,
-                                            &location, log);
-            location.len--;
-
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                           "http redirect cache alloc: %p", redirect);
-
-            if (redirect) {
-                redirect->fd = NGX_INVALID_FILE;
-                redirect->accessed = ngx_cached_time;
-                redirect->last_modified = 0;
-                redirect->updated = ngx_cached_time;
-                redirect->memory = 1;
-                ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
-                redirect_cleanup->valid = 0;
-            }
-
-        }
-
-#endif
+        r->headers_out.location->value = location;
 
         return NGX_HTTP_MOVED_PERMANENTLY;
     }
@@ -429,68 +273,20 @@ static ngx_int_t ngx_http_static_handler
 
 #endif
 
-
-#if (NGX_HTTP_CACHE)
-
-    if (clcf->open_files) {
-
-#if (NGX_USE_HTTP_FILE_CACHE_UNIQ)
-
-        if (file && file->uniq == ngx_file_uniq(&fi)) {
-            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                              ngx_close_file_n " \"%s\" failed", name.data);
-            }
-            file->accessed = ngx_cached_time;
-            file->updated = ngx_cached_time;
-            file->expired = 0;
-            r->cache = file;
-
-            return ngx_http_send_cached(r);
-
-        } else {
-            if (file) {
-                ngx_http_cache_unlock(clcf->open_files, file, log);
-                file = NULL;
-            }
+    log->action = "sending response to client";
 
-            file = ngx_http_cache_alloc(clcf->open_files, file,
-                                        file_cleanup,
-                                        &name, file_crc, NULL, log);
-            if (file) {
-                file->uniq = ngx_file_uniq(&fi);
-            }
-        }
-
-#else
-        file = ngx_http_cache_alloc(clcf->open_files, file,
-                                    file_cleanup,
-                                    &name, file_crc, NULL, log);
-#endif
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                       "http open file cache alloc: %p", file);
-
-        if (file) {
-            file->fd = fd;
-            file->data.size = ngx_file_size(&fi);
-            file->accessed = ngx_cached_time;
-            file->last_modified = ngx_file_mtime(&fi);
-            file->updated = ngx_cached_time;
-            r->cache = file;
-        }
-
-        return ngx_http_send_cached(r);
+    cln = ngx_palloc(r->pool, sizeof(ngx_pool_cleanup_file_t));
+    if (cln == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-#endif
-
-    log->action = "sending response to client";
+    cln->fd = fd;
+    cln->name = name.data;
+    cln->log = r->pool->log;
 
-    file_cleanup->data.file.fd = fd;
-    file_cleanup->data.file.name = name.data;
-    file_cleanup->valid = 1;
-    file_cleanup->cache = 0;
+    if (ngx_pool_cleanup_add(r->pool, ngx_pool_cleanup_file, cln) == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
     r->headers_out.status = NGX_HTTP_OK;
     r->headers_out.content_length_n = ngx_file_size(&fi);
@@ -532,10 +328,12 @@ static ngx_int_t ngx_http_static_handler
 
     b->in_file = 1;
 
-    if (!r->main) {
+    if (r->main == NULL) {
         b->last_buf = 1;
     }
 
+    b->last_in_chain = 1;
+
     b->file_pos = 0;
     b->file_last = ngx_file_size(&fi);
 
@@ -550,7 +348,8 @@ static ngx_int_t ngx_http_static_handler
 }
 
 
-static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf)
+static void *
+ngx_http_static_create_loc_conf(ngx_conf_t *cf)
 {
     ngx_http_static_loc_conf_t  *conf;
 
@@ -565,8 +364,8 @@ static void *ngx_http_static_create_loc_
 }
 
 
-static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf,
-                                            void *parent, void *child)
+static char *
+ngx_http_static_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
 {
     ngx_http_static_loc_conf_t  *prev = parent;
     ngx_http_static_loc_conf_t  *conf = child;
@@ -579,7 +378,8 @@ static char *ngx_http_static_merge_loc_c
 }
 
 
-static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle)
+static ngx_int_t
+ngx_http_static_init(ngx_cycle_t *cycle)
 {
     ngx_http_handler_pt        *h;
     ngx_http_core_main_conf_t  *cmcf;
--- a/src/http/modules/ngx_http_stub_status_module.c
+++ b/src/http/modules/ngx_http_stub_status_module.c
@@ -22,7 +22,8 @@ static ngx_command_t  ngx_http_status_co
 
     
 ngx_http_module_t  ngx_http_stub_status_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -36,7 +37,7 @@ ngx_http_module_t  ngx_http_stub_status_
 
 
 ngx_module_t  ngx_http_stub_status_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_stub_status_module_ctx,      /* module context */
     ngx_http_status_commands,              /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -63,15 +64,8 @@ static ngx_int_t ngx_http_status_handler
         return rc;
     }
 
-    r->headers_out.content_type = ngx_list_push(&r->headers_out.headers);
-    if (r->headers_out.content_type == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    r->headers_out.content_type->key.len = 0;
-    r->headers_out.content_type->key.data = NULL;
-    r->headers_out.content_type->value.len = sizeof("text/plain") - 1;
-    r->headers_out.content_type->value.data = (u_char *) "text/plain";
+    r->headers_out.content_type.len = sizeof("text/plain") - 1;
+    r->headers_out.content_type.data = (u_char *) "text/plain";
 
     if (r->method == NGX_HTTP_HEAD) {
         r->headers_out.status = NGX_HTTP_OK;
@@ -103,14 +97,14 @@ static ngx_int_t ngx_http_status_handler
     rd = *ngx_stat_reading;
     wr = *ngx_stat_writing;
 
-    b->last = ngx_sprintf(b->last, "Active connections: %A \n", ac);
+    b->last = ngx_sprintf(b->last, "Active connections: %uA \n", ac);
 
     b->last = ngx_cpymem(b->last, "server accepts handled requests\n",
                          sizeof("server accepts handled requests\n") - 1);
 
-    b->last = ngx_sprintf(b->last, " %A %A %A \n", ap, hn, rq);
+    b->last = ngx_sprintf(b->last, " %uA %uA %uA \n", ap, hn, rq);
 
-    b->last = ngx_sprintf(b->last, "Reading: %A Writing: %A Waiting: %A \n",
+    b->last = ngx_sprintf(b->last, "Reading: %uA Writing: %uA Waiting: %uA \n",
                           rd, wr, ac - (rd + wr));
 
     r->headers_out.status = NGX_HTTP_OK;
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -19,7 +19,7 @@
 
 
 typedef struct {
-    ngx_flag_t  enable;
+    ngx_uint_t  enable;
 
     ngx_int_t   service;
 
@@ -83,7 +83,7 @@ static ngx_conf_enum_t  ngx_http_userid_
 
 
 static ngx_conf_post_handler_pt  ngx_http_userid_domain_p =
-                                                        ngx_http_userid_domain;
+    ngx_http_userid_domain;
 
 static ngx_conf_post_handler_pt  ngx_http_userid_path_p = ngx_http_userid_path;
 static ngx_conf_post_handler_pt  ngx_http_userid_p3p_p = ngx_http_userid_p3p;
@@ -145,7 +145,8 @@ static ngx_command_t  ngx_http_userid_co
 
 
 ngx_http_module_t  ngx_http_userid_filter_module_ctx = {
-    ngx_http_userid_add_log_formats,       /* pre conf */
+    ngx_http_userid_add_log_formats,       /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -159,7 +160,7 @@ ngx_http_module_t  ngx_http_userid_filte
 
 
 ngx_module_t  ngx_http_userid_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_userid_filter_module_ctx,    /* module context */
     ngx_http_userid_commands,              /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -186,6 +187,10 @@ ngx_http_userid_filter(ngx_http_request_
     ngx_http_userid_ctx_t   *ctx;
     ngx_http_userid_conf_t  *conf;
 
+    if (r->main) {
+        return ngx_http_next_header_filter(r);
+    }
+
     conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
 
     if (conf->enable == NGX_HTTP_USERID_OFF) {
@@ -225,81 +230,46 @@ static ngx_int_t
 ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
     ngx_http_userid_conf_t *conf)
 {
-    u_char            *start, *last, *end;
-    ngx_uint_t         i;
+    ngx_int_t          n;
     ngx_str_t          src, dst;
     ngx_table_elt_t  **cookies;
 
-    cookies = r->headers_in.cookies.elts;
-
-    for (i = 0; i < r->headers_in.cookies.nelts; i++) {
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "cookie: \"%V\"", &cookies[i]->value);
-
-        if (conf->name.len >= cookies[i]->value.len) {
-            continue;
-        }
-
-        start = cookies[i]->value.data;
-        end = cookies[i]->value.data + cookies[i]->value.len;
-
-        while (start < end) {
-
-            if (ngx_strncmp(start, conf->name.data, conf->name.len) != 0) {
+    n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name,
+                                          &src);
+    if (n == NGX_DECLINED) {
+        return NGX_OK;
+    }
 
-                while (start < end && *start++ != ';') { /* void */ }
-                while (start < end && *start == ' ') { start++; }
-
-                continue;
-            }
-
-            start += conf->name.len;
-
-            while (start < end && *start == ' ') { start++; }
-
-            if (start == end || *start++ != '=') {
-                /* the invalid "Cookie" header */
-                break;
-            }
-
-            while (start < end && *start == ' ') { start++; }
+    if (src.len < 22) {
+        cookies = r->headers_in.cookies.elts;
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "client sent too short userid cookie \"%V\"",
+                      &cookies[n]->value);
+        return NGX_OK;
+    }
 
-            last = start;
-
-            while (last < end && *last++ != ';') { /* void */ }
+    /*
+     * we have to limit encoded string to 22 characters
+     * because there are already the millions cookies with a garbage
+     * instead of the correct base64 trail "=="
+     */
 
-            if (last - start < 22) {
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "client sent too short userid cookie \"%V\"",
-                              &cookies[i]->value);
-                break;
-            }
+    src.len = 22;
 
-            /*
-             * we have to limit encoded string to 22 characters
-             * because there are already the millions cookies with a garbage
-             * instead of the correct base64 trail "=="
-             */
+    dst.data = (u_char *) ctx->uid_got;
 
-            src.len = 22;
-            src.data = start;
-            dst.data = (u_char *) ctx->uid_got;
+    if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
+        cookies = r->headers_in.cookies.elts;
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "client sent invalid userid cookie \"%V\"",
+                      &cookies[n]->value);
+        return NGX_OK;
+    }
 
-            if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "client sent invalid userid cookie \"%V\"",
-                              &cookies[i]->value);
-                break;
-            }
-
-            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "uid: %08XD%08XD%08XD%08XD",
-                           ctx->uid_got[0], ctx->uid_got[1],
-                           ctx->uid_got[2], ctx->uid_got[3]);
-
-            return NGX_OK;
-        }
-    }
+    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "uid: %08XD%08XD%08XD%08XD",
+                   ctx->uid_got[0], ctx->uid_got[1],
+                   ctx->uid_got[2], ctx->uid_got[3]);
 
     return NGX_OK;
 }
@@ -404,6 +374,7 @@ ngx_http_userid_set_uid(ngx_http_request
         return NGX_ERROR;
     }
 
+    set_cookie->hash = 1;
     set_cookie->key.len = sizeof("Set-Cookie") - 1;
     set_cookie->key.data = (u_char *) "Set-Cookie";
     set_cookie->value.len = p - cookie;
@@ -421,6 +392,7 @@ ngx_http_userid_set_uid(ngx_http_request
         return NGX_ERROR;
     }
 
+    p3p->hash = 1;
     p3p->key.len = sizeof("P3P") - 1;
     p3p->key.data = (u_char *) "P3P";
     p3p->value = conf->p3p;
@@ -570,7 +542,7 @@ ngx_http_userid_create_conf(ngx_conf_t *
      *     conf->p3p.date = NULL;
      */
 
-    conf->enable = NGX_CONF_UNSET;
+    conf->enable = NGX_CONF_UNSET_UINT;
     conf->service = NGX_CONF_UNSET;
     conf->expires = NGX_CONF_UNSET;
 
@@ -584,7 +556,8 @@ ngx_http_userid_merge_conf(ngx_conf_t *c
     ngx_http_userid_conf_t *prev = parent;
     ngx_http_userid_conf_t *conf = child;
 
-    ngx_conf_merge_value(conf->enable, prev->enable, NGX_HTTP_USERID_OFF);
+    ngx_conf_merge_unsigned_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, "");
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -311,7 +311,7 @@ static ngx_http_log_op_name_t ngx_http_p
 
 
 
-ngx_http_header_t ngx_http_proxy_headers_in[] = {
+ngx_http_header0_t ngx_http_proxy_headers_in[] = {
     { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) },
     { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) },
 
@@ -490,13 +490,25 @@ static ngx_int_t ngx_http_proxy_cache_ge
 #endif
 
 
-void ngx_http_proxy_check_broken_connection(ngx_event_t *ev)
+void ngx_http_proxy_rd_check_broken_connection(ngx_http_request_t *r)
+{
+    ngx_http_proxy_check_broken_connection(r, r->connection->read);
+}
+
+
+void ngx_http_proxy_wr_check_broken_connection(ngx_http_request_t *r)
+{
+    ngx_http_proxy_check_broken_connection(r, r->connection->read);
+}
+
+
+void ngx_http_proxy_check_broken_connection(ngx_http_request_t *r,
+    ngx_event_t *ev)
 {
     int                    n;
     char                   buf[1];
     ngx_err_t              err;
     ngx_connection_t      *c;
-    ngx_http_request_t    *r;
     ngx_http_proxy_ctx_t  *p;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
@@ -510,8 +522,7 @@ void ngx_http_proxy_check_broken_connect
             return;
         }
 
-        c = ev->data;
-        r = c->data;
+        c = r->connection;
         p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
         ev->eof = 1;
@@ -542,8 +553,7 @@ void ngx_http_proxy_check_broken_connect
 
 #endif
 
-    c = ev->data;
-    r = c->data;
+    c = r->connection;
     p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
     n = recv(c->fd, buf, 1, MSG_PEEK);
@@ -712,13 +722,6 @@ void ngx_http_proxy_finalize_request(ngx
                        p->cache->ctx.file.fd);
     }
 
-    if (p->upstream && p->upstream->event_pipe) {
-        r->file.fd = p->upstream->event_pipe->temp_file->file.fd;
-
-    } else if (p->cache) {
-        r->file.fd = p->cache->ctx.file.fd;
-    }
-
     if (rc == 0 && r->main == NULL) {
         rc = ngx_http_send_last(r);
     }
--- a/src/http/modules/proxy/ngx_http_proxy_handler.h
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.h
@@ -249,7 +249,10 @@ void ngx_http_proxy_cache_busy_lock(ngx_
 
 #endif
 
-void ngx_http_proxy_check_broken_connection(ngx_event_t *ev);
+void ngx_http_proxy_rd_check_broken_connection(ngx_http_request_t *r);
+void ngx_http_proxy_wr_check_broken_connection(ngx_http_request_t *r);
+void ngx_http_proxy_check_broken_connection(ngx_http_request_t *r,
+    ngx_event_t *ev);
 
 void ngx_http_proxy_busy_lock_handler(ngx_event_t *rev);
 void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p);
@@ -265,7 +268,7 @@ int ngx_http_proxy_copy_header(ngx_http_
 
 
 extern ngx_module_t  ngx_http_proxy_module;
-extern ngx_http_header_t ngx_http_proxy_headers_in[];
+extern ngx_http_header0_t ngx_http_proxy_headers_in[];
 
 
 
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c
@@ -24,6 +24,7 @@ static void ngx_http_proxy_process_upstr
 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev);
 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *);
 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p);
+static void ngx_http_proxy_process_downstream(ngx_http_request_t *r);
 static void ngx_http_proxy_process_body(ngx_event_t *ev);
 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p,
                                          ngx_uint_t ft_type);
@@ -112,7 +113,7 @@ static ngx_chain_t *ngx_http_proxy_creat
         len = http_methods[p->upstream->method - 1].len + uc->uri.len;
 
     } else {
-        len = r->method_name.len + uc->uri.len;
+        len = r->method_name.len + 1 + uc->uri.len;
     }
 
     if (p->lcf->pass_unparsed_uri && r->valid_unparsed_uri) {
@@ -261,7 +262,8 @@ static ngx_chain_t *ngx_http_proxy_creat
                              http_methods[p->upstream->method - 1].data,
                              http_methods[p->upstream->method - 1].len);
     } else {
-        b->last = ngx_cpymem(b->last, r->method_name.data, r->method_name.len);
+        b->last = ngx_cpymem(b->last, r->method_name.data,
+                             r->method_name.len + 1);
     }
 
     b->last = ngx_cpymem(b->last, uc->uri.data, uc->uri.len);
@@ -502,12 +504,11 @@ static void ngx_http_proxy_init_upstream
         ngx_del_timer(r->connection->read);
     }
 
-    r->connection->read->event_handler = ngx_http_proxy_check_broken_connection;
+    r->read_event_handler = ngx_http_proxy_rd_check_broken_connection;
 
     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
 
-        r->connection->write->event_handler =
-                                        ngx_http_proxy_check_broken_connection;
+        r->write_event_handler = ngx_http_proxy_wr_check_broken_connection;
 
         if (!r->connection->write->active) {
             if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT,
@@ -770,8 +771,8 @@ static void ngx_http_proxy_connect(ngx_h
     c = p->upstream->peer.connection;
 
     c->data = p;
-    c->write->event_handler = ngx_http_proxy_send_request_handler;
-    c->read->event_handler = ngx_http_proxy_process_upstream_status_line;
+    c->write->handler = ngx_http_proxy_send_request_handler;
+    c->read->handler = ngx_http_proxy_process_upstream_status_line;
 
     c->sendfile = r->connection->sendfile;
 
@@ -925,9 +926,9 @@ static void ngx_http_proxy_send_request(
     }
 #endif
 
-    c->write->event_handler = ngx_http_proxy_dummy_handler;
+    c->write->handler = ngx_http_proxy_dummy_handler;
 
-    if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
+    if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
         ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
     }
@@ -1124,7 +1125,7 @@ static void ngx_http_proxy_process_upstr
     }
 
 
-    c->read->event_handler = ngx_http_proxy_process_upstream_headers;
+    c->read->handler = ngx_http_proxy_process_upstream_headers;
     ngx_http_proxy_process_upstream_headers(rev);
 }
 
@@ -1174,7 +1175,7 @@ static void ngx_http_proxy_process_upstr
 
         rc = ngx_http_parse_header_line(p->request, p->header_in);
 
-        if (rc == NGX_OK) {
+        if (rc == NGX_OK && !r->invalid_header) {
 
             /* a header line has been parsed successfully */
 
@@ -1241,6 +1242,10 @@ static void ngx_http_proxy_process_upstr
 
         } else if (rc != NGX_AGAIN) {
 
+            if (r->invalid_header) {
+                rc = NGX_HTTP_PARSE_INVALID_HEADER;
+            }
+
             /* there was error while a header line parsing */
 
             ngx_log_error(NGX_LOG_ERR, rev->log, 0,
@@ -1465,9 +1470,8 @@ static void ngx_http_proxy_send_response
     ep->send_timeout = clcf->send_timeout;
     ep->send_lowat = clcf->send_lowat;
 
-    p->upstream->peer.connection->read->event_handler =
-                                                   ngx_http_proxy_process_body;
-    r->connection->write->event_handler = ngx_http_proxy_process_body;
+    p->upstream->peer.connection->read->handler = ngx_http_proxy_process_body;
+    r->write_event_handler = ngx_http_proxy_process_downstream;
 
     ngx_http_proxy_process_body(p->upstream->peer.connection->read);
 
@@ -1475,6 +1479,12 @@ static void ngx_http_proxy_send_response
 }
 
 
+static void ngx_http_proxy_process_downstream(ngx_http_request_t *r)
+{
+    ngx_http_proxy_process_body(r->connection->write);
+}
+
+
 static void ngx_http_proxy_process_body(ngx_event_t *ev)
 {
     ngx_connection_t      *c;
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -53,7 +53,7 @@ static ngx_core_module_t  ngx_http_modul
 
 
 ngx_module_t  ngx_http_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_module_ctx,                  /* module context */
     ngx_http_commands,                     /* module directives */
     NGX_CORE_MODULE,                       /* module type */
@@ -85,11 +85,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     ngx_iocp_conf_t             *iocpcf;
 #endif
 
-#if (NGX_SUPPRESS_WARN)
-    /* MSVC thinks "in_ports" may be used without having been initialized */
-    ngx_memzero(&in_ports, sizeof(ngx_array_t));
-#endif
-
     /* the main http context */
 
     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
@@ -156,12 +151,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
         module = ngx_modules[m]->ctx;
         mi = ngx_modules[m]->ctx_index;
 
-        if (module->pre_conf) {
-            if (module->pre_conf(cf) != NGX_OK) {
-                return NGX_CONF_ERROR;
-            }
-        }
-
         if (module->create_main_conf) {
             ctx->main_conf[mi] = module->create_main_conf(cf);
             if (ctx->main_conf[mi] == NULL) {
@@ -184,11 +173,26 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
         }
     }
 
+    pcf = *cf;
+    cf->ctx = ctx;
+
+    for (m = 0; ngx_modules[m]; m++) {
+        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
+            continue;
+        }
+
+        module = ngx_modules[m]->ctx;
+        mi = ngx_modules[m]->ctx_index;
+
+        if (module->preconfiguration) {
+            if (module->preconfiguration(cf) != NGX_OK) {
+                return NGX_CONF_ERROR;
+            }
+        }
+    }
 
     /* parse inside the http{} block */
 
-    pcf = *cf;
-    cf->ctx = ctx;
     cf->module_type = NGX_HTTP_MODULE;
     cf->cmd_type = NGX_HTTP_MAIN_CONF;
     rv = ngx_conf_parse(cf, NULL);
@@ -264,11 +268,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     }
 
 
-    /* we needed http{}'s cf->ctx while the merging configuration */
-
-    *cf = pcf;
-
-
     /* init lists of the handlers */
 
     if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
@@ -321,7 +320,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     cmcf->headers_in_hash.bucket_size = sizeof(ngx_http_header_t);
     cmcf->headers_in_hash.name = "http headers_in";
 
-    if (ngx_hash_init(&cmcf->headers_in_hash, cf->pool, ngx_http_headers_in)
+    if (ngx_hash_init(&cmcf->headers_in_hash, cf->pool, ngx_http_headers_in, 0)
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
@@ -329,8 +328,32 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                    "http headers_in hash size: %ui, max buckets per entry: %ui",
-                    cmcf->headers_in_hash.hash_size,
-                    cmcf->headers_in_hash.min_buckets);
+                   cmcf->headers_in_hash.hash_size,
+                   cmcf->headers_in_hash.min_buckets);
+
+    for (m = 0; ngx_modules[m]; m++) {
+        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
+            continue;
+        }
+
+        module = ngx_modules[m]->ctx;
+        mi = ngx_modules[m]->ctx_index;
+
+        if (module->postconfiguration) {
+            if (module->postconfiguration(cf) != NGX_OK) {
+                return NGX_CONF_ERROR;
+            }
+        }
+    }
+
+
+    /*
+     * http{}'s cf->ctx was needed while the configuration merging
+     * and in postconfiguration process
+     */
+
+    *cf = pcf;
+
 
     /*
      * create the lists of ports, addresses and server names
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -12,11 +12,16 @@
 #include <ngx_core.h>
 #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;
-typedef struct ngx_http_variable_value_s  ngx_http_variable_value_t;
+
+typedef struct ngx_http_request_s   ngx_http_request_t;
+typedef struct ngx_http_upstream_s  ngx_http_upstream_t;
+typedef struct ngx_http_log_ctx_s   ngx_http_log_ctx_t;
+typedef struct ngx_http_in_addr_s   ngx_http_in_addr_t;
+
+typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r, u_char *buf,
+    size_t len);
 
 
 #if (NGX_HTTP_CACHE)
@@ -25,13 +30,13 @@ typedef struct ngx_http_variable_value_s
 /* STUB */
 #include <ngx_http_cache.h>
 
+#include <ngx_http_variables.h>
+#include <ngx_http_request.h>
 #include <ngx_http_upstream.h>
-#include <ngx_http_request.h>
 #include <ngx_http_config.h>
 #include <ngx_http_busy_lock.h>
 #include <ngx_http_log_module.h>
 #include <ngx_http_core_module.h>
-#include <ngx_http_variables.h>
 #include <ngx_http_script.h>
 
 #if (NGX_HTTP_SSL)
@@ -58,16 +63,18 @@ void ngx_http_init_connection(ngx_connec
 ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b);
 ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r);
 ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b);
+ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers,
+    ngx_str_t *name, ngx_str_t *value);
 
 ngx_int_t ngx_http_find_server_conf(ngx_http_request_t *r);
 void ngx_http_handler(ngx_http_request_t *r);
-void ngx_http_finalize_request(ngx_http_request_t *r, int error);
-void ngx_http_writer(ngx_event_t *wev);
+void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
 
 void ngx_http_empty_handler(ngx_event_t *wev);
+void ngx_http_request_empty_handler(ngx_http_request_t *r);
 
 ngx_int_t ngx_http_send_last(ngx_http_request_t *r);
-void ngx_http_close_request(ngx_http_request_t *r, int error);
+void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error);
 void ngx_http_close_connection(ngx_connection_t *c);
 u_char * ngx_http_log_error_info(ngx_http_request_t *r, u_char *buf,
     size_t len);
--- a/src/http/ngx_http_busy_lock.c
+++ b/src/http/ngx_http_busy_lock.c
@@ -46,8 +46,10 @@ int ngx_http_busy_lock(ngx_http_busy_loc
     if (bl->waiting < bl->max_waiting) {
         bl->waiting++;
 
+#if 0
         ngx_add_timer(bc->event, 1000);
         bc->event->event_handler = bc->event_handler;
+#endif
 
         /* TODO: ngx_handle_level_read_event() */
 
@@ -95,9 +97,11 @@ int ngx_http_busy_lock_cachable(ngx_http
     }
 
     if (bl->waiting < bl->max_waiting) {
+#if 0
         bl->waiting++;
         ngx_add_timer(bc->event, 1000);
         bc->event->event_handler = bc->event_handler;
+#endif
 
         /* TODO: ngx_handle_level_read_event() */
 
--- a/src/http/ngx_http_config.h
+++ b/src/http/ngx_http_config.h
@@ -20,7 +20,8 @@ typedef struct {
 
 
 typedef struct {
-    ngx_int_t   (*pre_conf)(ngx_conf_t *cf);
+    ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);
+    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);
 
     void       *(*create_main_conf)(ngx_conf_t *cf);
     char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -34,7 +34,8 @@ static ngx_command_t  ngx_http_copy_filt
 
 
 static ngx_http_module_t  ngx_http_copy_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -48,7 +49,7 @@ static ngx_http_module_t  ngx_http_copy_
 
 
 ngx_module_t  ngx_http_copy_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_copy_filter_module_ctx,      /* module context */
     ngx_http_copy_filter_commands,         /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -63,6 +64,7 @@ static ngx_http_output_body_filter_pt   
 static ngx_int_t
 ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
+    ngx_int_t                     rc;
     ngx_output_chain_ctx_t       *ctx;
     ngx_http_copy_filter_conf_t  *conf;
 
@@ -70,12 +72,13 @@ ngx_http_copy_filter(ngx_http_request_t 
         return NGX_ERROR;
     }
 
-    ctx = ngx_http_get_module_ctx(r->main ? r->main : r,
-                                            ngx_http_copy_filter_module);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "copy filter: \"%V\"", &r->uri);
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module);
 
     if (ctx == NULL) {
-        conf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
-                                            ngx_http_copy_filter_module);
+        conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module);
 
         ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
         if (ctx == NULL) {
@@ -97,7 +100,12 @@ ngx_http_copy_filter(ngx_http_request_t 
 
     }
 
-    return ngx_output_chain(ctx, in);
+    rc = ngx_output_chain(ctx, in);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "copy filter: %i \"%V\"", rc, &r->uri);
+
+    return rc;
 }
 
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -17,11 +17,12 @@
 #define NGX_HTTP_LOCATION_REGEX           4
 
 
-static void ngx_http_core_phase_event_handler(ngx_event_t *rev);
 static void ngx_http_core_run_phases(ngx_http_request_t *r);
 static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r,
     ngx_array_t *locations, size_t len);
 
+static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf);
+static ngx_int_t ngx_http_core_postconfiguration(ngx_conf_t *cf);
 static void *ngx_http_core_create_main_conf(ngx_conf_t *cf);
 static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf);
 static void *ngx_http_core_create_srv_conf(ngx_conf_t *cf);
@@ -54,9 +55,10 @@ static char *ngx_http_core_error_log(ngx
     void *conf);
 static char *ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+static char *ngx_http_core_internal(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 
 static char *ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data);
-static ngx_int_t ngx_http_core_init(ngx_cycle_t *cycle);
 
 static ngx_conf_post_t  ngx_http_core_lowat_post =
                                                  { ngx_http_core_lowat_check };
@@ -183,7 +185,8 @@ static ngx_command_t  ngx_http_core_comm
       NULL },
 
     { ngx_string("root"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                        |NGX_CONF_TAKE1,
       ngx_http_core_root,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -281,6 +284,13 @@ static ngx_command_t  ngx_http_core_comm
       0,
       NULL },
 
+    { ngx_string("internal"),
+      NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
+      ngx_http_core_internal,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("lingering_time"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -310,7 +320,8 @@ static ngx_command_t  ngx_http_core_comm
       NULL },
 
     { ngx_string("error_page"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                        |NGX_CONF_2MORE,
       ngx_http_core_error_page,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -339,7 +350,8 @@ static ngx_command_t  ngx_http_core_comm
 
 
 ngx_http_module_t  ngx_http_core_module_ctx = {
-    NULL,                                  /* pre conf */
+    ngx_http_core_preconfiguration,        /* preconfiguration */
+    ngx_http_core_postconfiguration,       /* postconfiguration */
 
     ngx_http_core_create_main_conf,        /* create main configuration */
     ngx_http_core_init_main_conf,          /* init main configuration */
@@ -353,11 +365,11 @@ ngx_http_module_t  ngx_http_core_module_
 
 
 ngx_module_t  ngx_http_core_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_core_module_ctx,             /* module context */
     ngx_http_core_commands,                /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
-    ngx_http_core_init,                    /* init module */
+    NULL,                                  /* init module */
     NULL                                   /* init process */
 };
 
@@ -413,11 +425,12 @@ ngx_http_handler(ngx_http_request_t *r)
     /* TEST STUB */ r->lingering_close = 1;
 #endif
 
-    r->connection->write->event_handler = ngx_http_core_phase_event_handler;
+    r->write_event_handler = ngx_http_core_run_phases;
 
     r->valid_unparsed_uri = 1;
+    r->valid_location = 1;
     r->uri_changed = 1;
-    r->uri_changes = 11;
+    r->uri_changes = NGX_HTTP_MAX_REWRITE_CYCLES + 1;
 
     r->phase = NGX_HTTP_REWRITE_PHASE;
     r->phase_handler = 0;
@@ -427,21 +440,6 @@ ngx_http_handler(ngx_http_request_t *r)
 
 
 static void
-ngx_http_core_phase_event_handler(ngx_event_t *ev)
-{
-    ngx_connection_t    *c;
-    ngx_http_request_t  *r;
-
-    c = ev->data;
-    r = c->data;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "phase event handler");
-
-    ngx_http_core_run_phases(r);
-}
-
-
-static void
 ngx_http_core_run_phases(ngx_http_request_t *r)
 {
     ngx_int_t                   rc;
@@ -449,6 +447,9 @@ ngx_http_core_run_phases(ngx_http_reques
     ngx_http_core_loc_conf_t   *clcf;
     ngx_http_core_main_conf_t  *cmcf;
 
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http phase handler");
+
     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
 
     for (/* void */; r->phase < NGX_HTTP_LAST_PHASE; r->phase++) {
@@ -478,7 +479,7 @@ ngx_http_core_run_phases(ngx_http_reques
         }
 
         if (r->phase == NGX_HTTP_CONTENT_PHASE && r->content_handler) {
-            r->connection->write->event_handler = ngx_http_empty_handler;
+            r->write_event_handler = ngx_http_request_empty_handler;
             ngx_http_finalize_request(r, r->content_handler(r));
             return;
         }
@@ -564,6 +565,10 @@ ngx_http_find_location_config(ngx_http_r
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
+    if (!r->internal && clcf->internal) {
+        return NGX_HTTP_NOT_FOUND;
+    }
+
     r->connection->log->file = clcf->err_log->file;
     if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
         r->connection->log->log_level = clcf->err_log->log_level;
@@ -608,6 +613,11 @@ ngx_http_find_location_config(ngx_http_r
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
+        /*
+         * we do not need to set the r->headers_out.location->hash and
+         * r->headers_out.location->key fields
+         */
+
         r->headers_out.location->value = clcf->name;
 
         return NGX_HTTP_MOVED_PERMANENTLY;
@@ -765,16 +775,6 @@ ngx_http_set_content_type(ngx_http_reque
     ngx_http_type_t           *type;
     ngx_http_core_loc_conf_t  *clcf;
 
-    r->headers_out.content_type = ngx_list_push(&r->headers_out.headers);
-    if (r->headers_out.content_type == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    r->headers_out.content_type->key.len = 0;
-    r->headers_out.content_type->key.data = NULL;
-    r->headers_out.content_type->value.len = 0;
-    r->headers_out.content_type->value.data = NULL;
-
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (r->exten.len) {
@@ -810,9 +810,6 @@ ngx_http_set_content_type(ngx_http_reque
             r->low_case_exten = 1;
         }
 
-#if 0
-        key = ngx_crc(r->exten.data, r->exten.key);
-#endif
         ngx_http_types_hash_key(key, r->exten);
 
         type = clcf->types[key].elts;
@@ -824,14 +821,14 @@ ngx_http_set_content_type(ngx_http_reque
             if (ngx_memcmp(r->exten.data, type[i].exten.data, r->exten.len)
                                                                            == 0)
             {
-                r->headers_out.content_type->value = type[i].type;
+                r->headers_out.content_type = type[i].type;
                 break;
             }
         }
     }
 
-    if (r->headers_out.content_type->value.len == 0) {
-        r->headers_out.content_type->value = clcf->default_type;
+    if (r->headers_out.content_type.len == 0) {
+        r->headers_out.content_type= clcf->default_type;
     }
 
     return NGX_OK;
@@ -841,10 +838,6 @@ ngx_http_set_content_type(ngx_http_reque
 ngx_int_t
 ngx_http_send_header(ngx_http_request_t *r)
 {
-    if (r->main) {
-        return NGX_OK;
-    }
-
     if (r->err_ctx) {
         r->headers_out.status = r->err_status;
         r->headers_out.status_line.len = 0;
@@ -863,12 +856,13 @@ ngx_http_output_filter(ngx_http_request_
         return NGX_ERROR;
     }
 
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http output filter \"%V\"", &r->uri);
+
     rc = ngx_http_top_body_filter(r, in);
 
     if (rc == NGX_ERROR) {
-
         /* NGX_ERROR may be returned by any filter */
-
         r->connection->write->error = 1;
     }
 
@@ -924,6 +918,114 @@ ngx_http_set_exten(ngx_http_request_t *r
 
 
 ngx_int_t
+ngx_http_subrequest(ngx_http_request_t *r,
+    ngx_str_t *uri, ngx_str_t *args)
+{
+    ngx_http_request_t            *sr;
+    ngx_http_core_srv_conf_t      *cscf;
+    ngx_http_postponed_request_t  *pr, *p;
+
+    sr = ngx_pcalloc(r->pool, sizeof(ngx_http_request_t));
+    if (sr == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    sr->signature = NGX_HTTP_MODULE;
+    sr->connection = r->connection;
+
+    sr->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
+    if (sr->ctx == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (ngx_list_init(&sr->headers_out.headers, r->pool, 20,
+                      sizeof(ngx_table_elt_t)) == NGX_ERROR)
+    {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+    sr->main_conf = cscf->ctx->main_conf;
+    sr->srv_conf = cscf->ctx->srv_conf;
+    sr->loc_conf = cscf->ctx->loc_conf;
+
+    sr->pool = r->pool;
+
+    sr->headers_in = r->headers_in;
+
+    sr->start_time = ngx_time();
+    sr->headers_out.content_length_n = -1;
+    sr->headers_out.last_modified_time = -1;
+
+    sr->request_body = r->request_body;
+
+    sr->method = NGX_HTTP_GET;
+    sr->http_version = r->http_version;
+    sr->http_major = r->http_minor;
+
+    sr->request_line = r->request_line;
+    sr->uri = *uri;
+    if (args) {
+        sr->args = *args;
+    }
+    sr->unparsed_uri = r->unparsed_uri;
+    sr->method_name = r->method_name;
+    sr->http_protocol = r->http_protocol;
+
+    if (ngx_http_set_exten(sr) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    sr->main = r->main ? r->main : r;
+    sr->parent = r;
+    sr->read_event_handler = ngx_http_request_empty_handler;
+    sr->write_event_handler = ngx_http_request_empty_handler;
+
+    if (r->connection->data == r) {
+        sr->connection->data = sr;
+    }
+
+    sr->in_addr = r->in_addr;
+    sr->port = r->port;
+    sr->port_text = r->port_text;
+    sr->server_name = r->server_name;
+
+    sr->variables = r->variables;
+
+    sr->log_handler = r->log_handler;
+
+    pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
+    if (pr == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    pr->request = sr;
+    pr->out = NULL;
+    pr->next = NULL;
+
+    if (r->postponed) {
+        for (p = r->postponed; p->next; p = p->next) { /* void */ }
+        p->next = pr;
+
+    } else {
+        r->postponed = pr;
+    }
+
+    sr->internal = 1;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http subrequest \"%V\"", uri);
+
+    ngx_http_handler(sr);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http subrequest \"%V\" done", uri);
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_http_internal_redirect(ngx_http_request_t *r,
     ngx_str_t *uri, ngx_str_t *args)
 {
@@ -936,6 +1038,10 @@ ngx_http_internal_redirect(ngx_http_requ
 
     if (args) {
         r->args = *args;
+
+    } else {
+        r->args.len = 0;
+        r->args.data = NULL;
     }
 
     if (ngx_http_set_exten(r) != NGX_OK) {
@@ -961,6 +1067,8 @@ ngx_http_internal_redirect(ngx_http_requ
     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
     r->loc_conf = cscf->ctx->loc_conf;
 
+    r->internal = 1;
+
     ngx_http_handler(r);
 
     return NGX_DONE;
@@ -1376,6 +1484,20 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c
 }
 
 
+static ngx_int_t
+ngx_http_core_preconfiguration(ngx_conf_t *cf)
+{
+    return ngx_http_variables_add_core_vars(cf);
+}
+
+
+static ngx_int_t
+ngx_http_core_postconfiguration(ngx_conf_t *cf)
+{
+    return ngx_http_variables_init_vars(cf);
+}
+
+
 static void *
 ngx_http_core_create_main_conf(ngx_conf_t *cf)
 {
@@ -1575,6 +1697,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     lcf->client_max_body_size = NGX_CONF_UNSET_SIZE;
     lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
     lcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
+    lcf->internal = NGX_CONF_UNSET;
     lcf->sendfile = NGX_CONF_UNSET;
     lcf->tcp_nopush = NGX_CONF_UNSET;
     lcf->tcp_nodelay = NGX_CONF_UNSET;
@@ -1673,9 +1796,12 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
                               (size_t) 2 * ngx_pagesize);
     ngx_conf_merge_msec_value(conf->client_body_timeout,
                               prev->client_body_timeout, 60000);
+
+    ngx_conf_merge_value(conf->internal, prev->internal, 0);
     ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
     ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0);
     ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 0);
+
     ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 60000);
     ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0);
     ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output,
@@ -1963,6 +2089,20 @@ ngx_http_core_error_page(ngx_conf_t *cf,
 
 
 static char *
+ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_core_loc_conf_t *lcf = conf;
+
+    lcf->err_log = ngx_log_create_errlog(cf->cycle, cf->args);
+    if (lcf->err_log == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    return ngx_set_error_log_levels(cf, lcf->err_log);
+}
+
+
+static char *
 ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_core_loc_conf_t *lcf = conf;
@@ -2004,16 +2144,17 @@ ngx_http_core_keepalive(ngx_conf_t *cf, 
 
 
 static char *
-ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+ngx_http_core_internal(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_core_loc_conf_t *lcf = conf;
 
-    lcf->err_log = ngx_log_create_errlog(cf->cycle, cf->args);
-    if (lcf->err_log == NULL) {
-        return NGX_CONF_ERROR;
+    if (lcf->internal != NGX_CONF_UNSET) {
+        return "is duplicate";
     }
 
-    return ngx_set_error_log_levels(cf, lcf->err_log);
+    lcf->internal = 1;
+
+    return NGX_CONF_OK;
 }
 
 
@@ -2044,10 +2185,3 @@ ngx_http_core_lowat_check(ngx_conf_t *cf
 
     return NGX_CONF_OK;
 }
-
-
-static ngx_int_t
-ngx_http_core_init(ngx_cycle_t *cycle)
-{
-    return ngx_http_variables_init(cycle);
-}
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -49,6 +49,7 @@ typedef struct {
     ngx_array_t                index_handlers;
 
     ngx_hash_t                 headers_in_hash;
+    ngx_hash_t                 variables_hash;
 
     ngx_uint_t                 server_names_hash;
     ngx_uint_t                 server_names_hash_threshold;
@@ -56,6 +57,7 @@ typedef struct {
     size_t                     max_server_name_len;
 
     ngx_array_t                variables;        /* ngx_http_variable_t */
+    ngx_array_t                all_variables;    /* ngx_http_variable_t */
 } ngx_http_core_main_conf_t;
 
 
@@ -197,6 +199,7 @@ struct ngx_http_core_loc_conf_s {
 
     time_t        keepalive_header;        /* keepalive_timeout */
 
+    ngx_flag_t    internal;                /* internal */
     ngx_flag_t    sendfile;                /* sendfile */
     ngx_flag_t    tcp_nopush;              /* tcp_nopush */
     ngx_flag_t    tcp_nodelay;             /* tcp_nodelay */
@@ -230,6 +233,8 @@ ngx_int_t ngx_http_find_location_config(
 ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r);
 ngx_int_t ngx_http_set_exten(ngx_http_request_t *r);
 
+ngx_int_t ngx_http_subrequest(ngx_http_request_t *r,
+    ngx_str_t *uri, ngx_str_t *args);
 ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r,
     ngx_str_t *uri, ngx_str_t *args);
 
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -15,7 +15,8 @@ static ngx_int_t ngx_http_header_filter(
 
 
 static ngx_http_module_t  ngx_http_header_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -29,7 +30,7 @@ static ngx_http_module_t  ngx_http_heade
 
 
 ngx_module_t  ngx_http_header_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_header_filter_module_ctx,    /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -38,10 +39,10 @@ ngx_module_t  ngx_http_header_filter_mod
 };
 
 
-static char server_string[] = "Server: " NGINX_VER CRLF;
+static char ngx_http_server_string[] = "Server: " NGINX_VER CRLF;
 
 
-static ngx_str_t http_codes[] = {
+static ngx_str_t ngx_http_status_lines[] = {
 
     ngx_string("200 OK"),
     ngx_null_string,  /* "201 Created" */
@@ -115,11 +116,13 @@ static ngx_str_t http_codes[] = {
 };
 
 
-ngx_http_header_t  ngx_http_headers_out[] = {
+ngx_http_header0_t  ngx_http_headers_out[] = {
     { ngx_string("Server"), offsetof(ngx_http_headers_out_t, server) },
     { ngx_string("Date"), offsetof(ngx_http_headers_out_t, date) },
+#if 0
     { ngx_string("Content-Type"),
                  offsetof(ngx_http_headers_out_t, content_type) },
+#endif
     { ngx_string("Content-Length"),
                  offsetof(ngx_http_headers_out_t, content_length) },
     { ngx_string("Content-Encoding"),
@@ -150,6 +153,10 @@ ngx_http_header_filter(ngx_http_request_
     ngx_table_elt_t           *header;
     ngx_http_core_loc_conf_t  *clcf;
 
+    if (r->main) {
+        return NGX_OK;
+    }
+
     if (r->http_version < NGX_HTTP_VERSION_10) {
         return NGX_OK;
     }
@@ -209,44 +216,44 @@ ngx_http_header_filter(ngx_http_request_
                                            + NGX_HTTP_LEVEL_400;
         }
 
-        len += http_codes[status].len;
+        len += ngx_http_status_lines[status].len;
     }
 
-    if (r->headers_out.server && r->headers_out.server->key.len) {
-        len += r->headers_out.server->key.len
-               + r->headers_out.server->value.len + 2;
-    } else {
-        len += sizeof(server_string) - 1;
+    if (r->headers_out.server == NULL) {
+        len += sizeof(ngx_http_server_string) - 1;
     }
 
-    if (r->headers_out.date && r->headers_out.date->key.len) {
-        len += r->headers_out.date->key.len
-               + r->headers_out.date->value.len + 2;
-    } else {
+    if (r->headers_out.date == NULL) {
         len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
     }
 
-    if (r->headers_out.content_length == NULL) {
-        if (r->headers_out.content_length_n >= 0) {
-            len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2;
-        }
-    }
-
-    if (r->headers_out.content_type && r->headers_out.content_type->value.len) {
-        r->headers_out.content_type->key.len = 0;
+    if (r->headers_out.content_type.len) {
         len += sizeof("Content-Type: ") - 1
-               + r->headers_out.content_type->value.len + 2;
+               + r->headers_out.content_type.len + 2;
 
         if (r->headers_out.charset.len) {
             len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
         }
     }
 
+    if (r->headers_out.content_length == NULL
+        && r->headers_out.content_length_n >= 0)
+    {
+        len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2;
+    }
+
+    if (r->headers_out.last_modified == NULL
+        && r->headers_out.last_modified_time != -1)
+    {
+        len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
+    }
+
     if (r->headers_out.location
         && r->headers_out.location->value.len
         && r->headers_out.location->value.data[0] == '/')
     {
-        r->headers_out.location->key.len = 0;
+        r->headers_out.location->hash = 0;
+
         len += sizeof("Location: http://") - 1
                + r->server_name.len + r->headers_out.location->value.len + 2;
 
@@ -255,14 +262,6 @@ ngx_http_header_filter(ngx_http_request_
         }
     }
 
-    if (r->headers_out.last_modified && r->headers_out.last_modified->key.len) {
-        len += r->headers_out.last_modified->key.len
-               + r->headers_out.last_modified->value.len + 2;
-
-    } else if (r->headers_out.last_modified_time != -1) {
-        len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
-    }
-
     if (r->chunked) {
         len += sizeof("Transfer-Encoding: chunked" CRLF) - 1;
     }
@@ -303,7 +302,7 @@ ngx_http_header_filter(ngx_http_request_
             i = 0;
         }
 
-        if (header[i].key.len == 0) {
+        if (header[i].hash == 0) {
             continue;
         }
 
@@ -325,16 +324,17 @@ ngx_http_header_filter(ngx_http_request_
                              r->headers_out.status_line.len);
 
     } else {
-        b->last = ngx_cpymem(b->last, http_codes[status].data,
-                             http_codes[status].len);
+        b->last = ngx_cpymem(b->last, ngx_http_status_lines[status].data,
+                             ngx_http_status_lines[status].len);
     }
     *b->last++ = CR; *b->last++ = LF;
 
-    if (!(r->headers_out.server && r->headers_out.server->key.len)) {
-        b->last = ngx_cpymem(b->last, server_string, sizeof(server_string) - 1);
+    if (r->headers_out.server == NULL) {
+        b->last = ngx_cpymem(b->last, ngx_http_server_string,
+                             sizeof(ngx_http_server_string) - 1);
     }
 
-    if (!(r->headers_out.date && r->headers_out.date->key.len)) {
+    if (r->headers_out.date == NULL) {
         b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1);
         b->last = ngx_cpymem(b->last, ngx_cached_http_time.data,
                              ngx_cached_http_time.len);
@@ -342,19 +342,12 @@ ngx_http_header_filter(ngx_http_request_
         *b->last++ = CR; *b->last++ = LF;
     }
 
-    if (r->headers_out.content_length == NULL) {
-        if (r->headers_out.content_length_n >= 0) {
-            b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF,
-                                  r->headers_out.content_length_n);
-        }
-    }
-
-    if (r->headers_out.content_type && r->headers_out.content_type->value.len) {
+    if (r->headers_out.content_type.len) {
         b->last = ngx_cpymem(b->last, "Content-Type: ",
                              sizeof("Content-Type: ") - 1);
         p = b->last;
-        b->last = ngx_cpymem(b->last, r->headers_out.content_type->value.data,
-                             r->headers_out.content_type->value.len);
+        b->last = ngx_cpymem(b->last, r->headers_out.content_type.data,
+                             r->headers_out.content_type.len);
 
         if (r->headers_out.charset.len) {
             b->last = ngx_cpymem(b->last, "; charset=",
@@ -362,13 +355,32 @@ ngx_http_header_filter(ngx_http_request_
             b->last = ngx_cpymem(b->last, r->headers_out.charset.data,
                                  r->headers_out.charset.len);
 
-            r->headers_out.content_type->value.len = b->last - p;
-            r->headers_out.content_type->value.data = p;
+            /* update r->headers_out.content_type for possible logging */
+
+            r->headers_out.content_type.len = b->last - p;
+            r->headers_out.content_type.data = p;
         }
 
         *b->last++ = CR; *b->last++ = LF;
     }
 
+    if (r->headers_out.content_length == NULL
+        && r->headers_out.content_length_n >= 0)
+    {
+        b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF,
+                              r->headers_out.content_length_n);
+    }
+
+    if (r->headers_out.last_modified == NULL
+        && r->headers_out.last_modified_time != -1)
+    {
+        b->last = ngx_cpymem(b->last, "Last-Modified: ",
+                             sizeof("Last-Modified: ") - 1);
+        b->last = ngx_http_time(b->last, r->headers_out.last_modified_time);
+
+        *b->last++ = CR; *b->last++ = LF;
+    }
+
     if (r->headers_out.location
         && r->headers_out.location->value.len
         && r->headers_out.location->value.data[0] == '/')
@@ -386,22 +398,14 @@ ngx_http_header_filter(ngx_http_request_
         b->last = ngx_cpymem(b->last, r->headers_out.location->value.data,
                              r->headers_out.location->value.len);
 
+        /* update r->headers_out.location->value for possible logging */
+
         r->headers_out.location->value.len = b->last - p;
         r->headers_out.location->value.data = p;
 
         *b->last++ = CR; *b->last++ = LF;
     }
 
-    if (!(r->headers_out.last_modified && r->headers_out.last_modified->key.len)
-        && r->headers_out.last_modified_time != -1)
-    {
-        b->last = ngx_cpymem(b->last, "Last-Modified: ",
-                             sizeof("Last-Modified: ") - 1);
-        b->last = ngx_http_time(b->last, r->headers_out.last_modified_time);
-
-        *b->last++ = CR; *b->last++ = LF;
-    }
-
     if (r->chunked) {
         b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF,
                              sizeof("Transfer-Encoding: chunked" CRLF) - 1);
@@ -436,7 +440,7 @@ ngx_http_header_filter(ngx_http_request_
             i = 0;
         }
 
-        if (header[i].key.len == 0) {
+        if (header[i].hash == 0) {
             continue;
         }
 
--- a/src/http/ngx_http_log_module.c
+++ b/src/http/ngx_http_log_module.c
@@ -106,7 +106,8 @@ static ngx_command_t  ngx_http_log_comma
 
 
 ngx_http_module_t  ngx_http_log_module_ctx = {
-    ngx_http_log_set_formats,              /* pre conf */
+    ngx_http_log_set_formats,              /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     ngx_http_log_create_main_conf,         /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -120,7 +121,7 @@ ngx_http_module_t  ngx_http_log_module_c
 
 
 ngx_module_t  ngx_http_log_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_log_module_ctx,              /* module context */
     ngx_http_log_commands,                 /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -391,6 +392,11 @@ ngx_http_log_header_in_compile(ngx_conf_
             continue;
         }
 
+        /* STUB: "Cookie" speacial handling */
+        if (ngx_http_headers_in[i].offset == 0) {
+            continue;
+        }
+
         if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, value->data,
                             value->len) == 0)
         {
@@ -733,22 +739,17 @@ static ngx_int_t
 ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
     ngx_str_t *value)
 {
-    ngx_uint_t            i;
-    ngx_http_variable_t  *var;
+    ngx_int_t  index;
 
-    for (i = 0; i < value->len; i++) {
-        value->data[i] = ngx_toupper(value->data[i]);
-    }
-
-    var = ngx_http_add_variable(cf, value, 0);
-    if (var == NULL) {
+    index = ngx_http_get_variable_index(cf, value);
+    if (index == NGX_ERROR) {
         return NGX_ERROR;
     }
 
     op->len = 0;
     op->getlen = ngx_http_log_variable_getlen;
     op->run = ngx_http_log_variable;
-    op->data = var->index;
+    op->data = index;
 
     return NGX_OK;
 }
@@ -762,7 +763,7 @@ ngx_http_log_variable_getlen(ngx_http_re
     value = ngx_http_get_indexed_variable(r, data);
 
     if (value == NULL
-        || value == NGX_HTTP_VARIABLE_NOT_FOUND
+        || value == NGX_HTTP_VAR_NOT_FOUND
         || value->text.len == 0)
     {
         return 1;
@@ -780,7 +781,7 @@ ngx_http_log_variable(ngx_http_request_t
     value = ngx_http_get_indexed_variable(r, op->data);
 
     if (value == NULL
-        || value == NGX_HTTP_VARIABLE_NOT_FOUND
+        || value == NGX_HTTP_VAR_NOT_FOUND
         || value->text.len == 0)
     {
         *buf = '-';
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -9,7 +9,8 @@
 #include <ngx_http.h>
 
 
-ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
+ngx_int_t
+ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
 {
     u_char  c, ch, *p, *m;
     enum {
@@ -63,7 +64,7 @@ ngx_int_t ngx_http_parse_request_line(ng
 
         case sw_method:
             if (ch == ' ') {
-                r->method_end = p;
+                r->method_end = p - 1;
                 m = r->request_start;
 
                 if (p - m == 3) {
@@ -502,7 +503,8 @@ done:
 }
 
 
-ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b)
+ngx_int_t
+ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b)
 {
     u_char      c, ch, *p;
     ngx_uint_t  hash;
@@ -513,7 +515,6 @@ ngx_int_t ngx_http_parse_header_line(ngx
         sw_value,
         sw_space_after_value,
         sw_ignore_line,
-        sw_skip_line,
         sw_almost_done,
         sw_header_almost_done
     } state;
@@ -528,8 +529,6 @@ ngx_int_t ngx_http_parse_header_line(ngx
 
         /* first char */
         case sw_start:
-            r->invalid_header = 0;
-
             switch (ch) {
             case CR:
                 r->header_end = p;
@@ -548,18 +547,11 @@ ngx_int_t ngx_http_parse_header_line(ngx
                     break;
                 }
 
-                if (ch == '-') {
-                    hash = ch;
-                    break;
-                }
-
                 if (ch >= '0' && ch <= '9') {
                     hash = ch;
                     break;
                 }
 
-                r->invalid_header = 1;
-                state = sw_skip_line;
                 break;
 
             }
@@ -589,18 +581,31 @@ ngx_int_t ngx_http_parse_header_line(ngx
                 break;
             }
 
+            if (ch == CR) {
+                r->header_name_end = p;
+                r->header_start = p;
+                r->header_end = p;
+                state = sw_almost_done;
+                break;
+            }
+
+            if (ch == LF) {
+                r->header_name_end = p;
+                r->header_start = p;
+                r->header_end = p;
+                goto done;
+            }
+
             /* IIS may send the duplicate "HTTP/1.1 ..." lines */
             if (ch == '/'
-                && r->proxy
-                && p - r->header_start == 4
-                && ngx_strncmp(r->header_start, "HTTP", 4) == 0)
+                && r->upstream
+                && p - r->header_name_start == 4
+                && ngx_strncmp(r->header_name_start, "HTTP", 4) == 0)
             {
                 state = sw_ignore_line;
                 break;
             }
 
-            r->invalid_header = 1;
-            state = sw_skip_line;
             break;
 
         /* space* before header value */
@@ -609,11 +614,13 @@ ngx_int_t ngx_http_parse_header_line(ngx
             case ' ':
                 break;
             case CR:
-                r->header_start = r->header_end = p;
+                r->header_start = p;
+                r->header_end = p;
                 state = sw_almost_done;
                 break;
             case LF:
-                r->header_start = r->header_end = p;
+                r->header_start = p;
+                r->header_end = p;
                 goto done;
             default:
                 r->header_start = p;
@@ -666,21 +673,6 @@ ngx_int_t ngx_http_parse_header_line(ngx
             }
             break;
 
-        /* skip header line */
-        case sw_skip_line:
-            switch (ch) {
-            case CR:
-                r->header_end = p;
-                state = sw_almost_done;
-                break;
-            case LF:
-                r->header_end = p;
-                goto done;
-            default:
-                break;
-            }
-            break;
-
         /* end of header line */
         case sw_almost_done:
             switch (ch) {
@@ -724,7 +716,8 @@ header_done:
 }
 
 
-ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r)
+ngx_int_t
+ngx_http_parse_complex_uri(ngx_http_request_t *r)
 {
     u_char  c, ch, decoded, *p, *u;
     enum {
@@ -1001,3 +994,75 @@ done:
 
     return NGX_OK;
 }
+
+
+ngx_int_t
+ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
+    ngx_str_t *value)
+{
+    ngx_uint_t         i;
+    u_char            *start, *last, *end, ch;
+    ngx_table_elt_t  **h;
+
+    h = headers->elts;
+
+    for (i = 0; i < headers->nelts; i++) {
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0,
+                       "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
+
+        if (name->len > h[i]->value.len) {
+            continue;
+        }
+    
+        start = h[i]->value.data;
+        end = h[i]->value.data + h[i]->value.len;
+
+        while (start < end) {
+
+            if (ngx_strncasecmp(start, name->data, name->len) != 0) {
+                goto skip;
+            }
+
+            for (start += name->len; start < end && *start == ' '; start++) {
+                /* void */
+            }
+
+            if (value == NULL) {
+                if (start == end || *start == ',') {
+                    return i;
+                }
+
+                goto skip;
+            }
+
+            if (start == end || *start++ != '=') {
+                /* the invalid header value */
+                goto skip;
+            }
+
+            while (start < end && *start == ' ') { start++; }
+
+            for (last = start; last < end && *last != ';'; last++) {
+                /* void */
+            }
+
+            value->len = last - start;
+            value->data = start;
+
+            return i;
+
+        skip:
+            while (start < end) {
+                ch = *start++;
+                if (ch == ';' || ch == ',') {
+                    break;
+                }
+            }
+
+            while (start < end && *start == ' ') { start++; }
+        }
+    }
+
+    return NGX_DECLINED;
+}
new file mode 100644
--- /dev/null
+++ b/src/http/ngx_http_postpone_filter_module.c
@@ -0,0 +1,126 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+static ngx_int_t ngx_http_postpone_filter_init(ngx_cycle_t *cycle);
+
+
+static ngx_http_module_t  ngx_http_postpone_filter_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
+
+    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_postpone_filter_module = {
+    NGX_MODULE_V1,
+    &ngx_http_postpone_filter_module_ctx,  /* module context */
+    NULL,                                  /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    ngx_http_postpone_filter_init,         /* init module */
+    NULL                                   /* init process */
+};
+
+
+static ngx_http_output_body_filter_pt    ngx_http_next_filter;
+
+
+static ngx_int_t
+ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
+{
+    ngx_int_t                      rc;
+    ngx_chain_t                   *out;
+    ngx_http_postponed_request_t  *pr, **ppr;
+
+    if (r->connection->write->error) {
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http postpone filter \"%V\" %p", &r->uri, in);
+
+    if (r != r->connection->data || (r->postponed && in)) {
+
+        if (r->postponed) {
+            for (pr = r->postponed; pr->next; pr = pr->next) { /* void */ }
+
+            ppr = pr->request ? &pr->next : NULL;
+
+        } else {
+            ppr = &r->postponed;
+#if (NGX_SUPPRESS_WARN)
+            pr = NULL;
+#endif
+        }
+
+        if (ppr) {
+            pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
+            if (pr == NULL) {
+                return NGX_ERROR;
+            }
+
+            *ppr = pr;
+
+            pr->request = NULL;
+            pr->out = NULL;
+            pr->next = NULL;
+        }
+
+        if (ngx_chain_add_copy(r->pool, &pr->out, in) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        if (r != r->connection->data || r->postponed->request) {
+            return NGX_AGAIN;
+        }
+    }
+
+    if (r->postponed) {
+        out = r->postponed->out;
+        r->postponed = r->postponed->next;
+
+    } else {
+        out = in;
+    }
+
+    if (out == NULL && r->out == NULL) {
+        return NGX_OK;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http postpone filter out \"%V\"", &r->uri);
+
+    rc = ngx_http_next_filter(r->main ? r->main : r, out);
+
+    if (rc == NGX_ERROR) {
+        /* NGX_ERROR may be returned by any filter */
+        r->connection->write->error = 1;
+    }
+
+    return rc;
+}
+
+
+static ngx_int_t
+ngx_http_postpone_filter_init(ngx_cycle_t *cycle)
+{
+    ngx_http_next_filter = ngx_http_top_body_filter;
+    ngx_http_top_body_filter = ngx_http_postpone_filter;
+
+    return NGX_OK;
+}
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -19,13 +19,22 @@ static void ngx_http_process_request_hea
 static ssize_t ngx_http_read_request_header(ngx_http_request_t *r);
 static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
     ngx_uint_t request_line);
+
+static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_process_cookie(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+
 static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r);
 static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r);
 
+static void ngx_http_request_handler(ngx_event_t *ev);
 static void ngx_http_set_write_handler(ngx_http_request_t *r);
-
-static void ngx_http_block_read(ngx_event_t *ev);
-static void ngx_http_read_discarded_body_event(ngx_event_t *rev);
+static void ngx_http_writer(ngx_http_request_t *r);
+static ngx_int_t ngx_http_postponed_handler(ngx_http_request_t *r);
+
+static void ngx_http_block_read(ngx_http_request_t *r);
+static void ngx_http_read_discarded_body_handler(ngx_http_request_t *r);
 static ngx_int_t ngx_http_read_discarded_body(ngx_http_request_t *r);
 
 static void ngx_http_set_keepalive(ngx_http_request_t *r);
@@ -34,6 +43,8 @@ static void ngx_http_set_lingering_close
 static void ngx_http_lingering_close_handler(ngx_event_t *ev);
 
 static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len);
+static u_char *ngx_http_log_error_handler(ngx_http_request_t *r, u_char *buf,
+    size_t len);
 
 
 static char *ngx_http_client_errors[] = {
@@ -50,59 +61,81 @@ static char *ngx_http_client_errors[] = 
 
 
 ngx_http_header_t  ngx_http_headers_in[] = {
-    { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host) },
-    { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection) },
+    { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host),
+                 ngx_http_process_header_line },
+
+    { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection),
+                 ngx_http_process_header_line },
+
     { ngx_string("If-Modified-Since"),
-                 offsetof(ngx_http_headers_in_t, if_modified_since) },
-    { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent) },
-    { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer) },
+                 offsetof(ngx_http_headers_in_t, if_modified_since),
+                 ngx_http_process_header_line },
+
+    { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent),
+                 ngx_http_process_header_line },
+
+    { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer),
+                 ngx_http_process_header_line },
+
     { ngx_string("Content-Length"),
-                 offsetof(ngx_http_headers_in_t, content_length) },
+                 offsetof(ngx_http_headers_in_t, content_length),
+                 ngx_http_process_header_line },
+
     { ngx_string("Content-Type"),
-                 offsetof(ngx_http_headers_in_t, content_type) },
-
-    { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range) },
+                 offsetof(ngx_http_headers_in_t, content_type),
+                 ngx_http_process_header_line },
+
+    { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range),
+                 ngx_http_process_header_line },
+
 #if 0
-    { ngx_string("If-Range"), offsetof(ngx_http_headers_in_t, if_range) },
+    { ngx_string("If-Range"), offsetof(ngx_http_headers_in_t, if_range),
+                 ngx_http_process_header_line },
 #endif
 
 #if (NGX_HTTP_GZIP)
     { ngx_string("Accept-Encoding"),
-                 offsetof(ngx_http_headers_in_t, accept_encoding) },
-    { ngx_string("Via"), offsetof(ngx_http_headers_in_t, via) },
+                 offsetof(ngx_http_headers_in_t, accept_encoding),
+                 ngx_http_process_header_line },
+
+    { ngx_string("Via"), offsetof(ngx_http_headers_in_t, via),
+                 ngx_http_process_header_line },
 #endif
 
     { ngx_string("Authorization"),
-                 offsetof(ngx_http_headers_in_t, authorization) },
-
-    { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive) },
+                 offsetof(ngx_http_headers_in_t, authorization),
+                 ngx_http_process_header_line },
+
+    { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive),
+                 ngx_http_process_header_line },
 
 #if (NGX_HTTP_PROXY)
     { ngx_string("X-Forwarded-For"),
-                 offsetof(ngx_http_headers_in_t, x_forwarded_for) },
-    { 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) },
+                 offsetof(ngx_http_headers_in_t, x_forwarded_for),
+                 ngx_http_process_header_line },
+
+    { ngx_string("X-Real-IP"), offsetof(ngx_http_headers_in_t, x_real_ip),
+                 ngx_http_process_header_line },
+
+    { ngx_string("X-URL"), offsetof(ngx_http_headers_in_t, x_url),
+                 ngx_http_process_header_line },
 #endif
 
 #if (NGX_HTTP_HEADERS)
-    { ngx_string("Accept"), offsetof(ngx_http_headers_in_t, accept) },
+    { ngx_string("Accept"), offsetof(ngx_http_headers_in_t, accept),
+                 ngx_http_process_header_line },
+
     { ngx_string("Accept-Language"),
-                 offsetof(ngx_http_headers_in_t, accept_language) },
+                 offsetof(ngx_http_headers_in_t, accept_language),
+                 ngx_http_process_header_line },
 #endif
 
-    { ngx_null_string, 0 }
+    { ngx_string("Cookie"), 0, ngx_http_process_cookie },
+
+    { ngx_null_string, 0, NULL }
 };
 
 
-#if 0
-static void
-ngx_http_dummy(ngx_event_t *wev)
-{
-    return;
-}
-#endif
-
-
 void
 ngx_http_init_connection(ngx_connection_t *c)
 {
@@ -126,9 +159,9 @@ ngx_http_init_connection(ngx_connection_
     c->log_error = NGX_ERROR_INFO;
 
     rev = c->read;
-    rev->event_handler = ngx_http_init_request;
-
-    /* STUB: epoll edge */ c->write->event_handler = ngx_http_empty_handler;
+    rev->handler = ngx_http_init_request;
+
+    /* STUB: epoll edge */ c->write->handler = ngx_http_empty_handler;
 
     if (rev->ready) {
         /* the deferred accept(), rtsig, aio, iocp */
@@ -165,18 +198,6 @@ ngx_http_init_connection(ngx_connection_
         return;
     }
 
-#if 0
-    /* TODO: learn SO_SNDBUF (to use in zerocopy) via kqueue's EV_CLEAR event */
-
-    c->write->ready = 0;
-    c->write->event_handler = ngx_http_dummy;
-
-    if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
-        ngx_http_close_connection(c);
-        return;
-    }
-#endif
-
 #if (NGX_STAT_STUB)
     ngx_atomic_inc(ngx_stat_reading);
 #endif
@@ -335,7 +356,7 @@ void ngx_http_init_request(ngx_event_t *
     r->srv_conf = cscf->ctx->srv_conf;
     r->loc_conf = cscf->ctx->loc_conf;
 
-    rev->event_handler = ngx_http_process_request_line;
+    rev->handler = ngx_http_process_request_line;
 
 #if (NGX_HTTP_SSL)
 
@@ -350,7 +371,7 @@ void ngx_http_init_request(ngx_event_t *
                 return;
             }
 
-            rev->event_handler = ngx_http_ssl_handshake;
+            rev->handler = ngx_http_ssl_handshake;
 
             /*
              * The majority of browsers do not send the "close notify" alert.
@@ -396,17 +417,9 @@ void ngx_http_init_request(ngx_event_t *
         return;
     }
 
-    if (ngx_array_init(&r->cleanup, r->pool, 4, sizeof(ngx_http_cleanup_t))
-                                                                  == NGX_ERROR)
-    { 
-        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        ngx_http_close_connection(c);
-        return;
-    }
-
 
     if (ngx_list_init(&r->headers_out.headers, r->pool, 20,
-                                         sizeof(ngx_table_elt_t)) == NGX_ERROR)
+                      sizeof(ngx_table_elt_t)) == NGX_ERROR)
     {
         ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
         ngx_http_close_connection(c);
@@ -426,8 +439,6 @@ void ngx_http_init_request(ngx_event_t *
 
     r->start_time = ngx_time();
 
-    r->file.fd = NGX_INVALID_FILE;
-
     r->headers_in.content_length_n = -1;
     r->headers_in.keep_alive_n = -1;
     r->headers_out.content_length_n = -1;
@@ -437,6 +448,7 @@ void ngx_http_init_request(ngx_event_t *
 
     ctx = c->log->data;
     ctx->request = r;
+    r->log_handler = ngx_http_log_error_handler;
 
 #if (NGX_STAT_STUB)
     ngx_atomic_inc(ngx_stat_reading);
@@ -444,7 +456,7 @@ void ngx_http_init_request(ngx_event_t *
     ngx_atomic_inc(ngx_stat_requests);
 #endif
 
-    rev->event_handler(rev);
+    rev->handler(rev);
 }
 
 
@@ -507,7 +519,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
         }
     }
 
-    rev->event_handler = ngx_http_process_request_line;
+    rev->handler = ngx_http_process_request_line;
     ngx_http_process_request_line(rev);
 }
 
@@ -593,10 +605,8 @@ ngx_http_process_request_line(ngx_event_
             r->unparsed_uri.data = r->uri_start;
 
 
-            if (r->method == 0) {
-                r->method_name.len = r->method_end - r->request_start + 1;
-                r->method_name.data = r->request_line.data;
-            }
+            r->method_name.len = r->method_end - r->request_start + 1;
+            r->method_name.data = r->request_line.data;
 
 
             if (r->http_protocol.data) {
@@ -634,7 +644,7 @@ ngx_http_process_request_line(ngx_event_
                            "http exten: \"%V\"", &r->exten);
 
             if (r->http_version < NGX_HTTP_VERSION_10) {
-                rev->event_handler = ngx_http_block_read;
+                r->read_event_handler = ngx_http_block_read;
                 ngx_http_handler(r);
                 return;
             }
@@ -659,7 +669,7 @@ ngx_http_process_request_line(ngx_event_
 
             c->log->action = "reading client request headers";
 
-            rev->event_handler = ngx_http_process_request_headers;
+            rev->handler = ngx_http_process_request_headers;
             ngx_http_process_request_headers(rev);
 
             return;
@@ -711,7 +721,7 @@ ngx_http_process_request_headers(ngx_eve
     ngx_int_t                   rc, rv;
     ngx_uint_t                  key;
     ngx_str_t                   header;
-    ngx_table_elt_t            *h, **cookie;
+    ngx_table_elt_t            *h;
     ngx_connection_t           *c;
     ngx_http_header_t          *hh;
     ngx_http_request_t         *r;
@@ -773,6 +783,7 @@ ngx_http_process_request_headers(ngx_eve
 
         if (rc == NGX_OK) {
 
+#if 0
             if (r->invalid_header) {
 
                 /* there was error while a header line parsing */
@@ -785,11 +796,10 @@ ngx_http_process_request_headers(ngx_eve
                               &header);
                 continue;
             }
+#endif
 
             /* a header line has been parsed successfully */
 
-            r->headers_n++;
-
             h = ngx_list_push(&r->headers_in.headers);
             if (h == NULL) {
                 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -807,27 +817,14 @@ ngx_http_process_request_headers(ngx_eve
             h->value.data = r->header_start;
             h->value.data[h->value.len] = '\0';
 
-            if (h->key.len == sizeof("Cookie") - 1
-                && ngx_strcasecmp(h->key.data, "Cookie") == 0)
+            key = h->hash % cmcf->headers_in_hash.hash_size;
+
+            if (hh[key].name.len == h->key.len
+                && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0)
             {
-                cookie = ngx_array_push(&r->headers_in.cookies);
-                if (cookie == NULL) {
-                    ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-                    ngx_http_close_connection(c);
+                if (hh[key].handler(r, h, hh[key].offset) != NGX_OK) {
                     return;
                 }
-
-                *cookie = h;
-
-            } else {
-                key = h->hash % cmcf->headers_in_hash.hash_size;
-
-                if (hh[key].name.len == h->key.len
-                    && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0)
-                {
-                    *((ngx_table_elt_t **)
-                              ((char *) &r->headers_in + hh[key].offset)) = h;
-                }
             }
 
             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -865,7 +862,10 @@ ngx_http_process_request_headers(ngx_eve
             r->stat_writing = 1;
 #endif
 
-            rev->event_handler = ngx_http_block_read;
+            rev->handler = ngx_http_request_handler;
+            c->write->handler = ngx_http_request_handler;
+            r->read_event_handler = ngx_http_block_read;
+
             ngx_http_handler(r);
             return;
         }
@@ -1091,6 +1091,41 @@ ngx_http_alloc_large_header_buffer(ngx_h
 
 
 static ngx_int_t
+ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{
+    ngx_table_elt_t  **ph;
+
+    ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset);
+
+    if (*ph == NULL) {
+        *ph = h;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_process_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{
+    ngx_table_elt_t  **cookie;
+
+    cookie = ngx_array_push(&r->headers_in.cookies);
+    if (cookie == NULL) {
+        ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        ngx_http_close_connection(r->connection);
+        return NGX_ERROR;
+    }
+
+    *cookie = h;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_http_process_request_header(ngx_http_request_t *r)
 {
     size_t                      len;
@@ -1108,6 +1143,10 @@ ngx_http_process_request_header(ngx_http
             r->headers_in.host->value.data[len] = ngx_tolower(ch);
         }
 
+        if (r->headers_in.host->value.data[len - 1] == '.') {
+            len--;
+        }
+
         r->headers_in.host_name_len = len;
 
         if (ngx_http_find_virtual_server(r) != NGX_OK) {
@@ -1167,13 +1206,13 @@ ngx_http_process_request_header(ngx_http
     if (r->headers_in.connection) {
         if (r->headers_in.connection->value.len == 5
             && ngx_strcasecmp(r->headers_in.connection->value.data, "close")
-                                                                          == 0)
+               == 0)
         {
             r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
 
         } else if (r->headers_in.connection->value.len == 10
                    && ngx_strcasecmp(r->headers_in.connection->value.data,
-                                                            "keep-alive") == 0)
+                                     "keep-alive") == 0)
         {
             r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE;
 
@@ -1237,7 +1276,7 @@ static ngx_int_t
 ngx_http_find_virtual_server(ngx_http_request_t *r)
 {
     ngx_int_t                   rc;
-    ngx_uint_t                  i, n, key, found;
+    ngx_uint_t                  i, n, key;
     ngx_http_server_name_t     *name;
     ngx_http_core_loc_conf_t   *clcf;
     ngx_http_core_srv_conf_t   *cscf;
@@ -1259,8 +1298,6 @@ ngx_http_find_virtual_server(ngx_http_re
         n = r->virtual_names->names.nelts;
     }
 
-    found = 0;
-
     for (i = 0; i < n; i++) {
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -1275,9 +1312,7 @@ ngx_http_find_virtual_server(ngx_http_re
 
         if (rc == 0) {
             r->server_name = name[i].name;
-
-            found = 1;
-            break;
+            goto found;
         }
 
         if (rc < 0) {
@@ -1286,7 +1321,7 @@ ngx_http_find_virtual_server(ngx_http_re
         }
     }
 
-    if (!found && r->virtual_names->wildcards.nelts) {
+    if (r->virtual_names->wildcards.nelts) {
 
         name = r->virtual_names->wildcards.elts;
         for (i = 0; i < r->virtual_names->wildcards.nelts; i++) {
@@ -1310,49 +1345,110 @@ ngx_http_find_virtual_server(ngx_http_re
                 r->server_name.len = r->headers_in.host_name_len;
                 r->server_name.data = r->headers_in.host->value.data;
 
-                found = 1;
-                break;
+                goto found;
             }
         }
     }
 
-    if (found) {
-        r->srv_conf = name[i].core_srv_conf->ctx->srv_conf;
-        r->loc_conf = name[i].core_srv_conf->ctx->loc_conf;
-
-        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-        r->connection->log->file = clcf->err_log->file;
-
-        if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
-            r->connection->log->log_level = clcf->err_log->log_level;
-        }
-
+    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+    if (cscf->restrict_host_names == NGX_HTTP_RESTRICT_HOST_OFF) {
         return NGX_OK;
     }
 
-    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
-
-    if (cscf->restrict_host_names != NGX_HTTP_RESTRICT_HOST_OFF) {
-        return NGX_ERROR;
+    return NGX_ERROR;
+
+found:
+
+    r->srv_conf = name[i].core_srv_conf->ctx->srv_conf;
+    r->loc_conf = name[i].core_srv_conf->ctx->loc_conf;
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+    r->connection->log->file = clcf->err_log->file;
+
+    if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
+        r->connection->log->log_level = clcf->err_log->log_level;
     }
 
     return NGX_OK;
 }
 
 
+static void
+ngx_http_request_handler(ngx_event_t *ev)
+{
+    ngx_connection_t    *c;
+    ngx_http_request_t  *r;
+
+    c = ev->data;
+    r = c->data;
+
+    if (ev->write) {
+        r->write_event_handler(r);
+
+    } else {
+        r->read_event_handler(r);
+    }
+}
+
+
 void
-ngx_http_finalize_request(ngx_http_request_t *r, int rc)
+ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
 {
+    ngx_http_request_t        *pr;
     ngx_http_core_loc_conf_t  *clcf;
 
-    /* r may be already destroyed when rc == NGX_DONE */
-
-    if (rc == NGX_DONE || r->main) {
+    if (rc == NGX_DONE) {
+        /* r may be already destroyed when rc == NGX_DONE */
+        return;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http finalize request: %d, \"%V\"", rc, &r->uri);
+
+    if (r->parent && rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+        ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc));
         return;
     }
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http finalize request: %d", rc);
+    if (r->parent || rc == NGX_AGAIN) {
+        r->write_event_handler = ngx_http_writer;
+    }
+
+    r->done = 1;
+
+    if (r != r->connection->data) {
+        return;
+    }
+
+    if (r->parent) {
+
+        pr = r->parent;
+
+        if (rc != NGX_AGAIN) {
+            pr->connection->data = pr;
+        }
+
+        if (pr->postponed) {
+
+            if (rc != NGX_AGAIN && pr->postponed->request == r) {
+                pr->postponed = pr->postponed->next;
+
+                if (pr->postponed == NULL) {
+                    return;
+                }
+            }
+
+            if (pr->done) {
+                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                               "http wake request: \"%V\"", &pr->uri);
+
+                pr->write_event_handler(pr);
+            }
+        }
+
+        return;
+    }
 
     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
 
@@ -1379,7 +1475,7 @@ ngx_http_finalize_request(ngx_http_reque
         ngx_http_close_connection(r->connection);
         return;
 
-    } else if (rc == NGX_AGAIN) {
+    } else if (rc == NGX_AGAIN || r->out) {
         ngx_http_set_write_handler(r);
         return;
     }
@@ -1430,17 +1526,15 @@ ngx_http_set_write_handler(ngx_http_requ
     ngx_event_t               *wev;
     ngx_http_core_loc_conf_t  *clcf;
 
+    r->http_state = NGX_HTTP_WRITING_REQUEST_STATE;
+
     wev = r->connection->write;
-    wev->event_handler = ngx_http_writer;
-
-    r->http_state = NGX_HTTP_WRITING_REQUEST_STATE;
 
     if (wev->ready && wev->delayed) {
         return;
     }
 
-    clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
-                                        ngx_http_core_module);
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
     if (!wev->delayed) {
         ngx_add_timer(wev, clcf->send_timeout);
     }
@@ -1449,23 +1543,22 @@ ngx_http_set_write_handler(ngx_http_requ
         ngx_http_close_request(r, 0);
         ngx_http_close_connection(r->connection);
     }
-
-    return;
 }
 
 
-void
-ngx_http_writer(ngx_event_t *wev)
+static void
+ngx_http_writer(ngx_http_request_t *r)
 {
     int                        rc;
+    ngx_event_t               *wev;
     ngx_connection_t          *c;
-    ngx_http_request_t        *r;
     ngx_http_core_loc_conf_t  *clcf;
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http writer handler");
-
-    c = wev->data;
-    r = c->data;
+    c = r->connection;
+    wev = c->write;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, wev->log, 0,
+                   "http writer handler: \"%V\"", &r->uri);
 
     if (wev->timedout) {
         if (!wev->delayed) {
@@ -1510,10 +1603,21 @@ ngx_http_writer(ngx_event_t *wev)
         }
     }
 
-    rc = ngx_http_output_filter(r, NULL);
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                  "http writer output filter: %d", rc);
+    if (r->postponed) {
+        rc = ngx_http_postponed_handler(r);
+
+        if (rc == NGX_DONE) {
+            /* r may be already destroyed when rc == NGX_DONE */
+            return;
+        }
+
+    } else {
+        rc = ngx_http_output_filter(r, NULL);
+
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http writer output filter: %d, \"%V\"", rc, &r->uri);
 
     if (rc == NGX_AGAIN) {
         clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
@@ -1530,28 +1634,81 @@ ngx_http_writer(ngx_event_t *wev)
         return;
     }
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http writer done");
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, wev->log, 0,
+                   "http writer done: \"%V\"", &r->uri);
 
     ngx_http_finalize_request(r, rc);
 }
 
 
+static ngx_int_t
+ngx_http_postponed_handler(ngx_http_request_t *r)
+{
+    ngx_int_t                      rc;
+    ngx_http_postponed_request_t  *pr;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http postpone handler \"%V\"", &r->uri);
+
+    pr = r->postponed;
+
+    if (pr->request == NULL) {
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http postponed data \"%V\" %p", &r->uri, pr->out);
+
+        rc = ngx_http_output_filter(r, NULL);
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http postponed output filter: %d", rc);
+
+        if (rc == NGX_AGAIN) {
+            return rc;
+        }
+
+        if (rc == NGX_ERROR) {
+            /* NGX_ERROR may be returned by any filter */
+            r->connection->write->error = 1;
+
+            ngx_http_finalize_request(r, rc);
+
+            return NGX_DONE;
+        }
+
+        pr = r->postponed;
+
+        if (pr == NULL) {
+            return NGX_OK;
+        }
+    }
+
+    r = pr->request;
+    r->connection->data = r;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http postponed request \"%V\"", &r->uri);
+
+    r->write_event_handler(r);
+
+    return NGX_DONE;
+}
+
+
 static void
-ngx_http_block_read(ngx_event_t *rev)
+ngx_http_block_read(ngx_http_request_t *r)
 {
-    ngx_connection_t          *c;
-    ngx_http_request_t        *r;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http read blocked");
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http read blocked");
 
     /* aio does not call this handler */
 
-    if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) {
-        if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
-            c = rev->data;
-            r = c->data;
+    if ((ngx_event_flags & NGX_USE_LEVEL_EVENT)
+        && r->connection->read->active)
+    {
+        if (ngx_del_event(r->connection->read, NGX_READ_EVENT, 0)
+            == NGX_ERROR)
+        {
             ngx_http_close_request(r, 0);
-            ngx_http_close_connection(c);
+            ngx_http_close_connection(r->connection);
         }
     }
 }
@@ -1588,9 +1745,9 @@ ngx_http_discard_body(ngx_http_request_t
         }
     }
 
-    rev->event_handler = ngx_http_read_discarded_body_event;
-
-    if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
+    r->read_event_handler = ngx_http_read_discarded_body_handler;
+
+    if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
@@ -1599,28 +1756,23 @@ ngx_http_discard_body(ngx_http_request_t
 
 
 static void
-ngx_http_read_discarded_body_event(ngx_event_t *rev)
+ngx_http_read_discarded_body_handler(ngx_http_request_t *r)
 {
-    ngx_int_t            rc;
-    ngx_connection_t    *c;
-    ngx_http_request_t  *r;
-
-    c = rev->data;
-    r = c->data;
+    ngx_int_t  rc;
 
     rc = ngx_http_read_discarded_body(r);
 
     if (rc == NGX_AGAIN) {
-        if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
+        if (ngx_handle_read_event(r->connection->read, 0) == NGX_ERROR) {
             ngx_http_close_request(r, rc);
-            ngx_http_close_connection(c);
+            ngx_http_close_connection(r->connection);
             return;
         }
     }
 
     if (rc != NGX_OK) {
         ngx_http_close_request(r, rc);
-        ngx_http_close_connection(c);
+        ngx_http_close_connection(r->connection);
     }
 }
 
@@ -1737,13 +1889,13 @@ ngx_http_set_keepalive(ngx_http_request_
 
     ngx_add_timer(rev, clcf->keepalive_timeout);
 
-    if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
+    if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
         ngx_http_close_connection(c);
         return;
     }
 
     wev = c->write;
-    wev->event_handler = ngx_http_empty_handler;
+    wev->handler = ngx_http_empty_handler;
 
     if (b->pos < b->last) {
 
@@ -1809,7 +1961,7 @@ ngx_http_set_keepalive(ngx_http_request_
         hc->nbusy = 0;
     }
 
-    rev->event_handler = ngx_http_keepalive_handler;
+    rev->handler = ngx_http_keepalive_handler;
 
     if (wev->active) {
         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
@@ -1944,7 +2096,7 @@ ngx_http_keepalive_handler(ngx_event_t *
     c->log_error = NGX_ERROR_INFO;
 
     if (n == NGX_AGAIN) {
-        if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
+        if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
             ngx_http_close_connection(c);
         }
 
@@ -1986,19 +2138,19 @@ ngx_http_set_lingering_close(ngx_http_re
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     rev = c->read;
-    rev->event_handler = ngx_http_lingering_close_handler;
+    rev->handler = ngx_http_lingering_close_handler;
 
     r->lingering_time = ngx_time() + clcf->lingering_time / 1000;
     ngx_add_timer(rev, clcf->lingering_timeout);
 
-    if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
+    if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
         ngx_http_close_request(r, 0);
         ngx_http_close_connection(c);
         return;
     }
 
     wev = c->write;
-    wev->event_handler = ngx_http_empty_handler;
+    wev->handler = ngx_http_empty_handler;
 
     if (wev->active) {
         if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
@@ -2075,7 +2227,7 @@ ngx_http_lingering_close_handler(ngx_eve
 
     } while (rev->ready);
 
-    if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
+    if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
         ngx_http_close_request(r, 0);
         ngx_http_close_connection(c);
         return;
@@ -2102,6 +2254,16 @@ ngx_http_empty_handler(ngx_event_t *wev)
 }
 
 
+void
+ngx_http_request_empty_handler(ngx_http_request_t *r)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http requets empty handler");
+
+    return;
+}
+
+
 ngx_int_t
 ngx_http_send_last(ngx_http_request_t *r)
 {
@@ -2122,14 +2284,12 @@ ngx_http_send_last(ngx_http_request_t *r
 
 
 void
-ngx_http_close_request(ngx_http_request_t *r, int error)
+ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error)
 {
-    ngx_uint_t                 i;
     ngx_log_t                 *log;
+    struct linger              linger;
     ngx_http_log_ctx_t        *ctx;
-    ngx_http_cleanup_t        *cleanup;
     ngx_http_core_loc_conf_t  *clcf;
-    struct linger              l;
 
     log = r->connection->log;
 
@@ -2157,62 +2317,15 @@ ngx_http_close_request(ngx_http_request_
 
     ngx_http_log_handler(r);
 
-    cleanup = r->cleanup.elts;
-    for (i = 0; i < r->cleanup.nelts; i++) {
-        if (!cleanup[i].valid) {
-            continue;
-        }
-
-#if (NGX_HTTP_CACHE)
-
-        if (cleanup[i].cache) {
-            ngx_http_cache_unlock(cleanup[i].data.cache.hash,
-                                  cleanup[i].data.cache.cache, log);
-            continue;
-        }
-
-#endif
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http cleanup fd: %d",
-                       cleanup[i].data.file.fd);
-
-        if (ngx_close_file(cleanup[i].data.file.fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                          ngx_close_file_n " \"%s\" failed",
-                          cleanup[i].data.file.name);
-        }
-    }
-
-    /* STUB */
-    if (r->file.fd != NGX_INVALID_FILE) {
-        if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                          ngx_close_file_n " \"%V\" failed", &r->file.name);
-        }
-    }
-
-    if (r->request_body
-        && r->request_body->temp_file
-        && r->request_body->temp_file->file.fd != NGX_INVALID_FILE)
-    {
-        if (ngx_close_file(r->request_body->temp_file->file.fd)
-                                                             == NGX_FILE_ERROR)
-        {
-            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                          ngx_close_file_n " deleted file \"%V\" failed",
-                          &r->request_body->temp_file->file.name);
-        }
-    }
-
     if (r->connection->timedout) {
         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
         if (clcf->reset_timedout_connection) {
-            l.l_onoff = 1;
-            l.l_linger = 0;
+            linger.l_onoff = 1;
+            linger.l_linger = 0;
 
             if (setsockopt(r->connection->fd, SOL_SOCKET, SO_LINGER,
-                           (const void *) &l, sizeof(struct linger)) == -1)
+                           (const void *) &linger, sizeof(struct linger)) == -1)
             {
                 ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
                               "setsockopt(SO_LINGER) failed");
@@ -2220,7 +2333,7 @@ ngx_http_close_request(ngx_http_request_
         }
     }
 
-    /* the variuos request strings were allocated from r->pool */
+    /* the various request strings were allocated from r->pool */
     ctx = log->data;
     ctx->request = NULL;
 
@@ -2263,8 +2376,8 @@ ngx_http_close_connection(ngx_connection
 
     if (c->ssl) {
         if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
-            c->read->event_handler = ngx_ssl_close_handler;
-            c->write->event_handler = ngx_ssl_close_handler;
+            c->read->handler = ngx_ssl_close_handler;
+            c->write->handler = ngx_ssl_close_handler;
             return;
         }
     }
@@ -2290,26 +2403,31 @@ ngx_http_log_error(ngx_log_t *log, u_cha
     ngx_http_request_t  *r;
     ngx_http_log_ctx_t  *ctx;
 
-    p = buf;
-
-    ctx = log->data;
-
     if (log->action) {
-        p = ngx_snprintf(p, len, " while %s", log->action);
+        p = ngx_snprintf(buf, len, " while %s", log->action);
         len -= p - buf;
         buf = p;
     }
 
+    ctx = log->data;
+
     p = ngx_snprintf(buf, len, ", client: %V", ctx->client);
+    len -= p - buf;
 
     r = ctx->request;
 
-    if (r == NULL) {
-        return p;
+    if (r) {
+        return r->log_handler(r, p, len);
     }
 
-    len -= p - buf;
-    buf = p;
+    return p;
+}
+
+
+static u_char *
+ngx_http_log_error_handler(ngx_http_request_t *r, u_char *buf, size_t len)
+{
+    u_char  *p;
 
     if (r->server_name.data) {
         p = ngx_snprintf(buf, len, ", server: %V", &r->server_name);
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -8,6 +8,9 @@
 #define _NGX_HTTP_REQUEST_H_INCLUDED_
 
 
+#define NGX_HTTP_MAX_REWRITE_CYCLES        10
+
+
 #define NGX_HTTP_DISCARD_BUFFER_SIZE       4096
 #define NGX_HTTP_LINGERING_BUFFER_SIZE     4096
 
@@ -114,10 +117,17 @@ typedef enum {
 typedef struct {
     ngx_str_t                         name;
     ngx_uint_t                        offset;
+    ngx_http_header_handler_pt        handler;
 } ngx_http_header_t;
 
 
 typedef struct {
+    ngx_str_t                         name;
+    ngx_uint_t                        offset;
+} ngx_http_header0_t;
+
+
+typedef struct {
     ngx_list_t                        headers;
 
     ngx_table_elt_t                  *host;
@@ -183,7 +193,6 @@ typedef struct {
 
     ngx_table_elt_t                  *server;
     ngx_table_elt_t                  *date;
-    ngx_table_elt_t                  *content_type;
     ngx_table_elt_t                  *content_length;
     ngx_table_elt_t                  *content_encoding;
     ngx_table_elt_t                  *location;
@@ -192,12 +201,14 @@ typedef struct {
     ngx_table_elt_t                  *accept_ranges;
     ngx_table_elt_t                  *www_authenticate;
     ngx_table_elt_t                  *expires;
-    ngx_table_elt_t                  *cache_control;
     ngx_table_elt_t                  *etag;
 
+    ngx_str_t                         content_type;
     ngx_str_t                         charset;
     ngx_array_t                       ranges;
 
+    ngx_array_t                       cache_control;
+
     off_t                             content_length_n;
     time_t                            date_time;
     time_t                            last_modified_time;
@@ -215,24 +226,6 @@ typedef struct {
 } ngx_http_request_body_t;
 
 
-struct ngx_http_cleanup_s {
-    union {
-        struct {
-            ngx_fd_t                  fd;
-            u_char                   *name;
-        } file;
-
-        struct {
-            ngx_http_cache_hash_t    *hash;
-            ngx_http_cache_entry_t   *cache;
-        } cache;
-    } data;
-
-    unsigned                          valid:1;
-    unsigned                          cache:1;
-};
-
-
 typedef struct {
     ngx_http_request_t               *request;
 
@@ -246,7 +239,18 @@ typedef struct {
 } ngx_http_connection_t;
 
 
+typedef struct ngx_http_postponed_request_s  ngx_http_postponed_request_t;
+
+struct ngx_http_postponed_request_s {
+    ngx_http_request_t            *request;
+    ngx_chain_t                   *out;
+    ngx_http_postponed_request_t  *next;
+};
+
+
 typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
+typedef void (*ngx_http_event_handler_pt)(ngx_http_request_t *r);
+
 
 struct ngx_http_request_s {
     uint32_t                          signature;         /* "HTTP" */
@@ -258,12 +262,13 @@ struct ngx_http_request_s {
     void                            **srv_conf;
     void                            **loc_conf;
 
+    ngx_http_event_handler_pt         read_event_handler;
+    ngx_http_event_handler_pt         write_event_handler;
+
     ngx_http_cache_t                 *cache;
 
     ngx_http_upstream_t              *upstream;
 
-    ngx_file_t                        file;
-
     ngx_pool_t                       *pool;
     ngx_buf_t                        *header_in;
 
@@ -289,7 +294,10 @@ struct ngx_http_request_s {
     ngx_str_t                         method_name;
     ngx_str_t                         http_protocol;
  
+    ngx_chain_t                      *out;
     ngx_http_request_t               *main;
+    ngx_http_request_t               *parent;
+    ngx_http_postponed_request_t     *postponed;
 
     uint32_t                          in_addr;
     ngx_uint_t                        port;
@@ -303,19 +311,18 @@ struct ngx_http_request_s {
 
     ngx_http_variable_value_t       **variables;
 
-    ngx_array_t                       cleanup;
-
     /* used to learn the Apache compatible response length without a header */
     size_t                            header_size;
 
     size_t                            request_length;
 
-    u_char                           *discarded_buffer;
     void                            **err_ctx;
     ngx_uint_t                        err_status;
 
     ngx_http_connection_t            *http_connection;
 
+    ngx_http_log_handler_pt           log_handler;
+
     unsigned                          http_state:4;
 
     /* URI with "/." and on Win32 with "//" */
@@ -330,12 +337,11 @@ struct ngx_http_request_s {
     /* URI with "\0" or "%00" */
     unsigned                          zero_in_uri:1;
 
+    unsigned                          valid_location:1;
     unsigned                          valid_unparsed_uri:1;
     unsigned                          uri_changed:1;
     unsigned                          uri_changes:4;
 
-    unsigned                          invalid_header:1;
-
     unsigned                          low_case_exten:1;
     unsigned                          header_timeout_set:1;
 
@@ -346,14 +352,16 @@ struct ngx_http_request_s {
 #if 0
     unsigned                          cachable:1;
 #endif
+
     unsigned                          pipeline:1;
-
     unsigned                          plain_http:1;
     unsigned                          chunked:1;
     unsigned                          header_only:1;
     unsigned                          keepalive:1;
     unsigned                          lingering_close:1;
+    unsigned                          internal:1;
     unsigned                          closed:1;
+    unsigned                          done:1;
 
     unsigned                          filter_need_in_memory:1;
     unsigned                          filter_ssi_need_in_memory:1;
@@ -365,8 +373,6 @@ struct ngx_http_request_s {
     unsigned                          stat_writing:1;
 #endif
 
-    ngx_uint_t                        headers_n;
-
     /* used to parse HTTP headers */
     ngx_uint_t                        state;
     u_char                           *uri_start;
@@ -391,8 +397,7 @@ struct ngx_http_request_s {
 
 
 extern ngx_http_header_t   ngx_http_headers_in[];
-extern ngx_http_header_t   ngx_http_headers_out[];
-
+extern ngx_http_header0_t   ngx_http_headers_out[];
 
 
 #endif /* _NGX_HTTP_REQUEST_H_INCLUDED_ */
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -10,9 +10,8 @@
 #include <ngx_http.h>
 
 
-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,
-    ngx_connection_t *c);
+static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
 
 /*
  * on completion ngx_http_read_client_request_body() adds to
@@ -29,10 +28,14 @@ ngx_http_read_client_request_body(ngx_ht
     ssize_t                    size;
     ngx_buf_t                 *b;
     ngx_chain_t               *cl;
-    ngx_connection_t          *c;
     ngx_http_request_body_t   *rb;
     ngx_http_core_loc_conf_t  *clcf;
 
+    if (r->request_body) {
+        post_handler(r);
+        return NGX_OK;
+    }
+
     rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
     if (rb == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -40,16 +43,6 @@ ngx_http_read_client_request_body(ngx_ht
 
     r->request_body = rb;
 
-    /* STUB */
-    if (r->file.fd != NGX_INVALID_FILE) {
-        if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
-                          ngx_close_file_n " \"%V\" failed", &r->file.name);
-        }
-        r->file.fd = NGX_INVALID_FILE;
-    }
-    /**/
-
     if (r->headers_in.content_length_n <= 0) {
         post_handler(r);
         return NGX_OK;
@@ -138,30 +131,23 @@ ngx_http_read_client_request_body(ngx_ht
         rb->bufs = cl;
     }
 
-    c = r->connection;
+    r->read_event_handler = ngx_http_read_client_request_body_handler;
 
-    c->read->event_handler = ngx_http_read_client_request_body_handler;
-
-    return ngx_http_do_read_client_request_body(r, c);
+    return ngx_http_do_read_client_request_body(r);
 }
 
 
 static void
-ngx_http_read_client_request_body_handler(ngx_event_t *rev)
+ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
 {
-    ngx_int_t            rc;
-    ngx_connection_t    *c;
-    ngx_http_request_t  *r;
+    ngx_int_t  rc;
 
-    c = rev->data;
-    r = c->data;
-
-    if (rev->timedout) {
+    if (r->connection->read->timedout) {
         ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
         return;
     }
 
-    rc = ngx_http_do_read_client_request_body(r, c);
+    rc = ngx_http_do_read_client_request_body(r);
 
     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
         ngx_http_finalize_request(r, rc);
@@ -170,16 +156,17 @@ ngx_http_read_client_request_body_handle
 
 
 static ngx_int_t
-ngx_http_do_read_client_request_body(ngx_http_request_t *r,
-    ngx_connection_t *c)
+ngx_http_do_read_client_request_body(ngx_http_request_t *r)
 {
     size_t                     size;
     ssize_t                    n;
     ngx_buf_t                 *b;
     ngx_temp_file_t           *tf;
+    ngx_connection_t          *c;
     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,
@@ -218,8 +205,6 @@ ngx_http_do_read_client_request_body(ngx
             }
 
             rb->temp_file->offset += n;
-
-            rb->buf->pos = rb->buf->start;
             rb->buf->last = rb->buf->start;
         }
 
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -9,107 +9,274 @@
 #include <ngx_http.h>
 
 
-ngx_int_t
-ngx_http_script_compile_lite(ngx_conf_t *cf, ngx_array_t *sources,
-    ngx_array_t **lengths, ngx_array_t **values,
-    ngx_http_script_compile_lite_start_pt start,
-    ngx_http_script_compile_lite_end_pt end)
+#define ngx_http_script_exit  (u_char *) &ngx_http_script_exit_code
+
+static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL;
+
+
+ngx_uint_t
+ngx_http_script_variables_count(ngx_str_t *value)
 {
-    uintptr_t                   *code;
-    ngx_uint_t                   i;
-    ngx_table_elt_t             *src;
-    ngx_http_variable_t         *var;
-    ngx_http_script_var_code_t  *var_code;
+    ngx_uint_t  i, n;
 
-    if (sources->nelts == 0) {
-        return NGX_OK;
+    for (n = 0, i = 0; i < value->len; i++) {
+        if (value->data[i] == '$') {
+            n++;
+        }
     }
 
-    if (*lengths == NULL) {
-        *lengths = ngx_array_create(cf->pool, 64, 1);
-        if (*lengths == NULL) {
+    return n;
+}
+
+
+ngx_int_t
+ngx_http_script_compile(ngx_http_script_compile_t *sc)
+{
+    u_char                                ch;
+    size_t                                size;
+    ngx_int_t                             index;
+    ngx_str_t                             name;
+    uintptr_t                            *code;
+    ngx_uint_t                            i, n, bracket;
+    ngx_http_script_var_code_t           *var_code;
+    ngx_http_script_copy_code_t          *copy;
+    ngx_http_script_copy_capture_code_t  *copy_capture;
+
+    if (*sc->lengths == NULL) {
+        n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
+                             + sizeof(ngx_http_script_var_code_t))
+            + sizeof(uintptr_t);
+
+        *sc->lengths = ngx_array_create(sc->cf->pool, n, 1);
+        if (*sc->lengths == NULL) {
+            return NGX_ERROR;
+        }
+    }
+
+
+    if (*sc->values == NULL) {
+        n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
+                              + sizeof(ngx_http_script_var_code_t))
+                + sizeof(uintptr_t)
+                + sc->source->len
+                + sizeof(uintptr_t) - 1)
+            & ~(sizeof(uintptr_t) - 1);
+
+        *sc->values = ngx_array_create(sc->cf->pool, n, 1);
+        if (*sc->values == NULL) {
             return NGX_ERROR;
         }
     }
 
-    if (*values == NULL) {
-        *values = ngx_array_create(cf->pool, 256, 1);
-        if (*values == NULL) {
-            return NGX_ERROR;
-        }
-    }
+    sc->variables = 0;
+
+    for (i = 0; i < sc->source->len; /* void */ ) {
+
+        name.len = 0;
+
+        if (sc->source->data[i] == '$') {
+
+            if (++i == sc->source->len) {
+                goto invalid_variable;
+            }
+
+            if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
+
+                copy_capture = ngx_http_script_add_code(*sc->lengths,
+                                   sizeof(ngx_http_script_copy_capture_code_t),
+                                   NULL);
+                if (copy_capture == NULL) {
+                    return NGX_ERROR;
+                }
+
+                copy_capture->code = (ngx_http_script_code_pt)
+                                         ngx_http_script_copy_capture_len_code;
+                copy_capture->n = 2 * (sc->source->data[i] - '0');
+
+                copy_capture = ngx_http_script_add_code(*sc->values,
+                                   sizeof(ngx_http_script_copy_capture_code_t),
+                                   &sc->main);
+                if (copy_capture == NULL) {
+                    return NGX_ERROR;
+                }
+
+                copy_capture->code = ngx_http_script_copy_capture_code;
+                copy_capture->n = sc->source->data[i] - '0';
+
+                if (sc->ncaptures < copy_capture->n) {
+                    sc->ncaptures = copy_capture->n;
+                }
+
+                copy_capture->n *= 2;
 
-    src = sources->elts;
-    for (i = 0; i < sources->nelts; i++) {
+                i++;
+
+                continue;
+            }
+
+            if (sc->source->data[i] == '{') {
+                bracket = 1;
+
+                if (++i == sc->source->len) {
+                    goto invalid_variable;
+                }
+
+                name.data = &sc->source->data[i];
+
+            } else {
+                bracket = 0;
+                name.data = &sc->source->data[i];
+            }
+
+            for ( /* void */ ; i < sc->source->len; i++, name.len++) {
+                ch = sc->source->data[i];
 
-        if (src[i].value.data[0] == '$') {
-            if (start(&src[i], *lengths, *values, 0) != NGX_OK) {
+                if (ch == '}' && bracket) {
+                    i++;
+                    bracket = 0;
+                    break;
+                }
+
+                if ((ch >= 'A' && ch <= 'Z')
+                    || (ch >= 'a' && ch <= 'z')
+                    || (ch >= '0' && ch <= '9')
+                    || ch == '_')
+                {
+                    continue;
+                }
+
+                break;
+            }
+
+            if (bracket) {
+                ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
+                                   "the closing bracket in \"%V\" "
+                                   "variable is missing", &name);
                 return NGX_ERROR;
             }
 
-            src[i].value.len--;
-            src[i].value.data++;
+            if (name.len == 0) {
+                goto invalid_variable;
+            }
 
-            var = ngx_http_add_variable(cf, &src[i].value, 0);
+            sc->variables++;
 
-            if (var == NULL) {
+            index = ngx_http_get_variable_index(sc->cf, &name);
+
+            if (index == NGX_ERROR) {
                 return NGX_ERROR;
             }
 
-            var_code = ngx_array_push_n(*lengths,
-                                        sizeof(ngx_http_script_var_code_t));
+            var_code = ngx_http_script_add_code(*sc->lengths,
+                                            sizeof(ngx_http_script_var_code_t),
+                                            NULL);
             if (var_code == NULL) {
                 return NGX_ERROR;
             }
 
             var_code->code = (ngx_http_script_code_pt)
-                                                  ngx_http_script_copy_var_len;
-            var_code->index = var->index;
+                                            ngx_http_script_copy_var_len_code;
+            var_code->index = (uintptr_t) index;
 
 
-            var_code = ngx_array_push_n(*values,
-                                        sizeof(ngx_http_script_var_code_t));
+            var_code = ngx_http_script_add_code(*sc->values,
+                                            sizeof(ngx_http_script_var_code_t),
+                                            &sc->main);
             if (var_code == NULL) {
                 return NGX_ERROR;
             }
 
-            var_code->code = ngx_http_script_copy_var;
-            var_code->index = var->index;
+            var_code->code = ngx_http_script_copy_var_code;
+            var_code->index = (uintptr_t) index;
+
+            continue;
+        }
 
+        if (sc->source->data[i] == '?' && sc->compile_args) {
+            sc->args = 1;
+            sc->compile_args = 0;
 
-            if (end(*lengths, *values) != NGX_OK) {
+            code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t),
+                                            &sc->main);
+            if (code == NULL) {
                 return NGX_ERROR;
             }
 
+            *code = (uintptr_t) ngx_http_script_start_args_code;
+
+            i++;
+
             continue;
         }
 
-        if (start(&src[i], *lengths, *values, 1) != NGX_OK) {
+        name.data = &sc->source->data[i];
+
+        while (i < sc->source->len
+               && sc->source->data[i] != '$'
+               && !(sc->source->data[i] == '?' && sc->compile_args))
+        {
+            i++;
+            name.len++;
+        }
+
+        sc->size += name.len;
+
+        copy = ngx_http_script_add_code(*sc->lengths,
+                                        sizeof(ngx_http_script_copy_code_t),
+                                        NULL);
+        if (copy == NULL) {
             return NGX_ERROR;
         }
-    }
+
+        copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+        copy->len = name.len;
+
+        size = (sizeof(ngx_http_script_copy_code_t) + name.len
+                   + sizeof(uintptr_t) - 1)
+                & ~(sizeof(uintptr_t) - 1);
 
-    code = ngx_array_push_n(*lengths, sizeof(uintptr_t));
-    if (code == NULL) {
-        return NGX_ERROR;
+        copy = ngx_http_script_add_code(*sc->values, size, &sc->main);
+        if (copy == NULL) {
+            return NGX_ERROR;
+        }
+
+        copy->code = ngx_http_script_copy_code;
+        copy->len = name.len;
+
+        ngx_memcpy((u_char *) copy + sizeof(ngx_http_script_copy_code_t),
+                   name.data, name.len);
     }
 
-    *code = (uintptr_t) NULL;
+    if (sc->complete_lengths) {
+        code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
+        if (code == NULL) {
+            return NGX_ERROR;
+        }
 
-    code = ngx_array_push_n(*values, sizeof(uintptr_t));
-    if (code == NULL) {
-        return NGX_ERROR;
+        *code = (uintptr_t) NULL;
     }
 
-    *code = (uintptr_t) NULL;
+    if (sc->complete_values) {
+        code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t),
+                                        &sc->main);
+        if (code == NULL) {
+            return NGX_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+    }
 
     return NGX_OK;
+
+invalid_variable:
+
+    ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name");
+
+    return NGX_ERROR;
 }
 
 
-#if 0
-
-static void *
+void *
 ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size)
 {
     if (*codes == NULL) {
@@ -122,51 +289,79 @@ ngx_http_script_start_code(ngx_pool_t *p
     return ngx_array_push_n(*codes, size);
 }
 
-#endif
+
+void *
+ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code)
+{
+    u_char  *elts, **p;
+    void    *new;
+
+    elts = codes->elts;
+
+    new = ngx_array_push_n(codes, size);
+    if (new == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (code) {
+        if (elts != codes->elts) {
+            p = code;
+            *p += (u_char *) codes->elts - elts;
+        }
+    }
+
+    return new;
+}
 
 
 size_t
-ngx_http_script_copy_len(ngx_http_script_engine_t *e)
+ngx_http_script_copy_len_code(ngx_http_script_engine_t *e)
 {
     ngx_http_script_copy_code_t  *code;
 
-    code = (ngx_http_script_copy_code_t *) e->lite.ip;
+    code = (ngx_http_script_copy_code_t *) e->ip;
 
-    e->lite.ip += sizeof(ngx_http_script_copy_code_t);
+    e->ip += sizeof(ngx_http_script_copy_code_t);
 
     return code->len;
 }
 
 
 void
-ngx_http_script_copy(ngx_http_script_engine_t *e)
+ngx_http_script_copy_code(ngx_http_script_engine_t *e)
 {
     ngx_http_script_copy_code_t  *code;
 
-    code = (ngx_http_script_copy_code_t *) e->lite.ip;
+    code = (ngx_http_script_copy_code_t *) e->ip;
+
+    if (!e->skip) {
+        e->pos = ngx_cpymem(e->pos, e->ip + sizeof(ngx_http_script_copy_code_t),
+                            code->len);
+    }
 
-    e->lite.pos = ngx_cpymem(e->lite.pos,
-                             e->lite.ip + sizeof(ngx_http_script_copy_code_t),
-                             code->len);
+    e->ip += sizeof(ngx_http_script_copy_code_t)
+          + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
 
-    e->lite.ip += sizeof(ngx_http_script_copy_code_t)
-            + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
+    if (e->log) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                       "http script copy: \"%V\"", &e->buf);
+    }
 }
 
 
 size_t
-ngx_http_script_copy_var_len(ngx_http_script_engine_t *e)
+ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e)
 {
     ngx_http_variable_value_t   *value;
     ngx_http_script_var_code_t  *code;
 
-    code = (ngx_http_script_var_code_t *) e->lite.ip;
+    code = (ngx_http_script_var_code_t *) e->ip;
 
-    e->lite.ip += sizeof(ngx_http_script_var_code_t);
+    e->ip += sizeof(ngx_http_script_var_code_t);
 
-    value = ngx_http_get_indexed_variable(e->lite.request, code->index);
+    value = ngx_http_get_indexed_variable(e->request, code->index);
 
-    if (value == NULL || value == NGX_HTTP_VARIABLE_NOT_FOUND) {
+    if (value == NULL || value == NGX_HTTP_VAR_NOT_FOUND) {
         return 0;
     }
 
@@ -175,20 +370,456 @@ ngx_http_script_copy_var_len(ngx_http_sc
 
 
 void
-ngx_http_script_copy_var(ngx_http_script_engine_t *e)
+ngx_http_script_copy_var_code(ngx_http_script_engine_t *e)
 {
     ngx_http_variable_value_t   *value;
     ngx_http_script_var_code_t  *code;
 
-    code = (ngx_http_script_var_code_t *) e->lite.ip;
+    code = (ngx_http_script_var_code_t *) e->ip;
+
+    e->ip += sizeof(ngx_http_script_var_code_t);
+
+    if (!e->skip) {
+        value = ngx_http_get_indexed_variable(e->request, code->index);
+
+        if (value == NULL || value == NGX_HTTP_VAR_NOT_FOUND) {
+            return;
+        }
+
+        e->pos = ngx_cpymem(e->pos, value->text.data, value->text.len);
+
+        if (e->log) {
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                       "http script var: \"%V\"", &e->buf);
+        }
+    }
+}
+
+
+size_t
+ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e)
+{
+    ngx_http_script_copy_capture_code_t  *code;
+
+    code = (ngx_http_script_copy_capture_code_t *) e->ip;
+
+    e->ip += sizeof(ngx_http_script_copy_capture_code_t);
+
+    if ((e->args || e->quote)
+        && (e->request->quoted_uri || e->request->plus_in_uri))
+    {
+        return e->captures[code->n + 1] - e->captures[code->n]
+               + ngx_escape_uri(NULL,
+                                &e->line->data[e->captures[code->n]],
+                                e->captures[code->n + 1] - e->captures[code->n],
+                                NGX_ESCAPE_ARGS);
+    } else {
+        return e->captures[code->n + 1] - e->captures[code->n];
+    }
+}
+
+
+void
+ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e)
+{
+    ngx_http_script_copy_capture_code_t  *code;
+
+    code = (ngx_http_script_copy_capture_code_t *) e->ip;
+
+    e->ip += sizeof(ngx_http_script_copy_capture_code_t);
 
-    e->lite.ip += sizeof(ngx_http_script_var_code_t);
+    if ((e->args || e->quote)
+        && (e->request->quoted_uri || e->request->plus_in_uri))
+    {
+        e->pos = (u_char *) ngx_escape_uri(e->pos,
+                                &e->line->data[e->captures[code->n]],
+                                e->captures[code->n + 1] - e->captures[code->n],
+                                NGX_ESCAPE_ARGS);
+    } else {
+        e->pos = ngx_cpymem(e->pos,
+                            &e->line->data[e->captures[code->n]],
+                            e->captures[code->n + 1] - e->captures[code->n]);
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script capture: \"%V\"", &e->buf);
+}
+
+
+void
+ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script args");
+    
+    e->args = e->pos;
+    e->ip += sizeof(uintptr_t);
+}
+
+
+void
+ngx_http_script_regex_start_code(ngx_http_script_engine_t *e)
+{
+    size_t                         len;
+    ngx_int_t                      rc;
+    ngx_uint_t                     n;
+    ngx_http_request_t            *r;
+    ngx_http_script_engine_t       le;
+    ngx_http_script_len_code_pt    lcode;
+    ngx_http_script_regex_code_t  *code;
+
+    code = (ngx_http_script_regex_code_t *) e->ip;
+
+    r = e->request;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http script regex: \"%V\"", &code->name);
+
+    if (code->uri) {
+        e->line = &r->uri;
+    } else {
+        e->sp--;
+        e->line = &e->sp->text;
+    }
 
-    value = ngx_http_get_indexed_variable(e->lite.request, code->index);
+    rc = ngx_regex_exec(code->regex, e->line, e->captures, code->ncaptures);
+
+    if (rc == NGX_REGEX_NO_MATCHED) {
+        if (e->log) {
+            ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
+                          "\"%V\" does not match \"%V\"", &code->name, e->line);
+        }
+
+        if (code->test) {
+            e->sp->value = 0; 
+            e->sp->text.len = 0;
+            e->sp->text.data = (u_char *) "";
+            e->sp++;
+
+            e->ip += sizeof(ngx_http_script_regex_code_t);
+            return;
+        }
+
+        e->ip += code->next;
+        return;
+    }
+
+    if (rc < 0) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
+                      rc, e->line, &code->name);
+
+        e->ip = ngx_http_script_exit;
+        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+        return;
+    }
+
+    if (e->log) {
+        ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
+                      "\"%V\" matches \"%V\"", &code->name, e->line);
+    }
+
+    if (code->test) {
+        e->sp->value = 1; 
+        e->sp->text.len = 1;
+        e->sp->text.data = (u_char *) "1";
+        e->sp++;
+
+        e->ip += sizeof(ngx_http_script_regex_code_t);
+        return;
+    }
+
+    if (code->status) {
+        e->status = code->status;
 
-    if (value == NULL || value == NGX_HTTP_VARIABLE_NOT_FOUND) {
+        if (!code->redirect) {
+            e->ip = ngx_http_script_exit;
+            return;
+        }
+    }
+
+    if (code->uri) {
+        r->internal = 1;
+        r->valid_unparsed_uri = 0;
+
+        if (code->break_cycle) {
+            r->valid_location = 0;
+
+        } else {
+            r->uri_changed = 1;
+        }
+    }
+
+    if (code->lengths == NULL) {
+        e->buf.len = code->size;
+
+        if (code->uri) {
+            if (rc && (r->quoted_uri || r->plus_in_uri)) {
+                e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
+                                                 NGX_ESCAPE_ARGS);
+            }
+        }
+
+        for (n = 1; n < (ngx_uint_t) rc; n++) {
+            e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n];
+        }
+
+    } else {
+        ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
+
+        le.ip = code->lengths->elts;
+        le.request = r;
+        le.captures = e->captures;
+
+        len = 1;  /* reserve 1 byte for possible "?" */
+
+        while (*(uintptr_t *) le.ip) {
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            len += lcode(&le);
+        }
+
+        e->buf.len = len;
+    }
+
+    if (code->args && code->add_args && r->args.len) {
+        e->buf.len += r->args.len + 1;
+    }
+
+    e->buf.data = ngx_palloc(r->pool, e->buf.len);
+    if (e->buf.data == NULL) {
+        e->ip = ngx_http_script_exit;
+        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
         return;
     }
 
-    e->lite.pos = ngx_cpymem(e->lite.pos, value->text.data, value->text.len);
+    e->quote = code->redirect;
+
+    e->pos = e->buf.data;
+
+    e->ip += sizeof(ngx_http_script_regex_code_t);
+}
+
+
+void
+ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
+{
+    ngx_http_request_t                *r;
+    ngx_http_script_regex_end_code_t  *code;
+
+    code = (ngx_http_script_regex_end_code_t *) e->ip;
+
+    r = e->request;
+
+    e->quote = 0;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http script regex end");
+
+    if (code->redirect) {
+
+        if (code->add_args && r->args.len) { 
+            *e->pos++ = (u_char) (code->args ? '&' : '?');
+            e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len);
+        }
+
+        e->buf.len = e->pos - e->buf.data;
+
+        if (e->log) {
+            ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
+                          "rewritten redirect: \"%V\"", &e->buf);
+        }
+
+        r->headers_out.location = ngx_list_push(&r->headers_out.headers);
+        if (r->headers_out.location == NULL) {
+            e->ip = ngx_http_script_exit;
+            e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+            return;
+        }
+
+        r->headers_out.location->hash = 1; 
+        r->headers_out.location->key.len = sizeof("Location") - 1;
+        r->headers_out.location->key.data = (u_char *) "Location";
+        r->headers_out.location->value = e->buf;
+
+        e->ip += sizeof(ngx_http_script_regex_end_code_t);
+        return;
+    }
+
+    if (e->args) { 
+        e->buf.len = e->args - e->buf.data;
+
+        if (code->add_args && r->args.len) {
+            *e->pos++ = '&';
+            e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len);
+        }
+
+        r->args.len = e->pos - e->args;
+        r->args.data = e->args;
+
+        e->args = NULL;
+
+    } else {
+        e->buf.len = e->pos - e->buf.data;
+    }
+
+    if (e->log) {
+        ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
+                      "rewritten data: \"%V\", args: \"%V\"",
+                      &e->buf, &r->args);
+    }
+
+    if (code->uri) {
+        r->uri = e->buf;
+
+        if (ngx_http_set_exten(r) != NGX_OK) {
+            e->ip = ngx_http_script_exit;
+            e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+            return;
+        }
+    }
+
+    e->ip += sizeof(ngx_http_script_regex_end_code_t);
+}
+
+
+void
+ngx_http_script_return_code(ngx_http_script_engine_t *e)
+{   
+    ngx_http_script_return_code_t  *code;
+    
+    code = (ngx_http_script_return_code_t *) e->ip;
+
+    e->status = code->status;
+
+    e->ip += sizeof(ngx_http_script_return_code_t) - sizeof(uintptr_t);
 }
+
+
+void
+ngx_http_script_if_code(ngx_http_script_engine_t *e)
+{
+    ngx_http_script_if_code_t  *code;
+
+    code = (ngx_http_script_if_code_t *) e->ip;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script if");
+
+    e->sp--;
+
+    if (e->sp->value) {
+        if (code->loc_conf) {
+            e->request->loc_conf = code->loc_conf;
+        }
+
+        e->ip += sizeof(ngx_http_script_if_code_t);
+        return;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script if false");
+
+    e->ip += code->next;
+}
+
+
+void
+ngx_http_script_value_code(ngx_http_script_engine_t *e)
+{
+    ngx_http_script_value_code_t  *code;
+
+    code = (ngx_http_script_value_code_t *) e->ip;
+
+    e->ip += sizeof(ngx_http_script_value_code_t);
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script value");
+
+    e->sp->value = (ngx_uint_t) code->value;
+    e->sp->text.len = (size_t) code->text_len;
+    e->sp->text.data = (u_char *) code->text_data;
+    e->sp++;
+}
+
+
+void
+ngx_http_script_set_var_code(ngx_http_script_engine_t *e)
+{
+    ngx_http_request_t          *r;
+    ngx_http_variable_value_t   *value;
+    ngx_http_core_main_conf_t   *cmcf;
+    ngx_http_script_var_code_t  *code;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script set var");
+
+    code = (ngx_http_script_var_code_t *) e->ip;
+
+    e->ip += sizeof(ngx_http_script_var_code_t);
+
+    r = e->request;
+
+    if (r->variables == NULL) {
+        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+        r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts
+                                        * sizeof(ngx_http_variable_value_t *));
+        if (r->variables == NULL) {
+            e->ip = ngx_http_script_exit;
+            e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+            return;
+        }
+    }
+
+    value = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (value == NULL) {
+        e->ip = ngx_http_script_exit;
+        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+        return;
+    }
+
+    e->sp--;
+
+    *value = *e->sp;
+
+    r->variables[code->index] = value;
+}
+
+
+void
+ngx_http_script_var_code(ngx_http_script_engine_t *e)
+{
+    ngx_http_variable_value_t   *value;
+    ngx_http_script_var_code_t  *code;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script var");
+
+    code = (ngx_http_script_var_code_t *) e->ip;
+
+    e->ip += sizeof(ngx_http_script_var_code_t);
+
+    value = ngx_http_get_indexed_variable(e->request, code->index);
+
+    if (value == NULL || value == NGX_HTTP_VAR_NOT_FOUND) {
+        e->sp->value = 0;
+        e->sp->text.len = 0;
+        e->sp->text.data = (u_char *) "";
+        e->sp++;
+
+        return;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script var: %ui, \"%V\"", value->value, &value->text);
+
+    *e->sp = *value;
+    e->sp++;
+}
+
+
+void
+ngx_http_script_nop_code(ngx_http_script_engine_t *e)
+{
+    e->ip += sizeof(uintptr_t);
+}
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -16,23 +16,48 @@
 typedef struct {
     u_char                         *ip;
     u_char                         *pos;
-    ngx_http_request_t             *request;
-} ngx_http_script_lite_engine_t;
+    ngx_http_variable_value_t      *sp;
+
+    ngx_str_t                       buf;
+    ngx_str_t                      *line;
+
+    /* the start of the rewritten arguments */
+    u_char                         *args;
 
+    unsigned                        skip:1;
+    unsigned                        quote:1;
+    unsigned                        log:1;
 
-typedef struct {
-    ngx_http_script_lite_engine_t   lite;
+    int                            *captures;
+
+    ngx_int_t                       status;
+    ngx_http_request_t             *request;
 } ngx_http_script_engine_t;
 
 
-typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e);
-typedef size_t (*ngx_http_script_len_code_pt)
-    (ngx_http_script_lite_engine_t *e);
+typedef struct {
+    ngx_conf_t                     *cf;
+    ngx_str_t                      *source;
+    ngx_array_t                   **lengths;
+    ngx_array_t                   **values;
+
+    ngx_uint_t                      variables;
+    ngx_uint_t                      ncaptures;
+    ngx_uint_t                      size;
+
+    void                           *main;
 
-typedef ngx_int_t (*ngx_http_script_compile_lite_start_pt) (ngx_table_elt_t *h,
-    ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value);
-typedef ngx_int_t (*ngx_http_script_compile_lite_end_pt) (ngx_array_t *lengths,
-    ngx_array_t *values);
+    unsigned                        compile_args:1;
+    unsigned                        compile_null:1;
+    unsigned                        complete_lengths:1;
+    unsigned                        complete_values:1;
+
+    unsigned                        args:1;
+} ngx_http_script_compile_t;
+
+
+typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e);
+typedef size_t (*ngx_http_script_len_code_pt) (ngx_http_script_engine_t *e);
 
 
 typedef struct {
@@ -47,20 +72,93 @@ typedef struct {
 } ngx_http_script_var_code_t;
 
 
-ngx_int_t ngx_http_script_compile_lite(ngx_conf_t *cf, ngx_array_t *sources,
-    ngx_array_t **lengths, ngx_array_t **values,
-    ngx_http_script_compile_lite_start_pt start,
-    ngx_http_script_compile_lite_end_pt end);
+typedef struct {
+    ngx_http_script_code_pt          code;
+    uintptr_t                        n;
+} ngx_http_script_copy_capture_code_t;
+
+
+typedef struct {
+    ngx_http_script_code_pt          code;
+    ngx_regex_t                     *regex;
+    ngx_array_t                     *lengths;
+    uintptr_t                        size;
+    uintptr_t                        ncaptures;
+    uintptr_t                        status;
+    uintptr_t                        next;
+
+    uintptr_t                        test:1;
+    uintptr_t                        uri:1;
+    uintptr_t                        args:1;
+
+    /* add the r->args to the new arguments */
+    uintptr_t                        add_args:1;
+    
+    uintptr_t                        redirect:1;
+    uintptr_t                        break_cycle:1;
+
+    ngx_str_t                        name;
+} ngx_http_script_regex_code_t;
+
+
+typedef struct {
+    ngx_http_script_code_pt          code;
+
+    uintptr_t                        uri:1;
+    uintptr_t                        args:1;
+
+    /* add the r->args to the new arguments */
+    uintptr_t                        add_args:1;
+
+    uintptr_t                        redirect:1;
+} ngx_http_script_regex_end_code_t;
 
 
-static void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes,
-    size_t size);
+typedef struct {
+    ngx_http_script_code_pt          code;
+    uintptr_t                        status;
+    uintptr_t                        null;
+} ngx_http_script_return_code_t;
+
+
+typedef struct {
+    ngx_http_script_code_pt          code;
+    uintptr_t                        next;
+    void                           **loc_conf;
+} ngx_http_script_if_code_t;
+
+
+typedef struct {
+    ngx_http_script_code_pt          code;
+    uintptr_t                        value;
+    uintptr_t                        text_len;
+    uintptr_t                        text_data;
+} ngx_http_script_value_code_t;
+
 
-size_t ngx_http_script_copy_len(ngx_http_script_engine_t *e);
-void ngx_http_script_copy(ngx_http_script_engine_t *e);
-size_t ngx_http_script_copy_var_len(ngx_http_script_engine_t *e);
-void ngx_http_script_copy_var(ngx_http_script_engine_t *e);
+ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value);
+ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc);
+
+void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes,
+    size_t size);
+void *ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code);
 
+size_t ngx_http_script_copy_len_code(ngx_http_script_engine_t *e);
+void ngx_http_script_copy_code(ngx_http_script_engine_t *e);
+size_t ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e);
+void ngx_http_script_copy_var_code(ngx_http_script_engine_t *e);
+size_t ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e);
+void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e);
+void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e);
+void ngx_http_script_regex_end_code(ngx_http_script_engine_t *e);
+void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e);
+void ngx_http_script_start_args_code(ngx_http_script_engine_t *e);
+void ngx_http_script_return_code(ngx_http_script_engine_t *e);
+void ngx_http_script_if_code(ngx_http_script_engine_t *e);
+void ngx_http_script_value_code(ngx_http_script_engine_t *e);
+void ngx_http_script_set_var_code(ngx_http_script_engine_t *e);
+void ngx_http_script_var_code(ngx_http_script_engine_t *e);
+void ngx_http_script_nop_code(ngx_http_script_engine_t *e);
 
 
 #endif /* _NGX_HTTP_SCRIPT_H_INCLUDED_ */
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -331,22 +331,15 @@ ngx_http_special_response_handler(ngx_ht
             msie_padding = 1;
         }
 
-        r->headers_out.content_type = ngx_list_push(&r->headers_out.headers);
-        if (r->headers_out.content_type == NULL) {
-            return NGX_ERROR;
-        }
-
-        r->headers_out.content_type->key.len = sizeof("Content-Type") - 1;
-        r->headers_out.content_type->key.data = (u_char *) "Content-Type";
-        r->headers_out.content_type->value.len = sizeof("text/html") - 1;
-        r->headers_out.content_type->value.data = (u_char *) "text/html";
+        r->headers_out.content_type.len = sizeof("text/html") - 1;
+        r->headers_out.content_type.data = (u_char *) "text/html";
 
     } else {
         r->headers_out.content_length_n = -1;
     }
 
     if (r->headers_out.content_length) {
-        r->headers_out.content_length->key.len = 0;
+        r->headers_out.content_length->hash = 0;
         r->headers_out.content_length = NULL;
     }
 
@@ -415,7 +408,11 @@ ngx_http_special_response_handler(ngx_ht
         cl->buf = b;
     }
 
-    b->last_buf = 1;
+    if (r->main == NULL) {
+        b->last_buf = 1;
+    }
+
+    b->last_in_chain = 1;
 
     cl->next = NULL;
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -6,14 +6,17 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_event_connect.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_rd_check_broken_connection(ngx_http_request_t *r);
+static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
+static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
+    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,
+static ngx_int_t 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);
@@ -21,6 +24,7 @@ static void ngx_http_upstream_send_reque
 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_downstream(ngx_http_request_t *r);
 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,
@@ -28,19 +32,125 @@ static void ngx_http_upstream_next(ngx_h
 static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
     ngx_http_upstream_t *u, ngx_int_t rc);
 
+static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t
+    ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t
+    ngx_http_upstream_conditional_copy_header_line(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t
+    ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+#if (NGX_HTTP_GZIP)
+static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
+#endif
+
 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 u_char *ngx_http_upstream_log_error(ngx_http_request_t *r, u_char *buf,
+    size_t len);
 static ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf);
+static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
+static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf);
+
+
+ngx_http_upstream_header_t  ngx_http_upstream_headers_in[] = {
+
+    { ngx_string("Status"),
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, status),
+                 /* STUB */ ngx_http_upstream_ignore_header_line, 0 },
+
+    { ngx_string("Content-Type"),
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, content_type),
+                 ngx_http_upstream_copy_content_type, 0 },
+
+    { ngx_string("Content-Length"),
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, content_length),
+                 ngx_http_upstream_copy_content_length, 0 },
+
+    { ngx_string("Date"),
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, date),
+                 ngx_http_upstream_conditional_copy_header_line,
+                 offsetof(ngx_http_upstream_conf_t, pass_date) },
+
+    { ngx_string("Server"),
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, server),
+                 ngx_http_upstream_conditional_copy_header_line,
+                 offsetof(ngx_http_upstream_conf_t, pass_server) },
+
+    { ngx_string("Location"),
+                 ngx_http_upstream_ignore_header_line, 0,
+                 ngx_http_upstream_rewrite_location, 0 },
+
+    { ngx_string("Refresh"),
+                 ngx_http_upstream_ignore_header_line, 0,
+                 ngx_http_upstream_rewrite_refresh, 0 },
+
+    { ngx_string("Cache-Control"),
+                 ngx_http_upstream_process_multi_header_lines,
+                 offsetof(ngx_http_upstream_headers_in_t, cache_control),
+                 ngx_http_upstream_copy_multi_header_lines,
+                 offsetof(ngx_http_headers_out_t, cache_control) },
+
+    { ngx_string("Connection"),
+                 ngx_http_upstream_ignore_header_line, 0,
+                 ngx_http_upstream_ignore_header_line, 0 },
+
+    { ngx_string("X-Pad"),
+                 ngx_http_upstream_ignore_header_line, 0,
+                 ngx_http_upstream_ignore_header_line, 0 },
+
+    { ngx_string("X-Powered-By"),
+                 ngx_http_upstream_ignore_header_line, 0,
+                 ngx_http_upstream_conditional_copy_header_line,
+                 offsetof(ngx_http_upstream_conf_t, pass_x_powered_by) },
+
+    { ngx_string("X-Accel-Expires"),
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, x_accel_expires),
+                 ngx_http_upstream_conditional_copy_header_line,
+                 offsetof(ngx_http_upstream_conf_t, pass_x_accel_expires) },
+
+#if (NGX_HTTP_GZIP)
+    { ngx_string("Content-Encoding"),
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, content_encoding),
+                 ngx_http_upstream_copy_content_encoding, 0 },
+#endif
+
+    { ngx_null_string, NULL, 0, NULL, 0 }
+};
 
 
 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 */
+    ngx_http_upstream_add_log_formats,     /* preconfiguration */
+    NULL,                                  /* postconfiguration */
+
+    ngx_http_upstream_create_main_conf,    /* create main configuration */
+    ngx_http_core_init_main_conf,          /* init main configuration */
 
     NULL,                                  /* create server configuration */
     NULL,                                  /* merge server configuration */
@@ -51,7 +161,7 @@ ngx_http_module_t  ngx_http_upstream_mod
     
 
 ngx_module_t  ngx_http_upstream_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_upstream_module_ctx,         /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -77,8 +187,9 @@ char *ngx_http_upstream_header_errors[] 
 void
 ngx_http_upstream_init(ngx_http_request_t *r)
 {
-    ngx_connection_t     *c;
-    ngx_http_upstream_t  *u;
+    ngx_connection_t          *c;
+    ngx_http_upstream_t       *u;
+    ngx_http_core_loc_conf_t  *clcf;
 
     c = r->connection;
 
@@ -89,11 +200,11 @@ ngx_http_upstream_init(ngx_http_request_
         ngx_del_timer(c->read);
     }
 
-    c->read->event_handler = ngx_http_upstream_check_broken_connection;
+    r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
     
     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
     
-        c->write->event_handler = ngx_http_upstream_check_broken_connection;
+        r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
 
         if (!c->write->active) {
             if (ngx_add_event(c->write, NGX_WRITE_EVENT,
@@ -107,7 +218,14 @@ ngx_http_upstream_init(ngx_http_request_
 
     u = r->upstream;
 
-    u->method = r->method;
+    u->request_bufs = r->request_body->bufs;
+
+    if (u->conf->method == NGX_CONF_UNSET_UINT) {
+        u->method = r->method;
+
+    } else {
+        u->method = u->conf->method;
+    }
 
     if (u->create_request(r) == NGX_ERROR) {
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -115,14 +233,15 @@ ngx_http_upstream_init(ngx_http_request_
     }
 
     u->peer.log = r->connection->log;
-    u->saved_log_ctx = r->connection->log->data;
-    u->saved_log_handler = r->connection->log->handler;
-    r->connection->log->data = u->log_ctx;
-    r->connection->log->handler = u->log_handler;
+    u->saved_log_handler = r->log_handler;
+    r->log_handler = ngx_http_upstream_log_error;
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     u->output.sendfile = r->connection->sendfile;
     u->output.pool = r->pool;
     u->output.bufs.num = 1;
+    u->output.bufs.size = clcf->client_body_buffer_size;
     u->output.output_filter = ngx_chain_writer;
     u->output.filter_ctx = &u->writer;
 
@@ -148,20 +267,33 @@ ngx_http_upstream_init(ngx_http_request_
 
 
 static void
-ngx_http_upstream_check_broken_connection(ngx_event_t *ev)
+ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r)
+{
+    ngx_http_upstream_check_broken_connection(r, r->connection->read);
+}
+
+
+static void
+ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r)
+{
+    ngx_http_upstream_check_broken_connection(r, r->connection->write);
+}
+
+
+static void
+ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
+    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);
 
-    c = ev->data;
-    r = c->data;
+    c = r->connection;
     u = r->upstream;
 
     if (u->peer.connection == NULL) {
@@ -296,8 +428,8 @@ ngx_http_upstream_connect(ngx_http_reque
     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->write->handler = ngx_http_upstream_send_request_handler;
+    c->read->handler = ngx_http_upstream_process_header;
 
     c->sendfile = r->connection->sendfile;
 
@@ -312,11 +444,20 @@ ngx_http_upstream_connect(ngx_http_reque
     u->writer.limit = 0;
 
     if (u->request_sent) {
-        ngx_http_upstream_reinit(r, u);
+        if (ngx_http_upstream_reinit(r, u) != NGX_OK) {
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
     }
 
-    if (r->request_body->buf) {
-        if (r->request_body->temp_file) {
+    if (r->request_body) {
+        if (r->request_body->temp_file && r->main == NULL) {
+
+            /*
+             * the r->request_body->buf can be reused for one request only,
+             * the subrequests should allocate their own temporay bufs
+             */
 
             u->output.free = ngx_alloc_chain_link(r->pool);
             if (u->output.free == NULL) {
@@ -332,9 +473,6 @@ ngx_http_upstream_connect(ngx_http_reque
             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;
         }
     }
 
@@ -351,29 +489,51 @@ ngx_http_upstream_connect(ngx_http_reque
 }
 
 
-static void
+static ngx_int_t
 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;
+    if (u->reinit_request(r) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    ngx_memzero(&r->upstream->headers_in,
+                sizeof(ngx_http_upstream_headers_in_t));
+
+    if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 8,
+                      sizeof(ngx_table_elt_t)) != NGX_OK)
+    {
+        return NGX_ERROR;
     }
 
     /* reinit the request chain */
     
-    for (cl = r->request_body->bufs; cl; cl = cl->next) {
+    for (cl = u->request_bufs; cl; cl = cl->next) {
         cl->buf->pos = cl->buf->start;
         cl->buf->file_pos = 0;
     }
 
-    /* reinit the ngx_output_chain() context */
+    /* reinit the subrequest's ngx_output_chain() context */
+
+    if (r->request_body) {
+        if (r->request_body->temp_file && r->main && u->output.buf) {
+
+            u->output.free = ngx_alloc_chain_link(r->pool);
+            if (u->output.free == NULL) {
+                return NGX_ERROR;
+            }
+
+            u->output.free->buf = u->output.buf;
+            u->output.free->next = NULL;
+
+            u->output.buf->pos = u->output.buf->start;
+            u->output.buf->last = u->output.buf->start;
+        }
+    }
 
     u->output.buf = NULL;
     u->output.in = NULL;
-    u->output.free = NULL;
     u->output.busy = NULL;
     
     /* reinit u->header_in buffer */
@@ -388,20 +548,22 @@ ngx_http_upstream_reinit(ngx_http_reques
         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 */
 
     u->state = ngx_array_push(&u->states);
     if (u->state == NULL) {
-        ngx_http_upstream_finalize_request(r, u,
-                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
+        return NGX_ERROR;
     }
 
     ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
+
+    return NGX_OK;
 }
 
 
@@ -433,8 +595,7 @@ ngx_http_upstream_send_request(ngx_http_
 
     c->log->action = "sending request to upstream";
 
-    rc = ngx_output_chain(&u->output,
-                          u->request_sent ? NULL : r->request_body->bufs);
+    rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs);
 
     u->request_sent = 1;
 
@@ -494,9 +655,9 @@ ngx_http_upstream_send_request(ngx_http_
     }
 #endif
 
-    c->write->event_handler = ngx_http_upstream_dummy_handler;
+    c->write->handler = ngx_http_upstream_dummy_handler;
 
-    if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
+    if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
         ngx_http_upstream_finalize_request(r, u,
                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
@@ -575,6 +736,14 @@ ngx_http_upstream_process_header(ngx_eve
 
         u->header_in.tag = u->output.tag;
 
+        if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 8,
+                          sizeof(ngx_table_elt_t)) == NGX_ERROR)
+        {
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
+
 #if 0
         if (u->cache) {
             u->header_in.pos += u->cache->ctx.header_size;
@@ -631,7 +800,7 @@ ngx_http_upstream_process_header(ngx_eve
         ngx_add_timer(rev, u->read_timeout);
 #endif
 
-        if (u->header_in.last == u->header_in.end) {
+        if (u->header_in.pos == u->header_in.end) {
             ngx_log_error(NGX_LOG_ERR, rev->log, 0,
                           "upstream sent too big header");
 
@@ -661,6 +830,38 @@ ngx_http_upstream_process_header(ngx_eve
 
     /* rc == NGX_OK */
 
+    if (r->headers_out.status == NGX_HTTP_INTERNAL_SERVER_ERROR) {
+
+        if (u->peer.tries > 1
+            && (u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_HTTP_500))
+        {
+            ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_500);
+            return;
+        }
+
+#if (NGX_HTTP_CACHE)
+
+        if (u->peer.tries == 0
+            && u->stale
+            && (u->conf->use_stale & NGX_HTTP_UPSTREAM_FT_HTTP_500))
+        {
+            ngx_http_upstream_finalize_request(r, u,
+                                             ngx_http_send_cached_response(r));
+            return;
+        }
+
+#endif
+    }
+
+    if (r->headers_out.status == NGX_HTTP_NOT_FOUND
+        && u->peer.tries > 1
+        && u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_HTTP_404)
+    {
+        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_404);
+        return;
+    }
+
+
     if (r->headers_out.status >= NGX_HTTP_BAD_REQUEST
         && u->conf->redirect_errors
         && r->err_ctx == NULL)
@@ -687,11 +888,55 @@ ngx_http_upstream_process_header(ngx_eve
 static void
 ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
 {
-    ngx_int_t                  rc;
-    ngx_event_pipe_t          *p;
-    ngx_http_core_loc_conf_t  *clcf;
+    ngx_int_t                       rc;
+    ngx_uint_t                      i, key;
+    ngx_list_part_t                *part;
+    ngx_table_elt_t                *h;
+    ngx_event_pipe_t               *p;
+    ngx_http_core_loc_conf_t       *clcf;
+    ngx_http_upstream_header_t     *hh;
+    ngx_http_upstream_main_conf_t  *umcf;
+
+    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+    hh = (ngx_http_upstream_header_t *) umcf->headers_in_hash.buckets;
+
+    part = &r->upstream->headers_in.headers.part;
+    h = part->elts;
+
+    for (i = 0; /* void */; i++) {
 
-    rc = u->send_header(r);
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
+                break;
+            }
+    
+            part = part->next;
+            h = part->elts;
+            i = 0;
+        }
+
+        key = h[i].hash % umcf->headers_in_hash.hash_size;
+
+        if (hh[key].name.len == h[i].key.len
+            && ngx_strcasecmp(hh[key].name.data, h[i].key.data) == 0)
+        {
+            if (hh[key].copy_handler(r, &h[i], hh[key].conf) != NGX_OK) {
+                ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+                return;
+            }
+
+            continue;
+        }
+
+        if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
+            ngx_http_upstream_finalize_request(r, u,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
+    }
+
+    rc = ngx_http_send_header(r);
 
     if (rc == NGX_ERROR || rc > NGX_OK) {
         ngx_http_upstream_finalize_request(r, u, rc);
@@ -820,20 +1065,27 @@ ngx_http_upstream_send_response(ngx_http
     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;
+    u->peer.connection->read->handler = ngx_http_upstream_process_body;
+    r->write_event_handler = ngx_http_upstream_process_downstream;
 
     ngx_http_upstream_process_body(u->peer.connection->read);
 }
 
 
 static void
+ngx_http_upstream_process_downstream(ngx_http_request_t *r)
+{
+    ngx_http_upstream_process_body(r->connection->write);
+}
+
+
+static void
 ngx_http_upstream_process_body(ngx_event_t *ev)
 {
+    ngx_event_pipe_t     *p;
     ngx_connection_t     *c;
     ngx_http_request_t   *r;
     ngx_http_upstream_t  *u;
-    ngx_event_pipe_t     *p;
 
     c = ev->data;
     r = c->data;
@@ -1046,11 +1298,6 @@ ngx_http_upstream_finalize_request(ngx_h
         rc = 0;
     }
 
-    if (u->saved_log_ctx) {
-        r->connection->log->data = u->saved_log_ctx;
-        r->connection->log->handler = u->saved_log_handler;
-    }
-
     if (u->pipe.temp_file) {
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "http upstream temp fd: %d",
@@ -1065,15 +1312,7 @@ ngx_http_upstream_finalize_request(ngx_h
     }
 #endif
 
-    if (u->pipe.temp_file) {
-        r->file.fd = u->pipe.temp_file->file.fd;
-
-#if 0
-    } else if (u->cache) {
-        r->file.fd = u->cache->ctx.file.fd;
-#endif
-    }
-
+    r->log_handler = u->saved_log_handler;
     r->connection->log->action = "sending to client";
 
     if (rc == 0 && r->main == NULL) {
@@ -1084,6 +1323,260 @@ ngx_http_upstream_finalize_request(ngx_h
 }
 
 
+static ngx_int_t
+ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{   
+    ngx_table_elt_t  **ph;
+    
+    ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
+
+    if (*ph == NULL) {
+        *ph = h;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset)
+{
+    ngx_array_t       *pa;
+    ngx_table_elt_t  **ph;
+
+    pa = (ngx_array_t *) ((char *) &r->upstream->headers_in + offset);
+
+    if (pa->elts == NULL) {
+       if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
+       {
+           return NGX_ERROR;
+       }
+    }
+
+    ph = ngx_array_push(pa);
+    if (ph == NULL) {
+        return NGX_ERROR;
+    }
+
+    *ph = h;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{
+    ngx_table_elt_t  *ho;
+
+    ho = ngx_list_push(&r->headers_out.headers);
+    if (ho == NULL) {
+        return NGX_ERROR;
+    }
+
+    *ho = *h;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_conditional_copy_header_line(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset)
+{
+    ngx_flag_t       *f;
+    ngx_table_elt_t  *ho;
+
+    f = (ngx_flag_t *) ((char *) r->upstream->conf + offset);
+
+    if (*f == 0) {
+        return NGX_OK;
+    }
+
+    ho = ngx_list_push(&r->headers_out.headers);
+    if (ho == NULL) {
+        return NGX_ERROR;
+    }
+
+    *ho = *h;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset)
+{
+    ngx_array_t      *pa;
+    ngx_table_elt_t  *ho, **ph;
+
+    pa = (ngx_array_t *) ((char *) &r->headers_out + offset);
+
+    if (pa->elts == NULL) {
+        if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
+        {
+            return NGX_ERROR;
+        }
+    }
+
+    ph = ngx_array_push(pa);
+    if (ph == NULL) {
+        return NGX_ERROR;
+    }
+
+    ho = ngx_list_push(&r->headers_out.headers);
+    if (ho == NULL) {
+        return NGX_ERROR;
+    }
+
+    *ho = *h;
+    *ph = ho;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{
+    r->headers_out.content_type = h->value;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_copy_content_length(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{
+    ngx_table_elt_t  *ho;
+
+    ho = ngx_list_push(&r->headers_out.headers);
+    if (ho == NULL) {
+        return NGX_ERROR;
+    }
+
+    *ho = *h;
+
+    r->headers_out.content_length = ho;
+    r->headers_out.content_length_n = ngx_atoof(h->value.data, h->value.len);
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{
+    ngx_int_t         rc;
+    ngx_table_elt_t  *ho;
+
+    ho = ngx_list_push(&r->headers_out.headers);
+    if (ho == NULL) {
+        return NGX_ERROR;
+    }
+
+    *ho = *h;
+
+    if (r->upstream->rewrite_redirect) {
+        rc = r->upstream->rewrite_redirect(r, ho, 0);
+
+        if (rc == NGX_OK) {
+            r->headers_out.location = ho;
+
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "rewritten location: \"%V\"", &ho->value);
+        }
+
+        return rc;
+    }
+
+    /*
+     * we do not set r->headers_out.location here to avoid the handling
+     * the local redirects without a host name by ngx_http_header_filter()
+     */
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{
+    u_char           *p;
+    ngx_int_t         rc;
+    ngx_table_elt_t  *ho;
+
+    ho = ngx_list_push(&r->headers_out.headers);
+    if (ho == NULL) {
+        return NGX_ERROR;
+    }
+
+    *ho = *h;
+
+    if (r->upstream->rewrite_redirect) {
+
+        p = (u_char *) ngx_strstr(ho->value.data, "url=");
+
+        if (p) {
+            rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data);
+
+        } else {
+            return NGX_OK;
+        }
+
+#if (NGX_DEBUG)
+        if (rc == NGX_OK) {
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "rewritten refresh: \"%V\"", &ho->value);
+        }
+#endif
+
+        return rc;
+    }
+
+    return NGX_OK;
+}
+
+
+#if (NGX_HTTP_GZIP)
+
+static ngx_int_t
+ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset)
+{
+    ngx_table_elt_t  *ho;
+
+    ho = ngx_list_push(&r->headers_out.headers);
+    if (ho == NULL) {
+        return NGX_ERROR;
+    }
+
+    *ho = *h;
+
+    r->headers_out.content_encoding = ho;
+
+    return NGX_OK;
+}
+
+#endif
+
+
 static size_t
 ngx_http_upstream_log_status_getlen(ngx_http_request_t *r, uintptr_t data)
 {
@@ -1131,51 +1624,45 @@ ngx_http_upstream_log_status(ngx_http_re
 }
 
 
-u_char *
-ngx_http_upstream_log_error(ngx_log_t *log, u_char *buf, size_t len)
+static u_char *
+ngx_http_upstream_log_error(ngx_http_request_t *r, u_char *buf, size_t len)
 {
     u_char                 *p;
     uintptr_t               escape;
-    ngx_http_log_ctx_t     *ctx;
-    ngx_http_request_t     *r;
     ngx_http_upstream_t    *u;
     ngx_peer_connection_t  *peer;
 
-    ctx = log->data;
-    r = ctx->request;
     u = r->upstream;
     peer = &u->peer;
 
     p = ngx_snprintf(buf, len,
-                     " while %s, client: %V, server: %V, URL: \"%V\","
+                     ", server: %V, URL: \"%V\","
                      " upstream: %V%V%s%V",
-                     log->action,
-                     &r->connection->addr_text,
                      &r->server_name,
                      &r->unparsed_uri,
-                     &u->schema0,
+                     &u->conf->schema,
                      &peer->peers->peer[peer->cur_peer].name,
                      peer->peers->peer[peer->cur_peer].uri_separator,
-                     &u->uri0);
+                     &u->conf->uri);
     len -= p - buf;
     buf = p;
 
     if (r->quoted_uri) {
-        escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location0->len,
-                                    r->uri.len - u->location0->len,
+        escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->conf->location->len,
+                                    r->uri.len - u->conf->location->len,
                                     NGX_ESCAPE_URI);
     } else {
         escape = 0;
     }
 
     if (escape) {
-        if (len >= r->uri.len - u->location0->len + escape) {
+        if (len >= r->uri.len - u->conf->location->len + escape) {
 
-            ngx_escape_uri(buf, r->uri.data + u->location0->len,
-                           r->uri.len - u->location0->len, NGX_ESCAPE_URI);
+            ngx_escape_uri(buf, r->uri.data + u->conf->location->len,
+                           r->uri.len - u->conf->location->len, NGX_ESCAPE_URI);
 
-            buf += r->uri.len - u->location0->len + escape;
-            len -= r->uri.len - u->location0->len + escape;
+            buf += r->uri.len - u->conf->location->len + escape;
+            len -= r->uri.len - u->conf->location->len + escape;
 
             if (r->args.len) {
                 p = ngx_snprintf(buf, len, "?%V", &r->args);
@@ -1186,19 +1673,19 @@ ngx_http_upstream_log_error(ngx_log_t *l
             return ngx_http_log_error_info(r, buf, len);
         }
 
-        p = ngx_palloc(r->pool, r->uri.len - u->location0->len + escape);
+        p = ngx_palloc(r->pool, r->uri.len - u->conf->location->len + escape);
         if (p == NULL) {
             return buf;
         }
 
-        ngx_escape_uri(p, r->uri.data + u->location0->len,
-                       r->uri.len - u->location0->len, NGX_ESCAPE_URI);
+        ngx_escape_uri(p, r->uri.data + u->conf->location->len,
+                       r->uri.len - u->conf->location->len, NGX_ESCAPE_URI);
 
-        p = ngx_cpymem(buf, p, r->uri.len - u->location0->len + escape);
+        p = ngx_cpymem(buf, p, r->uri.len - u->conf->location->len + escape);
 
     } else {
-        p = ngx_cpymem(buf, r->uri.data + u->location0->len,
-                       r->uri.len - u->location0->len);
+        p = ngx_cpymem(buf, r->uri.data + u->conf->location->len,
+                       r->uri.len - u->conf->location->len);
     }
 
     len -= p - buf;
@@ -1232,3 +1719,43 @@ ngx_http_upstream_add_log_formats(ngx_co
 
     return NGX_OK;
 }
+
+
+static void *
+ngx_http_upstream_create_main_conf(ngx_conf_t *cf)
+{
+    ngx_http_upstream_main_conf_t  *umcf;
+
+    umcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_main_conf_t));
+    if (umcf == NULL) {
+        return NULL;
+    }
+
+    return umcf;
+}
+
+
+static char *
+ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf)
+{
+    ngx_http_upstream_main_conf_t  *umcf = conf;
+
+    umcf->headers_in_hash.max_size = 100; 
+    umcf->headers_in_hash.bucket_limit = 1;
+    umcf->headers_in_hash.bucket_size = sizeof(ngx_http_upstream_header_t);
+    umcf->headers_in_hash.name = "upstream_headers_in";
+
+    if (ngx_hash_init(&umcf->headers_in_hash, cf->pool,
+                      ngx_http_upstream_headers_in, 0) != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
+                   "http upstream headers_in hash size: %ui, "
+                   "max buckets per entry: %ui",
+                   umcf->headers_in_hash.hash_size,
+                   umcf->headers_in_hash.min_buckets);
+
+    return NGX_CONF_OK;
+}
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -29,87 +29,140 @@
 
 
 typedef struct {
-    time_t                      bl_time;
-    ngx_uint_t                  bl_state;
+    time_t                          bl_time;
+    ngx_uint_t                      bl_state;
 
-    ngx_uint_t                  status;
-    time_t                      time;
+    ngx_uint_t                      status;
+    time_t                          time;
     
-    ngx_str_t                  *peer;
+    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;
+    ngx_hash_t                      headers_in_hash;
+} ngx_http_upstream_main_conf_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;
+    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_uint_t                      method;
 
-    ngx_uint_t                  next_upstream;
+    ngx_bufs_t                      bufs;
 
-    ngx_bufs_t                  bufs;
+    ngx_flag_t                      pass_request_headers;
+    ngx_flag_t                      pass_request_body;
+
+    ngx_flag_t                      redirect_errors;
+    ngx_flag_t                      pass_unparsed_uri;
+    ngx_flag_t                      cyclic_temp_file;
 
-    ngx_flag_t                  redirect_errors;
-    ngx_flag_t                  pass_unparsed_uri;
-    ngx_flag_t                  x_powered_by;
-    ngx_flag_t                  cyclic_temp_file;
+    ngx_flag_t                      pass_x_powered_by;
+    ngx_flag_t                      pass_server;
+    ngx_flag_t                      pass_date;
+    ngx_flag_t                      pass_x_accel_expires;
 
-    ngx_path_t                 *temp_path;
+    ngx_path_t                     *temp_path;
+
+    ngx_str_t                       schema;
+    ngx_str_t                       uri;
+    ngx_str_t                      *location;
+    ngx_str_t                       url;  /* used in proxy_rewrite_location */
 } ngx_http_upstream_conf_t;
 
 
-typedef struct ngx_http_upstream_s  ngx_http_upstream_t;
+typedef struct {
+    ngx_str_t                       name;
+    ngx_http_header_handler_pt      handler;
+    ngx_uint_t                      offset;
+    ngx_http_header_handler_pt      copy_handler;
+    ngx_uint_t                      conf;
+} ngx_http_upstream_header_t;
+
+
+typedef struct {
+    ngx_list_t                      headers;
+
+    ngx_table_elt_t                *status;
+    ngx_table_elt_t                *date;
+    ngx_table_elt_t                *server;
+    ngx_table_elt_t                *connection;
+
+    ngx_table_elt_t                *expires;
+    ngx_table_elt_t                *etag;
+    ngx_table_elt_t                *x_accel_expires;
+
+    ngx_table_elt_t                *content_type;
+    ngx_table_elt_t                *content_length;
+
+    ngx_table_elt_t                *last_modified;
+    ngx_table_elt_t                *location;
+    ngx_table_elt_t                *accept_ranges;
+
+#if (NGX_HTTP_GZIP)
+    ngx_table_elt_t                *content_encoding;
+#endif
+
+    ngx_array_t                     cache_control;
+} ngx_http_upstream_headers_in_t;
+
 
 struct ngx_http_upstream_s {
-    ngx_http_request_t         *request;
+    ngx_http_request_t             *request;
+
+    ngx_peer_connection_t           peer;
 
-    ngx_peer_connection_t       peer;
+    ngx_event_pipe_t                pipe;
 
-    ngx_event_pipe_t            pipe;
+    ngx_chain_t                    *request_bufs;
 
-    ngx_output_chain_ctx_t      output;
-    ngx_chain_writer_ctx_t      writer;
+    ngx_output_chain_ctx_t          output;
+    ngx_chain_writer_ctx_t          writer;
 
-    ngx_http_upstream_conf_t   *conf;
+    ngx_http_upstream_conf_t       *conf;
 
-    ngx_buf_t                   header_in;
+    ngx_http_upstream_headers_in_t  headers_in;
+
+    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_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);
+    void                          (*abort_request)(ngx_http_request_t *r);
+    void                          (*finalize_request)(ngx_http_request_t *r,
+                                        ngx_int_t rc);
+    ngx_int_t                     (*rewrite_redirect)(ngx_http_request_t *r,
+                                        ngx_table_elt_t *h, size_t prefix);
 
-    ngx_str_t                   schema0;
-    ngx_str_t                   uri0;
-    ngx_str_t                  *location0;
+    ngx_uint_t                      method;
 
-    ngx_http_log_ctx_t         *log_ctx;
-    ngx_log_handler_pt          log_handler;
-    ngx_http_log_ctx_t         *saved_log_ctx;
-    ngx_log_handler_pt          saved_log_handler;
+    ngx_http_log_handler_pt         saved_log_handler;
+
+    ngx_http_upstream_state_t      *state;
+    ngx_array_t                     states;  /* of ngx_http_upstream_state_t */
 
-    ngx_http_upstream_state_t  *state;
-    ngx_array_t                 states;    /* of ngx_http_upstream_state_t */
+    unsigned                        cachable:1;
+    unsigned                        accel:1;
 
-    unsigned                    cachable:1;
-
-    unsigned                    request_sent:1;
-    unsigned                    header_sent: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(ngx_log_t *log, u_char *buf, size_t len);
+
 
+extern ngx_module_t  ngx_http_upstream_module;
 
 extern char *ngx_http_upstream_header_errors[];
 
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -10,66 +10,157 @@
 #include <ngx_http.h>
 
 
-#define NGX_HTTP_VARS_HASH_PRIME  29
-
-#define ngx_http_vars_hash_key(key, vn)                                      \
-    {                                                                        \
-        ngx_uint_t  n;                                                       \
-        for (key = 0, n = 0; n < (vn)->len; n++) {                           \
-            key += (vn)->data[n];                                            \
-        }                                                                    \
-        key %= NGX_HTTP_VARS_HASH_PRIME;                                     \
-    }
-
-
+static ngx_http_variable_value_t *
+    ngx_http_variable_request(ngx_http_request_t *r, uintptr_t data);
 static ngx_http_variable_value_t *
     ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data);
 static ngx_http_variable_value_t *
     ngx_http_variable_unknown_header(ngx_http_request_t *r, uintptr_t data);
 static ngx_http_variable_value_t *
+    ngx_http_variable_host(ngx_http_request_t *r, uintptr_t data);
+static ngx_http_variable_value_t *
     ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data);
 static ngx_http_variable_value_t *
-    ngx_http_variable_uri(ngx_http_request_t *r, uintptr_t data);
+    ngx_http_variable_remote_port(ngx_http_request_t *r, uintptr_t data);
+static ngx_http_variable_value_t *
+    ngx_http_variable_server_addr(ngx_http_request_t *r, uintptr_t data);
 static ngx_http_variable_value_t *
-    ngx_http_variable_query_string(ngx_http_request_t *r, uintptr_t data);
-
-
-static ngx_array_t  *ngx_http_core_variables_hash;
+    ngx_http_variable_server_port(ngx_http_request_t *r, uintptr_t data);
+static ngx_http_variable_value_t *
+    ngx_http_variable_document_root(ngx_http_request_t *r, uintptr_t data);
+static ngx_http_variable_value_t *
+    ngx_http_variable_request_filename(ngx_http_request_t *r, uintptr_t data);
 
 
-static ngx_http_core_variable_t  ngx_http_core_variables[] = {
-
-    { ngx_string("HTTP_HOST"), ngx_http_variable_header,
-      offsetof(ngx_http_headers_in_t, host) },
+/*
+ * TODO:
+ *     Apache CGI: AUTH_TYPE, PATH_INFO (null), PATH_TRANSLATED
+ *                 REMOTE_HOST (null), REMOTE_IDENT (null),
+ *                 SERVER_SOFTWARE
+ *
+ *     Apache SSI: DATE_GMT, DOCUMENT_NAME, LAST_MODIFIED,
+ *                 USER_NAME (file owner)
+ */
 
-    { ngx_string("HTTP_USER_AGENT"), ngx_http_variable_header,
-      offsetof(ngx_http_headers_in_t, user_agent) },
+static ngx_http_variable_t  ngx_http_core_variables[] = {
+
+    { ngx_string("http_host"), ngx_http_variable_header,
+      offsetof(ngx_http_request_t, headers_in.host), 0 },
 
-    { ngx_string("HTTP_REFERER"), ngx_http_variable_header,
-      offsetof(ngx_http_headers_in_t, referer) },
+    { ngx_string("http_user_agent"), ngx_http_variable_header,
+      offsetof(ngx_http_request_t, headers_in.user_agent), 0 },
+
+    { ngx_string("http_referer"), ngx_http_variable_header,
+      offsetof(ngx_http_request_t, headers_in.referer), 0 },
 
 #if (NGX_HTTP_GZIP)
-    { ngx_string("HTTP_VIA"), ngx_http_variable_header,
-      offsetof(ngx_http_headers_in_t, via) },
+    { ngx_string("http_via"), ngx_http_variable_header,
+      offsetof(ngx_http_request_t, headers_in.via), 0 },
 #endif
 
 #if (NGX_HTTP_PROXY)
-    { ngx_string("HTTP_X_FORWARDED_FOR"), ngx_http_variable_header,
-      offsetof(ngx_http_headers_in_t, x_forwarded_for) },
+    { ngx_string("http_x_forwarded_for"), ngx_http_variable_header,
+      offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0 },
 #endif
 
-    { ngx_string("REMOTE_ADDR"), ngx_http_variable_remote_addr, 0 },
+    { ngx_string("content_length"), ngx_http_variable_header,
+      offsetof(ngx_http_request_t, headers_in.content_length), 0 },
+
+    { ngx_string("content_type"), ngx_http_variable_header,
+      offsetof(ngx_http_request_t, headers_in.content_type), 0 },
+
+    { ngx_string("host"), ngx_http_variable_host, 0, 0 },
+
+    { ngx_string("remote_addr"), ngx_http_variable_remote_addr, 0, 0 },
 
-    { ngx_string("DOCUMENT_URI"), ngx_http_variable_uri, 0 },
+    { ngx_string("remote_port"), ngx_http_variable_remote_port, 0, 0 },
+
+    { ngx_string("server_addr"), ngx_http_variable_server_addr, 0, 0 },
+
+    { ngx_string("server_port"), ngx_http_variable_server_port, 0, 0 },
+
+    { ngx_string("server_protocol"), ngx_http_variable_request,
+      offsetof(ngx_http_request_t, http_protocol), 0 },
+
+    { ngx_string("request_uri"), ngx_http_variable_request,
+      offsetof(ngx_http_request_t, unparsed_uri), 0 },
 
-    { ngx_string("QUERY_STRING"), ngx_http_variable_query_string, 0 },
+    { ngx_string("document_uri"), ngx_http_variable_request,
+      offsetof(ngx_http_request_t, uri), 0 },
+
+    { ngx_string("document_root"), ngx_http_variable_document_root, 0, 0 },
+
+    { ngx_string("query_string"), ngx_http_variable_request,
+      offsetof(ngx_http_request_t, args),
+      NGX_HTTP_VAR_NOCACHABLE },
 
-    { ngx_null_string, NULL, 0 }
+    { ngx_string("request_filename"), ngx_http_variable_request_filename, 0,
+      NGX_HTTP_VAR_NOCACHABLE },
+
+    { ngx_string("server_name"), ngx_http_variable_request,
+      offsetof(ngx_http_request_t, server_name), 0 },
+
+    { ngx_string("request_method"), ngx_http_variable_request,
+      offsetof(ngx_http_request_t, method_name), 0 },
+
+    { ngx_string("remote_user"), ngx_http_variable_request,
+      offsetof(ngx_http_request_t, headers_in.user), 0 },
+
+    { ngx_null_string, NULL, 0, 0 }
 };
 
 
 ngx_http_variable_t *
-ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t set)
+ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
+{
+    ngx_uint_t                  i;
+    ngx_http_variable_t        *v;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    v = cmcf->all_variables.elts;
+    for (i = 0; i < cmcf->all_variables.nelts; i++) {
+        if (name->len != v[i].name.len
+            || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
+        {
+            continue;
+        }
+
+        if (!(v[i].flags & NGX_HTTP_VAR_CHANGABLE)) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "the duplicate \"%V\" variable", name);
+            return NULL;
+        }
+
+        return &v[i];
+    }
+
+    v = ngx_array_push(&cmcf->all_variables);
+    if (v == NULL) {
+        return NULL;
+    }
+
+    v->name.len = name->len;
+    v->name.data = ngx_palloc(cf->pool, name->len);
+    if (v->name.data == NULL) {
+        return NULL;
+    }
+
+    for (i = 0; i < name->len; i++) {
+        v->name.data[i] = ngx_tolower(name->data[i]);
+    }
+
+    v->handler = NULL;
+    v->data = 0;
+    v->flags = flags;
+
+    return v;
+}
+
+
+ngx_int_t
+ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
 {
     ngx_uint_t                  i;
     ngx_http_variable_t        *v;
@@ -83,7 +174,7 @@ ngx_http_add_variable(ngx_conf_t *cf, ng
         if (ngx_array_init(&cmcf->variables, cf->pool, 4,
                            sizeof(ngx_http_variable_t)) == NGX_ERROR)
         {
-            return NULL;
+            return NGX_ERROR;
         }
 
     } else {
@@ -94,36 +185,30 @@ ngx_http_add_variable(ngx_conf_t *cf, ng
                 continue;
             }
 
-            if (set && v[i].handler) {
-                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                                   "the duplicate \"%V\" variable", name);
-                return NULL;
-            }
-
-            return &v[i];
+            return i;
         }
     }
 
     v = ngx_array_push(&cmcf->variables);
     if (v == NULL) {
-        return NULL;
+        return NGX_ERROR;
     }
 
     v->name.len = name->len;
     v->name.data = ngx_palloc(cf->pool, name->len);
     if (v->name.data == NULL) {
-        return NULL;
+        return NGX_ERROR;
     }
 
     for (i = 0; i < name->len; i++) {
-        v->name.data[i] = ngx_toupper(name->data[i]);
+        v->name.data[i] = ngx_tolower(name->data[i]);
     }
 
-    v->index = cmcf->variables.nelts - 1;
     v->handler = NULL;
     v->data = 0;
+    v->flags = 0;
 
-    return v;
+    return cmcf->variables.nelts - 1;
 }
 
 
@@ -158,7 +243,9 @@ ngx_http_get_indexed_variable(ngx_http_r
         }
     }
 
-    r->variables[index] = vv;
+    if (!(v[index].flags & NGX_HTTP_VAR_NOCACHABLE)) {
+        r->variables[index] = vv;
+    }
 
     return vv;
 }
@@ -169,43 +256,56 @@ ngx_http_get_variable(ngx_http_request_t
 {
     ngx_uint_t                  i, key;
     ngx_http_variable_t        *v;
-    ngx_http_core_variable_t   *cv;
     ngx_http_core_main_conf_t  *cmcf;
 
     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
 
-    v = cmcf->variables.elts;
-    for (i = 0; i < cmcf->variables.nelts; i++) {
-        if (v[i].name.len != name->len) {
-            continue;
-        }
-
-        if (ngx_strncmp(v[i].name.data, name->data, name->len) == 0) {
-            return ngx_http_get_indexed_variable(r, v[i].index);
-        }
+    key = 0;
+    for (i = 0; i < name->len; i++) {
+        key += name->data[i];
     }
 
-    ngx_http_vars_hash_key(key, name);
+    key %= cmcf->variables_hash.hash_size;
+    v = (ngx_http_variable_t *) cmcf->variables_hash.buckets;
 
-    cv = ngx_http_core_variables_hash[key].elts;
-    for (i = 0; i < ngx_http_core_variables_hash[key].nelts; i++) {
-        if (cv[i].name.len != name->len) {
-            continue;
-        }
-
-        if (ngx_strncmp(cv[i].name.data, name->data, name->len) == 0) {
-            return cv[i].handler(r, cv[i].data);
-        }
+    if (v[key].name.len == name->len
+        && ngx_strncmp(v[key].name.data, name->data, name->len) == 0)
+    {
+        return v[key].handler(r, v[key].data);
     }
 
-    if (ngx_strncmp(name->data, "HTTP_", 5) == 0) {
+    if (ngx_strncmp(name->data, "http_", 5) == 0) {
         return ngx_http_variable_unknown_header(r, (uintptr_t) name);
     }
 
     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   "unknown \"%V\" variable", name);
 
-    return NGX_HTTP_VARIABLE_NOT_FOUND;
+    return NGX_HTTP_VAR_NOT_FOUND;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_variable_request(ngx_http_request_t *r, uintptr_t data)
+{
+    ngx_str_t                  *s;
+    ngx_http_variable_value_t  *vv;
+
+    s = (ngx_str_t *) ((char *) r + data);
+
+    if (s->data == NULL) {
+        return NGX_HTTP_VAR_NOT_FOUND;
+    }
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    vv->value = 0;
+    vv->text = *s;
+
+    return vv;
 }
 
 
@@ -215,10 +315,10 @@ ngx_http_variable_header(ngx_http_reques
     ngx_table_elt_t            *h;
     ngx_http_variable_value_t  *vv;
 
-    h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data);
+    h = *(ngx_table_elt_t **) ((char *) r + data);
 
     if (h == NULL) {
-        return NGX_HTTP_VARIABLE_NOT_FOUND;
+        return NGX_HTTP_VAR_NOT_FOUND;
     }
 
     vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
@@ -259,12 +359,11 @@ ngx_http_variable_unknown_header(ngx_htt
             i = 0;
         }
 
-        for (n = 0; n + 5 < var->len && n < header[i].key.len; n++)
-        {
+        for (n = 0; n + 5 < var->len && n < header[i].key.len; n++) {
             ch = header[i].key.data[n];
 
-            if (ch >= 'a' && ch <= 'z') {
-                ch &= ~0x20;
+            if (ch >= 'A' && ch <= 'Z') {
+                ch |= 0x20;
 
             } else if (ch == '-') {
                 ch = '_';
@@ -287,7 +386,31 @@ ngx_http_variable_unknown_header(ngx_htt
         }
     }
 
-    return NGX_HTTP_VARIABLE_NOT_FOUND;
+    return NGX_HTTP_VAR_NOT_FOUND;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_variable_host(ngx_http_request_t *r, uintptr_t data)
+{
+    ngx_http_variable_value_t  *vv;
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    vv->value = 0;
+
+    if (r->headers_in.host) {
+        vv->text.len = r->headers_in.host_name_len;
+        vv->text.data = r->headers_in.host->value.data;
+
+    } else {
+        vv->text = r->server_name;
+    }
+
+    return vv;
 }
 
 
@@ -309,8 +432,49 @@ ngx_http_variable_remote_addr(ngx_http_r
 
 
 static ngx_http_variable_value_t *
-ngx_http_variable_uri(ngx_http_request_t *r, uintptr_t data)
+ngx_http_variable_remote_port(ngx_http_request_t *r, uintptr_t data)
 {
+    ngx_uint_t                  port;
+    struct sockaddr_in         *sin;
+    ngx_http_variable_value_t  *vv;
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    vv->value = 0;
+    vv->text.len = 0;
+
+    vv->text.data = ngx_palloc(r->pool, sizeof("65535") - 1);
+    if (vv->text.data == NULL) {
+        return NULL;
+    }
+
+    /* AF_INET only */
+    
+    if (r->connection->sockaddr->sa_family == AF_INET) {
+        sin = (struct sockaddr_in *) r->connection->sockaddr;
+    
+        port = ntohs(sin->sin_port);
+                             
+        if (port > 0 && port < 65536) {
+            vv->value = port;
+            vv->text.len = ngx_sprintf(vv->text.data, "%ui", port)
+                           - vv->text.data;
+        }
+    }
+
+    return vv;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_variable_server_addr(ngx_http_request_t *r, uintptr_t data)
+{
+    socklen_t                   len;
+    ngx_connection_t           *c;
+    struct sockaddr_in          sin;
     ngx_http_variable_value_t  *vv;
 
     vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
@@ -319,15 +483,75 @@ ngx_http_variable_uri(ngx_http_request_t
     }
 
     vv->value = 0;
-    vv->text = r->uri;
+
+    vv->text.data = ngx_palloc(r->pool, INET_ADDRSTRLEN);
+    if (vv->text.data == NULL) {
+        return NULL;
+    }
+
+    c = r->connection;
+
+    if (r->in_addr == 0) {
+        len = sizeof(struct sockaddr_in);
+        if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) {
+            ngx_log_error(NGX_LOG_CRIT, c->log,
+                          ngx_socket_errno, "getsockname() failed");
+            return NULL;
+        }
+
+        r->in_addr = sin.sin_addr.s_addr;
+    }
+
+    vv->text.len = ngx_inet_ntop(c->listening->family, &r->in_addr,
+                                 vv->text.data, INET_ADDRSTRLEN);
 
     return vv;
 }
 
 
 static ngx_http_variable_value_t *
-ngx_http_variable_query_string(ngx_http_request_t *r, uintptr_t data)
+ngx_http_variable_server_port(ngx_http_request_t *r, uintptr_t data)
+{
+    ngx_http_variable_value_t  *vv;
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    vv->value = r->port;
+    vv->text.len = r->port_text->len - 1;
+    vv->text.data = r->port_text->data + 1;
+
+    return vv;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_variable_document_root(ngx_http_request_t *r, uintptr_t data)
 {
+    ngx_http_core_loc_conf_t   *clcf;
+    ngx_http_variable_value_t  *vv;
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    vv->value = 0;
+    vv->text = clcf->root;
+
+    return vv;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_variable_request_filename(ngx_http_request_t *r, uintptr_t data)
+{
+    u_char                     *p;
+    ngx_http_core_loc_conf_t   *clcf;
     ngx_http_variable_value_t  *vv;
 
     vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
@@ -336,84 +560,130 @@ ngx_http_variable_query_string(ngx_http_
     }
 
     vv->value = 0;
-    vv->text = r->args;
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (!clcf->alias) {
+        vv->text.len = clcf->root.len + r->uri.len;
+        vv->text.data = ngx_palloc(r->pool, vv->text.len);
+        if (vv->text.data == NULL) {
+            return NULL;
+        }
+
+        p = ngx_cpymem(vv->text.data, clcf->root.data, clcf->root.len);
+        ngx_memcpy(p, r->uri.data, r->uri.len + 1);
+
+    } else {
+        vv->text.len = clcf->root.len + r->uri.len + 2 - clcf->name.len;
+        vv->text.data = ngx_palloc(r->pool, vv->text.len);
+        if (vv->text.data == NULL) {
+            return NULL;
+        }
+
+        p = ngx_cpymem(vv->text.data, clcf->root.data, clcf->root.len);
+        ngx_memcpy(p, r->uri.data + clcf->name.len,
+                   r->uri.len + 1 - clcf->name.len);
+    }
 
     return vv;
 }
 
 
 ngx_int_t
-ngx_http_variables_init(ngx_cycle_t *cycle)
+ngx_http_variables_add_core_vars(ngx_conf_t *cf)
 {
-    ngx_uint_t                  i, j, key;
-    ngx_http_variable_t        *v;
-    ngx_http_core_variable_t   *cv, *vp;
+    ngx_http_variable_t        *v, *cv;
     ngx_http_core_main_conf_t  *cmcf;
 
-    ngx_http_core_variables_hash = ngx_palloc(cycle->pool,
-                                              NGX_HTTP_VARS_HASH_PRIME
-                                              * sizeof(ngx_array_t));
-    if (ngx_http_core_variables_hash == NULL) {
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    if (ngx_array_init(&cmcf->all_variables, cf->pool, 32,
+                       sizeof(ngx_http_variable_t)) == NGX_ERROR)
+    {
         return NGX_ERROR;
     }
 
-    for (i = 0; i < NGX_HTTP_VARS_HASH_PRIME; i++) {
-        if (ngx_array_init(&ngx_http_core_variables_hash[i], cycle->pool, 4,
-                           sizeof(ngx_http_core_variable_t)) == NGX_ERROR)
-        {
-            return NGX_ERROR;
-        }
-    }
-
     for (cv = ngx_http_core_variables; cv->name.len; cv++) {
-        ngx_http_vars_hash_key(key, &cv->name);
-
-        vp = ngx_array_push(&ngx_http_core_variables_hash[key]);
-        if (vp == NULL) {
+        v = ngx_array_push(&cmcf->all_variables);
+        if (v == NULL) {
             return NGX_ERROR;
         }
 
-        *vp = *cv;
-    }
-
-
-    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
-
-    v = cmcf->variables.elts;
-    for (i = 0; i < cmcf->variables.nelts; i++) {
-
-        if (v[i].handler) {
-            continue;
-        }
-
-        ngx_http_vars_hash_key(key, &v[i].name);
-
-        cv = ngx_http_core_variables_hash[key].elts;
-        for (j = 0; j < ngx_http_core_variables_hash[key].nelts; j++) {
-            if (cv[j].name.len != v[i].name.len) {
-                continue;
-            }
-
-            if (ngx_strncmp(cv[j].name.data, v[i].name.data, v[i].name.len)
-                == 0)
-            {
-                v[i].handler = cv[j].handler;
-                v[i].data = cv[j].data;
-                continue;
-            }
-        }
-
-        if (ngx_strncmp(v[i].name.data, "HTTP_", 5) == 0) {
-            v[i].handler = ngx_http_variable_unknown_header;
-            v[i].data = (uintptr_t) &v[i].name;
-            continue;
-        }
-
-        ngx_log_error(NGX_LOG_ERR, cycle->log, 0,
-                      "unknown \"%V\" variable", &v[i].name);
-
-        return NGX_ERROR;
+        *v = *cv;
     }
 
     return NGX_OK;
 }
+
+
+ngx_int_t
+ngx_http_variables_init_vars(ngx_conf_t *cf)
+{
+    ngx_uint_t                  i, n;
+    ngx_http_variable_t        *v, *av;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    /* set the handlers for the indexed http variables */
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    v = cmcf->variables.elts;
+    av = cmcf->all_variables.elts;
+
+    for (i = 0; i < cmcf->variables.nelts; i++) {
+
+        for (n = 0; n < cmcf->all_variables.nelts; n++) {
+
+            if (v[i].name.len == av[n].name.len
+                && ngx_strncmp(v[i].name.data, av[n].name.data, v[i].name.len)
+                   == 0)
+            {
+                v[i].handler = av[n].handler;
+                v[i].data = av[n].data;
+                v[i].flags = av[n].flags;
+
+                goto next;
+            }
+        }
+
+        if (ngx_strncmp(v[i].name.data, "http_", 5) == 0) {
+            v[i].handler = ngx_http_variable_unknown_header;
+            v[i].data = (uintptr_t) &v[i].name;
+
+            continue;
+        }
+
+        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                      "unknown \"%V\" variable", &v[i].name);
+
+        return NGX_ERROR;
+
+    next:
+        continue;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
+                   "http variables: %ui", cmcf->variables.nelts);
+
+
+    /* init the all http variables hash */
+
+    cmcf->variables_hash.max_size = 500;
+    cmcf->variables_hash.bucket_limit = 1;
+    cmcf->variables_hash.bucket_size = sizeof(ngx_http_variable_t);
+    cmcf->variables_hash.name = "http variables";
+
+    if (ngx_hash_init(&cmcf->variables_hash, cf->pool,
+            cmcf->all_variables.elts, cmcf->all_variables.nelts) != NGX_OK)
+    {
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0,
+                   "http variables hash size: %ui for %ui values, "
+                   "max buckets per entry: %ui",
+                   cmcf->variables_hash.hash_size, cmcf->all_variables.nelts,
+                   cmcf->variables_hash.min_buckets);
+
+    return NGX_OK;
+}
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -14,13 +14,13 @@
 #include <ngx_http.h>
 
 
-#define NGX_HTTP_VARIABLE_NOT_FOUND  (ngx_http_variable_value_t *) -1
+#define NGX_HTTP_VAR_NOT_FOUND  (ngx_http_variable_value_t *) -1
 
 
-struct ngx_http_variable_value_s {
+typedef struct {
     ngx_uint_t                     value;
     ngx_str_t                      text;
-};
+} ngx_http_variable_value_t;
 
 typedef struct ngx_http_variable_s  ngx_http_variable_t;
 
@@ -28,30 +28,28 @@ typedef ngx_http_variable_value_t *
     (*ngx_http_get_variable_pt) (ngx_http_request_t *r, uintptr_t data);
 
 
+#define NGX_HTTP_VAR_CHANGABLE   1
+#define NGX_HTTP_VAR_NOCACHABLE  2
+
+
 struct ngx_http_variable_s {
-    ngx_str_t                  name;
-    ngx_uint_t                 index;
+    ngx_str_t                  name;   /* must be first to build the hash */
     ngx_http_get_variable_pt   handler;
     uintptr_t                  data;
+    ngx_uint_t                 flags;
 };
 
 
-typedef struct {
-    ngx_str_t                  name;
-    ngx_http_get_variable_pt   handler;
-    uintptr_t                  data;
-} ngx_http_core_variable_t;
-
-
 ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name,
-    ngx_uint_t set);
-ngx_int_t ngx_http_get_variable_index(ngx_http_core_main_conf_t *cmcf,
-    ngx_str_t *name);
+    ngx_uint_t flags);
+ngx_int_t ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name);
 ngx_http_variable_value_t *ngx_http_get_indexed_variable(ngx_http_request_t *r,
     ngx_uint_t index);
 ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
     ngx_str_t *name);
-ngx_int_t ngx_http_variables_init(ngx_cycle_t *cycle);
+
+ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf);
+ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf);
 
 
 #endif /* _NGX_HTTP_VARIABLES_H_INCLUDED_ */
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -10,16 +10,12 @@
 #include <ngx_http.h>
 
 
-typedef struct {
-    ngx_chain_t  *out;
-} ngx_http_write_filter_ctx_t;
-
-
 static ngx_int_t ngx_http_write_filter_init(ngx_cycle_t *cycle);
 
 
 ngx_http_module_t  ngx_http_write_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -33,7 +29,7 @@ ngx_http_module_t  ngx_http_write_filter
 
 
 ngx_module_t  ngx_http_write_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_write_filter_module_ctx,     /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -45,34 +41,20 @@ ngx_module_t  ngx_http_write_filter_modu
 ngx_int_t
 ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
-    off_t                         size, sent;
-    ngx_uint_t                    last, flush;
-    ngx_chain_t                  *cl, *ln, **ll, *chain;
-    ngx_connection_t             *c;
-    ngx_http_core_loc_conf_t     *clcf;
-    ngx_http_write_filter_ctx_t  *ctx;
-
-    ctx = ngx_http_get_module_ctx(r->main ? r->main : r,
-                                  ngx_http_write_filter_module);
-
-    if (ctx == NULL) {
-
-        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_write_filter_ctx_t));
-        if (ctx == NULL) {
-            return NGX_ERROR;
-        }
-
-        ngx_http_set_ctx(r, ctx, ngx_http_write_filter_module);
-    }
+    off_t                      size, sent;
+    ngx_uint_t                 last, flush;
+    ngx_chain_t               *cl, *ln, **ll, *chain;
+    ngx_connection_t          *c;
+    ngx_http_core_loc_conf_t  *clcf;
 
     size = 0;
     flush = 0;
     last = 0;
-    ll = &ctx->out;
+    ll = &r->out;
 
     /* find the size, the flush point and the last link of the saved chain */
 
-    for (cl = ctx->out; cl; cl = cl->next) {
+    for (cl = r->out; cl; cl = cl->next) {
         ll = &cl->next;
 
         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
@@ -174,11 +156,10 @@ ngx_http_write_filter(ngx_http_request_t
     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http write filter: l:%d f:%d s:%O", last, flush, size);
 
-    clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
-                                        ngx_http_core_module);
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     /*
-     * avoid the output if there is no last buf, no flush point,
+     * avoid the output if there are no last buf, no flush point,
      * there are the incoming bufs and the size of all bufs
      * is smaller than "postpone_output" directive
      */
@@ -187,20 +168,30 @@ ngx_http_write_filter(ngx_http_request_t
         return NGX_OK;
     }
 
+    /*
+     * avoid the output if there are no incoming bufs but there are
+     * the postponed requests or data
+     */
+
+    if (in == NULL && r->postponed) {
+        return NGX_OK;
+    }
+
     if (c->write->delayed) {
         return NGX_AGAIN;
     }
 
     if (size == 0 && !c->buffered) {
         if (last) {
+            r->out = NULL;
             return NGX_OK;
         }
 
         if (flush) {
             do {
-                ctx->out = ctx->out->next;
+                r->out = r->out->next;
             }
-            while (ctx->out);
+            while (r->out);
 
             return NGX_OK;
         }
@@ -215,7 +206,7 @@ ngx_http_write_filter(ngx_http_request_t
 
     sent = c->sent;
 
-    chain = c->send_chain(c, ctx->out, clcf->limit_rate);
+    chain = c->send_chain(c, r->out, clcf->limit_rate);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http write filter %p", chain);
@@ -231,13 +222,13 @@ ngx_http_write_filter(ngx_http_request_t
         return NGX_ERROR;
     }
 
-    for (cl = ctx->out; cl && cl != chain; /* void */) {
+    for (cl = r->out; cl && cl != chain; /* void */) {
         ln = cl;
         cl = cl->next;
         ngx_free_chain(r->pool, ln);
     }
 
-    ctx->out = chain;
+    r->out = chain;
 
     if (chain || (last && c->buffered)) {
         return NGX_AGAIN;
--- a/src/imap/ngx_imap.c
+++ b/src/imap/ngx_imap.c
@@ -34,7 +34,7 @@ static ngx_core_module_t  ngx_imap_modul
 
 
 ngx_module_t  ngx_imap_module = {
-    NGX_MODULE, 
+    NGX_MODULE_V1,
     &ngx_imap_module_ctx,                  /* module context */
     ngx_imap_commands,                     /* module directives */
     NGX_CORE_MODULE,                       /* module type */
--- a/src/imap/ngx_imap_handler.c
+++ b/src/imap/ngx_imap_handler.c
@@ -47,7 +47,7 @@ void ngx_imap_init_connection(ngx_connec
         return;
     }
 
-    c->read->event_handler = ngx_imap_init_session;
+    c->read->handler = ngx_imap_init_session;
 
     ngx_add_timer(c->read, /* STUB */ 60000);
 
@@ -93,7 +93,7 @@ static void ngx_imap_init_session(ngx_ev
         return;
     }
 
-    c->read->event_handler = ngx_pop3_auth_state;
+    c->read->handler = ngx_pop3_auth_state;
 
     ngx_pop3_auth_state(rev);
 }
--- a/src/imap/ngx_imap_proxy.c
+++ b/src/imap/ngx_imap_proxy.c
@@ -82,9 +82,9 @@ void ngx_imap_proxy_init(ngx_imap_sessio
     p->upstream.connection->data = s;
     p->upstream.connection->pool = s->connection->pool;
 
-    s->connection->read->event_handler = ngx_imap_proxy_block_read;
-    p->upstream.connection->read->event_handler = ngx_imap_proxy_auth_handler;
-    p->upstream.connection->write->event_handler = ngx_imap_proxy_dummy_handler;
+    s->connection->read->handler = ngx_imap_proxy_block_read;
+    p->upstream.connection->read->handler = ngx_imap_proxy_auth_handler;
+    p->upstream.connection->write->handler = ngx_imap_proxy_dummy_handler;
 }
 
 
@@ -200,10 +200,10 @@ static void ngx_imap_proxy_auth_handler(
     s->proxy->buffer->pos = s->proxy->buffer->start;
     s->proxy->buffer->last = s->proxy->buffer->start;
 
-    s->connection->read->event_handler = ngx_imap_proxy_handler;
-    s->connection->write->event_handler = ngx_imap_proxy_handler;
-    rev->event_handler = ngx_imap_proxy_handler;
-    c->write->event_handler = ngx_imap_proxy_handler;
+    s->connection->read->handler = ngx_imap_proxy_handler;
+    s->connection->write->handler = ngx_imap_proxy_handler;
+    rev->handler = ngx_imap_proxy_handler;
+    c->write->handler = ngx_imap_proxy_handler;
 }
 
 
--- a/src/os/unix/ngx_channel.c
+++ b/src/os/unix/ngx_channel.c
@@ -137,7 +137,7 @@ ngx_int_t ngx_read_channel(ngx_socket_t 
 
     if (ch->command == NGX_CMD_OPEN_CHANNEL) {
 
-        if (cmsg.cm.cmsg_len < sizeof(cmsg)) {
+        if (cmsg.cm.cmsg_len < (socklen_t) sizeof(cmsg)) {
             ngx_log_error(NGX_LOG_ALERT, log, 0,
                           "recvmsg() returned too small ancillary data");
             return NGX_ERROR;
@@ -215,7 +215,7 @@ ngx_int_t ngx_add_channel_event(ngx_cycl
 
     ev = (event == NGX_READ_EVENT) ? rev : wev;
 
-    ev->event_handler = handler;
+    ev->handler = handler;
 
     if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
         if (ngx_add_conn(c) == NGX_ERROR) {
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -97,9 +97,6 @@ pid_t rfork_thread(int flags, void *stac
 #endif
 
 
-#define ngx_setproctitle  setproctitle
-
-
 extern char *malloc_options;
 
 
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -97,10 +97,5 @@ extern ssize_t sendfile(int s, int fd, i
 #define NGX_HAVE_SELECT_CHANGE_TIMEOUT   1
 #endif
 
-#ifndef NGX_SETPROCTITLE_USES_ENV
-#define NGX_SETPROCTITLE_USES_ENV    1
-#define NGX_SETPROCTITLE_PAD         '\0' 
-#endif
-
 
 #endif /* _NGX_LINUX_CONFIG_H_INCLUDED_ */
--- a/src/os/unix/ngx_linux_init.c
+++ b/src/os/unix/ngx_linux_init.c
@@ -73,8 +73,6 @@ ngx_os_init(ngx_log_t *log)
         ngx_linux_rtsig_max = 0;
     }
 
-    ngx_init_setproctitle(log);
-
 
     return ngx_posix_init(log);
 }
--- a/src/os/unix/ngx_posix_config.h
+++ b/src/os/unix/ngx_posix_config.h
@@ -102,13 +102,6 @@
 #endif
 
 
-#if (NGX_HAVE_SETPROCTITLE)
-#define ngx_setproctitle        setproctitle
-#else
-#define ngx_setproctitle(title)
-#endif
-
-
 #define NGX_POSIX_IO  1
 
 
--- a/src/os/unix/ngx_posix_init.c
+++ b/src/os/unix/ngx_posix_init.c
@@ -6,6 +6,7 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_setproctitle.h>
 
 
 ngx_int_t   ngx_ncpu;
@@ -97,6 +98,8 @@ ngx_int_t ngx_posix_init(ngx_log_t *log)
     ngx_signal_t      *sig;
     struct sigaction   sa;
 
+    ngx_init_setproctitle(log);
+
     ngx_pagesize = getpagesize();
 
     if (ngx_ncpu == 0) {
--- a/src/os/unix/ngx_process.h
+++ b/src/os/unix/ngx_process.h
@@ -62,12 +62,6 @@ void ngx_debug_point(void);
 #endif
 
 
-#if !defined(ngx_setproctitle)
-ngx_int_t ngx_init_setproctitle(ngx_log_t *log);
-void ngx_setproctitle(char *title);
-#endif
-
-
 extern int            ngx_argc;
 extern char         **ngx_argv;
 extern char         **ngx_os_argv;
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -7,6 +7,7 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_event.h>
+#include <ngx_setproctitle.h>
 #include <ngx_channel.h>
 
 
--- a/src/os/unix/ngx_send.c
+++ b/src/os/unix/ngx_send.c
@@ -63,7 +63,7 @@ ssize_t ngx_unix_send(ngx_connection_t *
 
         } else {
             wev->error = 1;
-            ngx_connection_error(c, err, "recv() failed");
+            ngx_connection_error(c, err, "send() failed");
             return NGX_ERROR;
         }
     }
--- a/src/os/unix/ngx_setproctitle.c
+++ b/src/os/unix/ngx_setproctitle.c
@@ -6,6 +6,7 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_setproctitle.h>
 
 
 #if (NGX_SETPROCTITLE_USES_ENV)
@@ -131,19 +132,4 @@ ngx_setproctitle(char *title)
                    "setproctitle: \"%s\"", ngx_os_argv[0]);
 }
 
-
-#elif !defined(ngx_setproctitle)
-
-ngx_int_t
-ngx_init_setproctitle(ngx_log_t *log)
-{
-    return NGX_OK;
-}
-
-void
-ngx_setproctitle(char *title)
-{
-    return;
-}
-
-#endif
+#endif /* NGX_SETPROCTITLE_USES_ENV */
new file mode 100644
--- /dev/null
+++ b/src/os/unix/ngx_setproctitle.h
@@ -0,0 +1,45 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_SETPROCTITLE_H_INCLUDED_
+#define _NGX_SETPROCTITLE_H_INCLUDED_
+
+
+#if (NGX_HAVE_SETPROCTITLE)
+
+/* FreeBSD, NetBSD, OpenBSD */
+
+#define ngx_init_setproctitle(log)
+#define ngx_setproctitle           setproctitle
+
+
+#elif !defined NGX_SETPROCTITLE_USES_ENV
+
+#define NGX_SETPROCTITLE_USES_ENV  1
+
+#if (NGX_SOLARIS)
+
+#define NGX_SETPROCTITLE_PAD       ' '
+
+#elif (NGX_LINUX) || (NGX_DARWIN)
+
+#define NGX_SETPROCTITLE_PAD       '\0'
+
+#endif
+
+ngx_int_t ngx_init_setproctitle(ngx_log_t *log);
+void ngx_setproctitle(char *title);
+
+
+#else /* !NGX_SETPROCTITLE_USES_ENV */
+
+#define ngx_init_setproctitle(log)
+#define ngx_setproctitle(title)
+
+#endif
+
+
+#endif /* _NGX_SETPROCTITLE_H_INCLUDED_ */
--- a/src/os/unix/ngx_solaris_config.h
+++ b/src/os/unix/ngx_solaris_config.h
@@ -83,10 +83,4 @@
 #endif
 
 
-#ifndef NGX_SETPROCTITLE_USES_ENV
-#define NGX_SETPROCTITLE_USES_ENV  1
-#define NGX_SETPROCTITLE_PAD       ' '
-#endif
-
-
 #endif /* _NGX_SOLARIS_CONFIG_H_INCLUDED_ */
--- a/src/os/unix/ngx_solaris_init.c
+++ b/src/os/unix/ngx_solaris_init.c
@@ -53,8 +53,6 @@ ngx_int_t ngx_os_init(ngx_log_t *log)
         return NGX_ERROR;
     }
 
-    ngx_init_setproctitle(log);
-
 
     return ngx_posix_init(log);
 }
--- a/src/os/unix/ngx_time.c
+++ b/src/os/unix/ngx_time.c
@@ -29,3 +29,43 @@ void ngx_localtime(ngx_tm_t *tm)
     tm->ngx_tm_mon++;
     tm->ngx_tm_year += 1900;
 }
+
+
+void ngx_libc_localtime(struct tm *tm)
+{
+#if (NGX_HAVE_LOCALTIME_R)
+    time_t      now;
+
+    now = ngx_time();
+    localtime_r(&now, tm);
+
+#else
+    time_t      now;
+    struct tm  *t;
+
+    now = ngx_time();
+    t = localtime(&now);
+    *tm = *t;
+
+#endif
+}
+
+
+void ngx_libc_gmtime(struct tm *tm)
+{
+#if (NGX_HAVE_LOCALTIME_R)
+    time_t      now;
+
+    now = ngx_time();
+    gmtime_r(&now, tm);
+
+#else
+    time_t      now;
+    struct tm  *t;
+
+    now = ngx_time();
+    t = gmtime(&now);
+    *tm = *t;
+
+#endif
+}
--- a/src/os/unix/ngx_time.h
+++ b/src/os/unix/ngx_time.h
@@ -54,6 +54,8 @@ typedef struct tm      ngx_tm_t;
 
 
 void ngx_localtime(ngx_tm_t *tm);
+void ngx_libc_localtime(struct tm *tm);
+void ngx_libc_gmtime(struct tm *tm);
 
 #define ngx_gettimeofday(tp)  gettimeofday(tp, NULL);
 #define ngx_msleep(ms)        usleep(ms * 1000)
--- a/src/os/unix/ngx_user.c
+++ b/src/os/unix/ngx_user.c
@@ -27,11 +27,18 @@ ngx_crypt(ngx_pool_t *pool, u_char *key,
 {
     char               *value;
     size_t              len;
+    ngx_err_t           err;
     struct crypt_data   cd;
 
+    ngx_set_errno(0);
+
+    cd.initialized = 0;
+
     value = crypt_r((char *) key, (char *) salt, &cd);
 
-    if (value) {
+    err = ngx_errno;
+
+    if (err == 0) {
         len = ngx_strlen(value);
 
         *encrypted = ngx_palloc(pool, len);
@@ -41,6 +48,8 @@ ngx_crypt(ngx_pool_t *pool, u_char *key,
         }
     }
 
+    ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt_r() failed");
+
     return NGX_ERROR;
 }
 
@@ -51,7 +60,7 @@ ngx_crypt(ngx_pool_t *pool, u_char *key,
 {
     char       *value;
     size_t      len;
-    ngx_int_t   rc;
+    ngx_err_t   err;
 
 #if (NGX_THREADS && NGX_NONREENTRANT_CRYPT)
 
@@ -63,7 +72,7 @@ ngx_crypt(ngx_pool_t *pool, u_char *key,
 
 #endif
 
-    rc = NGX_ERROR;
+    ngx_set_errno(0);
 
     value = crypt((char *) key, (char *) salt);
 
@@ -73,15 +82,23 @@ ngx_crypt(ngx_pool_t *pool, u_char *key,
         *encrypted = ngx_palloc(pool, len);
         if (*encrypted) {
             ngx_memcpy(*encrypted, value, len + 1);
-            rc = NGX_OK;
         }
+
+#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT)
+        ngx_mutex_unlock(ngx_crypt_mutex);
+#endif
+        return NGX_OK;
     }
 
+    err = ngx_errno;
+
 #if (NGX_THREADS && NGX_NONREENTRANT_CRYPT)
     ngx_mutex_unlock(ngx_crypt_mutex);
 #endif
 
-    return rc;
+    ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt() failed");
+
+    return NGX_ERROR;
 }
 
 #endif
--- a/src/os/win32/ngx_gui.c
+++ b/src/os/win32/ngx_gui.c
@@ -11,7 +11,8 @@
 #define NGX_MAX_TEXT   2048
 
 
-void ngx_cdecl ngx_message_box(char *title, ngx_uint_t type, ngx_err_t err,
+void __cdecl
+ngx_message_box(char *title, ngx_uint_t type, ngx_err_t err,
     const char *fmt, ...)
 {
     va_list  args;
--- a/src/os/win32/ngx_process_cycle.c
+++ b/src/os/win32/ngx_process_cycle.c
@@ -12,7 +12,7 @@
 
 static void *ngx_worker_thread_cycle(void *data);
 static long __stdcall ngx_window_procedure(HWND window, u_int message,
-                                           u_int wparam, long lparam);
+    u_int wparam, long lparam);
 
 #if 0
 ngx_pid_t     ngx_new_binary;
@@ -45,7 +45,8 @@ sig_atomic_t  ngx_change_binary;
 static HMENU  ngx_menu;
 
 
-void ngx_master_process_cycle(ngx_cycle_t *cycle)
+void
+ngx_master_process_cycle(ngx_cycle_t *cycle)
 {
     ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "master mode is not supported");
 
@@ -53,7 +54,8 @@ void ngx_master_process_cycle(ngx_cycle_
 }
 
 
-void ngx_single_process_cycle(ngx_cycle_t *cycle)
+void
+ngx_single_process_cycle(ngx_cycle_t *cycle)
 {
     int               rc;
     ngx_int_t         i;
@@ -165,7 +167,7 @@ void ngx_single_process_cycle(ngx_cycle_
 
 
     if (ngx_system_tray_icon(window, NIM_ADD, tray, (u_char *) " nginx")
-                                                                  == NGX_ERROR)
+        != NGX_OK)
     {
         ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
                       "Shell_NotifyIcon(NIM_ADD) failed");
@@ -200,7 +202,8 @@ void ngx_single_process_cycle(ngx_cycle_
 }
 
 
-static void *ngx_worker_thread_cycle(void *data)
+static void *
+ngx_worker_thread_cycle(void *data)
 {
     ngx_cycle_t  *cycle;
 
@@ -216,8 +219,8 @@ static void *ngx_worker_thread_cycle(voi
 }
 
 
-static long __stdcall ngx_window_procedure(HWND window, u_int message,
-                                           u_int wparam, long lparam)
+static long __stdcall
+ngx_window_procedure(HWND window, u_int message, u_int wparam, long lparam)
 {
     POINT  mouse;
 
@@ -251,13 +254,13 @@ static long __stdcall ngx_window_procedu
     case WM_COMMAND:
         if (wparam == NGX_WM_ABOUT) {
             ngx_message_box("nginx", MB_OK, 0,
-                            NGINX_VER CRLF "(C) 2002-2004 Igor Sysoev");
+                            NGINX_VER CRLF "(C) 2002-2005 Igor Sysoev");
             return 0;
         }
 
         if (wparam == NGX_WM_EXIT) {
             if (ngx_system_tray_icon(window, NIM_DELETE, NULL, NULL)
-                                                                  == NGX_ERROR)
+                != NGX_OK)
             {
                 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
                               "Shell_NotifyIcon(NIM_DELETE) failed");
--- a/src/os/win32/ngx_time.c
+++ b/src/os/win32/ngx_time.c
@@ -36,6 +36,28 @@ void ngx_gettimeofday(struct timeval *tp
 }
 
 
+void ngx_libc_localtime(struct tm *tm)
+{
+    time_t      now;
+    struct tm  *t;
+
+    now = ngx_time();
+    t = localtime(&now);
+    *tm = *t;
+}
+
+
+void ngx_libc_gmtime(struct tm *tm)
+{
+    time_t      now;
+    struct tm  *t;
+
+    now = ngx_time();
+    t = gmtime(&now);
+    *tm = *t;
+}
+
+
 ngx_int_t ngx_gettimezone(void)
 {
     TIME_ZONE_INFORMATION  tz;
--- a/src/os/win32/ngx_time.h
+++ b/src/os/win32/ngx_time.h
@@ -42,6 +42,8 @@ typedef FILETIME       ngx_mtime_t;
 #define NGX_HAVE_GETTIMEZONE  1
 
 ngx_int_t ngx_gettimezone(void);
+void ngx_libc_localtime(struct tm *tm);
+void ngx_libc_gmtime(struct tm *tm);
 void ngx_gettimeofday(struct timeval *tp);
 
 
--- a/src/os/win32/ngx_win32_config.h
+++ b/src/os/win32/ngx_win32_config.h
@@ -29,6 +29,14 @@
 #include <stdlib.h>
 #include <stdarg.h>
 
+#ifdef __WATCOMC__
+#define _TIME_T_DEFINED
+typedef long  time_t;
+/* OpenWatcom defines time_t as "unsigned long" */
+#endif
+
+#include <time.h>      /* localtime(), strftime() */
+
 
 #ifdef _MSC_VER
 
@@ -51,11 +59,6 @@
 /* FD_SET() and FD_CLR(): conditional expression is constant */
 #pragma warning(disable:4127)
 
-#if 0
-/* assignment within conditional expression */
-#pragma warning(disable:4706)
-#endif
-
 /* function 'ngx_handle_write_event' not inlined */
 #pragma warning(disable:4710)
 
@@ -81,11 +84,6 @@
 /* unreferenced formal parameter */
 #pragma warn -8057
 
-#if 0
-/* assignment within conditional expression */
-#pragma warn -8060
-#endif
-
 #endif
 
 
@@ -117,7 +115,6 @@ typedef unsigned __int64  uint64_t;
 typedef u_int             uintptr_t;
 
 typedef int               ssize_t;
-typedef long              time_t;
 typedef __int64           off_t;
 typedef uint32_t          in_addr_t;
 typedef u_short           in_port_t;