changeset 58:b55cbf18157e NGINX_0_1_29

nginx 0.1.29 *) 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; bug 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 <http://sysoev.ru>
date Thu, 12 May 2005 00:00:00 +0400
parents 5df375c55338
children 4cb463ba8cce
files CHANGES CHANGES.ru 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 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_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_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_cache.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/modules/proxy/ngx_http_proxy_handler.h src/http/modules/proxy/ngx_http_proxy_header.c src/http/modules/proxy/ngx_http_proxy_parse.c 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/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
diffstat 115 files changed, 7604 insertions(+), 8496 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,90 @@
+
+Changes with nginx 0.1.29                                        12 May 2005
+
+    *) 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" is 
+       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_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; bug 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.
+
 
 Changes with nginx 0.1.28                                        08 Apr 2005
 
@@ -180,7 +267,7 @@ Changes with nginx 0.1.18               
 
 Changes with nginx 0.1.17                                        03 Feb 2005
 
-    *) Feature: the ngx_http_rewrite_module was rewritten from the scratch. 
+    *) Change: the ngx_http_rewrite_module was rewritten from the scratch. 
        Now it is possible to redirect, to return the error codes, to check 
        the variables and referrers. The directives can be used inside 
        locations. The redirect directive was canceled.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,3 +1,91 @@
+
+éÚÍÅÎÅÎÉÑ × nginx 0.1.29                                          12.05.2005
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_ssi_module ÐÏÄÄÅÒÖÉ×ÁÅÔ ËÏÍÁÎÄÕ include 
+       virtual.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_ssi_module ÐÏÄÄÅÒÖÉ×ÁÅÔ ÕÓÌÏ×ÎÕÀ ËÏÍÁÎÄÕ 
+       ×ÉÄÁ 'if expr="$NAME"' É ËÏÍÁÎÄÙ else É endif. äÏÐÕÓËÁÅÔÓÑ ÔÏÌØËÏ 
+       ÏÄÉÎ ÕÒÏ×ÅÎØ ×ÌÏÖÅÎÎÏÓÔÉ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_ssi_module ÐÏÄÄÅÒÖÉ×ÁÅÔ Ä×Å ÐÅÒÅÍÅÎÎÙÅ 
+       DATE_LOCAL É DATE_GMT É ËÏÍÁÎÄÕ config timefmt.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á ssi_ignore_recycled_buffers.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÐÅÒÅÍÅÎÎÁÑ QUERY_STRING ÎÅ ÂÙÌÁ ÏÐÒÅÄÅÌÅÎÁ, ÔÏ × 
+       ËÏÍÁÎÄÅ echo ÎÅ ÓÔÁ×ÉÌÏÓØ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ.
+
+    *) éÚÍÅÎÅÎÉÅ: ÍÏÄÕÌØ ngx_http_proxy_module ÐÏÌÎÏÓÔØÀ ÐÅÒÅÐÉÓÁÎ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Ù proxy_redirect, proxy_pass_request_headers, 
+       proxy_pass_request_body É proxy_method.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á proxy_set_header. äÉÒÅËÔÉ×Á proxy_x_var 
+       ÕÐÒÁÚÄÎÅÎÁ É ÄÏÌÖÎÁ ÂÙÔØ ÚÁÍÅÎÅÎÁ ÄÉÒÅËÔÉ×ÏÊ proxy_set_header.
+
+    *) éÚÍÅÎÅÎÉÅ: ÄÉÒÅËÔÉ×Á proxy_preserve_host ÕÐÒÁÚÄÎÅÎÁ É ÄÏÌÖÎÁ ÂÙÔØ 
+       ÚÁÍÅÎÅÎÁ ÄÉÒÅËÔÉ×ÁÍÉ "proxy_set_header Host $host" É "proxy_redirect 
+       off" ÉÌÉ ÄÉÒÅËÔÉ×ÏÊ "proxy_set_header Host $host:$proxy_port" É 
+       ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÍÉ ÅÊ ÄÉÒÅËÔÉ×ÁÍÉ proxy_redirect.
+
+    *) éÚÍÅÎÅÎÉÅ: ÄÉÒÅËÔÉ×Á proxy_set_x_real_ip ÕÐÒÁÚÄÎÅÎÁ É ÄÏÌÖÎÁ ÂÙÔØ 
+       ÚÁÍÅÎÅÎÁ ÄÉÒÅËÔÉ×ÏÊ "proxy_set_header X-Real-IP $remote_addr".
+
+    *) éÚÍÅÎÅÎÉÅ: ÄÉÒÅËÔÉ×Á proxy_add_x_forwarded_for ÕÐÒÁÚÄÎÅÎÁ É ÄÏÌÖÎÁ 
+       ÂÙÔØ ÚÁÍÅÎÅÎÁ ÄÉÒÅËÔÉ×ÏÊ 
+       "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for".
+
+    *) éÚÍÅÎÅÎÉÅ: ÄÉÒÅËÔÉ×Á proxy_set_x_url ÕÐÒÁÚÄÎÅÎÁ É ÄÏÌÖÎÁ ÂÙÔØ 
+       ÚÁÍÅÎÅÎÁ ÄÉÒÅËÔÉ×ÏÊ 
+       "proxy_set_header X-URL http://$host:$server_port$request_uri".
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á fastcgi_param.
+
+    *) éÚÍÅÎÅÎÉÅ: ÄÉÒÅËÔÉ×Ù fastcgi_set_var É fastcgi_params ÕÐÒÁÚÄÎÅÎÙ É 
+       ÄÏÌÖÎÙ ÂÙÔØ ÚÁÍÅÎÙ ÄÉÒÅËÔÉ×ÁÍÉ fastcgi_param.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á index ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØ ÐÅÒÅÍÅÎÎÙÅ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á index ÍÏÖÅÔ ÂÙÔØ ÕËÁÚÁÎÁ ÎÁ ÕÒÏ×ÎÅ http É 
+       server.
+
+    *) éÚÍÅÎÅÎÉÅ: ÔÏÌØËÏ ÐÏÓÌÅÄÎÉÊ ÐÁÒÁÍÅÔÒ × ÄÉÒÅËÔÉ×Å index ÍÏÖÅÔ ÂÙÔØ 
+       ÁÂÓÏÌÀÔÎÙÍ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: × ÄÉÒÅËÔÉ×Å rewrite ÍÏÇÕÔ ÉÓÐÏÌØÚÏ×ÁÔØÓÑ ÐÅÒÅÍÅÎÎÙÅ.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á internal.
+
+    *) äÏÂÁ×ÌÅÎÉÅ: ÐÅÒÅÍÅÎÎÙÅ CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, 
+       SERVER_ADDR, SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, 
+       SERVER_NAME, REQUEST_METHOD, REQUEST_URI É REMOTE_USER.
+
+    *) éÚÍÅÎÅÎÉÅ: nginx ÔÅÐÅÒØ ÐÅÒÅÄÁ£Ô ÎÅ×ÅÒÎÙÅ ÓÔÒÏËÉ × ÚÁÇÏÌÏ×ËÁÈ 
+       ÚÁÐÒÏÓÁ ËÌÉÅÎÔÁ É ÏÔ×ÅÔÁ ÂÜËÅÎÄÁ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÂÜËÅÎÄ ÄÏÌÇÏ ÎÅ ÐÅÒÅÄÁ×ÁÌ ÏÔ×ÅÔ É send_timeout ÂÙÌ 
+       ÍÅÎØÛÅ, ÞÅÍ proxy_read_timeout, ÔÏ ËÌÉÅÎÔÕ ×ÏÚ×ÒÁÝÁÌÓÑ ÏÔ×ÅÔ 408.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÅÓÌÉ ÂÜËÅÎÄ ÐÅÒÅÄÁ×ÁÌ ÎÅ×ÅÒÎÕÀ ÓÔÒÏËÕ × ÚÁÇÏÌÏ×ËÅ 
+       ÏÔ×ÅÔÁ, ÔÏ ÐÒÏÉÓÈÏÄÉÌ segmentation fault; ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.1.26.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÐÒÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÏÔËÁÚÏÕÓÔÏÊÞÉ×ÏÊ ËÏÎÆÉÇÕÒÁÃÉÉ × 
+       FastCGI ÍÏÇ ÐÒÏÉÓÈÏÄÉÔØ segmentation fault.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á expires ÎÅ ÕÄÁÌÑÌÁ ÕÖÅ ÕÓÔÁÎÏ×ÌÅÎÎÙÅ ÓÔÒÏËÉ 
+       ÚÁÇÏÌÏ×ËÁ "Expires" É "Cache-Control".
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÕÞÉÔÙ×ÁÌ ÚÁ×ÅÒÛÁÀÝÕÀ ÔÏÞËÕ × ÓÔÒÏËÅ ÚÁÇÏÌÏ×ËÁ 
+       ÚÁÐÒÏÓÁ "Host".
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_auth_module ÎÅ ÒÁÂÏÔÁÌ ÎÁ Linux.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: ÄÉÒÅËÔÉ×Á rewrite ÎÅ×ÅÒÎÏ ÒÁÂÏÔÁÌÁ, ÅÓÌÉ × ÚÁÐÒÏÓÅ 
+       ÐÒÉÓÕÔÓÔ×Ï×ÁÌÉ ÁÒÇÕÍÅÎÔÙ.
+
+    *) éÓÐÒÁ×ÌÅÎÉÅ: nginx ÎÅ ÓÏÂÉÒÁÌÓÑ ÎÁ MacOS X.
+
 
 éÚÍÅÎÅÎÉÑ × nginx 0.1.28                                          08.04.2005
 
@@ -181,7 +269,7 @@
 
 éÚÍÅÎÅÎÉÑ × nginx 0.1.17                                          03.02.2005
 
-    *) äÏÂÁ×ÌÅÎÉÅ: ÍÏÄÕÌØ ngx_http_rewrite_module ÐÏÌÎÏÓÔØÀ ÐÅÒÅÐÉÓÁÎ. 
+    *) éÚÍÅÎÅÎÉÅ: ÍÏÄÕÌØ ngx_http_rewrite_module ÐÏÌÎÏÓÔØÀ ÐÅÒÅÐÉÓÁÎ. 
        ôÅÐÅÒØ ÍÏÖÎÏ ÄÅÌÁÔØ ÒÅÄÉÒÅËÔÙ, ×ÏÚ×ÒÁÝÁÔØ ËÏÄÙ ÏÛÉÂÏË É ÐÒÏ×ÅÒÑÔØ 
        ÐÅÒÅÍÅÎÎÙÅ É ÒÅÆÅÒÅÒÙ. üÔÉ ÄÉÒÅËÔÉ×Ù ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ×ÎÕÔÒÉ 
        location. äÉÒÅËÔÉ×Á redirect ÕÐÒÁÚÄÎÅÎÁ.
--- 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/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_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_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
     }
 
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -0,0 +1,1934 @@
+
+/*  
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_http.h>
+
+
+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);
+
+struct ngx_http_proxy_redirect_s {
+    ngx_http_proxy_redirect_pt   handler;
+    ngx_str_t                    redirect;
+
+    union {
+        ngx_str_t                text;
+
+        struct {
+            void                *lengths;
+            void                *values;
+        } vars;
+
+        void                    *regex;
+    } replacement;
+};
+
+
+typedef struct {
+    ngx_http_upstream_conf_t     upstream;
+
+    ngx_peers_t                 *peers;
+
+    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_array_t                 *redirects;
+
+    ngx_str_t                    host_header;
+    ngx_str_t                    port_text;
+
+    ngx_flag_t                   redirect;
+} ngx_http_proxy_loc_conf_t;
+
+
+typedef struct {
+    ngx_uint_t                   status;
+    ngx_uint_t                   status_count;
+    u_char                      *status_start;
+    u_char                      *status_end;
+} ngx_http_proxy_ctx_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 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_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_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_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 };
+
+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 },
+    { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
+    { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
+    { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
+    { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_command_t  ngx_http_proxy_commands[] = {
+
+    { ngx_string("proxy_pass"),
+      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_proxy_pass,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      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,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
+      NULL },
+
+    { ngx_string("proxy_send_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
+      NULL },
+
+    { ngx_string("proxy_send_lowat"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_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,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_unparsed_uri),
+      NULL },
+
+    { 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, headers_source),
+      NULL },
+
+    { 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, upstream.pass_request_headers),
+      NULL },
+
+    { 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, upstream.pass_request_body),
+      NULL },
+
+    { ngx_string("proxy_header_buffer_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.header_buffer_size),
+      NULL },
+
+    { ngx_string("proxy_read_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
+      NULL },
+
+    { ngx_string("proxy_buffers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_bufs_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
+      NULL },
+
+    { ngx_string("proxy_busy_buffers_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size),
+      NULL },
+
+    { ngx_string("proxy_temp_path"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
+      ngx_conf_set_path_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
+      (void *) ngx_garbage_collector_temp_handler },
+
+    { ngx_string("proxy_max_temp_file_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size),
+      NULL },
+
+    { ngx_string("proxy_temp_file_write_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size),
+      NULL },
+
+    { ngx_string("proxy_next_upstream"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
+      ngx_conf_set_bitmask_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      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, 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, upstream.pass_x_accel_expires),
+      NULL },
+
+      ngx_null_command
+};
+
+
+ngx_http_module_t  ngx_http_proxy_module_ctx = {
+    ngx_http_proxy_add_variables,          /* preconfiguration */
+    NULL,                                  /* postconfiguration */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_proxy_create_loc_conf,        /* create location configration */
+    ngx_http_proxy_merge_loc_conf          /* merge location configration */
+};
+
+
+ngx_module_t  ngx_http_proxy_module = {
+    NGX_MODULE_V1,
+    &ngx_http_proxy_module_ctx,            /* module context */
+    ngx_http_proxy_commands,               /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init module */
+    NULL                                   /* init process */
+};
+
+
+static ngx_str_t ngx_http_proxy_methods[] = {
+    ngx_string("GET "),
+    ngx_string("HEAD "),
+    ngx_string("POST ")
+};
+
+
+static char  ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
+
+
+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)
+static ngx_str_t ngx_http_proxy_uri = ngx_string("/");
+#endif
+
+
+static ngx_int_t
+ngx_http_proxy_handler(ngx_http_request_t *r)
+{   
+    ngx_int_t                   rc;
+    ngx_http_upstream_t        *u;
+    ngx_http_proxy_loc_conf_t  *plcf;
+    
+    plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+    
+    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
+    if (u == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+    
+    u->peer.log = r->connection->log;
+    u->peer.log_error = NGX_ERROR_ERR;
+    u->peer.peers = plcf->peers;
+    u->peer.tries = plcf->peers->number;
+#if (NGX_THREADS)
+    u->peer.lock = &r->connection->lock;
+#endif
+
+    u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
+
+    u->conf = &plcf->upstream;
+
+    u->create_request = ngx_http_proxy_create_request;
+    u->reinit_request = ngx_http_proxy_reinit_request;
+    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->accel = 1;
+    
+    r->upstream = u;
+
+    rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
+
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+        return rc;
+    }
+
+    return NGX_DONE;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_create_request(ngx_http_request_t *r)
+{
+    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;
+
+    plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+    len = sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
+
+    if (u->method) {
+        len += ngx_http_proxy_methods[u->method - 1].len + u->conf->uri.len;
+    } else {
+        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 + loc_len,
+                                        r->uri.len - loc_len, NGX_ESCAPE_URI);
+        }
+
+        len += r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len;
+    }
+
+    ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+    le.ip = plcf->headers_set_len->elts;
+    le.request = r;
+
+    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);
+    }
+
+
+    hh = (ngx_str_t *) plcf->headers_set_hash->buckets;
+
+    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;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0; 
+            }
+
+            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;
+            }
+
+            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) {
+        return NGX_ERROR;
+    }
+
+    cl = ngx_alloc_chain_link(r->pool);
+    if (cl == NULL) {
+        return NGX_ERROR;
+    }
+
+    cl->buf = b;
+
+
+    /* the request line */
+
+    if (u->method) {
+        b->last = ngx_cpymem(b->last,
+                             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 + 1);
+    }
+
+    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 + 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 + loc_len,
+                                 r->uri.len - loc_len);
+        }
+
+        if (r->args.len > 0) {
+            *b->last++ = '?';
+            b->last = ngx_cpymem(b->last, r->args.data, r->args.len);
+        }
+    }
+
+    b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
+                         sizeof(ngx_http_proxy_version) - 1);
+
+
+    e.ip = plcf->headers_set->elts;
+    e.pos = b->last;
+    e.request = r;
+
+    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;
+
+
+    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;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0; 
+            }
+
+            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;
+            }
+
+            b->last = ngx_cpymem(b->last, header[i].key.data,
+                                 header[i].key.len);
+
+            *b->last++ = ':'; *b->last++ = ' ';
+
+            b->last = ngx_cpymem(b->last, header[i].value.data,
+                                 header[i].value.len);
+
+            *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);
+        }
+    }
+
+    /* add "\r\n" at the header end */
+    *b->last++ = CR; *b->last++ = LF;
+
+#if (NGX_DEBUG)
+    {
+    ngx_str_t  s;
+
+    s.len = b->last - b->pos;
+    s.data = b->pos;
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http proxy header:\n\"%V\"", &s);
+    }
+#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;
+}
+
+
+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;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_process_header(ngx_http_request_t *r)
+{
+    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;
+
+            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;
+    }
+}
+
+
+static void
+ngx_http_proxy_abort_request(ngx_http_request_t *r)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "abort http proxy request");
+    
+    return;
+}
+
+
+static void
+ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
+{   
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "finalize http proxy request");
+
+    return;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data)
+{
+    ngx_http_variable_value_t  *vv;
+    ngx_http_proxy_loc_conf_t  *plcf;
+
+    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);
+
+    vv->value = 0;
+    vv->text = plcf->host_header;
+
+    return vv;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data)
+{
+    ngx_http_variable_value_t  *vv;
+    ngx_http_proxy_loc_conf_t  *plcf;
+
+    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);
+
+    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;
+
+    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;
+}
+
+
+static void *
+ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_proxy_loc_conf_t  *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
+    if (conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     conf->upstream.bufs.num = 0;
+     *     conf->upstream.path = NULL;
+     *     conf->upstream.next_upstream = 0;
+     *     conf->upstream.temp_path = NULL;
+     *     conf->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;
+    conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
+    conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
+
+    conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
+    conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE;
+    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;
+
+    /* "proxy_cyclic_temp_file" is disabled */
+    conf->upstream.cyclic_temp_file = 0;
+
+    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->redirect = NGX_CONF_UNSET;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_proxy_loc_conf_t *prev = parent;
+    ngx_http_proxy_loc_conf_t *conf = child;
+
+    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);
+
+    ngx_conf_merge_msec_value(conf->upstream.send_timeout,
+                              prev->upstream.send_timeout, 60000);
+
+    ngx_conf_merge_msec_value(conf->upstream.read_timeout,
+                              prev->upstream.read_timeout, 60000);
+
+    ngx_conf_merge_size_value(conf->upstream.send_lowat,
+                              prev->upstream.send_lowat, 0);
+
+    ngx_conf_merge_size_value(conf->upstream.header_buffer_size,
+                              prev->upstream.header_buffer_size,
+                              (size_t) ngx_pagesize);
+
+    ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
+                              8, ngx_pagesize);
+
+    if (conf->upstream.bufs.num < 2) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 
+                           "there must be at least 2 \"proxy_buffers\"");
+        return NGX_CONF_ERROR;
+    }
+    
+
+    size = conf->upstream.header_buffer_size;
+    if (size < conf->upstream.bufs.size) { 
+        size = conf->upstream.bufs.size;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.busy_buffers_size,
+                              prev->upstream.busy_buffers_size,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.busy_buffers_size == NGX_CONF_UNSET_SIZE) {
+        conf->upstream.busy_buffers_size = 2 * size;
+
+    } else if (conf->upstream.busy_buffers_size < size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+             "\"proxy_busy_buffers_size\" must be equal or bigger than "
+             "maximum of the value of \"proxy_header_buffer_size\" and "
+             "one of the \"proxy_buffers\"");
+
+        return NGX_CONF_ERROR;
+
+    } else if (conf->upstream.busy_buffers_size
+               > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
+    {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+             "\"proxy_busy_buffers_size\" must be less than "
+             "the size of all \"proxy_buffers\" minus one buffer");
+
+        return NGX_CONF_ERROR;
+    }
+    
+
+    ngx_conf_merge_size_value(conf->upstream.temp_file_write_size,
+                              prev->upstream.temp_file_write_size,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.temp_file_write_size == NGX_CONF_UNSET_SIZE) {
+        conf->upstream.temp_file_write_size = 2 * size;
+
+    } else if (conf->upstream.temp_file_write_size < size) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+             "\"proxy_temp_file_write_size\" must be equal or bigger than "
+             "maximum of the value of \"proxy_header_buffer_size\" and "
+             "one of the \"proxy_buffers\"");
+
+        return NGX_CONF_ERROR;
+    }
+
+
+    ngx_conf_merge_size_value(conf->upstream.max_temp_file_size,
+                              prev->upstream.max_temp_file_size,
+                              NGX_CONF_UNSET_SIZE);
+
+    if (conf->upstream.max_temp_file_size == NGX_CONF_UNSET_SIZE) {
+
+        conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
+
+    } else if (conf->upstream.max_temp_file_size != 0
+               && conf->upstream.max_temp_file_size < size)
+    {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+             "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
+             "the temporary files usage or must be equal or bigger than "
+             "maximum of the value of \"fastcgi_header_buffer_size\" and "
+             "one of the \"fastcgi_buffers\"");
+
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
+                              prev->upstream.next_upstream,
+                              (NGX_CONF_BITMASK_SET
+                               |NGX_HTTP_UPSTREAM_FT_ERROR
+                               |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
+
+    ngx_conf_merge_path_value(conf->upstream.temp_path,
+                              prev->upstream.temp_path,
+                              NGX_HTTP_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->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;
+    }
+
+    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) {
+
+        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_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) {
+        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;
+        }
+    }
+
+    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;
+            }
+        }
+
+        s = ngx_array_push(conf->headers_source);
+        if (s == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *s = *h;
+
+    next:
+
+        continue;
+    }
+
+    for (i = 0; i < conf->headers_source->nelts; i++) {
+
+        name = ngx_array_push(conf->headers_names);
+        if (name == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *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;
+
+
+            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;
+
+
+            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;
+        }
+
+        code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *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;
+    }
+
+    code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
+    if (code == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    *code = (uintptr_t) NULL;
+
+
+    conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash_t));
+    if (conf->headers_set_hash == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    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, conf->headers_names->nelts) != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    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);
+
+    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 *plcf = conf;
+
+    ngx_uint_t                   i;
+    ngx_str_t                   *value, *url;
+    ngx_inet_upstream_t          inet_upstream;
+    ngx_http_core_loc_conf_t    *clcf;
+#if (NGX_HAVE_UNIX_DOMAIN)
+    ngx_unix_domain_upstream_t   unix_upstream;
+#endif
+
+    value = cf->args->elts;
+
+    url = &value[1];
+
+    if (ngx_strncasecmp(url->data, "http://", 7) != 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
+        return NGX_CONF_ERROR;
+    }
+
+    if (ngx_strncasecmp(url->data + 7, "unix:", 5) == 0) {
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+        ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t));
+
+        unix_upstream.name = *url;
+        unix_upstream.url.len = url->len - 7;
+        unix_upstream.url.data = url->data + 7;
+        unix_upstream.uri_part = 1;
+
+        plcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
+        if (plcf->peers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        plcf->peers->peer[0].uri_separator = ":";
+
+        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,
+                           "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 = *url;
+        inet_upstream.url.len = url->len - 7;
+        inet_upstream.url.data = url->data + 7;
+        inet_upstream.default_port_value = 80;
+        inet_upstream.uri_part = 1;
+
+        plcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
+        if (plcf->peers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        for (i = 0; i < plcf->peers->number; i++) {
+            plcf->peers->peer[i].uri_separator = ":";
+        }
+
+        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)
+    plcf->upstream.location = clcf->regex ? &ngx_http_proxy_uri : &clcf->name;
+#else
+    plcf->upstream.location = &clcf->name;
+#endif
+
+    plcf->upstream.url = *url;
+
+    if (clcf->name.data[clcf->name.len - 1] == '/') {
+        clcf->auto_redirect = 1;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+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;
+}
+
+
+static char *
+ngx_http_proxy_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,
+                           "\"proxy_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,
+                       "\"proxy_send_lowat\" is not supported, ignored");
+
+    *np = 0;
+
+#endif
+
+    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, "");
deleted file mode 100644
--- a/src/http/modules/proxy/ngx_http_proxy_cache.c
+++ /dev/null
@@ -1,628 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-#include <ngx_http_proxy_handler.h>
-
-
-static int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p,
-                                                  int rc);
-static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p);
-static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p);
-
-
-int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p)
-{
-    char                            *last;
-    ngx_http_request_t              *r;
-    ngx_http_proxy_cache_t          *c;
-    ngx_http_proxy_upstream_conf_t  *u;
-
-    r = p->request;
-
-    if (!(c = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_cache_t)))) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    p->cache = c;
-
-    c->ctx.file.fd = NGX_INVALID_FILE;
-    c->ctx.file.log = r->connection->log;
-    c->ctx.path = p->lcf->cache_path;
-
-    u = p->lcf->upstream;
-
-    c->ctx.key.len = u->url.len + r->uri.len - u->location->len + r->args.len;
-    if (!(c->ctx.key.data = ngx_palloc(r->pool, c->ctx.key.len + 1))) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    last = ngx_cpymem(c->ctx.key.data, u->url.data, u->url.len);
-
-    last = ngx_cpymem(last, r->uri.data + u->location->len,
-                      r->uri.len - u->location->len);
-
-    if (r->args.len > 0) {
-        *(last++) = '?';
-        last = ngx_cpymem(last, r->args.data, r->args.len);
-    }
-    *last = '\0';
-
-    p->header_in = ngx_create_temp_hunk(r->pool, p->lcf->header_buffer_size);
-    if (p->header_in == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-    p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
-
-    c->ctx.buf = p->header_in; 
-    c->ctx.log = r->connection->log;
-
-    return ngx_http_proxy_process_cached_response(p,
-                                          ngx_http_cache_get_file(r, &c->ctx));
-}
-
-
-static int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p,
-                                                  int rc)
-{
-    if (rc == NGX_OK) {
-        p->state->cache_state = NGX_HTTP_PROXY_CACHE_HIT;
-        p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
-
-        if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        p->valid_header_in = 1;
-
-        return ngx_http_proxy_send_cached_response(p);
-    }
-
-    if (rc == NGX_HTTP_CACHE_STALE) {
-        p->state->cache_state = NGX_HTTP_PROXY_CACHE_EXPR;
-
-    } else if (rc == NGX_HTTP_CACHE_AGED) {
-        p->state->cache_state = NGX_HTTP_PROXY_CACHE_AGED;
-    }
-
-    if (rc == NGX_HTTP_CACHE_STALE || rc == NGX_HTTP_CACHE_AGED) {
-        p->state->expired = ngx_time() - p->cache->ctx.expires;
-        p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
-
-        if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
-        p->header_in->last = p->header_in->pos;
-
-        p->stale = 1;
-        p->valid_header_in = 1;
-
-    } else if (rc == NGX_DECLINED) {
-        p->state->cache_state = NGX_HTTP_PROXY_CACHE_MISS;
-        p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
-        p->header_in->last = p->header_in->pos;
-    }
-
-    if (p->lcf->busy_lock) {
-        p->try_busy_lock = 1;
-
-        p->header_in->pos = p->header_in->start;
-        p->header_in->last = p->header_in->start;
-
-        p->busy_lock.time = 0;
-        p->busy_lock.event = p->request->connection->read;
-        p->busy_lock.event_handler = ngx_http_proxy_busy_lock_handler;
-        p->busy_lock.md5 = p->cache->ctx.md5;
-
-        ngx_http_proxy_cache_busy_lock(p);
-        return NGX_DONE;
-    }
-
-    return ngx_http_proxy_request_upstream(p);
-}
-
-
-static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p)
-{
-    int                      rc, i;
-    ngx_table_elt_t         *h;
-    ngx_http_request_t      *r;
-    ngx_http_proxy_cache_t  *c;
-
-    rc = ngx_http_proxy_parse_status_line(p);
-
-    c = p->cache;
-    r = p->request;
-
-    if (rc == NGX_AGAIN) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "\"proxy_header_buffer_size\" "
-                      "is too small to read header from \"%s\"",
-                      c->ctx.file.name.data);
-        return NGX_ERROR;
-    }
-
-    if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "no valid HTTP/1.0 header in \"%s\"",
-                      c->ctx.file.name.data);
-        return NGX_ERROR;
-    }
-
-    /* rc == NGX_OK */
-
-    c->status = p->status;
-    c->status_line.len = p->status_end - p->status_start;
-    c->status_line.data = ngx_palloc(r->pool, c->status_line.len + 1);
-    if (c->status_line.data == NULL) {
-        return NGX_ERROR;
-    }
-
-    /* reset for the possible parsing the upstream header */
-
-    p->status = 0;
-    p->status_count = 0;
-
-    ngx_cpystrn(c->status_line.data, p->status_start, c->status_line.len + 1);
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http cache status %ui \"%V\"", 
-                   c->status, &c->status_line);
-
-    /* TODO: ngx_init_table */
-    c->headers_in.headers = ngx_create_table(r->pool, 20);
-
-    for ( ;; ) {
-        rc = ngx_http_parse_header_line(r, p->header_in);
-
-        if (rc == NGX_OK) {
-
-            /* a header line has been parsed successfully */
-
-            h = ngx_http_add_header(&c->headers_in, ngx_http_proxy_headers_in);
-            if (h == NULL) {
-                return NGX_ERROR;
-            }
-
-            h->key.len = r->header_name_end - r->header_name_start;
-            h->value.len = r->header_end - r->header_start;
-
-            h->key.data = ngx_palloc(r->pool,
-                                     h->key.len + 1 + h->value.len + 1);
-            if (h->key.data == NULL) {
-                return NGX_ERROR;
-            }
-
-            h->value.data = h->key.data + h->key.len + 1;
-            ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
-            ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
-
-            for (i = 0; ngx_http_proxy_headers_in[i].name.len != 0; i++) {
-                if (ngx_http_proxy_headers_in[i].name.len != h->key.len) {
-                    continue;
-                }
-
-                if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data,
-                                                             h->key.data) == 0)
-                {
-                    *((ngx_table_elt_t **) ((char *) &c->headers_in
-                                   + ngx_http_proxy_headers_in[i].offset)) = h;
-                    break;
-                }
-            }
-
-            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "http cache header: \"%V: %V\"", &h->key, &h->value);
-
-            continue;
-
-        } else 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 cache header done");
-
-            c->ctx.file_start = p->header_in->pos - p->header_in->start;
-
-            return NGX_OK;
-
-        } else if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
-
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "invalid header in \"%s\"",
-                          c->ctx.file.name.data);
-            return NGX_ERROR;
-        }
-
-        /* rc == NGX_AGAIN || rc == NGX_HTTP_PARSE_TOO_LONG_HEADER */
-
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "\"proxy_header_buffer_size\" "
-                      "is too small to read header from \"%s\"",
-                      c->ctx.file.name.data);
-        return NGX_ERROR;
-    }
-}
-
-
-void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p)
-{
-    int  rc, ft_type;
-
-    rc = ngx_http_busy_lock_cachable(p->lcf->busy_lock, &p->busy_lock,
-                                     p->try_busy_lock);
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
-                   "http cache busy lock cachable: %d", rc);
-
-    if (rc == NGX_OK) {
-        if (p->try_busy_lock) {
-            p->busy_locked = 1;
-            p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
-            p->header_in->last = p->header_in->pos;
-
-            ngx_http_proxy_request_upstream(p);
-            return;
-        }
-
-        ngx_http_proxy_cache_look_complete_request(p);
-        return;
-    }
-
-    p->try_busy_lock = 0;
-
-    if (p->cache->ctx.file.fd != NGX_INVALID_FILE
-        && !p->cache->ctx.file.info_valid)
-    {
-        if (ngx_fd_info(p->cache->ctx.file.fd, &p->cache->ctx.file.info)
-                                                             == NGX_FILE_ERROR)
-        {
-            ngx_log_error(NGX_LOG_CRIT, p->request->connection->log, ngx_errno,
-                          ngx_fd_info_n " \"%s\" failed",
-                          p->cache->ctx.file.name.data);
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return;
-        }
-
-        p->cache->ctx.file.info_valid = 1;
-    }
-
-    if (rc == NGX_AGAIN) {
-
-        if ((ngx_event_flags & (NGX_USE_CLEAR_EVENT|NGX_USE_KQUEUE_EVENT))
-            && !p->request->connection->write->active)
-        {
-            /*
-             * kqueue allows to detect when client closes prematurely
-             * connection
-             */
-
-            p->request->connection->write->event_handler =
-                                        ngx_http_proxy_check_broken_connection;
-
-            if (ngx_add_event(p->request->connection->write, NGX_WRITE_EVENT,
-                                                NGX_CLEAR_EVENT) == NGX_ERROR)
-            {
-                ngx_http_proxy_finalize_request(p,
-                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
-                return;
-            }
-        }
-
-        return;
-    }
-
-    ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
-
-    if (rc == NGX_DONE) {
-        ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK;
-
-    } else {
-        /* rc == NGX_ERROR */
-        ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING;
-    }
-    
-    if (p->stale && (p->lcf->use_stale & ft_type)) {
-        ngx_http_proxy_finalize_request(p,
-                                        ngx_http_proxy_send_cached_response(p));
-        return;
-    }
-    
-    p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE;
-    ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE);
-}
-
-
-static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p)
-{
-    int                    rc;
-    ngx_http_cache_ctx_t  *ctx;
-
-    if (!(ctx = ngx_pcalloc(p->request->pool, sizeof(ngx_http_cache_ctx_t)))) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-
-    *ctx = p->cache->ctx;
-
-    rc = ngx_http_cache_open_file(ctx, ngx_file_uniq(&p->cache->ctx.file.info));
-
-    if (rc == NGX_DECLINED || rc == NGX_HTTP_CACHE_THE_SAME) {
-        p->try_busy_lock = 1;
-        p->busy_lock.time = 0;
-        ngx_http_proxy_cache_busy_lock(p);
-        return;
-    }
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
-                   "http cache old fd:%d, new fd:%d",
-                   p->cache->ctx.file.fd, ctx->file.fd);
-
-    if (p->cache->ctx.file.fd != NGX_INVALID_FILE) {
-        if (ngx_close_file(p->cache->ctx.file.fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, p->request->connection->log, ngx_errno,
-                          ngx_close_file_n " \"%s\" failed",
-                          p->cache->ctx.file.name.data);
-        }
-    }
-
-    p->cache->ctx = *ctx;
-
-    p->status = 0;
-    p->status_count = 0;
-
-    ngx_http_proxy_finalize_request(p,
-                                ngx_http_proxy_process_cached_response(p, rc));
-}
-
-
-int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p)
-{
-    int                  rc, len, i;
-    off_t                rest;
-    ngx_hunk_t          *h0, *h1;
-    ngx_chain_t          out[2];
-    ngx_http_request_t  *r;
-
-    r = p->request;
-
-    r->headers_out.status = p->cache->status;
-
-#if 0
-    r->headers_out.content_length_n = -1;
-    r->headers_out.content_length = NULL;
-#endif
-
-    /* copy an cached header to r->headers_out */
-    
-    if (ngx_http_proxy_copy_header(p, &p->cache->headers_in) == NGX_ERROR) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    /* we need to allocate all before the header would be sent */
-
-    len = p->header_in->end - (p->header_in->start + p->cache->ctx.file_start);
-
-    h0 = NULL;
-    h1 = NULL;
-
-    if (len) {
-        if (!((h0 = ngx_calloc_hunk(r->pool)))) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        if (!((h0->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-    }
-
-    if (len < p->cache->ctx.length) {
-        if (!((h1 = ngx_calloc_hunk(r->pool)))) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        if (!((h1->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-    }
-
-    rc = ngx_http_send_header(r);
-
-    /* NEEDED ??? */ p->header_sent = 1;
-
-    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
-        return rc;
-    }
-
-    rest = p->cache->ctx.length;
-
-    if (len) {
-        if (p->valid_header_in) {
-            h0->pos = p->header_in->start + p->cache->ctx.file_start;
-
-            if (len > p->cache->ctx.length) {
-                h0->last = h0->pos + p->cache->ctx.length;
-
-            } else {
-                h0->last = p->header_in->end;
-            }
-
-            h0->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
-        }
-
-        h0->type |= NGX_HUNK_FILE;
-        h0->file_pos = p->cache->ctx.file_start;
-
-        h0->file->fd = p->cache->ctx.file.fd;
-        h0->file->log = r->connection->log;
-
-        if (len > p->cache->ctx.length) {
-            h0->file_last = h0->file_pos + p->cache->ctx.length;
-            rest = 0;
-
-        } else {
-            h0->file_last = h0->file_pos + len;
-            rest -= len;
-        }
-
-        out[0].hunk = h0;
-        out[0].next = &out[1];
-        i = 0;
-
-    } else {
-        i = -1;
-    }
-
-    if (rest) {
-        h1->file_pos = p->cache->ctx.file_start + len;
-        h1->file_last = h1->file_pos + rest;
-        h1->type = NGX_HUNK_FILE;
-
-        h1->file->fd = p->cache->ctx.file.fd;
-        h1->file->log = r->connection->log;
-
-        out[++i].hunk = h1;
-    }
-
-    out[i].next = NULL;
-    if (!r->main) {
-        out[i].hunk->type |= NGX_HUNK_LAST;
-    }
-
-    r->file.fd = p->cache->ctx.file.fd;
-
-    return ngx_http_output_filter(r, out);
-}
-
-
-int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p)
-{
-    time_t                        date, last_modified, expires, t;
-    ngx_http_proxy_headers_in_t  *h;
-
-    switch (p->upstream->status) {
-    case NGX_HTTP_OK:
-    case NGX_HTTP_MOVED_PERMANENTLY:
-    case NGX_HTTP_MOVED_TEMPORARILY:
-        break;
-
-#if 0
-    case NGX_HTTP_NOT_MODIFIED:
-        return 1;
-#endif
-
-    default:
-        return 0;
-    }
-
-    h = &p->upstream->headers_in;
-
-    date = NGX_ERROR;
-    if (h->date) {
-        date = ngx_http_parse_time(h->date->value.data, h->date->value.len);
-    }
-    if (date == NGX_ERROR) {
-        date = ngx_time();
-    }
-    p->cache->ctx.date = date;
-
-    last_modified = NGX_ERROR;
-    if (h->last_modified) {
-        last_modified = ngx_http_parse_time(h->last_modified->value.data,
-                                            h->last_modified->value.len);
-        p->cache->ctx.last_modified = last_modified;
-    }
-
-    if (h->x_accel_expires) {
-        expires = ngx_atoi(h->x_accel_expires->value.data,
-                           h->x_accel_expires->value.len);
-        if (expires != NGX_ERROR) {
-            p->state->reason = NGX_HTTP_PROXY_CACHE_XAE;
-            p->state->expires = expires;
-            p->cache->ctx.expires = date + expires;
-            return (expires > 0);
-        }
-    }
-
-    if (!p->lcf->ignore_expires) {
-
-        /* TODO: Cache-Control: no-cache, max-age= */
-
-        if (h->expires) {
-            expires = ngx_http_parse_time(h->expires->value.data,
-                                          h->expires->value.len);
-            if (expires != NGX_ERROR) {
-                p->state->reason = NGX_HTTP_PROXY_CACHE_EXP;
-                p->state->expires = expires - date;
-                p->cache->ctx.expires = expires;
-                return (date < expires);
-            }
-        }
-    }
-
-    if (p->upstream->status == NGX_HTTP_MOVED_PERMANENTLY) {
-        p->state->reason = NGX_HTTP_PROXY_CACHE_MVD;
-        p->state->expires = /* STUB: 1 hour */ 60 * 60;
-        p->cache->ctx.expires = /* STUB: 1 hour */ 60 * 60;
-        return 1;
-    }
-
-    if (p->upstream->status == NGX_HTTP_MOVED_TEMPORARILY) {
-        return 1;
-    }
-
-    if (last_modified != NGX_ERROR && p->lcf->lm_factor > 0) {
-
-        /* FIXME: time_t == int_64_t, we can use fpu */ 
-
-        p->state->reason = NGX_HTTP_PROXY_CACHE_LMF;
-        t = (time_t)
-              ((((int64_t) (date - last_modified)) * p->lcf->lm_factor) / 100);
-        p->state->expires = t;
-        p->cache->ctx.expires = ngx_time() + t;
-        return 1;
-    }
-
-    if (p->lcf->default_expires > 0) {
-        p->state->reason = NGX_HTTP_PROXY_CACHE_PDE;
-        p->state->expires = p->lcf->default_expires;
-        p->cache->ctx.expires = ngx_time() + p->lcf->default_expires;
-        return 1;
-    }
-
-    return 0;
-}
-
-
-int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p)
-{
-    ngx_event_pipe_t  *ep;
-
-    if (p->cache == NULL) {
-        return NGX_OK;
-    }
-
-    ep = p->upstream->event_pipe;
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
-                   "http cache update len: %O:%O",
-                   p->cache->ctx.length, ep->read_length);
-
-    if (p->cache->ctx.length == -1) {
-        /* TODO: test rc */
-        ngx_write_file(&ep->temp_file->file,
-                       (char *) &ep->read_length, sizeof(off_t),
-                       offsetof(ngx_http_cache_header_t, length));
-    }
-
-    return ngx_http_cache_update_file(p->request, &p->cache->ctx,
-                                      &ep->temp_file->file.name);
-}
deleted file mode 100644
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ /dev/null
@@ -1,1509 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-#include <ngx_http_proxy_handler.h>
-
-
-static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r);
-#if 0
-static ngx_int_t ngx_http_proxy_cache_get(ngx_http_proxy_ctx_t *p);
-#endif
-
-static size_t ngx_http_proxy_log_proxy_state_getlen(ngx_http_request_t *r,
-                                                    uintptr_t data);
-static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r,
-                                              u_char *buf,
-                                              ngx_http_log_op_t *op);
-
-#if 0
-static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r,
-                                              u_char *buf, uintptr_t data);
-static u_char *ngx_http_proxy_log_reason(ngx_http_request_t *r, u_char *buf,
-                                         uintptr_t data);
-#endif
-
-static ngx_int_t ngx_http_proxy_add_log_formats(ngx_conf_t *cf);
-static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
-static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
-                                           void *parent, void *child);
-
-static char *ngx_http_proxy_set_pass(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 } ;
-
-
-static ngx_conf_bitmask_t  next_upstream_masks[] = {
-    { ngx_string("error"), NGX_HTTP_PROXY_FT_ERROR },
-    { ngx_string("timeout"), NGX_HTTP_PROXY_FT_TIMEOUT },
-    { ngx_string("invalid_header"), NGX_HTTP_PROXY_FT_INVALID_HEADER },
-    { ngx_string("http_500"), NGX_HTTP_PROXY_FT_HTTP_500 },
-    { ngx_string("http_404"), NGX_HTTP_PROXY_FT_HTTP_404 },
-    { ngx_null_string, 0 }
-};
-
-
-static ngx_conf_bitmask_t  use_stale_masks[] = {
-    { ngx_string("error"), NGX_HTTP_PROXY_FT_ERROR },
-    { ngx_string("timeout"), NGX_HTTP_PROXY_FT_TIMEOUT },
-    { ngx_string("invalid_header"), NGX_HTTP_PROXY_FT_INVALID_HEADER },
-    { ngx_string("http_500"), NGX_HTTP_PROXY_FT_HTTP_500 },
-    { ngx_string("busy_lock"), NGX_HTTP_PROXY_FT_BUSY_LOCK },
-    { ngx_string("max_waiting"), NGX_HTTP_PROXY_FT_MAX_WAITING },
-    { ngx_null_string, 0 }
-};
-
-
-static ngx_conf_num_bounds_t  ngx_http_proxy_lm_factor_bounds = {
-    ngx_conf_check_num_bounds, 0, 100
-};
-
-
-static ngx_command_t  ngx_http_proxy_commands[] = {
-
-    { ngx_string("proxy_pass"),
-      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_proxy_set_pass,
-      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,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, connect_timeout),
-      NULL },
-
-    { ngx_string("proxy_send_timeout"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_msec_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, send_timeout),
-      NULL },
-
-    { ngx_string("proxy_send_lowat"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, send_lowat),
-      &ngx_http_proxy_lowat_post },
-
-    { 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_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, preserve_host),
-      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,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, pass_unparsed_uri),
-      NULL },
-
-    { ngx_string("proxy_set_x_url"),
-      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),
-      NULL },
-
-    { ngx_string("proxy_set_x_real_ip"),
-      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),
-      NULL },
-
-    { ngx_string("proxy_header_buffer_size"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, header_buffer_size),
-      NULL },
-
-    { ngx_string("proxy_read_timeout"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_msec_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, read_timeout),
-      NULL },
-
-    { ngx_string("proxy_buffers"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
-      ngx_conf_set_bufs_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, bufs),
-      NULL },
-
-    { ngx_string("proxy_busy_buffers_size"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, busy_buffers_size),
-      NULL },
-
-#if 0
-
-    { ngx_string("proxy_cache_path"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
-      ngx_conf_set_path_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, cache_path),
-      (void *) ngx_http_cache_cleaner_handler },
-
-#endif
-
-    { ngx_string("proxy_temp_path"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
-      ngx_conf_set_path_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, temp_path),
-      (void *) ngx_garbage_collector_temp_handler },
-
-    { ngx_string("proxy_max_temp_file_size"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, max_temp_file_size),
-      NULL },
-
-    { ngx_string("proxy_temp_file_write_size"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, temp_file_write_size),
-      NULL },
-
-    { ngx_string("proxy_cache"),
-      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, cache),
-      NULL },
-
-
-    { ngx_string("proxy_busy_lock"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13,
-      ngx_http_set_busy_lock_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, busy_lock),
-      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),
-      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),
-      NULL },
-
-    { ngx_string("proxy_ignore_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, ignore_expires),
-      NULL },
-
-    { ngx_string("proxy_lm_factor"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_num_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, lm_factor),
-      &ngx_http_proxy_lm_factor_bounds },
-
-    { ngx_string("proxy_default_expires"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_sec_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, default_expires),
-      NULL },
-
-    { ngx_string("proxy_next_upstream"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
-      ngx_conf_set_bitmask_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, next_upstream),
-      &next_upstream_masks },
-
-    { ngx_string("proxy_use_stale"),
-      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_proxy_loc_conf_t, use_stale),
-      &use_stale_masks },
-
-      ngx_null_command
-};
-
-
-ngx_http_module_t  ngx_http_proxy_module_ctx = {
-    ngx_http_proxy_add_log_formats,        /* pre conf */
-
-    NULL,                                  /* create main configuration */
-    NULL,                                  /* init main configuration */
-
-    NULL,                                  /* create server configuration */
-    NULL,                                  /* merge server configuration */
-
-    ngx_http_proxy_create_loc_conf,        /* create location configration */
-    ngx_http_proxy_merge_loc_conf          /* merge location configration */
-};
-
-
-ngx_module_t  ngx_http_proxy_module = {
-    NGX_MODULE,
-    &ngx_http_proxy_module_ctx,            /* module context */
-    ngx_http_proxy_commands,               /* module directives */
-    NGX_HTTP_MODULE,                       /* module type */
-    NULL,                                  /* init module */
-    NULL                                   /* init process */
-};
-
-
-
-static ngx_http_log_op_name_t ngx_http_proxy_log_fmt_ops[] = {
-    { ngx_string("proxy"), 0, NULL,
-                              ngx_http_proxy_log_proxy_state_getlen,
-                              ngx_http_proxy_log_proxy_state },
-
-#if 0
-    { ngx_string("proxy_cache_state"), 0, ngx_http_proxy_log_cache_state },
-    { ngx_string("proxy_reason"), 0, ngx_http_proxy_log_reason },
-#endif
-
-    { ngx_null_string, 0, NULL, NULL, NULL }
-};
-
-
-
-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 }
-};
-
-
-static ngx_str_t cache_states[] = {
-    ngx_string("PASS"),
-    ngx_string("BYPASS"),
-    ngx_string("AUTH"),
-    ngx_string("PGNC"),
-    ngx_string("MISS"),
-    ngx_string("EXPR"),
-    ngx_string("AGED"),
-    ngx_string("HIT")
-};
-
-
-static ngx_str_t cache_reasons[] = {
-    ngx_string("BPS"),
-    ngx_string("XAE"),
-    ngx_string("CTL"),
-    ngx_string("EXP"),
-    ngx_string("MVD"),
-    ngx_string("LMF"),
-    ngx_string("PDE")
-};
-
-
-#if (NGX_PCRE)
-static ngx_str_t ngx_http_proxy_uri = ngx_string("/");
-#endif
-
-
-static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r)
-{
-    ngx_http_proxy_ctx_t  *p;
-
-    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);
-
-
-    p->lcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
-    p->request = r;
-
-    /* TODO: we currently support reverse proxy only */
-    p->accel = 1;
-
-    if (ngx_array_init(&p->states, r->pool, p->lcf->peers->number,
-                                  sizeof(ngx_http_proxy_state_t)) == NGX_ERROR)
-    {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    p->state = ngx_array_push(&p->states);
-    if (p->state == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    ngx_memzero(p->state, sizeof(ngx_http_proxy_state_t));
-
-#if 0
-
-    if (!p->lcf->cache
-        || (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD))
-    {
-        p->state->cache_state = NGX_HTTP_PROXY_CACHE_PASS;
-
-    } else if (r->bypass_cache) {
-        p->state->cache_state = NGX_HTTP_PROXY_CACHE_BYPASS;
-
-    } else if (r->headers_in.authorization) {
-        p->state->cache_state = NGX_HTTP_PROXY_CACHE_AUTH;
-
-    } else if (r->no_cache) {
-        p->state->cache_state = NGX_HTTP_PROXY_CACHE_PGNC;
-        p->cachable = 1;
-
-    } else {
-        p->cachable = 1;
-    }
-
-
-    if (p->state->cache_state != 0) {
-        return ngx_http_proxy_request_upstream(p);
-    }
-
-    return ngx_http_proxy_cache_get(p);
-
-#else
-
-    p->state->cache_state = NGX_HTTP_PROXY_CACHE_PASS;
-
-    return ngx_http_proxy_request_upstream(p);
-
-#endif
-}
-
-
-#if 0
-
-static ngx_int_t ngx_http_proxy_cache_get(ngx_http_proxy_ctx_t *p)
-{
-    u_char                          *last;
-    ngx_http_request_t              *r;
-    ngx_http_cache_ctx_t             ctx;
-    ngx_http_proxy_upstream_conf_t  *u;
-
-    r = p->request;
-    u = p->lcf->upstream;
-
-    ctx.key.len = u->url.len + r->uri.len - u->location->len + r->args.len;
-    ctx.key.data = ngx_palloc(r->pool, ctx.key.len);
-    if (ctx.key.data == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    last = ngx_cpymem(ctx.key.data, u->url.data, u->url.len);
-
-    last = ngx_cpymem(last, r->uri.data + u->location->len,
-                      r->uri.len - u->location->len);
-
-    if (r->args.len > 0) {
-        *(last++) = '?';
-        last = ngx_cpymem(last, r->args.data, r->args.len);
-    }
-
-    p->header_in = ngx_create_temp_buf(r->pool, p->lcf->header_buffer_size);
-    if (p->header_in == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-    p->header_in->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
-
-    ctx.buf = p->header_in;
-    ctx.path = p->lcf->cache_path;
-    ctx.file = 1;
-    ctx.primary = 1;
-
-    ngx_http_cache_get(r, &ctx);
-
-    return ngx_http_proxy_request_upstream(p);
-}
-
-#endif
-
-
-void ngx_http_proxy_check_broken_connection(ngx_event_t *ev)
-{
-    int                    n;
-    char                   buf[1];
-    ngx_err_t              err;
-    ngx_connection_t      *c;
-    ngx_http_request_t    *r;
-    ngx_http_proxy_ctx_t  *p;
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
-                   "http proxy check client, write event:%d", ev->write);
-
-#if (NGX_HAVE_KQUEUE)
-
-    if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
-
-        if (!ev->pending_eof) {
-            return;
-        }
-
-        c = ev->data;
-        r = c->data;
-        p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
-
-        ev->eof = 1;
-
-        if (ev->kq_errno) {
-            ev->error = 1;
-        }
-
-        if (!p->cachable && p->upstream->peer.connection) {
-            ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
-                          "kevent() reported that client closed "
-                          "prematurely connection, "
-                          "so upstream connection is closed too");
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
-            return;
-        }
-
-        ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
-                      "kevent() reported that client closed "
-                      "prematurely connection");
-
-        if (p->upstream == NULL || p->upstream->peer.connection == NULL) {
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
-        }
-
-        return;
-    }
-
-#endif
-
-    c = ev->data;
-    r = c->data;
-    p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
-
-    n = recv(c->fd, buf, 1, MSG_PEEK);
-
-    err = ngx_socket_errno;
-
-    /*
-     * we do not need to disable the write event because
-     * that event has NGX_USE_CLEAR_EVENT type
-     */
-
-    if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
-        return;
-    }
-
-    if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
-        if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        }
-    }
-
-    if (n > 0) {
-        return;
-    }
-
-    ev->eof = 1;
-
-    if (n == -1) {
-        if (err == NGX_EAGAIN) {
-            return;
-        }
-
-        ev->error = 1;
-
-    } else {
-        /* n == 0 */
-        err = 0;
-    }
-
-    if (!p->cachable && p->upstream->peer.connection) {
-        ngx_log_error(NGX_LOG_INFO, ev->log, err,
-                      "client closed prematurely connection, "
-                      "so upstream connection is closed too");
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
-        return;
-    }
-
-    ngx_log_error(NGX_LOG_INFO, ev->log, err,
-                  "client closed prematurely connection");
-
-    if (p->upstream == NULL || p->upstream->peer.connection == NULL) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
-    }
-}
-
-
-void ngx_http_proxy_busy_lock_handler(ngx_event_t *rev)
-{
-    ngx_connection_t      *c;
-    ngx_http_request_t    *r;
-    ngx_http_proxy_ctx_t  *p;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http proxy busy lock");
-
-    c = rev->data;
-    r = c->data;
-    p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
-    p->action = "waiting upstream in busy lock";
-
-    if (p->request->connection->write->eof) {
-        ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
-        return;
-    }
-
-    if (rev->timedout) {
-        rev->timedout = 0;
-        p->busy_lock.time++;
-        p->state->bl_time = p->busy_lock.time;
-
-#if (NGX_HTTP_FILE_CACHE)
-
-        if (p->state->cache_state < NGX_HTTP_PROXY_CACHE_MISS) {
-            ngx_http_proxy_upstream_busy_lock(p);
-
-        } else {
-            ngx_http_proxy_cache_busy_lock(p);
-        }
-#else
-
-        ngx_http_proxy_upstream_busy_lock(p);
-
-#endif
-
-        return;
-    }
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
-                   "http proxy: client sent while busy lock");
-
-    /*
-     * TODO: kevent() notify about error, otherwise we need to
-     * call ngx_peek(): recv(MSG_PEEK) to get errno. THINK about aio.
-     * if there's no error we need to disable event.
-     */
-
-#if 0
-#if (NGX_HAVE_KQUEUE)
-
-    if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && rev->kq_eof) {
-        ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
-
-        ngx_del_timer(rev);
-
-        ngx_log_error(NGX_LOG_ERR, c->log, rev->kq_errno,
-                      "client() closed connection");
-
-        if (ngx_del_event(rev, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) {
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return;
-        }
-
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
-        return;
-    }
-
-#endif
-#endif
-
-}
-
-
-void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc)
-{
-    ngx_http_request_t  *r;
-
-    r = p->request;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "finalize http proxy request");
-
-    if (p->upstream && p->upstream->peer.connection) {
-        ngx_http_proxy_close_connection(p);
-    }
-
-    if (p->header_sent
-        && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
-    {
-        rc = 0;
-    }
-
-    if (p->saved_ctx) {
-        r->connection->log->data = p->saved_ctx;
-        r->connection->log->handler = p->saved_handler;
-    }
-
-    if (p->upstream && p->upstream->event_pipe) {
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http proxy temp fd: %d",
-                       p->upstream->event_pipe->temp_file->file.fd);
-    }
-
-    if (p->cache) {
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http proxy cache fd: %d",
-                       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);
-    }
-
-    ngx_http_finalize_request(r, rc);
-}
-
-
-void ngx_http_proxy_close_connection(ngx_http_proxy_ctx_t *p)
-{
-    ngx_socket_t       fd;
-    ngx_connection_t  *c;
-
-    c = p->upstream->peer.connection;
-    p->upstream->peer.connection = NULL;
-
-    if (p->lcf->busy_lock) {
-        p->lcf->busy_lock->busy--;
-    }
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http proxy close connection: %d", c->fd);
-
-    if (c->fd == -1) {
-#if 0
-        ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
-#endif
-        return;
-    }
-
-    if (c->read->timer_set) {
-        ngx_del_timer(c->read);
-    }
-
-    if (c->write->timer_set) {
-        ngx_del_timer(c->write);
-    }
-
-    /* TODO: move connection to the connection pool */
-
-    if (ngx_del_conn) {
-        ngx_del_conn(c, NGX_CLOSE_EVENT);
-
-    } else {
-        if (c->read->active || c->read->disabled) {
-            ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
-        }
-
-        if (c->write->active || c->read->disabled) {
-            ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
-        }
-    }
-
-    /*
-     * we have to clean the connection information before the closing
-     * because another thread may reopen the same file descriptor
-     * before we clean the connection
-     */
-
-    if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_OK) {
-
-        if (c->read->prev) {
-            ngx_delete_posted_event(c->read);
-        }
-
-        if (c->write->prev) {
-            ngx_delete_posted_event(c->write);
-        }
-
-        c->read->closed = 1;
-        c->write->closed = 1;
-
-        ngx_mutex_unlock(ngx_posted_events_mutex);
-    }
-
-    fd = c->fd;
-    c->fd = (ngx_socket_t) -1;
-    c->data = NULL;
-
-    if (ngx_close_socket(fd) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
-                      ngx_close_socket_n " failed");
-    }
-}
-
-
-u_char *ngx_http_proxy_log_error(ngx_log_t *log, u_char *buf, size_t len)
-{
-    u_char                          *p;
-    ngx_int_t                        escape;
-    ngx_http_request_t              *r;
-    ngx_peer_connection_t           *peer;
-    ngx_http_proxy_log_ctx_t        *ctx;
-    ngx_http_proxy_upstream_conf_t  *uc;
-
-    ctx = log->data;
-    r = ctx->proxy->request;
-    uc = ctx->proxy->lcf->upstream;
-    peer = &ctx->proxy->upstream->peer;
-
-    p = ngx_snprintf(buf, len,
-                     " while %s, client: %V, server: %V, URL: \"%V\","
-                     " upstream: http://%V%s%V",
-                     ctx->proxy->action,
-                     &r->connection->addr_text,
-                     &r->server_name,
-                     &r->unparsed_uri,
-                     &peer->peers->peer[peer->cur_peer].name,
-                     ctx->proxy->lcf->upstream->uri_separator,
-                     &ctx->proxy->lcf->upstream->uri);
-    len -= p - buf;
-    buf = p;
-
-    if (ctx->proxy->lcf->pass_unparsed_uri && r->valid_unparsed_uri) {
-        p = ngx_cpymem(buf, r->unparsed_uri.data + 1, r->unparsed_uri.len - 1);
-        len -= p - buf;
-
-        return ngx_http_log_error_info(r, p, len);
-    }
-
-    if (r->quoted_uri) {
-        escape = 2 * ngx_escape_uri(NULL, r->uri.data + uc->location->len,
-                                    r->uri.len - uc->location->len,
-                                    NGX_ESCAPE_URI);
-    } else {
-        escape = 0;
-    }
-
-    if (escape) {
-        if (len >= r->uri.len - uc->location->len + escape) {
-
-            ngx_escape_uri(buf, r->uri.data + uc->location->len,
-                           r->uri.len - uc->location->len, NGX_ESCAPE_URI);
-
-            buf += r->uri.len - uc->location->len + escape;
-            len -= r->uri.len - uc->location->len + escape;
-
-            if (r->args.len) {
-                p = ngx_snprintf(buf, len, "?%V", &r->args);
-                len -= p - buf;
-                buf = p;
-            }
-
-            return ngx_http_log_error_info(r, buf, len);
-        }
-
-        p = ngx_palloc(r->pool, r->uri.len - uc->location->len + escape);
-        if (p == NULL) {
-            return buf;
-        }
-
-        ngx_escape_uri(p, r->uri.data + uc->location->len,
-                       r->uri.len - uc->location->len, NGX_ESCAPE_URI);
-
-        p = ngx_cpymem(buf, p, r->uri.len - uc->location->len + escape);
-
-    } else {
-        p = ngx_cpymem(buf, r->uri.data + uc->location->len,
-                       r->uri.len - uc->location->len);
-    }
-
-    len -= p - buf;
-    buf = p;
-
-    if (r->args.len) {
-        p = ngx_snprintf(buf, len, "?%V", &r->args);
-        len -= p - buf;
-        buf = p;
-    }
-
-    return ngx_http_log_error_info(r, buf, len);
-}
-
-
-static size_t ngx_http_proxy_log_proxy_state_getlen(ngx_http_request_t *r,
-                                                    uintptr_t data)
-{
-    ngx_http_proxy_ctx_t  *p;
-
-    p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
-
-    if (p == NULL) {
-        return 1;
-    }
-
-    return p->states.nelts * /* STUB */ 100;
-}
-
-
-static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r,
-                                              u_char *buf,
-                                              ngx_http_log_op_t *op)
-{
-    ngx_uint_t               i;
-    ngx_http_proxy_ctx_t    *p;
-    ngx_http_proxy_state_t  *state;
-
-    p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
-
-    if (p == NULL) {
-        *buf = '-';
-        return buf + 1;
-    }
-
-    i = 0;
-    state = p->states.elts;
-
-    for ( ;; ) {
-        if (state[i].cache_state == 0) {
-            *buf++ = '-';
-
-        } else {
-            buf = ngx_cpymem(buf, cache_states[state[i].cache_state - 1].data,
-                             cache_states[state[i].cache_state - 1].len);
-        }
-
-        *buf++ = '/';
-
-        if (state[i].expired == 0) {
-            *buf++ = '-';
-
-        } else {
-            buf = ngx_sprintf(buf, "%T", state[i].expired);
-        }
-
-        *buf++ = '/';
-
-        if (state[i].bl_time == 0) {
-            *buf++ = '-';
-
-        } else {
-            buf = ngx_sprintf(buf, "%T", state[i].bl_time);
-        }
-
-        *buf++ = '/';
-
-        *buf++ = '*';
-
-        *buf++ = ' ';
-
-        if (state[i].status == 0) {
-            *buf++ = '-';
-
-        } else {
-            buf = ngx_sprintf(buf, "%ui", state[i].status);
-        }
-
-        *buf++ = '/';
-
-        if (state[i].reason == 0) {
-            *buf++ = '-';
-
-        } else {
-            buf = ngx_cpymem(buf, cache_reasons[state[i].reason - 1].data,
-                             cache_reasons[state[i].reason - 1].len);
-        }
-
-        *buf++ = '/';
-
-        if (state[i].reason < NGX_HTTP_PROXY_CACHE_XAE) {
-            *buf++ = '-';
-
-        } else {
-            buf = ngx_sprintf(buf, "%T", state[i].expires);
-        }
-
-        *buf++ = ' ';
-        *buf++ = '*';
-
-        if (++i == p->states.nelts) {
-            return buf;
-        }
-
-        *buf++ = ',';
-        *buf++ = ' ';
-    }
-}
-
-
-#if 0
-
-static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r,
-                                              u_char *buf, uintptr_t data)
-{
-    ngx_uint_t               i;
-    ngx_http_proxy_ctx_t    *p;
-    ngx_http_proxy_state_t  *state;
-
-    p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
-
-    if (p == NULL || p->state->cache_state == 0) {
-        if (buf == NULL) {
-            return (u_char *) 1;
-        }
-
-        *buf = '-';
-        return buf + 1;
-    }
-
-    if (buf == NULL) {
-        /* find the request line length */
-        return (u_char *) (p->states.nelts * sizeof("BYPASS") - 1);
-    }
-
-    i = 0;
-    state = p->states.elts;
-
-    for ( ;; ) {
-        buf = ngx_cpymem(buf, cache_states[state[i].cache_state - 1].data,
-                         cache_states[state[i].cache_state - 1].len);
-
-        if (++i == p->states.nelts) {
-            return buf;
-        }
-
-        *buf++ = ',';
-        *buf++ = ' ';
-    }
-}
-
-
-static u_char *ngx_http_proxy_log_reason(ngx_http_request_t *r, u_char *buf,
-                                         uintptr_t data)
-{
-    ngx_uint_t               i;
-    ngx_http_proxy_ctx_t    *p;
-    ngx_http_proxy_state_t  *state;
-
-    p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
-
-    if (p == NULL || p->state->reason == 0) {
-        if (buf == NULL) {
-            return (u_char *) 1;
-        }
-
-        *buf = '-';
-        return buf + 1;
-    }
-
-    if (buf == NULL) {
-        /* find the request line length */
-        return (u_char *) (p->states.nelts * sizeof("BPS") - 1);
-    }
-
-    i = 0;
-    state = p->states.elts;
-
-    for ( ;; ) {
-        buf = ngx_cpymem(buf, cache_reasons[state[i].reason - 1].data,
-                         cache_reasons[state[i].reason - 1].len);
-
-        if (++i == p->states.nelts) {
-            return buf;
-        }
-
-        *buf++ = ',';
-        *buf++ = ' ';
-    }
-}
-
-#endif
-
-
-static ngx_int_t ngx_http_proxy_add_log_formats(ngx_conf_t *cf)
-{
-    ngx_http_log_op_name_t  *op;
-
-    for (op = ngx_http_proxy_log_fmt_ops; op->name.len; op++) { /* void */ }
-    op->run = NULL;
-
-    for (op = ngx_http_log_fmt_ops; op->run; op++) {
-        if (op->name.len == 0) {
-            op = (ngx_http_log_op_name_t *) op->run;
-        }
-    }
-
-    op->run = (ngx_http_log_op_run_pt) ngx_http_proxy_log_fmt_ops;
-
-    return NGX_OK;
-}
-
-
-static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
-{
-    ngx_http_proxy_loc_conf_t  *conf;
-
-    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
-    if (conf == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    /*
-     * set by ngx_pcalloc():
-     *
-     *    conf->bufs.num = 0;
-     *    conf->path = NULL;
-     *    conf->next_upstream = 0;
-     *    conf->use_stale = 0;
-     *    conf->upstreams = NULL;
-     *    conf->peers = NULL;
-     *    conf->cache_path = NULL;
-     *    conf->temp_path = NULL;
-     *    conf->x_vars;
-     *    conf->busy_lock = NULL;
-     */
-
-    conf->connect_timeout = NGX_CONF_UNSET_MSEC;
-    conf->send_timeout = NGX_CONF_UNSET_MSEC;
-    conf->send_lowat = NGX_CONF_UNSET_SIZE;
-
-    conf->pass_unparsed_uri = NGX_CONF_UNSET;
-    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->header_buffer_size = NGX_CONF_UNSET_SIZE;
-    conf->read_timeout = NGX_CONF_UNSET_MSEC;
-    conf->busy_buffers_size = NGX_CONF_UNSET_SIZE;
-
-    conf->max_temp_file_size = NGX_CONF_UNSET_SIZE;
-    conf->temp_file_write_size = NGX_CONF_UNSET_SIZE;
-
-    /* "proxy_cyclic_temp_file" is disabled */
-    conf->cyclic_temp_file = 0;
-
-    conf->cache = NGX_CONF_UNSET;
-
-    conf->pass_server = NGX_CONF_UNSET;
-    conf->pass_x_accel_expires = NGX_CONF_UNSET;
-    conf->ignore_expires = NGX_CONF_UNSET;
-    conf->lm_factor = NGX_CONF_UNSET;
-    conf->default_expires = NGX_CONF_UNSET;
-
-    return conf;
-}
-
-
-static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
-                                           void *parent, void *child)
-{
-    ngx_http_proxy_loc_conf_t *prev = parent;
-    ngx_http_proxy_loc_conf_t *conf = child;
-
-    size_t   size;
-
-    ngx_conf_merge_msec_value(conf->connect_timeout,
-                              prev->connect_timeout, 60000);
-    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_value(conf->pass_unparsed_uri, prev->pass_unparsed_uri, 0);
-
-    if (conf->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_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);
-
-    ngx_conf_merge_msec_value(conf->read_timeout, prev->read_timeout, 60000);
-
-    ngx_conf_merge_size_value(conf->header_buffer_size,
-                              prev->header_buffer_size, (size_t) ngx_pagesize);
-
-    ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 8, ngx_pagesize);
-
-    if (conf->bufs.num < 2) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "there must be at least 2 \"proxy_buffers\"");
-        return NGX_CONF_ERROR;
-    }
-
-    size = conf->header_buffer_size;
-    if (size < conf->bufs.size) {
-        size = conf->bufs.size;
-    }
-
-
-    ngx_conf_merge_size_value(conf->busy_buffers_size,
-                              prev->busy_buffers_size, NGX_CONF_UNSET_SIZE);
-
-    if (conf->busy_buffers_size == NGX_CONF_UNSET_SIZE) {
-        conf->busy_buffers_size = 2 * size;
-
-    } else if (conf->busy_buffers_size < size) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-             "\"proxy_busy_buffers_size\" must be equal or bigger than "
-             "maximum of the value of \"proxy_header_buffer_size\" and "
-             "one of the \"proxy_buffers\"");
-
-        return NGX_CONF_ERROR;
-
-    } else if (conf->busy_buffers_size > (conf->bufs.num - 1) * conf->bufs.size)
-    {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-             "\"proxy_busy_buffers_size\" must be less than "
-             "the size of all \"proxy_buffers\" minus one buffer");
-
-        return NGX_CONF_ERROR;
-    }
-
-
-    ngx_conf_merge_size_value(conf->temp_file_write_size,
-                              prev->temp_file_write_size, NGX_CONF_UNSET_SIZE);
-
-    if (conf->temp_file_write_size == NGX_CONF_UNSET_SIZE) {
-        conf->temp_file_write_size = 2 * size;
-
-    } else if (conf->temp_file_write_size < size) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-             "\"proxy_temp_file_write_size\" must be equal or bigger than "
-             "maximum of the value of \"proxy_header_buffer_size\" and "
-             "one of the \"proxy_buffers\"");
-
-        return NGX_CONF_ERROR;
-    }
-
-
-    ngx_conf_merge_size_value(conf->max_temp_file_size,
-                              prev->max_temp_file_size, NGX_CONF_UNSET_SIZE);
-
-    if (conf->max_temp_file_size == NGX_CONF_UNSET_SIZE) {
-
-        /*
-         * "proxy_max_temp_file_size" is set to 1G for reverse proxy,
-         * it should be much less in the generic proxy
-         */
-
-        conf->max_temp_file_size = 1024 * 1024 * 1024;
-
-#if 0
-        conf->max_temp_file_size = 2 * size;
-#endif
-
-
-    } else if (conf->max_temp_file_size != 0
-               && conf->max_temp_file_size < size)
-    {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-             "\"proxy_max_temp_file_size\" must be equal to zero to disable "
-             "the temporary files usage or must be equal or bigger than "
-             "maximum of the value of \"proxy_header_buffer_size\" and "
-             "one of the \"proxy_buffers\"");
-
-        return NGX_CONF_ERROR;
-    }
-
-
-    ngx_conf_merge_bitmask_value(conf->next_upstream, prev->next_upstream,
-                                 (NGX_CONF_BITMASK_SET
-                                  |NGX_HTTP_PROXY_FT_ERROR
-                                  |NGX_HTTP_PROXY_FT_TIMEOUT));
-
-    ngx_conf_merge_bitmask_value(conf->use_stale, prev->use_stale,
-                                 NGX_CONF_BITMASK_SET);
-
-#if 0
-    ngx_conf_merge_path_value(conf->cache_path, prev->cache_path,
-                              NGX_HTTP_PROXY_CACHE_PATH, 1, 2, 0,
-                              ngx_garbage_collector_temp_handler, cf);
-#endif
-
-    ngx_conf_merge_path_value(conf->temp_path, prev->temp_path,
-                              NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,
-                              ngx_garbage_collector_temp_handler, cf);
-
-    ngx_conf_merge_value(conf->cache, prev->cache, 0);
-
-
-    /* conf->cache must be merged */
-
-    if (conf->busy_lock == NULL) {
-        conf->busy_lock = prev->busy_lock;
-    }
-
-    if (conf->busy_lock && conf->cache && conf->busy_lock->md5 == NULL) {
-
-        /* ngx_calloc_shared() */
-        conf->busy_lock->md5_mask =
-                     ngx_pcalloc(cf->pool, (conf->busy_lock->max_busy + 7) / 8);
-        if (conf->busy_lock->md5_mask == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        /* 16 bytes are 128 bits of the md5 */
-
-        /* ngx_alloc_shared() */
-        conf->busy_lock->md5 = ngx_palloc(cf->pool,
-                                          16 * conf->busy_lock->max_busy);
-        if (conf->busy_lock->md5 == NULL) {
-            return NGX_CONF_ERROR;
-        }
-    }
-
-
-    ngx_conf_merge_value(conf->pass_server, prev->pass_server, 0);
-    ngx_conf_merge_value(conf->pass_x_accel_expires,
-                         prev->pass_x_accel_expires, 0);
-    ngx_conf_merge_value(conf->ignore_expires, prev->ignore_expires, 0);
-    ngx_conf_merge_value(conf->lm_factor, prev->lm_factor, 0);
-    ngx_conf_merge_sec_value(conf->default_expires, prev->default_expires, 0);
-
-    if (conf->x_vars == NULL) {
-        conf->x_vars = prev->x_vars;
-    }
-
-    if (conf->peers == NULL) {
-        conf->peers = prev->peers;
-        conf->upstream = prev->upstream;
-    }
-
-    return NULL;
-}
-
-
-static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
-                                     void *conf)
-{
-    ngx_http_proxy_loc_conf_t *lcf = conf;
-
-    ngx_str_t                   *value, *url;
-    ngx_inet_upstream_t          inet_upstream;
-    ngx_http_core_loc_conf_t    *clcf;
-#if (NGX_HAVE_UNIX_DOMAIN)
-    ngx_unix_domain_upstream_t   unix_upstream;
-#endif
-
-    value = cf->args->elts;
-
-    url = &value[1];
-
-    if (ngx_strncasecmp(url->data, "http://", 7) != 0) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
-        return NGX_CONF_ERROR;
-    }
-
-    lcf->upstream = ngx_pcalloc(cf->pool,
-                                sizeof(ngx_http_proxy_upstream_conf_t));
-    if (lcf->upstream == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    lcf->upstream->url = *url;
-
-    if (ngx_strncasecmp(url->data + 7, "unix:", 5) == 0) {
-
-#if (NGX_HAVE_UNIX_DOMAIN)
-
-        ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t));
-
-        unix_upstream.name = *url;
-        unix_upstream.url.len = url->len - 7;
-        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) {
-            return NGX_CONF_ERROR;
-        }
-
-        lcf->upstream->host_header.len = sizeof("localhost") - 1;
-        lcf->upstream->host_header.data = (u_char *) "localhost";
-        lcf->upstream->uri = unix_upstream.uri;
-        lcf->upstream->uri_separator = ":";
-        lcf->upstream->default_port = 1;
-
-#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 = *url;
-        inet_upstream.url.len = url->len - 7;
-        inet_upstream.url.data = url->data + 7;
-        inet_upstream.default_port_value = 80;
-        inet_upstream.uri_part = 1;
-
-        lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
-        if (lcf->peers == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        lcf->upstream->host_header = inet_upstream.host_header;
-        lcf->upstream->port_text = inet_upstream.port_text;
-        lcf->upstream->uri = inet_upstream.uri;
-        lcf->upstream->uri_separator = "";
-        lcf->upstream->default_port = inet_upstream.default_port;
-    }
-
-    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
-
-    clcf->handler = ngx_http_proxy_handler;
-
-#if (NGX_PCRE)
-    lcf->upstream->location = clcf->regex ? &ngx_http_proxy_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_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd,
-                                      void *conf)
-{
-    ngx_http_proxy_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->x_vars == NULL) {
-        lcf->x_vars = ngx_array_create(cf->pool, 4,
-                                       sizeof(ngx_http_variable_t *));
-        if (lcf->x_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->x_vars);
-            if (index == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            *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_proxy_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,
-                           "\"proxy_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,
-                       "\"proxy_send_lowat\" is not supported, ignored");
-
-    *np = 0;
-
-#endif
-
-    return NGX_CONF_OK;
-}
deleted file mode 100644
--- a/src/http/modules/proxy/ngx_http_proxy_handler.h
+++ /dev/null
@@ -1,272 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#ifndef _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_
-#define _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_event.h>
-#include <ngx_event_connect.h>
-#include <ngx_event_pipe.h>
-#include <ngx_http.h>
-
-
-typedef enum {
-    NGX_HTTP_PROXY_CACHE_PASS = 1,
-    NGX_HTTP_PROXY_CACHE_BYPASS,
-    NGX_HTTP_PROXY_CACHE_AUTH,
-    NGX_HTTP_PROXY_CACHE_PGNC,
-    NGX_HTTP_PROXY_CACHE_MISS,
-    NGX_HTTP_PROXY_CACHE_EXPR,
-    NGX_HTTP_PROXY_CACHE_AGED,
-    NGX_HTTP_PROXY_CACHE_HIT
-} ngx_http_proxy_state_e;
-
-
-typedef enum {
-    NGX_HTTP_PROXY_CACHE_BPS = 1,
-    NGX_HTTP_PROXY_CACHE_XAE,
-    NGX_HTTP_PROXY_CACHE_CTL,
-    NGX_HTTP_PROXY_CACHE_EXP,
-    NGX_HTTP_PROXY_CACHE_MVD,
-    NGX_HTTP_PROXY_CACHE_LMF,
-    NGX_HTTP_PROXY_CACHE_PDE
-} ngx_http_proxy_reason_e;
-
-
-typedef struct {
-    ngx_str_t                        url;
-    ngx_str_t                        host;
-    ngx_str_t                        uri;
-    ngx_str_t                        host_header;
-    ngx_str_t                        port_text;
-    ngx_str_t                       *location;
-
-    char                            *uri_separator;
-
-    in_port_t                        port;
-
-    unsigned                         default_port:1;
-} ngx_http_proxy_upstream_conf_t;
-
-
-typedef struct {
-    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_msec_t                       connect_timeout;
-    ngx_msec_t                       send_timeout;
-    ngx_msec_t                       read_timeout;
-    time_t                           default_expires;
-
-    ngx_int_t                        lm_factor;
-
-    ngx_uint_t                       next_upstream;
-    ngx_uint_t                       use_stale;
-
-    ngx_bufs_t                       bufs;
-
-    ngx_flag_t                       cyclic_temp_file;
-    ngx_flag_t                       cache;
-    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_unparsed_uri;
-    ngx_flag_t                       pass_server;
-    ngx_flag_t                       pass_x_accel_expires;
-    ngx_flag_t                       ignore_expires;
-
-    ngx_path_t                      *cache_path;
-    ngx_path_t                      *temp_path;
-
-    ngx_array_t                     *x_vars;
-
-    ngx_http_busy_lock_t            *busy_lock;
-
-    ngx_http_proxy_upstream_conf_t  *upstream;
-    ngx_peers_t                     *peers;
-} ngx_http_proxy_loc_conf_t;
-
-
-/*
- * "EXPR/10/5/- 200/EXP/60 4"
- * "MISS/-/-/B 503/-/- -"
- * "EXPR/10/20/SB HIT/-/- -"
- * "EXPR/10/15/NB HIT/-/- -"
- */
-
-typedef struct {
-    ngx_http_proxy_state_e           cache_state;
-    time_t                           expired;
-    time_t                           bl_time;
-    ngx_uint_t                       bl_state;
-
-    ngx_uint_t                       status;
-    ngx_http_proxy_reason_e          reason;
-    time_t                           time;
-    time_t                           expires;
-
-    ngx_str_t                       *peer;
-} ngx_http_proxy_state_t;
-
-
-typedef struct {
-    ngx_list_t                       headers;
-#if 0
-    ngx_table_t                      headers;   /* it must be first field */
-#endif
-
-    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_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;
-
-
-typedef struct {
-    ngx_http_cache_t                 ctx;
-    ngx_uint_t                       status;
-    ngx_str_t                        status_line;
-
-    ngx_http_proxy_headers_in_t      headers_in;
-} ngx_http_proxy_cache_t;
-
-
-typedef struct {
-    ngx_peer_connection_t            peer;
-    ngx_uint_t                       status;
-    ngx_str_t                        status_line;
-    ngx_uint_t                       method;
-
-    ngx_output_chain_ctx_t          *output_chain_ctx;
-    ngx_event_pipe_t                *event_pipe;
-
-    ngx_http_proxy_headers_in_t      headers_in;
-} ngx_http_proxy_upstream_t;
-
-
-typedef struct ngx_http_proxy_ctx_s  ngx_http_proxy_ctx_t;
-
-struct ngx_http_proxy_ctx_s {
-    ngx_http_request_t           *request;
-    ngx_http_proxy_loc_conf_t    *lcf;
-    ngx_http_proxy_upstream_t    *upstream;
-    ngx_http_proxy_cache_t       *cache;
-
-    ngx_buf_t                    *header_in;
-
-    ngx_http_busy_lock_ctx_t      busy_lock;
-
-    unsigned                      accel:1;
-
-    unsigned                      cachable:1;
-    unsigned                      stale:1;
-    unsigned                      try_busy_lock:1;
-    unsigned                      busy_locked:1;
-    unsigned                      valid_header_in:1;
-
-    unsigned                      request_sent:1;
-    unsigned                      header_sent:1;
-
-
-    /* used to parse an upstream HTTP header */
-    ngx_uint_t                    status;
-    u_char                       *status_start;
-    u_char                       *status_end;
-    ngx_uint_t                    status_count;
-    ngx_uint_t                    parse_state;
-
-    ngx_http_proxy_state_t       *state;
-    ngx_array_t                   states;    /* of ngx_http_proxy_state_t */
-
-    /*
-     * we declare "action" as "char *" because the actions are usually
-     * the static strings and in the "u_char *" case we have to override
-     * all the time their types
-     */
-
-    char                         *action;
-    ngx_http_log_ctx_t           *saved_ctx;
-    ngx_log_handler_pt            saved_handler;
-};
-
-
-typedef struct {
-    ngx_uint_t             connection;
-    ngx_http_proxy_ctx_t  *proxy;
-} ngx_http_proxy_log_ctx_t;
-
-
-#define NGX_HTTP_PROXY_PARSE_NO_HEADER       30
-
-
-#define NGX_HTTP_PROXY_FT_ERROR              0x02
-#define NGX_HTTP_PROXY_FT_TIMEOUT            0x04
-#define NGX_HTTP_PROXY_FT_INVALID_HEADER     0x08
-#define NGX_HTTP_PROXY_FT_HTTP_500           0x10
-#define NGX_HTTP_PROXY_FT_HTTP_404           0x20
-#define NGX_HTTP_PROXY_FT_BUSY_LOCK          0x40
-#define NGX_HTTP_PROXY_FT_MAX_WAITING        0x80
-
-
-int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p);
-
-#if (NGX_HTTP_FILE_CACHE)
-
-int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p);
-int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p);
-int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p);
-int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p);
-
-void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p);
-
-#endif
-
-void ngx_http_proxy_check_broken_connection(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);
-
-u_char *ngx_http_proxy_log_error(ngx_log_t *log, u_char *buf, size_t len);
-void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc);
-void ngx_http_proxy_close_connection(ngx_http_proxy_ctx_t *p);
-
-int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p);
-int ngx_http_proxy_copy_header(ngx_http_proxy_ctx_t *p,
-                               ngx_http_proxy_headers_in_t *headers_in);
-
-
-
-extern ngx_module_t  ngx_http_proxy_module;
-extern ngx_http_header_t ngx_http_proxy_headers_in[];
-
-
-
-#endif /* _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_ */
deleted file mode 100644
--- a/src/http/modules/proxy/ngx_http_proxy_header.c
+++ /dev/null
@@ -1,206 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-#include <ngx_http_proxy_handler.h>
-
-
-static int ngx_http_proxy_rewrite_location_header(ngx_http_proxy_ctx_t *p,
-                                                  ngx_table_elt_t *loc);
-
-int ngx_http_proxy_copy_header(ngx_http_proxy_ctx_t *p,
-                               ngx_http_proxy_headers_in_t *headers_in)
-{
-    ngx_uint_t           i;
-    ngx_list_part_t     *part;
-    ngx_table_elt_t     *ho, *h;
-    ngx_http_request_t  *r;
-
-    r = p->request;
-
-    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->connection) {
-            continue;
-        }
-
-        if (&h[i] == headers_in->x_pad) {
-            continue;
-        }
-
-        if (p->accel) {
-            if (&h[i] == headers_in->date
-                || &h[i] == headers_in->accept_ranges) {
-                continue;
-            }
-
-            if (&h[i] == headers_in->x_accel_expires
-                && !p->lcf->pass_x_accel_expires)
-            {
-                continue;
-            }
-
-            if (&h[i] == headers_in->server && !p->lcf->pass_server) {
-                continue;
-            }
-
-            if (&h[i] == headers_in->location) {
-                if (ngx_http_proxy_rewrite_location_header(p, &h[i])
-                                                                  == NGX_ERROR)
-                {
-                    return NGX_ERROR;
-                }
-
-                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_ERROR;
-        }
-
-        *ho = h[i];
-
-        if (&h[i] == headers_in->expires) {
-            r->headers_out.expires = ho;
-            continue;
-        }
-
-        if (&h[i] == headers_in->cache_control) {
-            r->headers_out.cache_control = ho;
-            continue;
-        }
-
-        if (&h[i] == headers_in->etag) {
-            r->headers_out.etag = ho;
-            continue;
-        }
-
-#if (NGX_HTTP_GZIP)
-        if (&h[i] == headers_in->content_encoding) {
-            r->headers_out.content_encoding = ho;
-            continue;
-        }
-#endif
-
-        if (&h[i] == headers_in->last_modified) {
-            r->headers_out.last_modified = ho;
-            /* TODO: update r->headers_out.last_modified_time */
-            continue;
-        }
-
-        /*
-         * ngx_http_header_filter() passes the following headers as is
-         * and does not handle them specially if they are set:
-         *     r->headers_out.server,
-         *     r->headers_out.date,
-         *     r->headers_out.content_length
-         */
-
-        if (&h[i] == headers_in->server) {
-            r->headers_out.server = ho;
-            continue;
-        }
-
-        if (&h[i] == headers_in->date) {
-            r->headers_out.date = ho;
-            continue;
-        }
-
-        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_OK;
-}
-
-
-static int ngx_http_proxy_rewrite_location_header(ngx_http_proxy_ctx_t *p,
-                                                  ngx_table_elt_t *loc)
-{
-    u_char                          *last;
-    ngx_table_elt_t                 *location;
-    ngx_http_request_t              *r;
-    ngx_http_proxy_upstream_conf_t  *uc;
-
-    r = p->request;
-    uc = p->lcf->upstream;
-
-    location = ngx_list_push(&r->headers_out.headers);
-    if (location == NULL) {
-        return NGX_ERROR;
-    }
-
-    if (p->lcf->preserve_host
-        || uc->url.len > loc->value.len
-        || ngx_rstrncmp(loc->value.data, uc->url.data, uc->url.len) != 0)
-    {
-
-       /*
-        * 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()
-        */
-
-        *location = *loc;
-        return NGX_OK;
-    }
-
-    /* TODO: proxy_reverse */
-
-    r->headers_out.location = location;
-
-    location->key.len = 0;
-    location->key.data = NULL;
-
-    location->value.len = uc->location->len
-                                          + (loc->value.len - uc->url.len) + 1;
-    location->value.data = ngx_palloc(r->pool, location->value.len);
-    if (location->value.data == NULL) {
-        return NGX_ERROR;
-    }
-
-    last = ngx_cpymem(location->value.data,
-                      uc->location->data, uc->location->len);
-
-    ngx_cpystrn(last, loc->value.data + uc->url.len,
-                loc->value.len - uc->url.len + 1);
-
-    return NGX_OK;
-}
deleted file mode 100644
--- a/src/http/modules/proxy/ngx_http_proxy_parse.c
+++ /dev/null
@@ -1,216 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-#include <ngx_http_proxy_handler.h>
-
-
-int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p)
-{
-    u_char   ch;
-    u_char  *pos;
-    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,
-        sw_done
-    } state;
-
-    state = p->parse_state;
-    pos = p->header_in->pos;
-
-    while (pos < p->header_in->last && state < sw_done) {
-        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 - 3;
-            }
-
-            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:
-                state = sw_done;
-                break;
-            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:
-                state = sw_done;
-                break;
-            }
-            break;
-
-        /* end of request line */
-        case sw_almost_done:
-            p->status_end = pos - 2;
-            switch (ch) {
-            case LF:
-                state = sw_done;
-                break;
-            default:
-                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
-            }
-            break;
-
-        /* suppress warning */
-        case sw_done:
-            break;
-        }
-    }
-
-    p->header_in->pos = pos;
-
-    if (state == sw_done) {
-        if (p->status_end == NULL) {
-            p->status_end = pos - 1;
-        }
-
-        p->parse_state = sw_start;
-        return NGX_OK;
-    }
-
-    p->parse_state = state;
-    return NGX_AGAIN;
-}
deleted file mode 100644
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ /dev/null
@@ -1,1646 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_event.h>
-#include <ngx_event_connect.h>
-#include <ngx_event_pipe.h>
-#include <ngx_http.h>
-#include <ngx_http_proxy_handler.h>
-
-
-static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p);
-static void ngx_http_proxy_init_upstream(ngx_http_request_t *r);
-static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p);
-static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p);
-static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p);
-static void ngx_http_proxy_send_request_handler(ngx_event_t *wev);
-static void ngx_http_proxy_dummy_handler(ngx_event_t *wev);
-static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev);
-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_body(ngx_event_t *ev);
-static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p,
-                                         ngx_uint_t ft_type);
-
-
-static ngx_str_t http_methods[] = {
-    ngx_string("GET "),
-    ngx_string("HEAD "),
-    ngx_string("POST ")
-};
-
-
-static char *upstream_header_errors[] = {
-    "upstream sent invalid header",
-    "upstream sent too long header line"
-};
-
-
-static char  http_version[] = " HTTP/1.0" CRLF;
-static char  host_header[] = "Host: ";
-static char  x_url_header[] = "X-URL: http";
-static char  x_real_ip_header[] = "X-Real-IP: ";
-static char  x_forwarded_for_header[] = "X-Forwarded-For: ";
-static char  connection_close_header[] = "Connection: close" CRLF;
-
-
-int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p)
-{
-    int                         rc;
-    ngx_http_request_t         *r;
-    ngx_http_proxy_upstream_t  *u;
-
-    r = p->request;
-
-    u = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_upstream_t));
-    if (u == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    p->upstream = u;
-
-    u->peer.log_error = NGX_ERROR_ERR;
-    u->peer.peers = p->lcf->peers;
-    u->peer.tries = p->lcf->peers->number;
-#if (NGX_THREADS)
-    u->peer.lock = &r->connection->lock;
-#endif
-
-    u->method = r->method;
-
-    rc = ngx_http_read_client_request_body(r, ngx_http_proxy_init_upstream);
-
-    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
-        return rc;
-    }
-
-    return NGX_DONE;
-}
-
-
-static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
-{
-    size_t                           len;
-    ngx_uint_t                       i, escape, *index;
-    ngx_buf_t                       *b;
-    ngx_chain_t                     *chain;
-    ngx_list_part_t                 *part;
-    ngx_table_elt_t                 *header;
-    ngx_http_request_t              *r;
-    ngx_http_variable_t             *var;
-    ngx_http_variable_value_t       *value;
-    ngx_http_core_main_conf_t       *cmcf;
-    ngx_http_proxy_upstream_conf_t  *uc;
-
-    r = p->request;
-    uc = p->lcf->upstream;
-
-#if (NGX_SUPPRESS_WARN)
-    var = NULL;
-    index = NULL;
-#endif
-
-    escape = 0;
-
-    if (p->upstream->method) {
-        len = http_methods[p->upstream->method - 1].len + uc->uri.len;
-
-    } else {
-        len = r->method_name.len + uc->uri.len;
-    }
-
-    if (p->lcf->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 + uc->location->len,
-                                        r->uri.len - uc->location->len,
-                                        NGX_ESCAPE_URI);
-        }
-
-        len += r->uri.len - uc->location->len + escape
-            + sizeof("?") - 1 + r->args.len;
-    }
-
-    len += sizeof(http_version) - 1
-        + sizeof(connection_close_header) - 1
-        + sizeof(CRLF) - 1;
-
-
-    if (p->lcf->set_x_url) {
-        len += sizeof(x_url_header) - 1
-            + sizeof("s://") - 1
-            + r->port_text->len
-            + r->unparsed_uri.len
-            + sizeof(CRLF) - 1;
-
-        if (r->headers_in.host) {
-            len += r->headers_in.host_name_len;
-
-        } else {
-            len += r->server_name.len;
-        }
-
-    }
-
-
-    if (p->lcf->preserve_host) {
-        if (r->headers_in.host) {
-            len += sizeof(host_header) - 1
-                + r->headers_in.host_name_len + sizeof(":") - 1
-                + uc->port_text.len + sizeof(CRLF) - 1;
-
-        } else {
-            len += sizeof(host_header) - 1
-                + r->server_name.len + sizeof(":") - 1
-                + uc->port_text.len + sizeof(CRLF) - 1;
-        }
-
-    } else {
-        len += sizeof(host_header) - 1 + uc->host_header.len
-            + sizeof(CRLF) - 1;
-    }
-
-
-    if (p->lcf->set_x_real_ip) {
-        len += sizeof(x_real_ip_header) - 1 + INET_ADDRSTRLEN - 1
-            + sizeof(CRLF) - 1;
-    }
-
-
-    if (p->lcf->add_x_forwarded_for) {
-        if (r->headers_in.x_forwarded_for) {
-            len += sizeof(x_forwarded_for_header) - 1
-                + r->headers_in.x_forwarded_for->value.len
-                + sizeof(", ") - 1 + INET_ADDRSTRLEN - 1 + sizeof(CRLF) - 1;
-
-        } else {
-            len += sizeof(x_forwarded_for_header) - 1 + INET_ADDRSTRLEN - 1
-                + sizeof(CRLF) - 1;
-        }
-    }
-
-
-    if (p->lcf->x_vars) {
-        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-
-        var = cmcf->variables.elts;
-        index = p->lcf->x_vars->elts;
-
-        for (i = 0; i < p->lcf->x_vars->nelts; i++) {
-
-            value = ngx_http_get_indexed_variable(r, index[i]);
-            if (value == NULL) {
-                continue;
-            }
-
-            if (value->text.len) {
-                len += sizeof("X-") - 1 + var[index[i]].name.len
-                    + sizeof(": ") - 1 + value->text.len + sizeof(CRLF) - 1;
-            }
-        }
-    }
-
-
-    part = &r->headers_in.headers.part;
-    header = part->elts;
-
-    for (i = 0; /* void */; i++) {
-
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
-            }
-
-            part = part->next;
-            header = part->elts;
-            i = 0;
-        }
-
-        if (&header[i] == r->headers_in.host) {
-            continue;
-        }
-
-        if (&header[i] == r->headers_in.connection) {
-            continue;
-        }
-
-        len += header[i].key.len + sizeof(": ") - 1
-            + header[i].value.len + sizeof(CRLF) - 1;
-    }
-
-#if (NGX_DEBUG)
-    len++;
-#endif
-
-    b = ngx_create_temp_buf(r->pool, len);
-    if (b == NULL) {
-        return NULL;
-    }
-
-    chain = ngx_alloc_chain_link(r->pool);
-    if (chain == NULL) {
-        return NULL;
-    }
-
-    chain->buf = b;
-    chain->next = NULL;
-
-
-    /* the request line */
-
-    if (p->upstream->method) {
-        b->last = ngx_cpymem(b->last,
-                             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, uc->uri.data, uc->uri.len);
-
-    if (p->lcf->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 + uc->location->len,
-                           r->uri.len - uc->location->len, NGX_ESCAPE_URI);
-            b->last += r->uri.len - uc->location->len + escape;
-
-        } else {
-            b->last = ngx_cpymem(b->last, r->uri.data + uc->location->len,
-                                 r->uri.len - uc->location->len);
-        }
-
-        if (r->args.len > 0) {
-            *b->last++ = '?';
-            b->last = ngx_cpymem(b->last, r->args.data, r->args.len);
-        }
-    }
-
-    b->last = ngx_cpymem(b->last, http_version, sizeof(http_version) - 1);
-
-
-    /* the "Connection: close" header */
-
-    b->last = ngx_cpymem(b->last, connection_close_header,
-                         sizeof(connection_close_header) - 1);
-
-
-    /* the "Host" header */
-
-    b->last = ngx_cpymem(b->last, host_header, sizeof(host_header) - 1);
-
-    if (p->lcf->preserve_host) {
-        if (r->headers_in.host) {
-            b->last = ngx_cpymem(b->last, r->headers_in.host->value.data,
-                                 r->headers_in.host_name_len);
-        } else {
-            b->last = ngx_cpymem(b->last, r->server_name.data,
-                                 r->server_name.len);
-        }
-
-        if (!uc->default_port) {
-            *b->last++ = ':';
-            b->last = ngx_cpymem(b->last, uc->port_text.data,
-                                 uc->port_text.len);
-        }
-
-    } else {
-        b->last = ngx_cpymem(b->last, uc->host_header.data,
-                             uc->host_header.len);
-    }
-    *b->last++ = CR; *b->last++ = LF;
-
-
-    /* the "X-URL" header */
-
-    if (p->lcf->set_x_url) {
-
-        b->last = ngx_cpymem(b->last, x_url_header,
-                             sizeof(x_url_header) - 1);
-
-#if (NGX_OPENSSL)
-
-        if (r->connection->ssl) {
-            *b->last++ = 's';
-        }
-
-#endif
-
-        *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/';
-
-        if (r->headers_in.host) {
-            b->last = ngx_cpymem(b->last, r->headers_in.host->value.data,
-                                 r->headers_in.host_name_len);
-        } else {
-            b->last = ngx_cpymem(b->last, r->server_name.data,
-                                 r->server_name.len);
-        }
-
-        b->last = ngx_cpymem(b->last, r->port_text->data, r->port_text->len);
-        b->last = ngx_cpymem(b->last, r->unparsed_uri.data,
-                             r->unparsed_uri.len);
-
-        *b->last++ = CR; *b->last++ = LF;
-    }
-
-
-    /* the "X-Real-IP" header */
-
-    if (p->lcf->set_x_real_ip) {
-        b->last = ngx_cpymem(b->last, x_real_ip_header,
-                             sizeof(x_real_ip_header) - 1);
-        b->last = ngx_cpymem(b->last, r->connection->addr_text.data,
-                             r->connection->addr_text.len);
-        *b->last++ = CR; *b->last++ = LF;
-    }
-
-
-    /* the "X-Forwarded-For" header */
-
-    if (p->lcf->add_x_forwarded_for) {
-        if (r->headers_in.x_forwarded_for) {
-            b->last = ngx_cpymem(b->last, x_forwarded_for_header,
-                                 sizeof(x_forwarded_for_header) - 1);
-
-            b->last = ngx_cpymem(b->last,
-                                 r->headers_in.x_forwarded_for->value.data,
-                                 r->headers_in.x_forwarded_for->value.len);
-
-            *b->last++ = ','; *b->last++ = ' ';
-
-        } else {
-            b->last = ngx_cpymem(b->last, x_forwarded_for_header,
-                                 sizeof(x_forwarded_for_header) - 1);
-        }
-
-        b->last = ngx_cpymem(b->last, r->connection->addr_text.data,
-                             r->connection->addr_text.len);
-        *b->last++ = CR; *b->last++ = LF;
-    }
-
-
-    if (p->lcf->x_vars) {
-        for (i = 0; i < p->lcf->x_vars->nelts; i++) {
-
-            value = ngx_http_get_indexed_variable(r, index[i]);
-            if (value == NULL) {
-                continue;
-            }
-
-            if (value->text.len == 0) {
-                continue;
-            }
-
-            *b->last++ = 'X'; *b->last++ = '-';
-
-            b->last = ngx_cpymem(b->last, var[index[i]].name.data,
-                                 var[index[i]].name.len);
-
-            *b->last++ = ':'; *b->last++ = ' ';
-
-            b->last = ngx_cpymem(b->last, value->text.data, value->text.len);
-
-            *b->last++ = CR; *b->last++ = LF;
-        }
-    }
-
-
-    part = &r->headers_in.headers.part;
-    header = part->elts;
-
-    for (i = 0; /* void */; i++) {
-
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
-            }
-
-            part = part->next;
-            header = part->elts;
-            i = 0;
-        }
-
-        if (&header[i] == r->headers_in.host) {
-            continue;
-        }
-
-        if (&header[i] == r->headers_in.connection) {
-            continue;
-        }
-
-        if (&header[i] == r->headers_in.keep_alive) {
-            continue;
-        }
-
-        if (&header[i] == r->headers_in.x_forwarded_for
-            && p->lcf->add_x_forwarded_for)
-        {
-            continue;
-        }
-
-        if (&header[i] == r->headers_in.x_real_ip && p->lcf->set_x_real_ip) {
-            continue;
-        }
-
-        if (&header[i] == r->headers_in.x_url && p->lcf->set_x_url) {
-            continue;
-        }
-
-        b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len);
-
-        *b->last++ = ':'; *b->last++ = ' ';
-
-        b->last = ngx_cpymem(b->last, header[i].value.data,
-                             header[i].value.len);
-
-        *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);
-    }
-
-    /* add "\r\n" at the header end */
-    *b->last++ = CR; *b->last++ = LF;
-
-#if (NGX_DEBUG)
-    *b->last = '\0';
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http proxy header:\n\"%s\"", b->pos);
-#endif
-
-    return chain;
-}
-
-
-static void ngx_http_proxy_init_upstream(ngx_http_request_t *r)
-{
-
-    ngx_chain_t               *cl;
-    ngx_http_proxy_ctx_t      *p;
-    ngx_output_chain_ctx_t    *output;
-    ngx_chain_writer_ctx_t    *writer;
-    ngx_http_proxy_log_ctx_t  *ctx;
-
-    p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                  "http proxy init upstream, client timer: %d",
-                  r->connection->read->timer_set);
-
-    if (r->connection->read->timer_set) {
-        ngx_del_timer(r->connection->read);
-    }
-
-    r->connection->read->event_handler = ngx_http_proxy_check_broken_connection;
-
-    if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
-
-        r->connection->write->event_handler =
-                                        ngx_http_proxy_check_broken_connection;
-
-        if (!r->connection->write->active) {
-            if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT,
-                                                NGX_CLEAR_EVENT) == NGX_ERROR)
-            {
-                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-                return;
-            }
-        }
-    }
-
-
-    cl = ngx_http_proxy_create_request(p);
-    if (cl == NULL) {
-        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-
-    if (r->request_body->bufs) {
-        cl->next = r->request_body->bufs;
-    }
-
-    r->request_body->bufs = cl;
-
-    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_log_ctx_t));
-    if (ctx == NULL) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-    ctx->connection = r->connection->number;
-    ctx->proxy = p;
-
-    p->upstream->peer.log = r->connection->log;
-    p->saved_ctx = r->connection->log->data;
-    p->saved_handler = r->connection->log->handler;
-    r->connection->log->data = ctx;
-    r->connection->log->handler = ngx_http_proxy_log_error;
-    p->action = "connecting to upstream";
-
-    output = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
-    if (output == NULL) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-
-    p->upstream->output_chain_ctx = output;
-
-    output->sendfile = r->connection->sendfile;
-    output->pool = r->pool;
-    output->bufs.num = 1;
-    output->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
-    output->output_filter = ngx_chain_writer;
-
-    writer = ngx_palloc(r->pool, sizeof(ngx_chain_writer_ctx_t));
-    if (writer == NULL) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-
-    output->filter_ctx = writer;
-    writer->pool = r->pool;
-
-#if 0
-    if (p->lcf->busy_lock && p->busy_lock == NULL) {
-#else
-    if (p->lcf->busy_lock && !p->busy_locked) {
-#endif
-        ngx_http_proxy_upstream_busy_lock(p);
-    } else {
-        ngx_http_proxy_connect(p);
-    }
-}
-
-
-static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p)
-{
-    ngx_chain_t             *cl;
-    ngx_output_chain_ctx_t  *output;
-    ngx_http_proxy_state_e   state;
-
-    /* reinit the request chain */
-
-    for (cl = p->request->request_body->bufs; cl; cl = cl->next) {
-        cl->buf->pos = cl->buf->start;
-        cl->buf->file_pos = 0;
-    }
-
-    /* reinit the ngx_output_chain() context */
-
-    output = p->upstream->output_chain_ctx;
-
-    output->buf = NULL;
-    output->in = NULL;
-    output->free = NULL;
-    output->busy = NULL;
-
-    /* reinit r->header_in buffer */
-
-    if (p->header_in) {
-        if (p->cache) {
-            p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
-            p->header_in->last = p->header_in->pos;
-
-        } else {
-            p->header_in->pos = p->header_in->start;
-            p->header_in->last = p->header_in->start;
-        }
-    }
-
-    /* add one more state */
-
-    state = p->state->cache_state;
-
-    p->state = ngx_array_push(&p->states);
-    if (p->state == NULL) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-
-    ngx_memzero(p->state, sizeof(ngx_http_proxy_state_t));
-
-    p->state->cache_state = state; 
-
-    p->status = 0;
-    p->status_count = 0;
-}
-
-
-#if 0
-
-void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p)
-{
-    ngx_int_t  rc;
-
-    rc = ngx_event_busy_lock(p->lcf->busy_lock, p->busy_lock);
-
-    if (rc == NGX_AGAIN) {
-        return;
-    }
-
-    if (rc == NGX_OK) {
-        ngx_http_proxy_connect(p);
-        return;
-    }
-
-    if (rc == NGX_ERROR) {
-        p->state->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-
-    /* rc == NGX_BUSY */
-
-#if (NGX_HTTP_CACHE)
-
-    if (p->busy_lock->timer) {
-        ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING;
-    } else {
-        ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK;
-    }
-
-    if (p->stale && (p->lcf->use_stale & ft_type)) {
-        ngx_http_proxy_finalize_request(p,
-                                        ngx_http_proxy_send_cached_response(p));
-        return;
-    }
-
-#endif
-
-    p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE;
-    ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE);
-}
-
-#endif
-
-
-#if 1
-
-void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p)
-{
-    ngx_int_t  rc;
-#if (NGX_HTTP_CACHE)
-    ngx_int_t  ft_type;
-#endif
-
-    if (p->busy_lock.time == 0) {
-        p->busy_lock.event = p->request->connection->read;
-        p->busy_lock.event_handler = ngx_http_proxy_busy_lock_handler;
-    }
-
-    rc = ngx_http_busy_lock(p->lcf->busy_lock, &p->busy_lock);
-
-    if (rc == NGX_AGAIN) {
-        return;
-    }
-
-    if (rc == NGX_OK) {
-        ngx_http_proxy_connect(p);
-        return;
-    }
-
-    ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
-
-#if (NGX_HTTP_CACHE)
-
-    if (rc == NGX_DONE) {
-        ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK;
-
-    } else {
-        /* rc == NGX_ERROR */
-        ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING;
-    }
-
-    if (p->stale && (p->lcf->use_stale & ft_type)) {
-        ngx_http_proxy_finalize_request(p,
-                                        ngx_http_proxy_send_cached_response(p));
-        return;
-    }
-
-#endif
-
-    p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE;
-    ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE);
-}
-
-#endif
-
-
-static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p)
-{
-    ngx_int_t                rc;
-    ngx_connection_t        *c;
-    ngx_http_request_t      *r;
-    ngx_output_chain_ctx_t  *output;
-    ngx_chain_writer_ctx_t  *writer;
-
-    p->action = "connecting to upstream";
-
-    p->request->connection->single_connection = 0;
-
-    rc = ngx_event_connect_peer(&p->upstream->peer);
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
-                   "http proxy connect: %i", rc);
-
-    if (rc == NGX_ERROR) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-
-    p->state->peer =
-               &p->upstream->peer.peers->peer[p->upstream->peer.cur_peer].name;
-
-    if (rc == NGX_CONNECT_ERROR) {
-        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
-        return;
-    }
-
-    r = p->request;
-    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->sendfile = r->connection->sendfile;
-
-    c->pool = r->pool;
-    c->read->log = c->write->log = c->log = r->connection->log;
-
-    /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
-
-    output = p->upstream->output_chain_ctx;
-    writer = output->filter_ctx;
-    writer->out = NULL;
-    writer->last = &writer->out;
-    writer->connection = c;
-    writer->limit = 0;
-
-    if (p->request_sent) {
-        ngx_http_proxy_reinit_upstream(p);
-    }
-
-    if (r->request_body->buf) {
-        if (r->request_body->temp_file) {
-
-            output->free = ngx_alloc_chain_link(r->pool);
-            if (output->free == NULL) {
-                ngx_http_proxy_finalize_request(p,
-                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
-                return;
-            }
-
-            output->free->buf = r->request_body->buf;
-            output->free->next = NULL;
-            output->allocated = 1;
-
-            r->request_body->buf->pos = r->request_body->buf->start;
-            r->request_body->buf->last = r->request_body->buf->start;
-            r->request_body->buf->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
-
-        } else {
-            r->request_body->buf->pos = r->request_body->buf->start;
-        }
-    }
-
-    p->request_sent = 0;
-
-    if (rc == NGX_AGAIN) {
-        ngx_add_timer(c->write, p->lcf->connect_timeout);
-        return;
-    }
-
-    /* rc == NGX_OK */
-
-#if 0 /* test only, see below about "post aio operation" */
-
-    if (c->read->ready) {
-        /* post aio operation */
-        ngx_http_proxy_process_upstream_status_line(c->read);
-#if 0
-        return;
-#endif
-    }
-
-#endif
-
-    ngx_http_proxy_send_request(p);
-}
-
-
-static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p)
-{
-    int                rc;
-    ngx_connection_t  *c;
-
-    c = p->upstream->peer.connection;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                   "http proxy send request");
-
-#if (NGX_HAVE_KQUEUE)
-
-    if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT)
-        && !p->request_sent
-        && c->write->pending_eof)
-    {
-        ngx_log_error(NGX_LOG_ERR, c->log, c->write->kq_errno,
-                      "connect() failed");
-
-        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
-        return;
-    }
-
-#endif
-
-    p->action = "sending request to upstream";
-
-    rc = ngx_output_chain(p->upstream->output_chain_ctx,
-                          p->request_sent ? NULL:
-                                            p->request->request_body->bufs);
-
-    p->request_sent = 1;
-
-    if (rc == NGX_ERROR) {
-        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
-        return;
-    }
-
-    if (c->write->timer_set) {
-        ngx_del_timer(c->write);
-    }
-
-    if (rc == NGX_AGAIN) {
-        ngx_add_timer(c->write, p->lcf->send_timeout);
-
-        if (ngx_handle_write_event(c->write, p->lcf->send_lowat) == NGX_ERROR) {
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return;
-        }
-
-        return;
-    }
-
-    /* rc == NGX_OK */
-
-    if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
-        if (ngx_tcp_push(c->fd) == NGX_ERROR) {
-            ngx_log_error(NGX_LOG_CRIT, c->log,
-                          ngx_socket_errno,
-                          ngx_tcp_push_n " failed");
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return; 
-        }
-
-        c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
-        return;
-    }
-
-    ngx_add_timer(c->read, p->lcf->read_timeout);
-
-#if 1
-    if (c->read->ready) {
-
-        /* post aio operation */
-
-        /*
-         * although we can post aio operation just in the end
-         * of ngx_http_proxy_connect() CHECK IT !!!
-         * it's better to do here because we postpone header buffer allocation
-         */
-
-        ngx_http_proxy_process_upstream_status_line(c->read);
-        return;
-    }
-#endif
-
-    c->write->event_handler = ngx_http_proxy_dummy_handler;
-
-    if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-}
-
-
-static void ngx_http_proxy_send_request_handler(ngx_event_t *wev)
-{
-    ngx_connection_t      *c;
-    ngx_http_proxy_ctx_t  *p;
-
-    c = wev->data;
-    p = c->data;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
-                   "http proxy send request handler");
-
-    if (wev->timedout) {
-        p->action = "sending request to upstream";
-        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
-        return;
-    }
-
-    if (p->request->connection->write->eof
-        && (!p->cachable || !p->request_sent))
-    {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
-        return;
-    }
-
-    ngx_http_proxy_send_request(p);
-}
-
-
-static void ngx_http_proxy_dummy_handler(ngx_event_t *wev)
-{
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http proxy dummy handler");
-}
-
-
-static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
-{
-    int                    rc;
-    ssize_t                n;
-    ngx_connection_t      *c;
-    ngx_http_proxy_ctx_t  *p;
-
-    c = rev->data;
-    p = c->data;
-    p->action = "reading upstream status line";
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
-                   "http proxy process status line");
-
-    if (rev->timedout) {
-        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
-        return;
-    }
-
-    if (p->header_in == NULL) {
-        p->header_in = ngx_create_temp_buf(p->request->pool,
-                                           p->lcf->header_buffer_size);
-        if (p->header_in == NULL) {
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return;
-        }
-        p->header_in->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
-
-        if (p->cache) {
-            p->header_in->pos += p->cache->ctx.header_size;
-            p->header_in->last = p->header_in->pos;
-        }
-    }
-
-    n = ngx_http_proxy_read_upstream_header(p);
-
-    if (n == NGX_AGAIN) {
-        return;
-    }
-
-    if (n == 0) {
-        ngx_log_error(NGX_LOG_ERR, rev->log, 0,
-                      "upstream prematurely closed connection");
-    }
-
-    if (n == NGX_ERROR || n == 0) {
-        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
-        return;
-    }
-
-    p->valid_header_in = 0;
-
-    p->upstream->peer.cached = 0;
-
-    rc = ngx_http_proxy_parse_status_line(p);
-
-    if (rc == NGX_AGAIN) {
-        if (p->header_in->pos == p->header_in->end) {
-            ngx_log_error(NGX_LOG_ERR, rev->log, 0,
-                          "upstream sent too long status line");
-            ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
-        }
-        return;
-    }
-
-    if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
-        ngx_log_error(NGX_LOG_ERR, rev->log, 0,
-                      "upstream sent no valid HTTP/1.0 header");
-
-        if (p->accel) {
-            ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
-
-        } else {
-            p->request->http_version = NGX_HTTP_VERSION_9;
-            p->upstream->status = NGX_HTTP_OK;
-            ngx_http_proxy_send_response(p);
-        }
-
-        return;
-    }
-
-    /* rc == NGX_OK */
-
-    p->upstream->status = p->status;
-    p->state->status = p->status;
-
-    if (p->status == NGX_HTTP_INTERNAL_SERVER_ERROR) {
-
-        if (p->upstream->peer.tries > 1
-            && (p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_500))
-        {
-            ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_500);
-            return;
-        }
-
-#if (NGX_HTTP_CACHE)
-
-        if (p->upstream->peer.tries == 0
-            && p->stale
-            && (p->lcf->use_stale & NGX_HTTP_PROXY_FT_HTTP_500))
-        {
-            ngx_http_proxy_finalize_request(p,
-                                       ngx_http_proxy_send_cached_response(p));
-
-            return;
-        }
-
-#endif
-    }
-
-    if (p->status == NGX_HTTP_NOT_FOUND
-        && p->upstream->peer.tries > 1
-        && p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_404)
-    {
-        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_404);
-        return;
-    }
-
-    /* TODO: "proxy_error_page" */
-
-    p->upstream->status_line.len = p->status_end - p->status_start;
-    p->upstream->status_line.data = ngx_palloc(p->request->pool,
-                                              p->upstream->status_line.len + 1);
-    if (p->upstream->status_line.data == NULL) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-    ngx_cpystrn(p->upstream->status_line.data, p->status_start,
-                p->upstream->status_line.len + 1);
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
-                   "http proxy status %ui \"%V\"",
-                   p->upstream->status, &p->upstream->status_line);
-
-
-    /* init or reinit the p->upstream->headers_in.headers table */
-
-    if (p->upstream->headers_in.headers.part.elts) {
-        p->upstream->headers_in.headers.part.nelts = 0;
-        p->upstream->headers_in.headers.part.next = NULL;
-        p->upstream->headers_in.headers.last =
-                                         &p->upstream->headers_in.headers.part;
-
-        ngx_memzero(&p->upstream->headers_in.date,
-                    sizeof(ngx_http_proxy_headers_in_t) - sizeof(ngx_list_t));
-
-    } else {
-        if (ngx_list_init(&p->upstream->headers_in.headers, p->request->pool,
-                                     20, sizeof(ngx_table_elt_t)) == NGX_ERROR)
-        {
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return;
-        }
-    }
-
-
-    c->read->event_handler = ngx_http_proxy_process_upstream_headers;
-    ngx_http_proxy_process_upstream_headers(rev);
-}
-
-
-static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev)
-{
-    int                    i, rc;
-    ssize_t                n;
-    ngx_table_elt_t       *h;
-    ngx_connection_t      *c;
-    ngx_http_request_t    *r;
-    ngx_http_proxy_ctx_t  *p;
-
-    c = rev->data;
-    p = c->data;
-    r = p->request;
-    p->action = "reading upstream headers";
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
-                   "http proxy process header line");
-
-    if (rev->timedout) {
-        ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
-        return;
-    }
-
-    rc = NGX_AGAIN;
-
-    for ( ;; ) {
-        if (rc == NGX_AGAIN) {
-            n = ngx_http_proxy_read_upstream_header(p);
-
-            if (n == 0) {
-                ngx_log_error(NGX_LOG_ERR, rev->log, 0,
-                              "upstream prematurely closed connection");
-            }
-
-            if (n == NGX_ERROR || n == 0) {
-                ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
-                return;
-            }
-
-            if (n == NGX_AGAIN) {
-                return;
-            }
-        }
-
-        rc = ngx_http_parse_header_line(p->request, p->header_in);
-
-        if (rc == NGX_OK) {
-
-            /* a header line has been parsed successfully */
-
-            h = ngx_list_push(&p->upstream->headers_in.headers);
-            if (h == NULL) {
-                ngx_http_proxy_finalize_request(p,
-                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
-                return;
-            }
-
-            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(p->request->pool,
-                                     h->key.len + 1 + h->value.len + 1);
-            if (h->key.data == NULL) {
-                ngx_http_proxy_finalize_request(p,
-                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
-                return;
-            }
-
-            h->value.data = h->key.data + h->key.len + 1;
-            ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
-            ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
-
-            for (i = 0; ngx_http_proxy_headers_in[i].name.len != 0; i++) {
-                if (ngx_http_proxy_headers_in[i].name.len != h->key.len) {
-                    continue;
-                }
-
-                if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data,
-                                                           h->key.data) == 0)
-                {
-                    *((ngx_table_elt_t **) ((char *) &p->upstream->headers_in
-                                   + ngx_http_proxy_headers_in[i].offset)) = h;
-                    break;
-                }
-            }
-
-            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                           "http proxy header: \"%V: %V\"", &h->key, &h->value);
-
-            continue;
-
-        } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
-
-            /* a whole header has been parsed successfully */
-
-            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
-                           "http proxy header done");
-
-            /* TODO: hook to process the upstream header */
-
-#if (NGX_HTTP_CACHE)
-
-            if (p->cachable) {
-                p->cachable = ngx_http_proxy_is_cachable(p);
-            }
-
-#endif
-
-            ngx_http_proxy_send_response(p);
-            return;
-
-        } else if (rc != NGX_AGAIN) {
-
-            /* there was error while a header line parsing */
-
-            ngx_log_error(NGX_LOG_ERR, rev->log, 0,
-                      upstream_header_errors[rc - NGX_HTTP_PARSE_HEADER_ERROR]);
-
-            ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
-            return;
-        }
-
-        /* rc == NGX_AGAIN: a header line parsing is still not complete */
-
-        if (p->header_in->last == p->header_in->end) {
-            ngx_log_error(NGX_LOG_ERR, rev->log, 0,
-                          "upstream sent too big header");
-
-            ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
-            return;
-        }
-    }
-}
-
-
-static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p)
-{
-    ssize_t       n;
-    ngx_event_t  *rev;
-
-    rev = p->upstream->peer.connection->read;
-
-    n = p->header_in->last - p->header_in->pos;
-
-    if (n > 0) {
-        return n;
-    }
-
-    n = ngx_recv(p->upstream->peer.connection, p->header_in->last,
-                 p->header_in->end - p->header_in->last);
-
-    if (n == NGX_AGAIN) {
-#if 0
-        ngx_add_timer(rev, p->lcf->read_timeout);
-#endif
-
-        if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
-            ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return NGX_ERROR;
-        }
-
-        return NGX_AGAIN;
-    }
-
-    if (n == 0) {
-        ngx_log_error(NGX_LOG_ERR, rev->log, 0,
-                      "upstream closed prematurely connection");
-    }
-
-    if (n == 0 || n == NGX_ERROR) {
-        return NGX_ERROR;
-    }
-
-    p->header_in->last += n;
-
-    return n;
-}
-
-
-static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p)
-{
-    int                           rc;
-    ngx_event_pipe_t             *ep;
-    ngx_http_request_t           *r;
-    ngx_http_cache_header_t      *header;
-    ngx_http_core_loc_conf_t     *clcf;
-
-    r = p->request;
-
-    r->headers_out.status = p->upstream->status;
-    r->headers_out.status_line = p->upstream->status_line;
-
-#if 0
-    r->headers_out.content_length_n = -1;
-    r->headers_out.content_length = NULL;
-#endif
-
-    /* copy an upstream header to r->headers_out */
-
-    if (ngx_http_proxy_copy_header(p, &p->upstream->headers_in) == NGX_ERROR) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
-        return;
-    }
-
-    /* TODO: preallocate event_pipe bufs, look "Content-Length" */
-
-    rc = ngx_http_send_header(r);
-
-    if (rc == NGX_ERROR || rc > NGX_OK) {
-        ngx_http_proxy_finalize_request(p, rc);
-        return;
-    }
-
-    p->header_sent = 1;
-
-    if (p->cache && p->cache->ctx.file.fd != NGX_INVALID_FILE) {
-        if (ngx_close_file(p->cache->ctx.file.fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
-                          ngx_close_file_n " \"%s\" failed",
-                          p->cache->ctx.file.name.data);
-        }
-    }
-
-    if (p->cachable) {
-        header = (ngx_http_cache_header_t *) p->header_in->start;
-
-        header->expires = p->cache->ctx.expires;
-        header->last_modified = p->cache->ctx.last_modified;
-        header->date = p->cache->ctx.date;
-        header->length = r->headers_out.content_length_n;
-        p->cache->ctx.length = r->headers_out.content_length_n;
-
-        header->key_len = p->cache->ctx.key0.len;
-        ngx_memcpy(&header->key, p->cache->ctx.key0.data, header->key_len);
-        header->key[header->key_len] = LF;
-    }
-
-    ep = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
-    if (ep == NULL) {
-        ngx_http_proxy_finalize_request(p, 0);
-        return;
-    }
-
-    p->upstream->event_pipe = ep;
-
-    ep->input_filter = ngx_event_pipe_copy_input_filter;
-    ep->output_filter = (ngx_event_pipe_output_filter_pt)
-                                                        ngx_http_output_filter;
-    ep->output_ctx = r;
-    ep->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
-    ep->bufs = p->lcf->bufs;
-    ep->busy_size = p->lcf->busy_buffers_size;
-    ep->upstream = p->upstream->peer.connection;
-    ep->downstream = r->connection;
-    ep->pool = r->pool;
-    ep->log = r->connection->log;
-
-    ep->cachable = p->cachable;
-
-    ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
-    if (ep->temp_file == NULL) {
-        ngx_http_proxy_finalize_request(p, 0);
-        return;
-    }
-
-    ep->temp_file->file.fd = NGX_INVALID_FILE;
-    ep->temp_file->file.log = r->connection->log;
-    ep->temp_file->path = p->lcf->temp_path;
-    ep->temp_file->pool = r->pool;
-
-    if (p->cachable) {
-        ep->temp_file->persistent = 1;
-    } else {
-        ep->temp_file->warn = "an upstream response is buffered "
-                              "to a temporary file";
-    }
-
-    ep->max_temp_file_size = p->lcf->max_temp_file_size;
-    ep->temp_file_write_size = p->lcf->temp_file_write_size;
-
-    ep->preread_bufs = ngx_alloc_chain_link(r->pool);
-    if (ep->preread_bufs == NULL) {
-        ngx_http_proxy_finalize_request(p, 0);
-        return;
-    }
-    ep->preread_bufs->buf = p->header_in;
-    ep->preread_bufs->next = NULL;
-    p->header_in->recycled = 1;
-
-    ep->preread_size = p->header_in->last - p->header_in->pos;
-
-    if (p->cachable) {
-        ep->buf_to_file = ngx_calloc_buf(r->pool);
-        if (ep->buf_to_file == NULL) {
-            ngx_http_proxy_finalize_request(p, 0);
-            return;
-        }
-        ep->buf_to_file->pos = p->header_in->start;
-        ep->buf_to_file->last = p->header_in->pos;
-        ep->buf_to_file->temporary = 1;
-    }
-
-    if (ngx_event_flags & NGX_USE_AIO_EVENT) {
-        /* the posted aio operation can currupt a shadow buffer */
-        ep->single_buf = 1;
-    }
-
-    /* TODO: ep->free_bufs = 0 if use ngx_create_chain_of_bufs() */
-    ep->free_bufs = 1;
-
-    /*
-     * event_pipe would do p->header_in->last += ep->preread_size
-     * as though these bytes were read.
-     */
-    p->header_in->last = p->header_in->pos;
-
-    if (p->lcf->cyclic_temp_file) {
-
-        /*
-         * we need to disable the use of sendfile() if we use cyclic temp file
-         * because the writing a new data can interfere with sendfile()
-         * that uses the same kernel file pages (at least on FreeBSD)
-         */
-
-        ep->cyclic_temp_file = 1;
-        r->connection->sendfile = 0;
-
-    } else {
-        ep->cyclic_temp_file = 0;
-    }
-
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
-    ep->read_timeout = p->lcf->read_timeout;
-    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;
-
-    ngx_http_proxy_process_body(p->upstream->peer.connection->read);
-
-    return;
-}
-
-
-static void ngx_http_proxy_process_body(ngx_event_t *ev)
-{
-    ngx_connection_t      *c;
-    ngx_http_request_t    *r;
-    ngx_http_proxy_ctx_t  *p;
-    ngx_event_pipe_t      *ep;
-
-    c = ev->data;
-
-    if (ev->write) {
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
-                       "http proxy process downstream");
-        r = c->data;
-        p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
-        p->action = "sending to client";
-
-    } else {
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
-                       "http proxy process upstream");
-        p = c->data;
-        p->action = "reading upstream body";
-    }
-
-    ep = p->upstream->event_pipe;
-
-    if (ev->timedout) {
-        if (ev->write) {
-            ep->downstream_error = 1;
-            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                          "client timed out");
-
-        } else {
-            ep->upstream_error = 1;
-            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                          "upstream timed out");
-        }
-
-    } else {
-        if (ngx_event_pipe(ep, ev->write) == NGX_ABORT) {
-            ngx_http_proxy_finalize_request(p, 0);
-            return;
-        }
-    }
-
-    if (p->upstream->peer.connection) {
-
-#if (NGX_HTTP_FILE_CACHE)
-
-        if (ep->upstream_done && p->cachable) {
-            if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
-                ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
-                ngx_http_proxy_finalize_request(p, 0);
-                return;
-            }
-
-        } else if (ep->upstream_eof && p->cachable) {
-
-            /* TODO: check length & update cache */
-
-            if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
-                ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
-                ngx_http_proxy_finalize_request(p, 0);
-                return;
-            }
-        }
-
-#endif
-
-        if (ep->upstream_done || ep->upstream_eof || ep->upstream_error) {
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
-                           "http proxy upstream exit: %p", ep->out);
-            ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
-            ngx_http_proxy_finalize_request(p, 0);
-            return;
-        }
-    }
-
-    if (ep->downstream_error) {
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
-                       "http proxy downstream error");
-        if (!p->cachable && p->upstream->peer.connection) {
-            ngx_http_proxy_finalize_request(p, 0);
-        }
-    }
-}
-
-
-static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p,
-                                         ngx_uint_t ft_type)
-{
-    ngx_uint_t  status;
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
-                   "http proxy next upstream: %ui", ft_type);
-
-    ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
-
-    if (ft_type != NGX_HTTP_PROXY_FT_HTTP_404) {
-        ngx_event_connect_peer_failed(&p->upstream->peer);
-    }
-
-    if (ft_type == NGX_HTTP_PROXY_FT_TIMEOUT) {
-        ngx_log_error(NGX_LOG_ERR, p->request->connection->log, NGX_ETIMEDOUT,
-                      "upstream timed out");
-    }
-
-    if (p->upstream->peer.cached && ft_type == NGX_HTTP_PROXY_FT_ERROR) {
-        status = 0;
-
-    } else {
-        switch(ft_type) {
-        case NGX_HTTP_PROXY_FT_TIMEOUT:
-            status = NGX_HTTP_GATEWAY_TIME_OUT;
-            break;
-
-        case NGX_HTTP_PROXY_FT_HTTP_500:
-            status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-            break;
-
-        case NGX_HTTP_PROXY_FT_HTTP_404:
-            status = NGX_HTTP_NOT_FOUND;
-            break;
-
-        /*
-         * NGX_HTTP_PROXY_FT_BUSY_LOCK and NGX_HTTP_PROXY_FT_MAX_WAITING
-         * never reach here
-         */
-
-        default:
-            status = NGX_HTTP_BAD_GATEWAY;
-        }
-    }
-
-    if (p->upstream->peer.connection) {
-        ngx_http_proxy_close_connection(p);
-    }
-
-    if (p->request->connection->write->eof) {
-        ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
-        return;
-    }
-
-    if (status) {
-        p->state->status = status;
-
-        if (p->upstream->peer.tries == 0 || !(p->lcf->next_upstream & ft_type))
-        {
-
-#if (NGX_HTTP_CACHE)
-
-            if (p->stale && (p->lcf->use_stale & ft_type)) {
-                ngx_http_proxy_finalize_request(p,
-                                       ngx_http_proxy_send_cached_response(p));
-                return;
-            }
-
-#endif
-
-            ngx_http_proxy_finalize_request(p, status);
-            return;
-        }
-    }
-
-    if (p->lcf->busy_lock && !p->busy_locked) {
-        ngx_http_proxy_upstream_busy_lock(p);
-    } else {
-        ngx_http_proxy_connect(p);
-    }
-}
--- 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/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