changeset 629:65bf042c0b4f release-0.3.36

nginx-0.3.36-RELEASE import *) Feature: the ngx_http_addition_filter_module. *) Feature: the "proxy_pass" and "fastcgi_pass" directives may be used inside the "if" block. *) Feature: the "proxy_ignore_client_abort" and "fastcgi_ignore_client_abort" directives. *) Feature: the "$request_completion" variable. *) Feature: the ngx_http_perl_module supports the $r->request_method and $r->remote_addr. *) Feature: the ngx_http_ssi_module supports the "elif" command. *) Bugfix: the "\/" string in the expression of the "if" command of the ngx_http_ssi_module was treated incorrectly. *) Bugfix: in the regular expressions in the "if" command of the ngx_http_ssi_module. *) Bugfix: if the relative path was specified in the "client_body_temp_path", "proxy_temp_path", "fastcgi_temp_path", and "perl_modules" directives, then the directory was used relatively to a current path but not to a server prefix.
author Igor Sysoev <igor@sysoev.ru>
date Wed, 05 Apr 2006 13:40:54 +0000
parents b338276e1aab
children 375dab4fd227
files auto/modules auto/options auto/os/linux auto/sources docs/xml/nginx/changes.xml src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_file.c src/core/ngx_palloc.c src/http/modules/ngx_http_addition_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_memcached_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssi_filter_module.h src/http/modules/perl/nginx.xs src/http/modules/perl/ngx_http_perl_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_request.c src/http/ngx_http_request.h src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h src/http/ngx_http_variables.c
diffstat 29 files changed, 576 insertions(+), 4574 deletions(-) [+]
line wrap: on
line diff
--- a/auto/modules
+++ b/auto/modules
@@ -78,6 +78,7 @@ fi
 #     ngx_http_postpone_filter
 #     ngx_http_charset_filter
 #     ngx_http_ssi_filter
+#         ngx_http_addition_filter
 #         ngx_http_userid_filter
 #         ngx_http_headers_filter
 #     ngx_http_copy_filter
@@ -114,6 +115,11 @@ if [ $HTTP_SSI = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_SSI_SRCS"
 fi
 
+if [ $HTTP_ADDITION = YES ]; then
+    HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_ADDITION_FILTER_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_ADDITION_SRCS"
+fi
+
 if [ $HTTP_USERID = YES ]; then
     HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_USERID_FILTER_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_USERID_SRCS"
--- a/auto/options
+++ b/auto/options
@@ -52,6 +52,7 @@ HTTP_SSL=NO
 HTTP_SSI=YES
 HTTP_POSTPONE=NO
 HTTP_REALIP=NO
+HTTP_ADDITION=NO
 HTTP_ACCESS=YES
 HTTP_AUTH_BASIC=YES
 HTTP_USERID=YES
@@ -139,6 +140,7 @@ do
 
         --with-http_ssl_module)          HTTP_SSL=YES               ;;
         --with-http_realip_module)       HTTP_REALIP=YES            ;;
+        --with-http_addition_module)     HTTP_ADDITION=YES          ;;
         --without-http_charset_module)   HTTP_CHARSET=NO            ;;
         --without-http_gzip_module)      HTTP_GZIP=NO               ;;
         --without-http_ssi_module)       HTTP_SSI=NO                ;;
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -59,7 +59,7 @@ fi
 
 # sendfile()
 
-CC_AUX_FLAGS="-D_GNU_SOURCE"
+CC_AUX_FLAGS="$CC_AUX_FLAGS -D_GNU_SOURCE"
 ngx_feature="sendfile()"
 ngx_feature_name="NGX_HAVE_SENDFILE"
 ngx_feature_run=yes
@@ -79,7 +79,7 @@ fi
 
 # sendfile64()
 
-CC_AUX_FLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64"
+CC_AUX_FLAGS="$CC_AUX_FLAGS -D_FILE_OFFSET_BITS=64"
 ngx_feature="sendfile64()"
 ngx_feature_name="NGX_HAVE_SENDFILE64"
 ngx_feature_run=yes
--- a/auto/sources
+++ b/auto/sources
@@ -319,6 +319,10 @@ HTTP_REALIP_MODULE=ngx_http_realip_modul
 HTTP_REALIP_SRCS=src/http/modules/ngx_http_realip_module.c
 
 
+HTTP_ADDITION_FILTER_MODULE=ngx_http_addition_filter_module
+HTTP_ADDITION_SRCS=src/http/modules/ngx_http_addition_filter_module.c
+
+
 HTTP_ACCESS_MODULE=ngx_http_access_module
 HTTP_ACCESS_SRCS=src/http/modules/ngx_http_access_module.c
 
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -9,6 +9,102 @@
 <title lang="en">nginx changelog</title>
 
 
+<changes ver="0.3.36" date="05.04.2006">
+
+<change type="feature">
+<para lang="ru">
+модуль ngx_http_addition_filter_module.
+</para>
+<para lang="en">
+the ngx_http_addition_filter_module.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директивы proxy_pass и fastcgi_pass можно использовать внутри блока if.
+</para>
+<para lang="en">
+the "proxy_pass" and "fastcgi_pass" directives may be used inside
+the "if" block.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директивы proxy_ignore_client_abort и fastcgi_ignore_client_abort.
+</para>
+<para lang="en">
+the "proxy_ignore_client_abort" and "fastcgi_ignore_client_abort" directives.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+переменная $request_completion.
+</para>
+<para lang="en">
+the "$request_completion" variable.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+модуль ngx_http_perl_module поддерживает методы $r->request_method и
+$r->remote_addr.
+</para>
+<para lang="en">
+the ngx_http_perl_module supports the $r->request_method and $r->remote_addr.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+модуль ngx_http_ssi_module поддерживает команду elif.
+</para>
+<para lang="en">
+the ngx_http_ssi_module supports the "elif" command.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+строка "\/" в начале выражения команды if модуля ngx_http_ssi_module
+воспринималась неверно.
+</para>
+<para lang="en">
+the "\/" string in the expression of the "if" command of the
+ngx_http_ssi_module was treated incorrectly.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в использовании регулярных выражениях в команде if модуля ngx_http_ssi_module.
+</para>
+<para lang="en">
+in the regular expressions in the "if" command of the ngx_http_ssi_module.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при задании относительного пути в директивах
+client_body_temp_path, proxy_temp_path, fastcgi_temp_path и perl_modules
+использовался каталог относительно текущего каталога, а не относительно
+префикса сервера.
+</para>
+<para lang="en">
+if the relative path was specified in the "client_body_temp_path",
+"proxy_temp_path", "fastcgi_temp_path", and "perl_modules" directives,
+then the directory was used relatively to a current path but not
+to a server prefix.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="0.3.35" date="22.03.2006">
 
 <change type="bugfix">
@@ -64,7 +160,7 @@ the "http_503" parameter of the "proxy_n
 
 <change type="bugfix">
 <para lang="ru">
-ngx_http_perl_module не работал со встроенным в конфигурацинный файл кодом,
+ngx_http_perl_module не работал со встроенным в конфигурационный файл кодом,
 если он не начинался сразу же с "sub".
 </para>
 <para lang="en">
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.35"
+#define NGINX_VER          "nginx/0.3.36"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -63,6 +63,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t
     char             *rv;
     ngx_fd_t          fd;
     ngx_int_t         rc;
+    ngx_buf_t        *b;
     ngx_uint_t        block;
     ngx_conf_file_t  *prev;
 
@@ -95,11 +96,23 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t
                           ngx_fd_info_n " \"%s\" failed", filename->data);
         }
 
-        cf->conf_file->buffer = ngx_create_temp_buf(cf->pool, ngx_pagesize);
-        if (cf->conf_file->buffer == NULL) {
+        b = ngx_calloc_buf(cf->pool);
+        if (b == NULL) {
             return NGX_CONF_ERROR;
         }
 
+        cf->conf_file->buffer = b;
+
+        b->start = ngx_alloc(ngx_pagesize, cf->log);
+        if (b->start == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        b->pos = b->start;
+        b->last = b->start;
+        b->end = b->last + ngx_pagesize;
+        b->temporary = 1;
+
         cf->conf_file->file.fd = fd;
         cf->conf_file->file.name.len = filename->len;
         cf->conf_file->file.name.data = filename->data;
@@ -183,7 +196,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t
 
 
     if (filename) {
-        ngx_pfree(cf->pool, cf->conf_file->buffer->start);
+        ngx_free(cf->conf_file->buffer->start);
 
         cf->conf_file = prev;
 
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -211,8 +211,8 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n
     char  *p = conf;
 
     ssize_t      level;
+    ngx_str_t   *value;
     ngx_uint_t   i, n;
-    ngx_str_t   *value;
     ngx_path_t  *path, **slot;
 
     slot = (ngx_path_t **) (p + cmd->offset);
@@ -229,6 +229,11 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n
     value = cf->args->elts;
 
     path->name = value[1];
+
+    if (ngx_conf_full_name(cf->cycle, &path->name) == NGX_ERROR) {
+        return NULL;
+    }
+
     path->len = 0;
     path->cleaner = (ngx_gc_handler_pt) cmd->post;
     path->conf_file = cf->conf_file->file.name.data;
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -86,7 +86,7 @@ ngx_palloc(ngx_pool_t *pool, size_t size
 {
     u_char            *m;
     ngx_pool_t        *p, *n;
-    ngx_pool_large_t  *large, *last;
+    ngx_pool_large_t  *large;
 
     if (size <= (size_t) NGX_MAX_ALLOC_FROM_POOL
         && size <= (size_t) (pool->end - (u_char *) pool)
@@ -134,34 +134,6 @@ ngx_palloc(ngx_pool_t *pool, size_t size
         return m;
     }
 
-    /* allocate a large block */
-
-    large = NULL;
-    last = NULL;
-
-    if (pool->large) {
-        for (last = pool->large; /* void */ ; last = last->next) {
-            if (last->alloc == NULL) {
-                large = last;
-                last = NULL;
-                break;
-            }
-
-            if (last->next == NULL) {
-                break;
-            }
-        }
-    }
-
-    if (large == NULL) {
-        large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
-        if (large == NULL) {
-            return NULL;
-        }
-
-        large->next = NULL;
-    }
-
 #if 0
     p = ngx_memalign(ngx_pagesize, size, pool->log);
     if (p == NULL) {
@@ -174,14 +146,14 @@ ngx_palloc(ngx_pool_t *pool, size_t size
     }
 #endif
 
-    if (pool->large == NULL) {
-        pool->large = large;
-
-    } else if (last) {
-        last->next = large;
+    large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
+    if (large == NULL) {
+        return NULL;
     }
 
     large->alloc = p;
+    large->next = pool->large;
+    pool->large = large;
 
     return p;
 }
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_addition_filter_module.c
@@ -0,0 +1,228 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+    ngx_str_t   before_body;
+    ngx_str_t   after_body;
+} ngx_http_addition_conf_t;
+
+
+typedef struct {
+    unsigned    before_body_sent:1;
+    unsigned    after_body_sent:1;
+} ngx_http_addition_ctx_t;
+
+
+static ngx_int_t ngx_http_addition_filter_init(ngx_cycle_t *cycle);
+static void *ngx_http_addition_create_conf(ngx_conf_t *cf);
+static char *ngx_http_addition_merge_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+
+
+static ngx_command_t  ngx_http_addition_commands[] = {
+
+    { ngx_string("add_before_body"),
+      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_addition_conf_t, before_body),
+      NULL },
+
+    { ngx_string("add_after_body"),
+      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_addition_conf_t, after_body),
+      NULL },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_addition_filter_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_addition_create_conf,         /* create location configuration */
+    ngx_http_addition_merge_conf           /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_addition_filter_module = {
+    NGX_MODULE_V1,
+    &ngx_http_addition_filter_module_ctx,  /* module context */
+    ngx_http_addition_commands,            /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    ngx_http_addition_filter_init,         /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
+static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
+
+
+static ngx_int_t
+ngx_http_addition_header_filter(ngx_http_request_t *r)
+{
+    ngx_http_addition_ctx_t   *ctx;
+    ngx_http_addition_conf_t  *conf;
+
+    if (r->headers_out.status != NGX_HTTP_OK || r != r->main) {
+        return ngx_http_next_header_filter(r);
+    }
+
+    if (ngx_strncasecmp(r->headers_out.content_type.data, "text/html",
+                        sizeof("text/html") - 1)
+        != 0)
+    {
+        return ngx_http_next_header_filter(r);
+    }
+
+    conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);
+
+    if (conf->before_body.len == 0 && conf->after_body.len == 0) {
+        return ngx_http_next_header_filter(r);
+    }
+
+    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_addition_ctx_t));
+    if (ctx == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_http_set_ctx(r, ctx, ngx_http_addition_filter_module);
+
+    ngx_http_clear_content_length(r);
+    ngx_http_clear_accept_ranges(r);
+
+    return ngx_http_next_header_filter(r);
+}
+
+
+static ngx_int_t
+ngx_http_addition_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
+{
+    ngx_int_t                  rc;
+    ngx_uint_t                 last;
+    ngx_chain_t               *cl;
+    ngx_http_addition_ctx_t   *ctx;
+    ngx_http_addition_conf_t  *conf;
+
+    if (in == NULL || r->header_only) {
+        return ngx_http_next_body_filter(r, in);
+    }
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_addition_filter_module);
+
+    if (ctx == NULL) {
+        return ngx_http_next_body_filter(r, in);
+    }
+
+    conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);
+
+    if (!ctx->before_body_sent) {
+        ctx->before_body_sent = 1;
+
+        if (conf->before_body.len) {
+            if (ngx_http_subrequest(r, &conf->before_body, NULL, 0) != NGX_OK) {
+                return NGX_ERROR;
+            }
+        }
+    }
+
+    last = 0;
+
+    for (cl = in; cl; cl = cl->next) {
+        if (cl->buf->last_buf) {
+            cl->buf->last_buf = 0;
+            last = 1;
+        }
+    }
+
+    rc = ngx_http_next_body_filter(r, in);
+
+    if (rc == NGX_ERROR
+        || !last
+        || ctx->after_body_sent
+        || conf->after_body.len == 0)
+    {
+        return rc;
+    }
+
+    if (ngx_http_subrequest(r, &conf->after_body, NULL, 0) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    ctx->after_body_sent = 1;
+
+    return ngx_http_send_special(r, NGX_HTTP_LAST);
+}
+
+
+static ngx_int_t
+ngx_http_addition_filter_init(ngx_cycle_t *cycle)
+{
+    ngx_http_next_header_filter = ngx_http_top_header_filter;
+    ngx_http_top_header_filter = ngx_http_addition_header_filter;
+
+    ngx_http_next_body_filter = ngx_http_top_body_filter;
+    ngx_http_top_body_filter = ngx_http_addition_body_filter;
+
+    return NGX_OK;
+}
+
+
+static void *
+ngx_http_addition_create_conf(ngx_conf_t *cf)
+{
+    ngx_http_addition_conf_t  *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_addition_conf_t));
+    if (conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     conf->before_body.len = 0;
+     *     conf->before_body.date = NULL;
+     *     conf->after_body.len = 0;
+     *     conf->after_body.date = NULL;
+     */
+
+    return conf;
+}
+
+
+static char *
+ngx_http_addition_merge_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_addition_conf_t *prev = parent;
+    ngx_http_addition_conf_t *conf = child;
+
+    ngx_conf_merge_str_value(conf->before_body, prev->before_body, "");
+    ngx_conf_merge_str_value(conf->after_body, prev->after_body, "");
+
+    return NGX_CONF_OK;
+}
--- a/src/http/modules/ngx_http_chunked_filter_module.c
+++ b/src/http/modules/ngx_http_chunked_filter_module.c
@@ -23,7 +23,7 @@ static ngx_http_module_t  ngx_http_chunk
     NULL,                                  /* merge server configuration */
 
     NULL,                                  /* create location configuration */
-    NULL,                                  /* merge location configuration */
+    NULL                                   /* merge location configuration */
 };
 
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -170,7 +170,7 @@ static ngx_conf_bitmask_t  ngx_http_fast
 static ngx_command_t  ngx_http_fastcgi_commands[] = {
 
     { ngx_string("fastcgi_pass"),
-      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
       ngx_http_fastcgi_pass,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -183,6 +183,13 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, index),
       NULL },
 
+    { ngx_string("fastcgi_ignore_client_abort"),
+      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.ignore_client_abort),
+      NULL },
+
     { ngx_string("fastcgi_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -1470,6 +1477,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
      */
 
     conf->upstream.buffering = NGX_CONF_UNSET;
+    conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
 
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
@@ -1520,6 +1528,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     ngx_conf_merge_value(conf->upstream.buffering,
                               prev->upstream.buffering, 1);
 
+    ngx_conf_merge_value(conf->upstream.ignore_client_abort,
+                              prev->upstream.ignore_client_abort, 0);
+
     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                               prev->upstream.connect_timeout, 60000);
 
@@ -1670,6 +1681,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
     if (conf->peers == NULL) {
         conf->peers = prev->peers;
+        conf->upstream.schema = prev->upstream.schema;
     }
 
     if (conf->params_source == NULL) {
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -517,6 +517,8 @@ ngx_http_memcached_create_loc_conf(ngx_c
     conf->upstream.cyclic_temp_file = 0;
 
     /* the hardcoded values */
+    conf->upstream.buffering = 0;
+    conf->upstream.ignore_client_abort = 0;
     conf->upstream.send_lowat = 0;
     conf->upstream.bufs.num = 0;
     conf->upstream.busy_buffers_size = 0;
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -130,7 +130,7 @@ static ngx_conf_bitmask_t  ngx_http_prox
 static ngx_command_t  ngx_http_proxy_commands[] = {
 
     { ngx_string("proxy_pass"),
-      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
       ngx_http_proxy_pass,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -150,6 +150,13 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
       NULL },
 
+    { ngx_string("proxy_ignore_client_abort"),
+      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.ignore_client_abort),
+      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,
@@ -1415,6 +1422,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
      */
 
     conf->upstream.buffering = NGX_CONF_UNSET;
+    conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
 
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
@@ -1468,6 +1476,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
     ngx_conf_merge_value(conf->upstream.buffering,
                               prev->upstream.buffering, 1);
 
+    ngx_conf_merge_value(conf->upstream.ignore_client_abort,
+                              prev->upstream.ignore_client_abort, 0);
+
     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                               prev->upstream.connect_timeout, 60000);
 
@@ -1654,6 +1665,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
 
     if (conf->peers == NULL) {
         conf->peers = prev->peers;
+
+        conf->host_header = prev->host_header;
+        conf->port_text = prev->port_text;
+        conf->upstream.schema = prev->upstream.schema;
     }
 
 
@@ -2057,11 +2072,12 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
 
 #if (NGX_PCRE)
 
-    if (clcf->regex) {
+    if (clcf->regex || clcf->noname) {
         if (plcf->upstream.uri.len) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "\"proxy_pass\" may not have URI part in "
-                               "location given by regular expression");
+                               "location given by regular expression or "
+                               "inside the \"if\" statement");
             return NGX_CONF_ERROR;
         }
 
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -13,6 +13,7 @@
 #define NGX_HTTP_SSI_DATE_LEN       2048
 
 #define NGX_HTTP_SSI_ADD_PREFIX     1
+#define NGX_HTTP_SSI_ADD_ZERO       2
 
 
 typedef struct {
@@ -247,8 +248,12 @@ static ngx_http_ssi_command_t  ngx_http_
     { ngx_string("set"), ngx_http_ssi_set, ngx_http_ssi_set_params, 0, 0 },
 
     { 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_string("elif"), ngx_http_ssi_if, ngx_http_ssi_if_params,
+                       NGX_HTTP_SSI_COND_IF, 0 },
+    { ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params,
+                       NGX_HTTP_SSI_COND_IF, 0 },
+    { ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params,
+                       NGX_HTTP_SSI_COND_ELSE, 0 },
 
     { ngx_null_string, NULL, NULL, 0, 0 }
 };
@@ -523,7 +528,17 @@ ngx_http_ssi_body_filter(ngx_http_reques
                     continue;
                 }
 
-                if (!ctx->output && !cmd->conditional) {
+                if (cmd->conditional
+                    && (ctx->conditional == 0
+                        || ctx->conditional > cmd->conditional))
+                {
+                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                                  "invalid context of SSI command: \"%V\"",
+                                  &ctx->command);
+                    goto ssi_error;
+                }
+
+                if (!ctx->output && cmd->conditional == 0) {
                     continue;
                 }
 
@@ -926,6 +941,7 @@ ngx_http_ssi_parse(ngx_http_request_t *r
                 ctx->key = ngx_hash(ctx->key, ch);
 
                 ctx->params.nelts = 0;
+
                 state = ssi_command_state;
                 break;
             }
@@ -1565,7 +1581,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re
         }
     }
 
-    p = ngx_palloc(r->pool, len);
+    p = ngx_palloc(r->pool, len + ((flags & NGX_HTTP_SSI_ADD_ZERO) ? 1 : 0));
     if (p == NULL) {
         return NGX_ERROR;
     }
@@ -1809,13 +1825,26 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
     u_char       *p, *last;
     ngx_str_t    *expr, left, right;
     ngx_int_t     rc;
-    ngx_uint_t    negative, noregex;
+    ngx_uint_t    negative, noregex, flags;
 #if (NGX_PCRE)
     ngx_str_t     err;
     ngx_regex_t  *regex;
     u_char        errstr[NGX_MAX_CONF_ERRSTR];
 #endif
 
+    if (ctx->command.len == 2) {
+        if (ctx->conditional) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "the \"if\" command inside the \"if\" command");
+            return NGX_HTTP_SSI_ERROR;
+        }
+    }
+
+    if (ctx->output_chosen) {
+        ctx->output = 0;
+        return NGX_OK;
+    }
+
     expr = params[NGX_HTTP_SSI_IF_EXPR];
 
     left.data = expr->data;
@@ -1857,11 +1886,14 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
     if (p == last) {
         if (left.len) {
             ctx->output = 1;
+            ctx->output_chosen = 1;
 
         } else {
             ctx->output = 0;
         }
 
+        ctx->conditional = NGX_HTTP_SSI_COND_IF;
+
         return NGX_OK;
     }
 
@@ -1887,11 +1919,17 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
         }
 
         noregex = 0;
+        flags = NGX_HTTP_SSI_ADD_ZERO;
         last--;
 	p++;
 
     } else {
         noregex = 1;
+        flags = 0;
+
+        if (p < last - 1 && p[0] == '\\' && p[1] == '/') {
+	    p++;
+        }
     }
 
     right.len = last - p;
@@ -1900,7 +1938,7 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "right: \"%V\"", &right);
 
-    if (ngx_http_ssi_evaluate_string(r, ctx, &right, 0) != NGX_OK) {
+    if (ngx_http_ssi_evaluate_string(r, ctx, &right, flags) != NGX_OK) {
         return NGX_HTTP_SSI_ERROR;
     }
 
@@ -1948,11 +1986,14 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
 
     if ((rc == 0 && !negative) || (rc != 0 && negative)) {
         ctx->output = 1;
+        ctx->output_chosen = 1;
 
     } else {
         ctx->output = 0;
     }
 
+    ctx->conditional = NGX_HTTP_SSI_COND_IF;
+
     return NGX_OK;
 
 invalid_expression:
@@ -1968,7 +2009,13 @@ 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;
+    if (ctx->output_chosen) {
+        ctx->output = 0;
+    } else {
+        ctx->output = 1;
+    }
+
+    ctx->conditional = NGX_HTTP_SSI_COND_ELSE;
 
     return NGX_OK;
 }
@@ -1979,6 +2026,8 @@ ngx_http_ssi_endif(ngx_http_request_t *r
     ngx_str_t **params)
 {
     ctx->output = 1;
+    ctx->output_chosen = 0;
+    ctx->conditional = 0;
 
     return NGX_OK;
 }
--- a/src/http/modules/ngx_http_ssi_filter_module.h
+++ b/src/http/modules/ngx_http_ssi_filter_module.h
@@ -20,6 +20,10 @@
 #define NGX_HTTP_SSI_PARAMS_N       4
 
 
+#define NGX_HTTP_SSI_COND_IF        1
+#define NGX_HTTP_SSI_COND_ELSE      2
+
+
 typedef struct {
     ngx_hash_t                hash;
     ngx_hash_keys_arrays_t    commands;
@@ -54,7 +58,9 @@ typedef struct {
 
     ngx_array_t               variables;
 
-    ngx_uint_t                output;        /* unsigned  output:1; */
+    unsigned                  conditional:2;
+    unsigned                  output:1;
+    unsigned                  output_chosen:1;
 
     void                     *value_buf;
     ngx_str_t                 timefmt;
@@ -80,7 +86,7 @@ typedef struct {
     ngx_http_ssi_command_pt   handler;
     ngx_http_ssi_param_t     *params;
 
-    unsigned                  conditional:1;
+    unsigned                  conditional:2;
     unsigned                  flush:1;
 } ngx_http_ssi_command_t;
 
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -178,6 +178,35 @@ args(r, ...)
 
 
 char *
+request_method(r)
+    nginx  r
+
+    CODE:
+
+    RETVAL = ngx_palloc(r->pool, r->method_name.len + 1);
+    if (RETVAL == NULL) {
+        XSRETURN_UNDEF;
+    }
+
+    ngx_cpystrn((u_char *) RETVAL, r->method_name.data, r->method_name.len + 1);
+
+    OUTPUT:
+    RETVAL
+
+
+char *
+remote_addr(r)
+    nginx  r
+
+    CODE:
+
+    RETVAL = (char *) r->connection->addr_text.data;
+
+    OUTPUT:
+    RETVAL
+
+
+char *
 header_in(r, key)
     nginx             r
     SV               *key
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -39,6 +39,7 @@ static ngx_int_t ngx_http_perl_ssi(ngx_h
     ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params);
 #endif
 
+static void ngx_http_perl_handle_request(ngx_http_request_t *r);
 static ngx_int_t
     ngx_http_perl_get_interpreter(ngx_http_perl_main_conf_t *pmcf,
     PerlInterpreter **perl, ngx_log_t *log);
@@ -174,23 +175,39 @@ ngx_http_perl_xs_init(pTHX)
 static ngx_int_t
 ngx_http_perl_handler(ngx_http_request_t *r)
 {
+    ngx_int_t  rc;
+
+    /* TODO: Win32 */
+    if (r->zero_in_uri) {
+        return NGX_HTTP_NOT_FOUND;
+    }
+
+    rc = ngx_http_read_client_request_body(r, ngx_http_perl_handle_request);
+
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+        return rc;
+    }
+
+    return NGX_DONE;
+}
+
+
+static void
+ngx_http_perl_handle_request(ngx_http_request_t *r)
+{
     ngx_int_t                   rc;
     ngx_str_t                   uri, args;
     ngx_http_perl_ctx_t        *ctx;
     ngx_http_perl_loc_conf_t   *plcf;
     ngx_http_perl_main_conf_t  *pmcf;
 
-    /* TODO: Win32 */
-    if (r->zero_in_uri) {
-        return NGX_HTTP_NOT_FOUND;
-    }
-
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler");
 
     /* mod_perl's content handler assumes that content type was already set */
 
     if (ngx_http_set_content_type(r) != NGX_OK) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
     }
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
@@ -198,7 +215,8 @@ ngx_http_perl_handler(ngx_http_request_t
     if (ctx == NULL) {
         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
         if (ctx == NULL) {
-            return NGX_ERROR;
+            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+	    return;
         }
 
         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
@@ -209,7 +227,8 @@ ngx_http_perl_handler(ngx_http_request_t
     rc = ngx_http_perl_get_interpreter(pmcf, &ctx->perl, r->connection->log);
 
     if (rc != NGX_OK) {
-        return rc;
+        ngx_http_finalize_request(r, rc);
+        return;
     }
 
     {
@@ -235,20 +254,24 @@ ngx_http_perl_handler(ngx_http_request_t
     if (ctx->redirect_uri.len) {
         uri = ctx->redirect_uri;
         args = ctx->redirect_args;
+
+    } else {
+        uri.len = 0;
     }
 
     ctx->filename = NULL;
     ctx->redirect_uri.len = 0;
 
     if (uri.len) {
-        return ngx_http_internal_redirect(r, &uri, &args);
+        ngx_http_internal_redirect(r, &uri, &args);
+        return;
     }
 
     if (rc == NGX_OK || rc == NGX_HTTP_OK) {
-        return ngx_http_send_special(r, NGX_HTTP_LAST);
+        ngx_http_send_special(r, NGX_HTTP_LAST);
     }
 
-    return rc;
+    ngx_http_finalize_request(r, rc);
 }
 
 
@@ -448,6 +471,10 @@ ngx_http_perl_init_interpreter(ngx_conf_
     }
 #endif
 
+    if (ngx_conf_full_name(cf->cycle, &pmcf->modules) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
     PERL_SYS_INIT(&ngx_argc, &ngx_argv);
 
     pmcf->perl = ngx_http_perl_create_interpreter(pmcf, cf->log);
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,1512 +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_header0_t ngx_http_proxy_headers_in[] = {
-    { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) },
-    { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) },
-
-    { 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_rd_check_broken_connection(ngx_http_request_t *r)
-{
-    ngx_http_proxy_check_broken_connection(r, r->connection->read);
-}
-
-
-void ngx_http_proxy_wr_check_broken_connection(ngx_http_request_t *r)
-{
-    ngx_http_proxy_check_broken_connection(r, r->connection->read);
-}
-
-
-void ngx_http_proxy_check_broken_connection(ngx_http_request_t *r,
-    ngx_event_t *ev)
-{
-    int                    n;
-    char                   buf[1];
-    ngx_err_t              err;
-    ngx_connection_t      *c;
-    ngx_http_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 = r->connection;
-        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 = r->connection;
-    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 (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,275 +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_rd_check_broken_connection(ngx_http_request_t *r);
-void ngx_http_proxy_wr_check_broken_connection(ngx_http_request_t *r);
-void ngx_http_proxy_check_broken_connection(ngx_http_request_t *r,
-    ngx_event_t *ev);
-
-void ngx_http_proxy_busy_lock_handler(ngx_event_t *rev);
-void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p);
-
-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_header0_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,1656 +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_downstream(ngx_http_request_t *r);
-static void ngx_http_proxy_process_body(ngx_event_t *ev);
-static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p,
-                                         ngx_uint_t ft_type);
-
-
-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 + 1 + 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 + 1);
-    }
-
-    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->read_event_handler = ngx_http_proxy_rd_check_broken_connection;
-
-    if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
-
-        r->write_event_handler = ngx_http_proxy_wr_check_broken_connection;
-
-        if (!r->connection->write->active) {
-            if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT,
-                                                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->handler = ngx_http_proxy_send_request_handler;
-    c->read->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->handler = ngx_http_proxy_dummy_handler;
-
-    if (ngx_handle_write_event(c->write, 0) == 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->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 && !r->invalid_header) {
-
-            /* 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) {
-
-            if (r->invalid_header) {
-                rc = NGX_HTTP_PARSE_INVALID_HEADER;
-            }
-
-            /* there was error while a header line parsing */
-
-            ngx_log_error(NGX_LOG_ERR, rev->log, 0,
-                      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->handler = ngx_http_proxy_process_body;
-    r->write_event_handler = ngx_http_proxy_process_downstream;
-
-    ngx_http_proxy_process_body(p->upstream->peer.connection->read);
-
-    return;
-}
-
-
-static void ngx_http_proxy_process_downstream(ngx_http_request_t *r)
-{
-    ngx_http_proxy_process_body(r->connection->write);
-}
-
-
-static void ngx_http_proxy_process_body(ngx_event_t *ev)
-{
-    ngx_connection_t      *c;
-    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_request.c
+++ b/src/http/ngx_http_request.c
@@ -1503,6 +1503,10 @@ ngx_http_finalize_request(ngx_http_reque
         return;
     }
 
+    if (!r->post_action) {
+        r->request_complete = 1;
+    }
+
     if (ngx_http_post_action(r) == NGX_OK) {
         return;
     }
@@ -2254,6 +2258,7 @@ ngx_http_post_action(ngx_http_request_t 
 
     r->http_version = NGX_HTTP_VERSION_9;
     r->header_only = 1;
+    r->post_action = 1;
 
     ngx_http_internal_redirect(r, &clcf->post_action, NULL);
 
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -405,6 +405,8 @@ struct ngx_http_request_s {
     unsigned                          lingering_close:1;
     unsigned                          discard_body:1;
     unsigned                          internal:1;
+    unsigned                          post_action:1;
+    unsigned                          request_complete:1;
     unsigned                          done:1;
     unsigned                          utf8:1;
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -277,9 +277,9 @@ ngx_http_upstream_init(ngx_http_request_
         ngx_del_timer(c->read);
     }
 
-    if (!(r->http_version == NGX_HTTP_VERSION_9 && r->header_only)) {
-        /* not a post_action */
-
+    u = r->upstream;
+
+    if (!r->post_action && !u->conf->ignore_client_abort) {
         r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
         r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
     }
@@ -296,8 +296,6 @@ ngx_http_upstream_init(ngx_http_request_
         }
     }
 
-    u = r->upstream;
-
     if (r->request_body) {
         u->request_bufs = r->request_body->bufs;
     }
@@ -1208,10 +1206,7 @@ ngx_http_upstream_send_response(ngx_http
 
     rc = ngx_http_send_header(r);
 
-    if (rc == NGX_ERROR
-        || rc > NGX_OK
-                          /* post_action */
-        || (r->http_version == NGX_HTTP_VERSION_9 && r->header_only)) {
+    if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
         ngx_http_upstream_finalize_request(r, u, rc);
         return;
     }
@@ -1947,11 +1942,7 @@ ngx_http_upstream_finalize_request(ngx_h
 
     r->connection->log->action = "sending to client";
 
-    if (rc == 0
-        && r == r->main
-             /* not a post_action */
-        && !(r->http_version == NGX_HTTP_VERSION_9 && r->header_only))
-    {
+    if (rc == 0 && r == r->main && !r->post_action) {
         rc = ngx_http_send_special(r, NGX_HTTP_LAST);
     }
 
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -73,6 +73,7 @@ typedef struct {
     ngx_flag_t                      pass_request_headers;
     ngx_flag_t                      pass_request_body;
 
+    ngx_flag_t                      ignore_client_abort;
     ngx_flag_t                      redirect_errors;
     ngx_flag_t                      cyclic_temp_file;
 
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -44,6 +44,8 @@ static ngx_int_t ngx_http_variable_remot
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_body_bytes_sent(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 
 
 /*
@@ -135,6 +137,9 @@ static ngx_http_variable_t  ngx_http_cor
     { ngx_string("body_bytes_sent"), ngx_http_variable_body_bytes_sent,
       0, 0, 0 },
 
+    { ngx_string("request_completion"), ngx_http_variable_request_completion,
+      0, 0, 0 },
+
     { ngx_null_string, NULL, 0, 0, 0 }
 };
 
@@ -798,6 +803,30 @@ ngx_http_variable_body_bytes_sent(ngx_ht
 }
 
 
+static ngx_int_t
+ngx_http_variable_request_completion(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    if (r->request_complete) {
+        v->len = 2;
+        v->valid = 1;
+        v->no_cachable = 0;
+        v->not_found = 0;
+        v->data = (u_char *) "OK";
+
+        return NGX_OK;
+    }
+
+    v->len = 0;
+    v->valid = 1;
+    v->no_cachable = 0;
+    v->not_found = 0;
+    v->data = (u_char *) "";
+
+    return NGX_OK;
+}
+
+
 ngx_int_t
 ngx_http_variables_add_core_vars(ngx_conf_t *cf)
 {