nginx-0.1.29-RELEASE import

    *) Feature: the ngx_http_ssi_module supports "include virtual" command.

    *) Feature: the ngx_http_ssi_module supports the condition command like
       'if expr="$NAME"' and "else" and "endif" commands. Only one nested
       level is supported.

    *) Feature: the ngx_http_ssi_module supports the DATE_LOCAL and
       DATE_GMT variables and "config timefmt" command.

    *) Feature: the "ssi_ignore_recycled_buffers" directive.

    *) Bugfix: the "echo" command did not show the default value for the
       empty QUERY_STRING variable.

    *) Change: the ngx_http_proxy_module was rewritten.

    *) Feature: the "proxy_redirect", "proxy_pass_request_headers",
       "proxy_pass_request_body", and "proxy_method" directives.

    *) Feature: the "proxy_set_header" directive. The "proxy_x_var" was
       canceled and must be replaced with the proxy_set_header directive.

    *) Change: the "proxy_preserve_host" is canceled and must be replaced
       with the "proxy_set_header Host $host" and the "proxy_redirect off"
       directives, the "proxy_set_header Host $host:$proxy_port" directive
       and the appropriate proxy_redirect directives.

    *) Change: the "proxy_set_x_real_ip" is canceled and must be replaced
       with the "proxy_set_header X-Real-IP $remote_addr" directive.

    *) Change: the "proxy_add_x_forwarded_for" is canceled and must be
       replaced with
       the "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for"
       directive.

    *) Change: the "proxy_set_x_url" is canceled and must be replaced with
       the "proxy_set_header X-URL http://$host:$server_port$request_uri"
       directive.

    *) Feature: the "fastcgi_param" directive.

    *) Change: the "fastcgi_root", "fastcgi_set_var" and "fastcgi_params"
       directive are canceled and must be replaced with the fastcgi_param
       directives.

    *) Feature: the "index" directive can use the variables.

    *) Feature: the "index" directive can be used at http and server levels.

    *) Change: the last index only in the "index" directive can be absolute.

    *) Feature: the "rewrite" directive can use the variables.

    *) Feature: the "internal" directive.

    *) Feature: the CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR,
       SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME,
       REQUEST_METHOD, REQUEST_URI, and REMOTE_USER variables.

    *) Change: nginx now passes the invalid lines in a client request
       headers or a backend response header.

    *) Bugfix: if the backend did not transfer response for a long time and
       the "send_timeout" was less than "proxy_read_timeout", then nginx
       returned the 408 response.

    *) Bugfix: the segmentation fault was occurred if the backend sent an
       invalid line in response header; the bug had appeared in 0.1.26.

    *) Bugfix: the segmentation fault may occurred in FastCGI fault
       tolerance configuration.

    *) Bugfix: the "expires" directive did not remove the previous
       "Expires" and "Cache-Control" headers.

    *) Bugfix: nginx did not take into account trailing dot in "Host"
       header line.

    *) Bugfix: the ngx_http_auth_module did not work under Linux.

    *) Bugfix: the rewrite directive worked incorrectly, if the arguments
       were in a request.

    *) Bugfix: nginx could not be built on MacOS X.
diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c
index 685d15d..47f9944 100644
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -54,7 +54,8 @@
 
 
 ngx_http_module_t  ngx_http_access_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -68,7 +69,7 @@
 
 
 ngx_module_t  ngx_http_access_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_access_module_ctx,           /* module context */
     ngx_http_access_commands,              /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c
index 03314b5..98c47bd 100644
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -60,7 +60,8 @@
 
 
 ngx_http_module_t  ngx_http_auth_basic_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -74,7 +75,7 @@
 
 
 ngx_module_t  ngx_http_auth_basic_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_auth_basic_module_ctx,       /* module context */
     ngx_http_auth_basic_commands,          /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -327,6 +328,7 @@
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    r->headers_out.www_authenticate->hash = 1;
     r->headers_out.www_authenticate->key.len = sizeof("WWW-Authenticate") - 1;
     r->headers_out.www_authenticate->key.data = (u_char *) "WWW-Authenticate";
     r->headers_out.www_authenticate->value = *realm;
diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c
index ff163ed..76c5b03 100644
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -63,7 +63,8 @@
 
 
 ngx_http_module_t  ngx_http_autoindex_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -77,7 +78,7 @@
 
 
 ngx_module_t  ngx_http_autoindex_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_autoindex_module_ctx,        /* module context */ 
     ngx_http_autoindex_commands,           /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -419,16 +420,8 @@
 
     r->headers_out.status = NGX_HTTP_OK;
     r->headers_out.content_length_n = b->last - b->pos;
-
-    r->headers_out.content_type = ngx_list_push(&r->headers_out.headers);
-    if (r->headers_out.content_type == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    r->headers_out.content_type->key.len = 0;
-    r->headers_out.content_type->key.data = NULL;
-    r->headers_out.content_type->value.len = sizeof("text/html") - 1;
-    r->headers_out.content_type->value.data = (u_char *) "text/html";
+    r->headers_out.content_type.len = sizeof("text/html") - 1;
+    r->headers_out.content_type.data = (u_char *) "text/html";
 
     rc = ngx_http_send_header(r);
 
@@ -436,10 +429,12 @@
         return rc;
     }
 
-    if (!r->main) {
+    if (r->main == NULL) {
         b->last_buf = 1;
     }
 
+    b->last_in_chain = 1;
+
     out.buf = b;
     out.next = NULL;
 
diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c
index dad26ba..0c76a5f 100644
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -106,7 +106,8 @@
 
 
 static ngx_http_module_t  ngx_http_charset_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     ngx_http_charset_create_main_conf,     /* create main configuration */
     ngx_http_charset_init_main_conf,       /* init main configuration */
@@ -120,7 +121,7 @@
 
 
 ngx_module_t  ngx_http_charset_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_charset_filter_module_ctx,   /* module context */
     ngx_http_charset_filter_commands,      /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -148,19 +149,18 @@
         return ngx_http_next_header_filter(r);
     }
 
-    if (r->headers_out.content_type == NULL) {
+    if (r->headers_out.content_type.len == 0) {
         return ngx_http_next_header_filter(r);
     }
 
-    if (ngx_strncasecmp(r->headers_out.content_type->value.data,
-                                                              "text/", 5) != 0
-        && ngx_strncasecmp(r->headers_out.content_type->value.data,
-                                          "application/x-javascript", 24) != 0)
+    if (ngx_strncasecmp(r->headers_out.content_type.data, "text/", 5) != 0
+        && ngx_strncasecmp(r->headers_out.content_type.data,
+                           "application/x-javascript", 24) != 0)
     {
         return ngx_http_next_header_filter(r);
     }
 
-    if (ngx_strstr(r->headers_out.content_type->value.data, "charset") != NULL)
+    if (ngx_strstr(r->headers_out.content_type.data, "charset") != NULL)
     {
         return ngx_http_next_header_filter(r);
     }
diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c
index b742dbb..4136613 100644
--- a/src/http/modules/ngx_http_chunked_filter_module.c
+++ b/src/http/modules/ngx_http_chunked_filter_module.c
@@ -13,7 +13,8 @@
 
 
 static ngx_http_module_t  ngx_http_chunked_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -27,7 +28,7 @@
 
 
 ngx_module_t  ngx_http_chunked_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_chunked_filter_module_ctx,   /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -43,7 +44,7 @@
 static ngx_int_t
 ngx_http_chunked_header_filter(ngx_http_request_t *r)
 {
-    if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) {
+    if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED || r->main) {
         return ngx_http_next_header_filter(r);
     }
 
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 4b92cd4..cf9d008 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -15,37 +15,14 @@
 
     ngx_peers_t                    *peers;
 
-    ngx_uint_t                      params;
-
-    ngx_str_t                       root;
     ngx_str_t                       index;
 
-    ngx_array_t                    *vars;
-
-    ngx_str_t                      *location;
+    ngx_array_t                    *params_len;
+    ngx_array_t                    *params;
+    ngx_array_t                    *params_source;
 } ngx_http_fastcgi_loc_conf_t;
 
 
-typedef struct {
-    ngx_list_t                      headers;
-
-    ngx_table_elt_t                *status;
-
-    ngx_table_elt_t                *content_type;
-    ngx_table_elt_t                *content_length;
-    ngx_table_elt_t                *x_powered_by;
-
-#if (NGX_HTTP_GZIP)
-    ngx_table_elt_t                *content_encoding;
-#endif
-} ngx_http_fastcgi_headers_in_t;
-
-
-typedef struct {
-    ngx_http_fastcgi_headers_in_t   headers_in;
-} ngx_http_fastcgi_upstream_t;
-
-
 typedef enum {
     ngx_http_fastcgi_st_version = 0,
     ngx_http_fastcgi_st_type,
@@ -69,28 +46,9 @@
     size_t                        padding;
 
     ngx_uint_t                    header;
-
-    ngx_http_fastcgi_upstream_t  *upstream;
 } ngx_http_fastcgi_ctx_t;
 
 
-#define NGX_HTTP_FASTCGI_REMOTE_ADDR          0x00000002
-#define NGX_HTTP_FASTCGI_REMOTE_USER          0x00000004
-#define NGX_HTTP_FASTCGI_SERVER_NAME          0x00000008
-#define NGX_HTTP_FASTCGI_SERVER_ADDR          0x00000010
-#define NGX_HTTP_FASTCGI_SERVER_PORT          0x00000020
-#define NGX_HTTP_FASTCGI_SCRIPT_NAME          0x00000040
-#define NGX_HTTP_FASTCGI_AUTH_TYPE            0x00000080
-#define NGX_HTTP_FASTCGI_SERVER_PROTOCOL      0x00000100
-#define NGX_HTTP_FASTCGI_SERVER_SOFTWARE      0x00000200
-#define NGX_HTTP_FASTCGI_GATEWAY_INTERFACE    0x00000400
-#define NGX_HTTP_FASTCGI_REQUEST_URI          0x00000800
-#define NGX_HTTP_FASTCGI_REDIRECT_STATUS      0x00001000
-#define NGX_HTTP_FASTCGI_DOCUMENT_ROOT        0x00002000
-#define NGX_HTTP_FASTCGI_SCRIPT_FILENAME      0x00004000
-#define NGX_HTTP_FASTCGI_REMOTE_PORT          0x00008000
-
-
 #define NGX_HTTP_FASTCGI_RESPONDER      1
 
 #define NGX_HTTP_FASTCGI_BEGIN_REQUEST  1
@@ -123,10 +81,24 @@
 } ngx_http_fastcgi_begin_request_t;
 
 
+typedef struct {
+    u_char  version;
+    u_char  type;
+    u_char  request_id_hi;
+    u_char  request_id_lo;
+} ngx_http_fastcgi_header_small_t;
+
+
+typedef struct {
+    ngx_http_fastcgi_header_t         h0;
+    ngx_http_fastcgi_begin_request_t  br;
+    ngx_http_fastcgi_header_small_t   h1;
+} ngx_http_fastcgi_request_start_t;
+
+
 static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r);
 static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r);
 static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r);
-static ngx_int_t ngx_http_fastcgi_send_header(ngx_http_request_t *r);
 static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
     ngx_buf_t *buf);
 static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r,
@@ -135,22 +107,54 @@
 static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r,
     ngx_int_t rc);
 
-static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
-static char *ngx_http_fastcgi_set_var(ngx_conf_t *cf, ngx_command_t *cmd,
-    void *conf);
-static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
-    void *data);
+static ngx_int_t ngx_http_fastcgi_add_variables(ngx_conf_t *cf);
 static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf,
     void *parent, void *child);
+static ngx_http_variable_value_t *
+    ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
+    uintptr_t data);
+
+static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
+    void *data);
 
 
+static ngx_http_fastcgi_request_start_t  ngx_http_fastcgi_request_start = {
+    { 1,                                               /* version */
+      NGX_HTTP_FASTCGI_BEGIN_REQUEST,                  /* type */
+      0,                                               /* request_id_hi */
+      1,                                               /* request_id_lo */
+      0,                                               /* content_length_hi */
+      sizeof(ngx_http_fastcgi_begin_request_t),        /* content_length_lo */
+      0,                                               /* padding_length */
+      0 },                                             /* reserved */
+
+    { 0,                                               /* role_hi */
+      NGX_HTTP_FASTCGI_RESPONDER,                      /* role_lo */
+      0, /* NGX_HTTP_FASTCGI_KEEP_CONN */              /* flags */
+      { 0, 0, 0, 0, 0 } },                             /* reserved[5] */
+
+    { 1,                                               /* version */
+      NGX_HTTP_FASTCGI_PARAMS,                         /* type */
+      0,                                               /* request_id_hi */
+      1 },                                             /* request_id_lo */
+
+};
+
+
+#if 0
 static ngx_str_t ngx_http_fastcgi_methods[] = {
     ngx_string("GET"),
     ngx_string("HEAD"),
     ngx_string("POST")
 };
+#endif
+
+
+static ngx_str_t  ngx_http_fastcgi_script_name =
+    ngx_string("fastcgi_script_name");
 
 
 #if (NGX_PCRE)
@@ -158,30 +162,14 @@
 #endif
 
 
-static ngx_http_header_t ngx_http_fastcgi_headers_in[] = {
-    { ngx_string("Status"), offsetof(ngx_http_fastcgi_headers_in_t, status) },
+static ngx_conf_post_t  ngx_http_fastcgi_lowat_post =
+    { ngx_http_fastcgi_lowat_check };
 
-    { ngx_string("Content-Type"),
-                 offsetof(ngx_http_fastcgi_headers_in_t, content_type) },
-
-    { ngx_string("Content-Length"),
-                 offsetof(ngx_http_fastcgi_headers_in_t, content_length) },
-
-    { ngx_string("X-Powered-By"),
-                 offsetof(ngx_http_fastcgi_headers_in_t, x_powered_by) },
-
-#if (NGX_HTTP_GZIP)
-    { ngx_string("Content-Encoding"),
-                 offsetof(ngx_http_fastcgi_headers_in_t, content_encoding) },
-#endif
-
+static ngx_conf_enum_t  ngx_http_fastcgi_set_methods[] = {
+    { ngx_string("get"), NGX_HTTP_GET },
     { ngx_null_string, 0 }
 };
 
-
-static ngx_conf_post_t  ngx_http_fastcgi_lowat_post =
-                                              { ngx_http_fastcgi_lowat_check };
-
 static ngx_conf_bitmask_t  ngx_http_fastcgi_next_upstream_masks[] = {
     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
@@ -192,28 +180,6 @@
 };
 
 
-static ngx_conf_bitmask_t  ngx_http_fastcgi_params_masks[] = {
-    { ngx_string("remote_addr"), NGX_HTTP_FASTCGI_REMOTE_ADDR },
-    { ngx_string("server_port"), NGX_HTTP_FASTCGI_SERVER_PORT },
-    { ngx_string("server_addr"), NGX_HTTP_FASTCGI_SERVER_ADDR },
-    { ngx_string("server_name"), NGX_HTTP_FASTCGI_SERVER_NAME },
-    { ngx_string("script_name"), NGX_HTTP_FASTCGI_SCRIPT_NAME },
-
-    { ngx_string("server_protocol"), NGX_HTTP_FASTCGI_SERVER_PROTOCOL },
-    { ngx_string("server_software"), NGX_HTTP_FASTCGI_SERVER_SOFTWARE },
-    { ngx_string("gateway_interface"), NGX_HTTP_FASTCGI_GATEWAY_INTERFACE },
-
-    { ngx_string("redirect_status"), NGX_HTTP_FASTCGI_REDIRECT_STATUS },
-    { ngx_string("request_uri"), NGX_HTTP_FASTCGI_REQUEST_URI },
-
-    { ngx_string("document_root"), NGX_HTTP_FASTCGI_DOCUMENT_ROOT },
-    { ngx_string("script_filename"), NGX_HTTP_FASTCGI_SCRIPT_FILENAME },
-    { ngx_string("remote_port"), NGX_HTTP_FASTCGI_REMOTE_PORT },
-
-    { ngx_null_string, 0 }
-};
-
-
 static ngx_command_t  ngx_http_fastcgi_commands[] = {
 
     { ngx_string("fastcgi_pass"),
@@ -223,13 +189,6 @@
       0,
       NULL },
 
-    { ngx_string("fastcgi_root"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fastcgi_loc_conf_t, root),
-      NULL },
-
     { ngx_string("fastcgi_index"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
@@ -265,6 +224,27 @@
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.header_buffer_size),
       NULL },
 
+    { ngx_string("fastcgi_method"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.method),
+      ngx_http_fastcgi_set_methods },
+
+    { ngx_string("fastcgi_pass_request_headers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_headers),
+      NULL },
+
+    { ngx_string("fastcgi_pass_request_body"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_body),
+      NULL },
+
     { ngx_string("fastcgi_redirect_errors"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -276,7 +256,7 @@
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.x_powered_by),
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_x_powered_by),
       NULL },
 
     { ngx_string("fastcgi_read_timeout"),
@@ -328,26 +308,20 @@
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
       &ngx_http_fastcgi_next_upstream_masks },
 
-    { ngx_string("fastcgi_set_var"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_fastcgi_set_var,
+    { ngx_string("fastcgi_param"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_table_elt_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      0,
+      offsetof(ngx_http_fastcgi_loc_conf_t, params_source),
       NULL },
 
-    { ngx_string("fastcgi_params"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
-      ngx_conf_set_bitmask_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_fastcgi_loc_conf_t, params),
-      &ngx_http_fastcgi_params_masks },
-
       ngx_null_command
 };
 
 
 ngx_http_module_t  ngx_http_fastcgi_module_ctx = {
-    NULL,                                  /* pre conf */
+    ngx_http_fastcgi_add_variables,        /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -361,7 +335,7 @@
 
 
 ngx_module_t  ngx_http_fastcgi_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_fastcgi_module_ctx,          /* module context */
     ngx_http_fastcgi_commands,             /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -396,26 +370,15 @@
 
     u->conf = &flcf->upstream;
 
-    u->location0 = flcf->location;
-
     u->create_request = ngx_http_fastcgi_create_request;
     u->reinit_request = ngx_http_fastcgi_reinit_request;
     u->process_header = ngx_http_fastcgi_process_header;
-    u->send_header = ngx_http_fastcgi_send_header;
     u->abort_request = ngx_http_fastcgi_abort_request;
     u->finalize_request = ngx_http_fastcgi_finalize_request;
 
     u->pipe.input_filter = ngx_http_fastcgi_input_filter;
     u->pipe.input_ctx = r;
 
-    u->log_ctx = r->connection->log->data;
-    u->log_handler = ngx_http_upstream_log_error;
-
-    u->schema0.len = sizeof("fastcgi://") - 1;
-    u->schema0.data = (u_char *) "fastcgi://";
-    u->uri0.len = sizeof("/") - 1;
-    u->uri0.data = (u_char *) "/";
-
     r->upstream = u;
 
     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
@@ -431,206 +394,67 @@
 static ngx_int_t
 ngx_http_fastcgi_create_request(ngx_http_request_t *r)
 {
-    u_char                             ch, *pos, addr_text[INET_ADDRSTRLEN],
-                                       port_text[sizeof("65535") - 1];
-    size_t                             size, len, index, padding,
-                                       addr_len, port_len;
-    off_t                              file_pos;
-    ngx_buf_t                         *b;
-    socklen_t                          slen;
-    ngx_chain_t                       *cl, *body;
-    ngx_uint_t                         i, n, next, *vindex, port;
-    ngx_list_part_t                   *part;
-    ngx_table_elt_t                   *header;
-    struct sockaddr_in                 sin, *sinp;
-    ngx_http_variable_t               *var;
-    ngx_http_variable_value_t         *value;
-    ngx_http_core_loc_conf_t          *clcf;
-    ngx_http_core_main_conf_t         *cmcf;
-    ngx_http_fastcgi_header_t         *h;
-    ngx_http_fastcgi_loc_conf_t       *flcf;
-    ngx_http_fastcgi_begin_request_t  *br;
+    off_t                         file_pos;
+    u_char                        ch, *pos;
+    size_t                        size, len, key_len, val_len, padding;
+    ngx_uint_t                    i, n, next;
+    ngx_buf_t                    *b;
+    ngx_chain_t                  *cl, *body;
+    ngx_list_part_t              *part;
+    ngx_table_elt_t              *header;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e, le;
+    ngx_http_fastcgi_header_t    *h;
+    ngx_http_fastcgi_loc_conf_t  *flcf;
+    ngx_http_script_len_code_pt   lcode;
 
+    len = 0;
 
     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
 
-    if ((flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) && r->in_addr == 0) {
+    if (flcf->params_len) {
+        ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
 
-        slen = sizeof(struct sockaddr_in);
-        if (getsockname(r->connection->fd,
-                        (struct sockaddr *) &sin, &slen) == -1)
-        {
-            ngx_log_error(NGX_LOG_CRIT, r->connection->log,
-                          ngx_socket_errno, "getsockname() failed");
-            return NGX_ERROR;
-        }
+        le.ip = flcf->params_len->elts;
+        le.request = r;
 
-        r->in_addr = sin.sin_addr.s_addr;
-    }
+        while (*(uintptr_t *) le.ip) {
 
-    addr_len = ngx_inet_ntop(r->connection->listening->family, &r->in_addr,
-                             addr_text, INET_ADDRSTRLEN);
-    if (addr_len == 0) {
-        return NGX_ERROR;
-    }
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            key_len = lcode(&le);
 
-#if (NGX_SUPPRESS_WARN)
-    clcf = NULL;
-    var = NULL;
-    vindex = NULL;
-#endif
-
-
-    if (r->upstream->method) {
-        len = 1 + 1 + sizeof("REQUEST_METHOD") - 1
-                + ngx_http_fastcgi_methods[r->upstream->method - 1].len;
-    
-    } else {
-        len = 1 + ((r->method_name.len - 1 > 127) ? 4 : 1)
-                                            + sizeof("REQUEST_METHOD") - 1
-                                            + r->method_name.len - 1;
-    }
-
-
-    index = (r->uri.data[r->uri.len - 1] == '/') ? flcf->index.len : 0;
-
-    len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1)
-        + sizeof("PATH_TRANSLATED") - 1 + flcf->root.len + r->uri.len + index;
-
-    if (r->args.len) {
-        len += 1 + ((r->args.len > 127) ? 4 : 1) + sizeof("QUERY_STRING") - 1
-            + r->args.len;
-    }
-
-    if (r->headers_in.content_length_n > 0) {
-        len += 1 + ((r->headers_in.content_length->value.len > 127) ? 4 : 1)
-            + sizeof("CONTENT_LENGTH") - 1
-            + r->headers_in.content_length->value.len;
-    }
-
-
-    if (r->headers_in.content_type) {
-        len += 1 + ((r->headers_in.content_type->value.len > 127) ? 4 : 1)
-            + sizeof("CONTENT_TYPE") - 1
-            + r->headers_in.content_type->value.len;
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) {
-        len += 1 + 1 + sizeof("REDIRECT_STATUS200") - 1;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) {
-        len += 1 + ((r->unparsed_uri.len > 127) ? 4 : 1)
-            + sizeof("REQUEST_URI") - 1 + r->unparsed_uri.len;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_DOCUMENT_ROOT) {
-        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-        len += 1 + ((clcf->root.len > 127) ? 4 : 1)
-            + sizeof("DOCUMENT_ROOT") - 1 + clcf->root.len;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_FILENAME) {
-        len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1)
-            + sizeof("SCRIPT_FILENAME") - 1
-            + flcf->root.len + r->uri.len + index;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) {
-        len += 1 + ((r->uri.len + index > 127) ? 4 : 1)
-            + sizeof("SCRIPT_NAME") - 1 + r->uri.len + index ;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) {
-        len += 1 + 1 + sizeof("REMOTE_ADDR") - 1 + r->connection->addr_text.len;
-    }
-
-    port_len = 0;
-
-    if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_PORT) {
-
-        /* AF_INET only */
-
-        if (r->connection->sockaddr->sa_family == AF_INET) {
-            sinp = (struct sockaddr_in *) r->connection->sockaddr;
-
-            port = ntohs(sinp->sin_port);
-
-            if (port > 0 && port < 65536) {
-                port_len = ngx_sprintf(port_text, "%ui", port) - port_text;
+            for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
+                lcode = *(ngx_http_script_len_code_pt *) le.ip;
             }
+            le.ip += sizeof(uintptr_t);
 
-            len += 1 + 1 + sizeof("REMOTE_PORT") - 1 + port_len;
-        }
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) {
-        len += 1 + 1 + sizeof("SERVER_NAME") - 1 + r->server_name.len;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) {
-        len += 1 + 1 + sizeof("SERVER_PORT") - 1 + r->port_text->len - 1;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) {
-        len += 1 + 1 + sizeof("SERVER_ADDR") - 1 + addr_len;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL
-        && r->http_protocol.len)
-    {
-        len += 1 + ((r->http_protocol.len > 127) ? 4 : 1)
-            + sizeof("SERVER_PROTOCOL") - 1 + r->http_protocol.len;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) {
-        len += 1 + 1 + sizeof("SERVER_SOFTWARE") - 1 + sizeof(NGINX_VER) - 1;
-    }
-
-    if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) {
-        len += 1 + 1 + sizeof("GATEWAY_INTERFACE") - 1 + sizeof("CGI/1.1") - 1;
-    }
-
-
-    if (flcf->vars) {
-        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-
-        var = cmcf->variables.elts;
-        vindex = flcf->vars->elts;
-
-        for (i = 0; i < flcf->vars->nelts; i++) {
-
-            value = ngx_http_get_indexed_variable(r, vindex[i]);
-            if (value == NULL) {
-                continue;
-            }
-
-            if (value->text.len) {
-                len += 1 + 1 + var[vindex[i]].name.len + value->text.len;
+            if (val_len) {
+                len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
             }
         }
     }
 
+    if (flcf->upstream.pass_request_headers) {
 
-    part = &r->headers_in.headers.part;
-    header = part->elts;
+        part = &r->headers_in.headers.part;
+        header = part->elts;
 
-    for (i = 0; /* void */; i++) {
+        for (i = 0; /* void */; i++) {
 
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0;
             }
 
-            part = part->next;
-            header = part->elts;
-            i = 0;
+            len += ((sizeof("HTTP_") - 1 + header[i].key.len > 127) ? 4 : 1)
+                + ((header[i].value.len > 127) ? 4 : 1)
+                + sizeof("HTTP_") - 1 + header[i].key.len + header[i].value.len;
         }
-
-        len += ((header[i].key.len > 127) ? 4 : 1)
-            + ((header[i].value.len > 127) ? 4 : 1)
-            + 5 + header[i].key.len + header[i].value.len;
     }
 
 
@@ -667,36 +491,13 @@
 
     cl->buf = b;
 
-    h = (ngx_http_fastcgi_header_t *) b->pos;
-
-    h->version = 1;
-    h->type = NGX_HTTP_FASTCGI_BEGIN_REQUEST;
-    h->request_id_hi = 0;
-    h->request_id_lo = 1;
-    h->content_length_hi = 0;
-    h->content_length_lo = sizeof(ngx_http_fastcgi_begin_request_t);
-    h->padding_length = 0;
-    h->reserved = 0;
-
-    br = (ngx_http_fastcgi_begin_request_t *)
-                                  (b->pos + sizeof(ngx_http_fastcgi_header_t));
-    br->role_hi = 0;
-    br->role_lo = NGX_HTTP_FASTCGI_RESPONDER;
-    br->flags = 0; /* NGX_HTTP_FASTCGI_KEEP_CONN */
-    br->reserved[0] = 0;
-    br->reserved[1] = 0;
-    br->reserved[2] = 0;
-    br->reserved[3] = 0;
-    br->reserved[4] = 0;
+    ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
+               sizeof(ngx_http_fastcgi_request_start_t));
 
     h = (ngx_http_fastcgi_header_t *)
              (b->pos + sizeof(ngx_http_fastcgi_header_t)
                      + sizeof(ngx_http_fastcgi_begin_request_t));
 
-    h->version = 1;
-    h->type = NGX_HTTP_FASTCGI_PARAMS;
-    h->request_id_hi = 0;
-    h->request_id_lo = 1;
     h->content_length_hi = (u_char) ((len >> 8) & 0xff);
     h->content_length_lo = (u_char) (len & 0xff);
     h->padding_length = (u_char) padding;
@@ -707,376 +508,109 @@
                      + sizeof(ngx_http_fastcgi_header_t);
 
 
-    *b->last++ = sizeof("PATH_TRANSLATED") - 1;
+    if (flcf->params_len) {
+        ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
 
-    len = flcf->root.len + r->uri.len + index;
-    if (len > 127) {
-        *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-        *b->last++ = (u_char) ((len >> 16) & 0xff);
-        *b->last++ = (u_char) ((len >> 8) & 0xff);
-        *b->last++ = (u_char) (len & 0xff);
+        e.ip = flcf->params->elts;
+        e.pos = b->last;
+        e.request = r;
 
-    } else {
-        *b->last++ = (u_char) len;
-    }
+        le.ip = flcf->params_len->elts;
 
-    b->last = ngx_cpymem(b->last, "PATH_TRANSLATED",
-                         sizeof("PATH_TRANSLATED") - 1);
-    b->last = ngx_cpymem(b->last, flcf->root.data, flcf->root.len);
-    b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
+        while (*(uintptr_t *) le.ip) {
 
-    if (index) {
-        b->last = ngx_cpymem(b->last, flcf->index.data, index);
-    }
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            key_len = (u_char) lcode(&le);
 
+            for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
+                lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            }
+            le.ip += sizeof(uintptr_t);
 
-    *b->last++ = sizeof("REQUEST_METHOD") - 1;
+            if (val_len) {
+                *e.pos++ = (u_char) key_len;
 
-    if (r->upstream->method) {
-        *b->last++ = (u_char)
-                         ngx_http_fastcgi_methods[r->upstream->method - 1].len;
+                if (val_len > 127) {
+                    *e.pos++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
+                    *e.pos++ = (u_char) ((val_len >> 16) & 0xff);
+                    *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
+                    *e.pos++ = (u_char) (val_len & 0xff);
 
-        b->last = ngx_cpymem(b->last, "REQUEST_METHOD",
-                             sizeof("REQUEST_METHOD") - 1);
-
-        b->last = ngx_cpymem(b->last,
-                        ngx_http_fastcgi_methods[r->upstream->method - 1].data,
-                        ngx_http_fastcgi_methods[r->upstream->method - 1].len);
-
-    } else {
-        len = r->method_name.len - 1;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        b->last = ngx_cpymem(b->last, "REQUEST_METHOD",
-                             sizeof("REQUEST_METHOD") - 1);
-        b->last = ngx_cpymem(b->last, r->method_name.data, len);
-    }
-
-
-    if (r->args.len) {
-        *b->last++ = sizeof("QUERY_STRING") - 1;
-
-        len = r->args.len;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        b->last = ngx_cpymem(b->last, "QUERY_STRING",
-                             sizeof("QUERY_STRING") - 1);
-        b->last = ngx_cpymem(b->last, r->args.data, len);
-    }
-
-
-    if (r->headers_in.content_length_n > 0) {
-        *b->last++ = sizeof("CONTENT_LENGTH") - 1;
-
-        len = r->headers_in.content_length->value.len;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        b->last = ngx_cpymem(b->last, "CONTENT_LENGTH",
-                             sizeof("CONTENT_LENGTH") - 1);
-        b->last = ngx_cpymem(b->last, r->headers_in.content_length->value.data,
-                             len);
-    }
-
-
-    if (r->headers_in.content_type) {
-        *b->last++ = sizeof("CONTENT_TYPE") - 1;
-
-        len = r->headers_in.content_type->value.len;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        b->last = ngx_cpymem(b->last, "CONTENT_TYPE",
-                             sizeof("CONTENT_TYPE") - 1);
-        b->last = ngx_cpymem(b->last, r->headers_in.content_type->value.data,
-                             len);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) {
-        *b->last++ = sizeof("REDIRECT_STATUS") - 1;
-        *b->last++ = sizeof("200") - 1;
-        b->last = ngx_cpymem(b->last, "REDIRECT_STATUS200",
-                             sizeof("REDIRECT_STATUS200") - 1);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) {
-        *b->last++ = sizeof("REQUEST_URI") - 1;
-
-        len = r->unparsed_uri.len;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        b->last = ngx_cpymem(b->last, "REQUEST_URI", sizeof("REQUEST_URI") - 1);
-        b->last = ngx_cpymem(b->last, r->unparsed_uri.data, len);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_DOCUMENT_ROOT) {
-        *b->last++ = sizeof("DOCUMENT_ROOT") - 1;
-
-        len = clcf->root.len;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        b->last = ngx_cpymem(b->last, "DOCUMENT_ROOT",
-                             sizeof("DOCUMENT_ROOT") - 1);
-        b->last = ngx_cpymem(b->last, clcf->root.data, len);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_FILENAME) {
-        *b->last++ = sizeof("SCRIPT_FILENAME") - 1;
-
-        len = flcf->root.len + r->uri.len + index;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        b->last = ngx_cpymem(b->last, "SCRIPT_FILENAME",
-                             sizeof("SCRIPT_FILENAME") - 1);
-        b->last = ngx_cpymem(b->last, flcf->root.data, flcf->root.len);
-        b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
-
-        if (index) {
-            b->last = ngx_cpymem(b->last, flcf->index.data, index);
-        }
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) {
-        *b->last++ = sizeof("SCRIPT_NAME") - 1;
-
-        len = r->uri.len + index;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        b->last = ngx_cpymem(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME") - 1);
-        b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len);
-
-        if (index) {
-            b->last = ngx_cpymem(b->last, flcf->index.data, index);
-        }
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) {
-        *b->last++ = sizeof("REMOTE_ADDR") - 1;
-        *b->last++ = (u_char) (r->connection->addr_text.len);
-        b->last = ngx_cpymem(b->last, "REMOTE_ADDR", sizeof("REMOTE_ADDR") - 1);
-        b->last = ngx_cpymem(b->last, r->connection->addr_text.data,
-                             r->connection->addr_text.len);
-    }
-
-
-    if (port_len) {
-        *b->last++ = sizeof("REMOTE_PORT") - 1;
-        *b->last++ = (u_char) port_len;
-        b->last = ngx_cpymem(b->last, "REMOTE_PORT", sizeof("REMOTE_PORT") - 1);
-        b->last = ngx_cpymem(b->last, port_text, port_len);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) {
-        *b->last++ = sizeof("SERVER_NAME") - 1;
-        *b->last++ = (u_char) r->server_name.len;
-        b->last = ngx_cpymem(b->last, "SERVER_NAME", sizeof("SERVER_NAME") - 1);
-        b->last = ngx_cpymem(b->last, r->server_name.data, r->server_name.len);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) {
-        *b->last++ = sizeof("SERVER_PORT") - 1;
-        *b->last++ = (u_char) (r->port_text->len - 1);
-        b->last = ngx_cpymem(b->last, "SERVER_PORT", sizeof("SERVER_PORT") - 1);
-        b->last = ngx_cpymem(b->last, r->port_text->data + 1,
-                             r->port_text->len - 1);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) {
-        *b->last++ = sizeof("SERVER_ADDR") - 1;
-        *b->last++ = (u_char) addr_len;
-        b->last = ngx_cpymem(b->last, "SERVER_ADDR", sizeof("SERVER_ADDR") - 1);
-        b->last = ngx_cpymem(b->last, addr_text, addr_len);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL
-        && r->http_protocol.len)
-    {
-        *b->last++ = sizeof("SERVER_PROTOCOL") - 1;
-
-        len = r->http_protocol.len;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        b->last = ngx_cpymem(b->last, "SERVER_PROTOCOL",
-                             sizeof("SERVER_PROTOCOL") - 1);
-        b->last = ngx_cpymem(b->last, r->http_protocol.data, len);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) {
-        *b->last++ = sizeof("SERVER_SOFTWARE") - 1;
-        *b->last++ = (u_char) (sizeof(NGINX_VER) - 1);
-        b->last = ngx_cpymem(b->last, "SERVER_SOFTWARE",
-                             sizeof("SERVER_SOFTWARE") - 1);
-        b->last = ngx_cpymem(b->last, NGINX_VER, sizeof(NGINX_VER) - 1);
-    }
-
-
-    if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) {
-        *b->last++ = sizeof("GATEWAY_INTERFACE") - 1;
-        *b->last++ = (u_char) (sizeof("CGI/1.1") - 1);
-        b->last = ngx_cpymem(b->last, "GATEWAY_INTERFACE",
-                             sizeof("GATEWAY_INTERFACE") - 1);
-        b->last = ngx_cpymem(b->last, "CGI/1.1", sizeof("CGI/1.1") - 1);
-    }
-
-
-    if (flcf->vars) {
-        for (i = 0; i < flcf->vars->nelts; i++) {
-
-            value = ngx_http_get_indexed_variable(r, vindex[i]);
-            if (value == NULL) {
-                continue;
+                } else {
+                    *e.pos++ = (u_char) val_len;
+                }
             }
 
-            if (value->text.len == 0) {
-                continue;
+            e.skip = val_len ? 0 : 1;
+
+            while (*(uintptr_t *) e.ip) {
+                code = *(ngx_http_script_code_pt *) e.ip;
+                code((ngx_http_script_engine_t *) &e);
             }
-
-            *b->last++ = (u_char) var[vindex[i]].name.len;
-            *b->last++ = (u_char) value->text.len;
-
-            b->last = ngx_cpymem(b->last, var[vindex[i]].name.data,
-                                 var[vindex[i]].name.len);
-
-            b->last = ngx_cpymem(b->last, value->text.data, value->text.len);
+            e.ip += sizeof(uintptr_t);
         }
+
+        b->last = e.pos;
     }
 
 
-    part = &r->headers_in.headers.part;
-    header = part->elts;
+    if (flcf->upstream.pass_request_headers) {
 
-    for (i = 0; /* void */; i++) {
+        part = &r->headers_in.headers.part;
+        header = part->elts;
 
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
+        for (i = 0; /* void */; i++) {
+
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break; 
+                }
+    
+                part = part->next;
+                header = part->elts;
+                i = 0;
             }
 
-            part = part->next;
-            header = part->elts;
-            i = 0;
-        }
-
-        len = 5 + header[i].key.len;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        len = header[i].value.len;
-        if (len > 127) {
-            *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
-            *b->last++ = (u_char) ((len >> 16) & 0xff);
-            *b->last++ = (u_char) ((len >> 8) & 0xff);
-            *b->last++ = (u_char) (len & 0xff);
-
-        } else {
-            *b->last++ = (u_char) len;
-        }
-
-        b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
-
-        for (n = 0; n < header[i].key.len; n++) {
-            ch = header[i].key.data[n];
-
-            if (ch >= 'a' && ch <= 'z') {
-                ch &= ~0x20;
-
-            } else if (ch == '-') {
-                ch = '_';
+            len = sizeof("HTTP_") - 1 + header[i].key.len;
+            if (len > 127) {
+                *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+                *b->last++ = (u_char) ((len >> 16) & 0xff);
+                *b->last++ = (u_char) ((len >> 8) & 0xff);
+                *b->last++ = (u_char) (len & 0xff);
+    
+            } else {
+                *b->last++ = (u_char) len;
             }
 
-            *b->last++ = ch;
-        }
+            len = header[i].value.len;
+            if (len > 127) {
+                *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80);
+                *b->last++ = (u_char) ((len >> 16) & 0xff);
+                *b->last++ = (u_char) ((len >> 8) & 0xff);
+                *b->last++ = (u_char) (len & 0xff);
 
-        b->last = ngx_cpymem(b->last, header[i].value.data,
-                             header[i].value.len);
+            } else {
+                *b->last++ = (u_char) len;
+            }
+
+            b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
+
+            for (n = 0; n < header[i].key.len; n++) {
+                ch = header[i].key.data[n];
+
+                if (ch >= 'a' && ch <= 'z') {
+                    ch &= ~0x20;
+
+                } else if (ch == '-') {
+                    ch = '_';
+                }
+
+                *b->last++ = ch;
+            }
+
+            b->last = ngx_cpymem(b->last, header[i].value.data,
+                                 header[i].value.len);
+        }
     }
 
 
@@ -1101,103 +635,109 @@
     h = (ngx_http_fastcgi_header_t *) b->last;
     b->last += sizeof(ngx_http_fastcgi_header_t);
 
-    body = r->request_body->bufs;
-    r->request_body->bufs = cl;
+    if (flcf->upstream.pass_request_body) {
+        body = r->upstream->request_bufs;
+        r->upstream->request_bufs = cl;
 
 #if (NGX_SUPPRESS_WARN)
-    file_pos = 0;
-    pos = NULL;
+        file_pos = 0;
+        pos = NULL;
 #endif
 
-    while (body) {
-
-        if (body->buf->in_file) {
-            file_pos = body->buf->file_pos;
-
-        } else {
-            pos = body->buf->pos;
-        }
-
-        next = 0;
-
-        do {
-            b = ngx_alloc_buf(r->pool);
-            if (b == NULL) {
-                return NGX_ERROR;
-            }
-
-            ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
+        while (body) {
 
             if (body->buf->in_file) {
-                b->file_pos = file_pos;
-                file_pos += 32 * 1024;
-
-                if (file_pos > body->buf->file_last) {
-                    file_pos = body->buf->file_last;
-                    next = 1;
-                }
-
-                b->file_last = file_pos;
-                len = (ngx_uint_t) (file_pos - b->file_pos);
+                file_pos = body->buf->file_pos;
 
             } else {
-                b->pos = pos;
-                pos += 32 * 1024;
+                pos = body->buf->pos;
+            }
 
-                if (pos > body->buf->last) {
-                    pos = body->buf->last;
-                    next = 1;
+            next = 0;
+
+            do {
+                b = ngx_alloc_buf(r->pool);
+                if (b == NULL) {
+                    return NGX_ERROR;
                 }
 
-                b->last = pos;
-                len = (ngx_uint_t) (pos - b->pos);
-            }
+                ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
 
-            padding = 8 - len % 8;
-            padding = (padding == 8) ? 0 : padding;
+                if (body->buf->in_file) {
+                    b->file_pos = file_pos;
+                    file_pos += 32 * 1024;
 
-            h->version = 1;
-            h->type = NGX_HTTP_FASTCGI_STDIN;
-            h->request_id_hi = 0;
-            h->request_id_lo = 1;
-            h->content_length_hi = (u_char) ((len >> 8) & 0xff);
-            h->content_length_lo = (u_char) (len & 0xff);
-            h->padding_length = (u_char) padding;
-            h->reserved = 0;
+                    if (file_pos > body->buf->file_last) {
+                        file_pos = body->buf->file_last;
+                        next = 1;
+                    }
 
-            cl->next = ngx_alloc_chain_link(r->pool);
-            if (cl->next == NULL) {
-                return NGX_ERROR;
-            }
+                    b->file_last = file_pos;
+                    len = (ngx_uint_t) (file_pos - b->file_pos);
 
-            cl = cl->next;
-            cl->buf = b;
+                } else {
+                    b->pos = pos;
+                    pos += 32 * 1024;
 
-            b = ngx_create_temp_buf(r->pool, sizeof(ngx_http_fastcgi_header_t)
-                                             + padding);
-            if (b == NULL) {
-                return NGX_ERROR;
-            }
+                    if (pos > body->buf->last) {
+                        pos = body->buf->last;
+                        next = 1;
+                    }
 
-            if (padding) {
-                ngx_memzero(b->last, padding);
-                b->last += padding;
-            }
+                    b->last = pos;
+                    len = (ngx_uint_t) (pos - b->pos);
+                }
 
-            h = (ngx_http_fastcgi_header_t *) b->last;
-            b->last += sizeof(ngx_http_fastcgi_header_t);
+                padding = 8 - len % 8;
+                padding = (padding == 8) ? 0 : padding;
 
-            cl->next = ngx_alloc_chain_link(r->pool);
-            if (cl->next == NULL) {
-                return NGX_ERROR;
-            }
+                h->version = 1;
+                h->type = NGX_HTTP_FASTCGI_STDIN;
+                h->request_id_hi = 0;
+                h->request_id_lo = 1;
+                h->content_length_hi = (u_char) ((len >> 8) & 0xff);
+                h->content_length_lo = (u_char) (len & 0xff);
+                h->padding_length = (u_char) padding;
+                h->reserved = 0;
 
-            cl = cl->next;
-            cl->buf = b;
+                cl->next = ngx_alloc_chain_link(r->pool);
+                if (cl->next == NULL) {
+                    return NGX_ERROR;
+                }
 
-        } while (!next);
+                cl = cl->next;
+                cl->buf = b;
 
-        body = body->next;
+                b = ngx_create_temp_buf(r->pool,
+                                        sizeof(ngx_http_fastcgi_header_t)
+                                        + padding);
+                if (b == NULL) {
+                    return NGX_ERROR;
+                }
+
+                if (padding) {
+                    ngx_memzero(b->last, padding);
+                    b->last += padding;
+                }
+
+                h = (ngx_http_fastcgi_header_t *) b->last;
+                b->last += sizeof(ngx_http_fastcgi_header_t);
+
+                cl->next = ngx_alloc_chain_link(r->pool);
+                if (cl->next == NULL) {
+                    return NGX_ERROR;
+                }
+
+                cl = cl->next;
+                cl->buf = b;
+
+            } while (!next);
+
+            body = body->next;
+        }
+
+    } else {
+        r->upstream->request_bufs = cl;
     }
 
     h->version = 1;
@@ -1229,17 +769,6 @@
     f->state = ngx_http_fastcgi_st_version;
     f->header = 0;
 
-    ngx_memzero(&f->upstream->headers_in,
-                sizeof(ngx_http_fastcgi_headers_in_t));
-
-    if (f->upstream->headers_in.headers.part.elts) {
-        if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 8,
-                                         sizeof(ngx_table_elt_t)) == NGX_ERROR)
-        {
-            return NGX_ERROR;
-        }
-    }
-
     return NGX_OK;
 }
 
@@ -1247,16 +776,21 @@
 static ngx_int_t
 ngx_http_fastcgi_process_header(ngx_http_request_t *r)
 {
-    u_char                  *start, *last;
-    ngx_str_t               *status_line, line;
-    ngx_int_t                rc, status;
-    ngx_uint_t               i;
-    ngx_table_elt_t         *h;
-    ngx_http_upstream_t     *u;
-    ngx_http_fastcgi_ctx_t  *f;
+    u_char                         *start, *last;
+    ngx_str_t                      *status_line, line;
+    ngx_int_t                       rc, status;
+    ngx_uint_t                      key;
+    ngx_table_elt_t                *h;
+    ngx_http_upstream_t            *u;
+    ngx_http_fastcgi_ctx_t         *f;
+    ngx_http_upstream_header_t     *hh;
+    ngx_http_upstream_main_conf_t  *umcf;
 
     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
 
+    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+    hh = (ngx_http_upstream_header_t *) umcf->headers_in_hash.buckets;
+
     if (f == NULL) {
         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
         if (f == NULL) {
@@ -1264,17 +798,6 @@
         }
 
         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
-
-        f->upstream = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_upstream_t));
-        if (f->upstream == NULL) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 8,
-                                         sizeof(ngx_table_elt_t)) == NGX_ERROR)
-        {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
     }
 
     u = r->upstream;
@@ -1424,11 +947,13 @@
 
                 /* a header line has been parsed successfully */
 
-                h = ngx_list_push(&f->upstream->headers_in.headers);
+                h = ngx_list_push(&u->headers_in.headers);
                 if (h == NULL) {
                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
                 }
 
+                h->hash = r->header_hash;
+
                 h->key.len = r->header_name_end - r->header_name_start;
                 h->value.len = r->header_end - r->header_start;
 
@@ -1443,18 +968,13 @@
                 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
                 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
 
-                for (i = 0; ngx_http_fastcgi_headers_in[i].name.len != 0; i++) {
-                    if (ngx_http_fastcgi_headers_in[i].name.len != h->key.len) {
-                        continue;
-                    }
+                key = h->hash % umcf->headers_in_hash.hash_size;
 
-                    if (ngx_strcasecmp(ngx_http_fastcgi_headers_in[i].name.data,
-                                                             h->key.data) == 0)
-                    {
-                        *((ngx_table_elt_t **)
-                                 ((char *) &f->upstream->headers_in
-                                 + ngx_http_fastcgi_headers_in[i].offset)) = h;
-                        break;
+                if (hh[key].name.len == h->key.len
+                    && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0)
+                {
+                    if (hh[key].handler(r, h, hh[key].offset) != NGX_OK) {
+                        return NGX_HTTP_INTERNAL_SERVER_ERROR;
                     }
                 }
 
@@ -1472,8 +992,8 @@
                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                                "http fastcgi header done");
 
-                if (f->upstream->headers_in.status) {
-                    status_line = &f->upstream->headers_in.status->value;
+                if (u->headers_in.status) {
+                    status_line = &u->headers_in.status->value;
 
                     status = ngx_atoi(status_line->data, 3);
 
@@ -1541,84 +1061,6 @@
 
 
 static ngx_int_t
-ngx_http_fastcgi_send_header(ngx_http_request_t *r)
-{
-    ngx_uint_t                      i;
-    ngx_list_part_t                *part;
-    ngx_table_elt_t                *ho, *h;
-    ngx_http_fastcgi_ctx_t         *f;
-    ngx_http_fastcgi_headers_in_t  *headers_in;
-
-    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
-
-    headers_in = &f->upstream->headers_in;
-    part = &headers_in->headers.part;
-    h = part->elts;
-
-    for (i = 0; /* void */; i++) {
-
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
-            }
-
-            part = part->next;
-            h = part->elts;
-            i = 0;
-        }
-
-        /* ignore some headers */
-
-        if (&h[i] == headers_in->status) {
-            continue;
-        }
-
-
-        if (&h[i] == headers_in->x_powered_by
-            && !r->upstream->conf->x_powered_by)
-        {
-            continue;
-        }
-
-
-        /* "Content-Type" is handled specially */
-
-        if (&h[i] == headers_in->content_type) {
-            r->headers_out.content_type = &h[i];
-            r->headers_out.content_type->key.len = 0;
-            continue;
-        }
-
-
-        /* copy some header pointers and set up r->headers_out */
-
-        ho = ngx_list_push(&r->headers_out.headers);
-        if (ho == NULL) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        *ho = h[i];
-
-#if (NGX_HTTP_GZIP)
-        if (&h[i] == headers_in->content_encoding) {
-            r->headers_out.content_encoding = ho;
-            continue;
-        }
-#endif
-
-        if (&h[i] == headers_in->content_length) {
-            r->headers_out.content_length = ho;
-            r->headers_out.content_length_n = ngx_atoi(ho->value.data,
-                                                       ho->value.len);
-            continue;
-        }
-    }
-
-    return ngx_http_send_header(r);
-}
-
-
-static ngx_int_t
 ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
 {
     ngx_int_t                rc;
@@ -1937,7 +1379,6 @@
         }
     }
 
-    f->pos = p + 1;
     f->state = state;
 
     return NGX_AGAIN;
@@ -1964,140 +1405,19 @@
 }
 
 
-static char *
-ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+static ngx_int_t
+ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
 {
-    ngx_http_fastcgi_loc_conf_t *lcf = conf;
+    ngx_http_variable_t  *var;
 
-    ngx_str_t                   *value;
-    ngx_inet_upstream_t          inet_upstream;
-    ngx_http_core_loc_conf_t    *clcf;
-#if (NGX_HAVE_UNIX_DOMAIN)
-    ngx_unix_domain_upstream_t   unix_upstream;
-#endif
-
-    value = cf->args->elts;
-
-    if (ngx_strncasecmp(value[1].data, "unix:", 5) == 0) {
-
-#if (NGX_HAVE_UNIX_DOMAIN)
-
-        ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t));
-
-        unix_upstream.name = value[1];
-        unix_upstream.url = value[1];
-
-        lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
-        if (lcf->peers == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-#else
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "the unix domain sockets are not supported "
-                           "on this platform");
-        return NGX_CONF_ERROR;
-
-#endif
-
-    } else {
-        ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t));
-
-        inet_upstream.name = value[1];
-        inet_upstream.url = value[1];
-    
-        lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
-        if (lcf->peers == NULL) {
-            return NGX_CONF_ERROR;
-        }
+    var = ngx_http_add_variable(cf, &ngx_http_fastcgi_script_name, 0);
+    if (var == NULL) {
+        return NGX_ERROR;
     }
 
-    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+    var->handler = ngx_http_fastcgi_script_name_variable;
 
-    clcf->handler = ngx_http_fastcgi_handler;
-
-#if (NGX_PCRE)
-    lcf->location = clcf->regex ? &ngx_http_fastcgi_uri : &clcf->name;
-#else
-    lcf->location = &clcf->name;
-#endif
-
-    if (clcf->name.data[clcf->name.len - 1] == '/') {
-        clcf->auto_redirect = 1;
-    }
-
-    return NGX_CONF_OK;
-}
-
-
-static char *
-ngx_http_fastcgi_set_var(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_http_fastcgi_loc_conf_t *lcf = conf;
-
-    ngx_uint_t                  i, *index;
-    ngx_str_t                  *value;
-    ngx_http_variable_t        *var;
-    ngx_http_core_main_conf_t  *cmcf;
-
-    if (lcf->vars == NULL) {
-        lcf->vars = ngx_array_create(cf->pool, 4,
-                                     sizeof(ngx_http_variable_t *));
-        if (lcf->vars == NULL) {
-            return NGX_CONF_ERROR;
-        }
-    }
-
-    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
-
-    value = cf->args->elts;
-
-    var = cmcf->variables.elts;
-    for (i = 0; i < cmcf->variables.nelts; i++) {
-        if (ngx_strcasecmp(var[i].name.data, value[1].data) == 0) {
-
-            index = ngx_array_push(lcf->vars);
-            if (index == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            *index = var[i].index;
-            return NGX_CONF_OK;
-        }
-    }
-
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "unknown variable name \"%V\"", &value[1]);
-    return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
-{
-#if (NGX_FREEBSD)
-    ssize_t *np = data;
-
-    if (*np >= ngx_freebsd_net_inet_tcp_sendspace) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "\"fastcgi_send_lowat\" must be less than %d "
-                           "(sysctl net.inet.tcp.sendspace)",
-                           ngx_freebsd_net_inet_tcp_sendspace);
-
-        return NGX_CONF_ERROR;
-    }
-
-#elif !(NGX_HAVE_SO_SNDLOWAT)
-    ssize_t *np = data;
-
-    ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
-                       "\"fastcgi_send_lowat\" is not supported, ignored");
-
-    *np = 0;
-
-#endif
-
-    return NGX_CONF_OK;
+    return NGX_OK;
 }
 
 
@@ -2118,12 +1438,12 @@
      *     conf->upstream.path = NULL;
      *     conf->upstream.next_upstream = 0;
      *     conf->upstream.temp_path = NULL;
-     *     conf->params = 0;
-     *     conf->root.len = 0;
-     *     conf->root.data = NULL;
+     *     conf->upstream.schema = { 0, NULL };
+     *     conf->upstream.uri = { 0, NULL };
+     *     conf->upstream.location = NULL;
+     *
      *     conf->index.len = 0;
      *     conf->index.data = NULL;
-     *     conf->location = NULL;
      */
 
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
@@ -2135,14 +1455,23 @@
     conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE;
     conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE; 
     conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE;
-    
-    conf->upstream.redirect_errors = NGX_CONF_UNSET;
+
     conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET;
-    conf->upstream.x_powered_by = NGX_CONF_UNSET;
+    conf->upstream.method = NGX_CONF_UNSET_UINT;
+    conf->upstream.pass_request_headers = NGX_CONF_UNSET;
+    conf->upstream.pass_request_body = NGX_CONF_UNSET;
+
+    conf->upstream.redirect_errors = NGX_CONF_UNSET;
 
     /* "fastcgi_cyclic_temp_file" is disabled */
     conf->upstream.cyclic_temp_file = 0;
 
+    conf->upstream.pass_x_powered_by = NGX_CONF_UNSET;
+
+    /* the hardcoded values */
+    conf->upstream.pass_server = 1;
+    conf->upstream.pass_date = 1;
+
     return conf;
 }
 
@@ -2153,7 +1482,13 @@
     ngx_http_fastcgi_loc_conf_t *prev = parent;
     ngx_http_fastcgi_loc_conf_t *conf = child;
 
-    size_t  size;
+    u_char                       *p;
+    size_t                        size;
+    uintptr_t                    *code;
+    ngx_uint_t                    i;
+    ngx_table_elt_t              *src;
+    ngx_http_script_compile_t     sc;
+    ngx_http_script_copy_code_t  *copy;
 
     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                               prev->upstream.connect_timeout, 60000);
@@ -2263,51 +1598,300 @@
                               NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0,
                               ngx_garbage_collector_temp_handler, cf);
 
-
-    ngx_conf_merge_msec_value(conf->upstream.redirect_errors,
-                              prev->upstream.redirect_errors, 0);
-
     ngx_conf_merge_msec_value(conf->upstream.pass_unparsed_uri,
                               prev->upstream.pass_unparsed_uri, 0);
 
-    if (conf->upstream.pass_unparsed_uri && conf->location->len > 1) {
+    if (conf->upstream.pass_unparsed_uri && conf->upstream.location->len > 1) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                       "\"fastcgi_pass_unparsed_uri\" can be set for "
                       "location \"/\" or given by regular expression.");
         return NGX_CONF_ERROR;
     }
 
-    ngx_conf_merge_msec_value(conf->upstream.x_powered_by,
-                              prev->upstream.x_powered_by, 1);
-
-
-    ngx_conf_merge_bitmask_value(conf->params, prev->params,
-                              (NGX_CONF_BITMASK_SET
-                               |NGX_HTTP_FASTCGI_REMOTE_ADDR
-                               |NGX_HTTP_FASTCGI_REMOTE_USER
-                               |NGX_HTTP_FASTCGI_SERVER_NAME
-                               |NGX_HTTP_FASTCGI_SERVER_PORT
-                               |NGX_HTTP_FASTCGI_SCRIPT_NAME
-                               |NGX_HTTP_FASTCGI_AUTH_TYPE
-                               |NGX_HTTP_FASTCGI_REQUEST_URI
-                               |NGX_HTTP_FASTCGI_REDIRECT_STATUS));
-
-    ngx_conf_merge_str_value(conf->root, prev->root, "");
-
-    if (conf->root.len && conf->root.data[conf->root.len - 1] == '/') {
-        conf->root.len--;
+    if (conf->upstream.method == NGX_CONF_UNSET_UINT) {
+        conf->upstream.method = prev->upstream.method; 
     }
 
+    ngx_conf_merge_value(conf->upstream.pass_request_headers,
+                              prev->upstream.pass_request_headers, 1);
+    ngx_conf_merge_value(conf->upstream.pass_request_body,
+                              prev->upstream.pass_request_body, 1);
+
+    ngx_conf_merge_msec_value(conf->upstream.redirect_errors,
+                              prev->upstream.redirect_errors, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.pass_x_powered_by,
+                              prev->upstream.pass_x_powered_by, 1);
+
+
     ngx_conf_merge_str_value(conf->index, prev->index, "");
 
-    if (conf->vars == NULL) {
-        conf->vars = prev->vars;
-    }
-
     if (conf->peers == NULL) {
         conf->peers = prev->peers;
         conf->upstream = prev->upstream;
     }
 
+    if (conf->params_source == NULL) {
+        conf->params_source = prev->params_source;
+        conf->params_len = prev->params_len;
+        conf->params = prev->params;
+
+        if (conf->params_source == NULL) {
+            return NGX_CONF_OK;
+        }
+    }
+
+    conf->params_len = ngx_array_create(cf->pool, 64, 1);
+    if (conf->params_len == NULL) {
+        return NGX_CONF_ERROR;
+    }
+    
+    conf->params = ngx_array_create(cf->pool, 512, 1);
+    if (conf->params == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    src = conf->params_source->elts;
+    for (i = 0; i < conf->params_source->nelts; i++) {
+
+        if (ngx_http_script_variables_count(&src[i].value) == 0) {
+            copy = ngx_array_push_n(conf->params_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                  ngx_http_script_copy_len_code;
+            copy->len = src[i].key.len;
+
+
+            copy = ngx_array_push_n(conf->params_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                 ngx_http_script_copy_len_code;
+            copy->len = src[i].value.len;
+
+
+            size = (sizeof(ngx_http_script_copy_code_t)
+                       + src[i].key.len + src[i].value.len
+                       + sizeof(uintptr_t) - 1)
+                    & ~(sizeof(uintptr_t) - 1);
+
+            copy = ngx_array_push_n(conf->params, size);
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+    
+            copy->code = ngx_http_script_copy_code;
+            copy->len = src[i].key.len + src[i].value.len;
+
+            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+
+            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
+            ngx_memcpy(p, src[i].value.data, src[i].value.len);
+
+        } else {
+            copy = ngx_array_push_n(conf->params_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                 ngx_http_script_copy_len_code;
+            copy->len = src[i].key.len;
+
+
+            size = (sizeof(ngx_http_script_copy_code_t)
+                    + src[i].key.len + sizeof(uintptr_t) - 1)
+                    & ~(sizeof(uintptr_t) - 1);
+
+            copy = ngx_array_push_n(conf->params, size);
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+    
+            copy->code = ngx_http_script_copy_code;
+            copy->len = src[i].key.len;
+
+            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+            ngx_memcpy(p, src[i].key.data, src[i].key.len);
+
+
+            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+            sc.cf = cf;
+            sc.source = &src[i].value;
+            sc.lengths = &conf->params_len;
+            sc.values = &conf->params;
+
+            if (ngx_http_script_compile(&sc) != NGX_OK) {
+                return NGX_CONF_ERROR;
+            }
+        }
+
+        code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+
+
+        code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+    }
+
+    code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
+    if (code == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    *code = (uintptr_t) NULL;
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, uintptr_t data)
+{
+    u_char                       *p;
+    ngx_http_variable_value_t    *vv;
+    ngx_http_fastcgi_loc_conf_t  *flcf;
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    vv->value = 0;
+
+    flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
+
+    if (r->uri.data[r->uri.len - 1] != '/') {
+        vv->text = r->uri;
+        return vv;
+    }
+
+    vv->text.len = r->uri.len + flcf->index.len;
+
+    vv->text.data = ngx_palloc(r->pool, vv->text.len);
+    if (vv->text.data == NULL) {
+        return NULL;
+    }
+
+    p = ngx_cpymem(vv->text.data, r->uri.data, r->uri.len);
+    ngx_memcpy(p, flcf->index.data, flcf->index.len);
+
+    return vv;
+}
+
+
+static char *
+ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_fastcgi_loc_conf_t *lcf = conf;
+
+    ngx_str_t                   *value;
+    ngx_inet_upstream_t          inet_upstream;
+    ngx_http_core_loc_conf_t    *clcf;
+#if (NGX_HAVE_UNIX_DOMAIN)
+    ngx_unix_domain_upstream_t   unix_upstream;
+#endif
+
+    value = cf->args->elts;
+
+    if (ngx_strncasecmp(value[1].data, "unix:", 5) == 0) {
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+        ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t));
+
+        unix_upstream.name = value[1];
+        unix_upstream.url = value[1];
+
+        lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
+        if (lcf->peers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+#else
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "the unix domain sockets are not supported "
+                           "on this platform");
+        return NGX_CONF_ERROR;
+
+#endif
+
+    } else {
+        ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t));
+
+        inet_upstream.name = value[1];
+        inet_upstream.url = value[1];
+    
+        lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
+        if (lcf->peers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    lcf->upstream.schema.len = sizeof("fastcgi://") - 1;
+    lcf->upstream.schema.data = (u_char *) "fastcgi://";
+    lcf->upstream.uri.len = sizeof("/") - 1;
+    lcf->upstream.uri.data = (u_char *) "/";
+
+    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+
+    clcf->handler = ngx_http_fastcgi_handler;
+
+#if (NGX_PCRE)
+    lcf->upstream.location = clcf->regex ? &ngx_http_fastcgi_uri : &clcf->name;
+#else
+    lcf->upstream.location = &clcf->name;
+#endif
+
+    if (clcf->name.data[clcf->name.len - 1] == '/') {
+        clcf->auto_redirect = 1;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
+{
+#if (NGX_FREEBSD)
+    ssize_t *np = data;
+
+    if (*np >= ngx_freebsd_net_inet_tcp_sendspace) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "\"fastcgi_send_lowat\" must be less than %d "
+                           "(sysctl net.inet.tcp.sendspace)",
+                           ngx_freebsd_net_inet_tcp_sendspace);
+
+        return NGX_CONF_ERROR;
+    }
+
+#elif !(NGX_HAVE_SO_SNDLOWAT)
+    ssize_t *np = data;
+
+    ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                       "\"fastcgi_send_lowat\" is not supported, ignored");
+
+    *np = 0;
+
+#endif
+
     return NGX_CONF_OK;
 }
diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c
index 865f825..723eff9 100644
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -34,7 +34,8 @@
 
 
 static ngx_http_module_t  ngx_http_geo_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -48,7 +49,7 @@
 
 
 ngx_module_t  ngx_http_geo_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_geo_module_ctx,              /* module context */
     ngx_http_geo_commands,                 /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -110,7 +111,7 @@
         name.data++;
     }
 
-    var = ngx_http_add_variable(cf, &name, 1);
+    var = ngx_http_add_variable(cf, &name, 0);
     if (var == NULL) {
         return NGX_CONF_ERROR;
     }
diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c
index 4a4da7f..1f7c232 100644
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -207,7 +207,8 @@
 
 
 static ngx_http_module_t  ngx_http_gzip_filter_module_ctx = {
-    ngx_http_gzip_add_log_formats,         /* pre conf */
+    ngx_http_gzip_add_log_formats,         /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -221,7 +222,7 @@
 
 
 ngx_module_t  ngx_http_gzip_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_gzip_filter_module_ctx,      /* module context */
     ngx_http_gzip_filter_commands,         /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -257,6 +258,11 @@
 #endif
 
 
+static ngx_str_t  ngx_http_gzip_no_cache = ngx_string("no-cache");
+static ngx_str_t  ngx_http_gzip_no_store = ngx_string("no-store");
+static ngx_str_t  ngx_http_gzip_private = ngx_string("private");
+
+
 static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
 static ngx_http_output_body_filter_pt    ngx_http_next_body_filter;
 
@@ -276,8 +282,9 @@
             && r->headers_out.status != NGX_HTTP_FORBIDDEN
             && r->headers_out.status != NGX_HTTP_NOT_FOUND)
         || r->header_only
+        || r->main
         || r->http_version < conf->http_version
-        || r->headers_out.content_type == NULL
+        || r->headers_out.content_type.len == 0
         || (r->headers_out.content_encoding
             && r->headers_out.content_encoding->value.len)
         || r->headers_in.accept_encoding == NULL
@@ -294,8 +301,8 @@
     type = conf->types->elts;
 
     for (i = 0; i < conf->types->nelts; i++) {
-        if (r->headers_out.content_type->value.len >= type[i].name.len
-            && ngx_strncasecmp(r->headers_out.content_type->value.data, 
+        if (r->headers_out.content_type.len >= type[i].name.len
+            && ngx_strncasecmp(r->headers_out.content_type.data, 
                                type[i].name.data, type[i].name.len) == 0)
         {
             found = 1;
@@ -346,6 +353,7 @@
         return NGX_ERROR;
     }
 
+    r->headers_out.content_encoding->hash = 1;
     r->headers_out.content_encoding->key.len = sizeof("Content-Encoding") - 1;
     r->headers_out.content_encoding->key.data = (u_char *) "Content-Encoding";
     r->headers_out.content_encoding->value.len = sizeof("gzip") - 1;
@@ -353,10 +361,12 @@
 
     ctx->length = r->headers_out.content_length_n;
     r->headers_out.content_length_n = -1;
+
     if (r->headers_out.content_length) {
-        r->headers_out.content_length->key.len = 0;
+        r->headers_out.content_length->hash = 0;
         r->headers_out.content_length = NULL;
     }
+
     r->filter_need_in_memory = 1;
 
     return ngx_http_next_header_filter(r);
@@ -404,22 +414,25 @@
         return NGX_DECLINED;
     }
 
-    if (r->headers_out.cache_control) {
+    if (r->headers_out.cache_control.elts) {
 
         if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_CACHE)
-            && ngx_strstr(r->headers_out.cache_control->value.data, "no-cache"))
+            && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control,
+                   &ngx_http_gzip_no_cache, NULL) >= 0)
         {
             return NGX_OK;
         }
 
         if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_STORE)
-            && ngx_strstr(r->headers_out.cache_control->value.data, "no-store"))
+            && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control,
+                   &ngx_http_gzip_no_store, NULL) >= 0)
         {
             return NGX_OK;
         }
 
         if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_PRIVATE)
-            && ngx_strstr(r->headers_out.cache_control->value.data, "private"))
+            && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control,
+                   &ngx_http_gzip_private, NULL) >= 0)
         {
             return NGX_OK;
         }
@@ -484,8 +497,8 @@
          * and do not wait while a whole response will be sent to a client.
          *
          * 8K is for zlib deflate_state, it takes
-         *  * 5816 bytes on x86 and sparc64 (32-bit mode)
-         *  * 5920 bytes on amd64 and sparc64
+         *  *) 5816 bytes on i386 and sparc64 (32-bit mode)
+         *  *) 5920 bytes on amd64 and sparc64
          */
 
         ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9));
@@ -696,7 +709,8 @@
 
             if (ctx->flush == Z_SYNC_FLUSH) {
 
-                ctx->out_buf->flush = 0;
+                ctx->zstream.avail_out = 0;
+                ctx->out_buf->flush = 1;
                 ctx->flush = Z_NO_FLUSH;
 
                 cl = ngx_alloc_chain_link(r->pool);
diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c
index 793cefd..f27ab47 100644
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -41,7 +41,8 @@
 
 
 static ngx_http_module_t  ngx_http_headers_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -55,7 +56,7 @@
 
 
 ngx_module_t  ngx_http_headers_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_headers_filter_module_ctx,   /* module context */
     ngx_http_headers_filter_commands,      /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -71,10 +72,11 @@
 ngx_http_headers_filter(ngx_http_request_t *r)
 {
     size_t                    len;
+    ngx_uint_t                i;
     ngx_table_elt_t          *expires, *cc;
     ngx_http_headers_conf_t  *conf;
 
-    if (r->headers_out.status != NGX_HTTP_OK) {
+    if (r->headers_out.status != NGX_HTTP_OK || r->main) {
         return ngx_http_next_header_filter(r);
     }
 
@@ -82,28 +84,43 @@
 
     if (conf->expires != NGX_HTTP_EXPIRES_OFF) {
 
-        expires = ngx_list_push(&r->headers_out.headers);
+        expires = r->headers_out.expires;
+
         if (expires == NULL) {
-            return NGX_ERROR;
+
+            expires = ngx_list_push(&r->headers_out.headers);
+            if (expires == NULL) {
+                return NGX_ERROR;
+            }
+
+            r->headers_out.expires = expires;
+
+            expires->hash = 1;
+            expires->key.len = sizeof("Expires") - 1;
+            expires->key.data = (u_char *) "Expires";
         }
 
-        r->headers_out.expires = expires;
-
-        cc = ngx_list_push(&r->headers_out.headers);
-        if (cc == NULL) {
-            return NGX_ERROR;
-        }
-
-        r->headers_out.cache_control = cc;
-
         len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT");
-
-        expires->key.len = sizeof("Expires") - 1;
-        expires->key.data = (u_char *) "Expires";
         expires->value.len = len - 1;
 
-        cc->key.len = sizeof("Cache-Control") - 1;
-        cc->key.data = (u_char *) "Cache-Control";
+        cc = r->headers_out.cache_control.elts;
+
+        if (cc == NULL) {
+
+            cc = ngx_list_push(&r->headers_out.headers);
+            if (cc == NULL) {
+                return NGX_ERROR;
+            }
+
+            cc->hash = 1;
+            cc->key.len = sizeof("Cache-Control") - 1;
+            cc->key.data = (u_char *) "Cache-Control";
+
+        } else {
+            for (i = 1; i < r->headers_out.cache_control.nelts; i++) {
+                cc[i].hash = 0;
+            }
+        }
 
         if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) {
             expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT";
diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c
index 373c315..5315704 100644
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -10,42 +10,52 @@
 
 
 typedef struct {
-    ngx_array_t              indices;
+    ngx_str_t                name;
+    ngx_array_t             *lengths;
+    ngx_array_t             *values;
+} ngx_http_index_t;
+
+
+typedef struct {
+    ngx_array_t             *indices;    /* array of ngx_http_index_t */
     size_t                   max_index_len;
-    ngx_http_cache_hash_t   *index_cache;
 } ngx_http_index_loc_conf_t;
 
 
 typedef struct {
-    ngx_uint_t               index;
-    u_char                  *last;
-    ngx_str_t                path;
-    ngx_str_t                redirect;
-    ngx_http_cache_entry_t  *cache;
-    ngx_uint_t               tested; /* unsigned  tested:1 */
+    ngx_uint_t               current;
+    size_t                   allocated;
+
+    u_char                  *path;
+    ngx_str_t                uri;
+    ngx_str_t                index;
+
+    ngx_uint_t               tested;     /* unsigned  tested:1 */
 } ngx_http_index_ctx_t;
 
 
 #define NGX_HTTP_DEFAULT_INDEX   "index.html"
 
 
+static ngx_int_t ngx_http_index_alloc(ngx_http_request_t *r, size_t size,
+    ngx_http_index_ctx_t *ctx, ngx_http_core_loc_conf_t *clcf);
 static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r,
-                                         ngx_http_index_ctx_t *ctx);
+    ngx_http_index_ctx_t *ctx);
 static ngx_int_t ngx_http_index_error(ngx_http_request_t *r,
-                                      ngx_http_index_ctx_t *ctx, ngx_err_t err);
+    ngx_http_index_ctx_t *ctx, ngx_err_t err);
 
 static ngx_int_t ngx_http_index_init(ngx_cycle_t *cycle);
 static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf,
-                                       void *parent, void *child);
+    void *parent, void *child);
 static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
-                                      void *conf);
+    void *conf);
 
 
 static ngx_command_t  ngx_http_index_commands[] = {
 
     { ngx_string("index"),
-      NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_http_index_set_index,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -67,7 +77,8 @@
 
 
 ngx_http_module_t  ngx_http_index_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -81,7 +92,7 @@
 
 
 ngx_module_t  ngx_http_index_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_index_module_ctx,            /* module context */
     ngx_http_index_commands,               /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -100,21 +111,24 @@
  * that path contains the usual file in place of the directory.
  */
 
-static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r)
+static ngx_int_t
+ngx_http_index_handler(ngx_http_request_t *r)
 {
-    u_char                     *name;
-    ngx_fd_t                    fd;
-    ngx_int_t                   rc;
-    ngx_str_t                  *index;
-    ngx_err_t                   err;
-    ngx_log_t                  *log;
-    ngx_http_index_ctx_t       *ctx;
-    ngx_http_core_loc_conf_t   *clcf;
-    ngx_http_index_loc_conf_t  *ilcf;
-#if (NGX_HTTP_CACHE0)
-    /* crc must be in ctx !! */
-    uint32_t                    crc;
-#endif
+    u_char                       *name;
+    size_t                        len;
+    ngx_fd_t                      fd;
+    ngx_int_t                     rc;
+    ngx_err_t                     err;
+    ngx_log_t                    *log;
+    ngx_uint_t                    i;
+    ngx_http_index_t             *index;
+    ngx_http_index_ctx_t         *ctx;
+    ngx_pool_cleanup_file_t      *cln;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e;
+    ngx_http_core_loc_conf_t     *clcf;
+    ngx_http_index_loc_conf_t    *ilcf;
+    ngx_http_script_len_code_pt   lcode;
 
     if (r->uri.data[r->uri.len - 1] != '/') {
         return NGX_DECLINED;
@@ -128,8 +142,8 @@
     log = r->connection->log;
 
     /*
-     * we use context because the handler supports an async file opening
-     * and thus can be called several times
+     * we use context because the handler supports an async file opening,
+     * and may be called several times
      */
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -144,115 +158,71 @@
         }
 
         ngx_http_set_ctx(r, ctx, ngx_http_index_module);
-
-#if (NGX_HTTP_CACHE)
-
-        if (ilcf->index_cache) {
-            ctx->cache = ngx_http_cache_get(ilcf->index_cache, NULL,
-                                            &r->uri, &crc);
-
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                           "http index cache get: %p", ctx->cache);
-
-            if (ctx->cache && !ctx->cache->expired) {
-
-                ctx->cache->accessed = ngx_cached_time;
-
-                ctx->redirect.len = ctx->cache->data.value.len;
-                ctx->redirect.data = ngx_palloc(r->pool, ctx->redirect.len + 1);
-                if (ctx->redirect.data == NULL) {
-                    ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
-                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
-                }
-
-                ngx_memcpy(ctx->redirect.data, ctx->cache->data.value.data,
-                           ctx->redirect.len + 1);
-                ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
-
-                return ngx_http_internal_redirect(r, &ctx->redirect, NULL);
-            }
-        }
-
-#endif
-
-#if 0
-        ctx->path.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len
-                                             + ilcf->max_index_len
-                                             - clcf->alias * clcf->name.len);
-        if (ctx->path.data == NULL) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->root.data,
-                                        clcf->root.len);
-#endif
-
-        if (clcf->alias) {
-            ctx->path.data = ngx_palloc(r->pool, clcf->root.len
-                                              + r->uri.len + 1 - clcf->name.len
-                                              + ilcf->max_index_len);
-            if (ctx->path.data == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
-
-            ctx->redirect.data = ngx_palloc(r->pool, r->uri.len
-                                            + ilcf->max_index_len);
-            if (ctx->redirect.data == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
-
-            ngx_memcpy(ctx->path.data, clcf->root.data, clcf->root.len);
-
-            ctx->last = ngx_cpystrn(ctx->path.data + clcf->root.len,
-                                    r->uri.data + clcf->name.len,
-                                    r->uri.len + 1 - clcf->name.len);
-
-#if 0
-            /*
-             * aliases usually have trailling "/",
-             * set it in the start of the possible redirect
-             */
-
-            if (*ctx->redirect.data != '/') {
-                ctx->redirect.data--; 
-            }
-#endif
-
-        } else {
-            ctx->path.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len
-                                                 + ilcf->max_index_len);
-            if (ctx->path.data == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
-
-            ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->root.data,
-                                            clcf->root.len);
-
-            ctx->last = ngx_cpystrn(ctx->redirect.data, r->uri.data,
-                                    r->uri.len + 1);
-        }
     }
 
-    ctx->path.len = ctx->last - ctx->path.data;
+    index = ilcf->indices->elts;
+    for (i = ctx->current; i < ilcf->indices->nelts; i++) {
 
-    index = ilcf->indices.elts;
-    for (/* void */; ctx->index < ilcf->indices.nelts; ctx->index++) {
+        if (index[i].lengths == NULL) {
 
-        if (index[ctx->index].data[0] == '/') {
-            name = index[ctx->index].data;
+            if (index[i].name.data[0] == '/') {
+                return ngx_http_internal_redirect(r, &index[i].name, &r->args);
+            }
+
+            len = ilcf->max_index_len;
+            ctx->index.len = index[i].name.len;
 
         } else {
-            ngx_memcpy(ctx->last, index[ctx->index].data,
-                       index[ctx->index].len + 1);
-            name = ctx->path.data;
+            ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+            e.ip = index[i].lengths->elts;
+            e.request = r;
+
+            len = 1;
+
+            while (*(uintptr_t *) e.ip) {
+                lcode = *(ngx_http_script_len_code_pt *) e.ip;
+                len += lcode(&e);
+            }
+
+            ctx->index.len = len;
         }
 
+        if (len > ctx->allocated) {
+            if (ngx_http_index_alloc(r, len, ctx, clcf) != NGX_OK) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+        }
+
+        if (index[i].values == NULL) {
+            ngx_memcpy(ctx->index.data, index[i].name.data, ctx->index.len);
+
+        } else {
+            e.ip = index[i].values->elts;
+            e.pos = ctx->index.data;
+
+            while (*(uintptr_t *) e.ip) {
+                code = *(ngx_http_script_code_pt *) e.ip;
+                code((ngx_http_script_engine_t *) &e);
+            }
+
+            if (*ctx->index.data == '/') {
+                ctx->index.len--;
+                return ngx_http_internal_redirect(r, &ctx->index, &r->args);
+            }
+
+            *e.pos++ = '\0';
+        }
+
+        name = ctx->path;
+
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                        "open index \"%s\"", name);
 
         fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN);
 
         if (fd == (ngx_fd_t) NGX_AGAIN) {
+            ctx->current = i;
             return NGX_AGAIN;
         }
 
@@ -290,131 +260,268 @@
         }
 
 
-        /* STUB: open file cache */
-
-        r->file.name.data = name;
-        r->file.fd = fd;
-
-        if (index[ctx->index].data[0] == '/') {
-            r->file.name.len = index[ctx->index].len;
-            ctx->redirect.len = index[ctx->index].len;
-            ctx->redirect.data = index[ctx->index].data;
-
-        } else {
-            if (clcf->alias) {
-                name = ngx_cpymem(ctx->redirect.data, r->uri.data, r->uri.len);
-                ngx_memcpy(name, index[ctx->index].data,
-                           index[ctx->index].len + 1);
-            }
-
-            ctx->redirect.len = r->uri.len + index[ctx->index].len;
-            r->file.name.len = clcf->root.len + r->uri.len
-                                                - clcf->alias * clcf->name.len
-                                                       + index[ctx->index].len;
+        cln = ngx_palloc(r->pool, sizeof(ngx_pool_cleanup_file_t));
+        if (cln == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR; 
         }
 
-        /**/
+        cln->fd = fd;
+        cln->name = name;
+        cln->log = r->pool->log;
 
-
-#if (NGX_HTTP_CACHE)
-
-        if (ilcf->index_cache) {
-
-            if (ctx->cache) {
-                if (ctx->redirect.len == ctx->cache->data.value.len
-                    && ngx_memcmp(ctx->cache->data.value.data,
-                                  ctx->redirect.data, ctx->redirect.len) == 0)
-                {
-                    ctx->cache->accessed = ngx_cached_time;
-                    ctx->cache->updated = ngx_cached_time;
-                    ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
-
-                    return ngx_http_internal_redirect(r, &ctx->redirect, NULL);
-                }
-            }
-
-            ctx->redirect.len++;
-            ctx->cache = ngx_http_cache_alloc(ilcf->index_cache, ctx->cache,
-                                              NULL, &r->uri, crc,
-                                              &ctx->redirect, log);
-            ctx->redirect.len--;
-
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                           "http index cache alloc: %p", ctx->cache);
-
-            if (ctx->cache) {
-                ctx->cache->fd = NGX_INVALID_FILE;
-                ctx->cache->accessed = ngx_cached_time;
-                ctx->cache->last_modified = 0;
-                ctx->cache->updated = ngx_cached_time;
-                ctx->cache->memory = 1;
-                ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
-            }
+        if (ngx_pool_cleanup_add(r->pool, ngx_pool_cleanup_file, cln) == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-#endif
 
-        return ngx_http_internal_redirect(r, &ctx->redirect, NULL);
+        if (clcf->alias) {
+            name = ngx_cpymem(ctx->uri.data, r->uri.data, r->uri.len);
+            ngx_memcpy(name, ctx->index.data, ctx->index.len - 1);
+        }
+
+        ctx->uri.len = r->uri.len + ctx->index.len - 1;
+
+        return ngx_http_internal_redirect(r, &ctx->uri, &r->args);
     }
 
     return NGX_DECLINED;
 }
 
 
-static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r,
-                                         ngx_http_index_ctx_t *ctx)
+static ngx_int_t
+ngx_http_index_alloc(ngx_http_request_t *r, size_t size,
+    ngx_http_index_ctx_t *ctx, ngx_http_core_loc_conf_t *clcf)
 {
-    ngx_err_t  err;
+    ctx->allocated = size;
 
-    ctx->path.data[ctx->path.len - 1] = '\0';
-    ctx->path.data[ctx->path.len] = '\0';
+    if (!clcf->alias) {
+        ctx->path = ngx_palloc(r->pool, clcf->root.len + r->uri.len + size);
+        if (ctx->path == NULL) {
+            return NGX_ERROR;
+        }
+
+        ctx->uri.data = ngx_cpymem(ctx->path, clcf->root.data, clcf->root.len);
+
+        ctx->index.data = ngx_cpymem(ctx->uri.data, r->uri.data, r->uri.len);
+
+    } else {
+        ctx->path = ngx_palloc(r->pool,
+                          clcf->root.len + r->uri.len - clcf->name.len + size);
+        if (ctx->path == NULL) {
+            return NGX_ERROR;
+        }
+
+        ctx->uri.data = ngx_palloc(r->pool, r->uri.len + size);
+        if (ctx->uri.data == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_memcpy(ctx->path, clcf->root.data, clcf->root.len);
+
+        ctx->index.data = ngx_cpymem(ctx->path + clcf->root.len,
+                                     r->uri.data + clcf->name.len,
+                                     r->uri.len - clcf->name.len);
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx)
+{
+    ngx_err_t        err;
+    ngx_file_info_t  fi;
+
+    *(ctx->index.data - 1) = '\0';
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http check dir: \"%s\"", ctx->path.data);
+                   "http index check dir: \"%s\"", ctx->path);
 
-    if (ngx_file_info(ctx->path.data, &r->file.info) == -1) {
+    if (ngx_file_info(ctx->path, &fi) == -1) {
 
         err = ngx_errno;
 
         if (err == NGX_ENOENT) {
-            ctx->path.data[ctx->path.len - 1] = '/';
+            *(ctx->index.data - 1) = '/';
             return ngx_http_index_error(r, ctx, err);
         }
 
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
-                      ngx_file_info_n " \"%s\" failed", ctx->path.data);
+                      ngx_file_info_n " \"%s\" failed", ctx->path);
 
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    ctx->path.data[ctx->path.len - 1] = '/';
+    *(ctx->index.data - 1) = '/';
 
-    if (ngx_is_dir(&r->file.info)) {
+    if (ngx_is_dir(&fi)) {
         return NGX_OK;
     }
 
-    /* THINK: not reached ??? */
-    return ngx_http_index_error(r, ctx, 0);
+    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                  "\"%s\" is not a directory", ctx->path);
+
+    return NGX_HTTP_INTERNAL_SERVER_ERROR;
 }
 
 
-static ngx_int_t ngx_http_index_error(ngx_http_request_t *r,
-                                      ngx_http_index_ctx_t *ctx, ngx_err_t err)
+static ngx_int_t
+ngx_http_index_error(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx,
+    ngx_err_t err)
 {
     if (err == NGX_EACCES) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
-                      "\"%s\" is forbidden", ctx->path.data);
+                      "\"%s\" is forbidden", ctx->path);
     
         return NGX_HTTP_FORBIDDEN;
     }
 
     ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
-                  "\"%s\" is not found", ctx->path.data);
+                  "\"%s\" is not found", ctx->path);
+
     return NGX_HTTP_NOT_FOUND;
 }
 
 
-static ngx_int_t ngx_http_index_init(ngx_cycle_t *cycle)
+static void *
+ngx_http_index_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_index_loc_conf_t  *conf;
+
+    conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t));
+    if (conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->indices = NULL;
+    conf->max_index_len = 1;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_index_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_index_loc_conf_t  *prev = parent;
+    ngx_http_index_loc_conf_t  *conf = child;
+
+    ngx_http_index_t  *index;
+
+    if (conf->indices == NULL) {
+        conf->indices = prev->indices;
+        conf->max_index_len = prev->max_index_len;
+    }
+
+    if (conf->indices == NULL) {
+        conf->indices = ngx_array_create(cf->pool, 1, sizeof(ngx_http_index_t));
+        if (conf->indices == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        index = ngx_array_push(conf->indices);
+        if (index == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        index->name.len = sizeof(NGX_HTTP_DEFAULT_INDEX);
+        index->name.data = (u_char *) NGX_HTTP_DEFAULT_INDEX;
+        index->lengths = NULL;
+        index->values = NULL;
+
+        conf->max_index_len = sizeof(NGX_HTTP_DEFAULT_INDEX);
+
+        return NGX_CONF_OK;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+/* TODO: warn about duplicate indices */
+
+static char *
+ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_index_loc_conf_t *ilcf = conf;
+
+    ngx_uint_t                  i, n;
+    ngx_str_t                  *value;
+    ngx_http_index_t           *index;
+    ngx_http_script_compile_t   sc;
+
+    if (ilcf->indices == NULL) {
+        ilcf->indices = ngx_array_create(cf->pool, 2, sizeof(ngx_http_index_t));
+        if (ilcf->indices == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    value = cf->args->elts;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+        if (value[i].data[0] == '/' && i != cf->args->nelts - 1) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "only the last index in \"index\" directive "
+                               "may be absolute");
+            return NGX_CONF_ERROR;
+        }
+
+        if (value[i].len == 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "index \"%V\" in \"index\" directive is invalid",
+                               &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+        index = ngx_array_push(ilcf->indices);
+        if (index == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        index->name.len = value[i].len;
+        index->name.data = value[i].data;
+        index->lengths = NULL;
+        index->values = NULL;
+
+        n = ngx_http_script_variables_count(&value[i]);
+
+        if (n == 0) {
+            index->name.len++;
+
+            if (ilcf->max_index_len != 0
+                && ilcf->max_index_len < index->name.len)
+            {
+                ilcf->max_index_len = index->name.len;
+            }
+
+            continue;
+        }
+
+        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+        sc.cf = cf;
+        sc.source = &value[i];
+        sc.lengths = &index->lengths;
+        sc.values = &index->values;
+        sc.variables = n;
+        sc.complete_lengths = 1;
+        sc.complete_values = 1;
+
+        if (ngx_http_script_compile(&sc) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
+
+        ilcf->max_index_len = 0;
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_index_init(ngx_cycle_t *cycle)
 {
     ngx_http_handler_pt        *h;
     ngx_http_core_main_conf_t  *cmcf;
@@ -430,129 +537,3 @@
 
     return NGX_OK;
 }
-
-
-static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf)
-{
-    ngx_http_index_loc_conf_t  *conf;
-
-    conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t));
-    if (conf == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    if (ngx_array_init(&conf->indices, cf->pool, 2, sizeof(ngx_str_t))
-                                                                  == NGX_ERROR)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->max_index_len = 0;
-
-    conf->index_cache = NULL;
-
-    return conf;
-}
-
-
-/* TODO: remove duplicate indices */
-
-static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf,
-                                           void *parent, void *child)
-{
-    ngx_http_index_loc_conf_t  *prev = parent;
-    ngx_http_index_loc_conf_t  *conf = child;
-
-    ngx_str_t  *index;
-
-    if (conf->max_index_len == 0) {
-        if (prev->max_index_len != 0) {
-            ngx_memcpy(conf, prev, sizeof(ngx_http_index_loc_conf_t));
-            return NGX_CONF_OK;
-        }
-
-        index = ngx_array_push(&conf->indices);
-        if (index == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        index->len = sizeof(NGX_HTTP_DEFAULT_INDEX) - 1;
-        index->data = (u_char *) NGX_HTTP_DEFAULT_INDEX;
-        conf->max_index_len = sizeof(NGX_HTTP_DEFAULT_INDEX);
-
-        return NGX_CONF_OK;
-    }
-
-#if 0
-
-    if (prev->max_index_len != 0) {
-
-        prev_index = prev->indices.elts;
-        for (i = 0; i < prev->indices.nelts; i++) {
-            index = ngx_array_push(&conf->indices);
-            if (index == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            index->len = prev_index[i].len;
-            index->data = prev_index[i].data;
-        }
-    }
-
-    if (conf->max_index_len < prev->max_index_len) {
-        conf->max_index_len = prev->max_index_len;
-    }
-
-#endif
-
-    if (conf->index_cache == NULL) {
-        conf->index_cache = prev->index_cache;
-    }
-
-    return NGX_CONF_OK;
-}
-
-
-/* TODO: warn about duplicate indices */
-
-static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
-                                      void *conf)
-{
-    ngx_http_index_loc_conf_t *ilcf = conf;
-
-    ngx_uint_t  i;
-    ngx_str_t  *index, *value;
-
-    value = cf->args->elts;
-
-    if (value[1].data[0] == '/' && ilcf->indices.nelts == 0) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "first index \"%V\" in \"%V\" directive "
-                           "must not be absolute",
-                           &value[1], &cmd->name);
-        return NGX_CONF_ERROR;
-    }
-
-    for (i = 1; i < cf->args->nelts; i++) {
-        if (value[i].len == 0) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "index \"%V\" in \"%V\" directive is invalid",
-                               &value[1], &cmd->name);
-            return NGX_CONF_ERROR;
-        }
-
-        index = ngx_array_push(&ilcf->indices);
-        if (index == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        index->len = value[i].len;
-        index->data = value[i].data;
-
-        if (ilcf->max_index_len < index->len + 1) {
-            ilcf->max_index_len = index->len + 1;
-        }
-    }
-
-    return NGX_CONF_OK;
-}
diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c
index 24ea58d..23ea572 100644
--- a/src/http/modules/ngx_http_not_modified_filter_module.c
+++ b/src/http/modules/ngx_http_not_modified_filter_module.c
@@ -14,7 +14,8 @@
 
 
 static ngx_http_module_t  ngx_http_not_modified_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -28,7 +29,7 @@
 
 
 ngx_module_t  ngx_http_not_modified_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_not_modified_filter_module_ctx, /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -45,6 +46,7 @@
     time_t  ims;
 
     if (r->headers_out.status != NGX_HTTP_OK
+        || r->main
         || r->headers_in.if_modified_since == NULL
         || r->headers_out.last_modified_time == -1)
     {
@@ -63,12 +65,11 @@
 
     if (ims != NGX_ERROR && ims == r->headers_out.last_modified_time) {
         r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
-        r->headers_out.content_type->key.len = 0;
-        r->headers_out.content_type = NULL;
+        r->headers_out.content_type.len = 0;
         r->headers_out.content_length_n = -1;
         r->headers_out.content_length = NULL;
 #if 0
-        r->headers_out.accept_ranges->key.len = 0;
+        r->headers_out.accept_ranges->hash = 0;
 #endif
     }
 
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 8020856..5504610 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -10,89 +10,100 @@
 #include <ngx_http.h>
 
 
+typedef struct ngx_http_proxy_redirect_s  ngx_http_proxy_redirect_t;
+
+typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r,
+    ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr);
+
+struct ngx_http_proxy_redirect_s {
+    ngx_http_proxy_redirect_pt   handler;
+    ngx_str_t                    redirect;
+
+    union {
+        ngx_str_t                text;
+
+        struct {
+            void                *lengths;
+            void                *values;
+        } vars;
+
+        void                    *regex;
+    } replacement;
+};
+
+
 typedef struct {
-    ngx_http_upstream_conf_t   upstream;
+    ngx_http_upstream_conf_t     upstream;
 
-    ngx_peers_t               *peers;
+    ngx_peers_t                 *peers;
 
-    ngx_array_t               *headers_set_len;
-    ngx_array_t               *headers_set;
-    ngx_hash_t                *headers_set_hash;
+    ngx_array_t                 *headers_set_len;
+    ngx_array_t                 *headers_set;
+    ngx_hash_t                  *headers_set_hash;
 
-    ngx_flag_t                 preserve_host;
-    ngx_flag_t                 set_x_url;
-    ngx_flag_t                 set_x_real_ip;
-    ngx_flag_t                 add_x_forwarded_for;
-    ngx_flag_t                 pass_server;
-    ngx_flag_t                 pass_x_accel_expires;
+    ngx_array_t                 *headers_source;
+    ngx_array_t                 *headers_names;
 
-    ngx_str_t                 *location0;
+    ngx_array_t                 *redirects;
 
-    ngx_str_t                  host_header;
-    ngx_str_t                  uri0;
+    ngx_str_t                    host_header;
+    ngx_str_t                    port_text;
 
-    ngx_array_t               *headers_sources;
-    ngx_array_t               *headers_names;
+    ngx_flag_t                   redirect;
 } ngx_http_proxy_loc_conf_t;
 
 
 typedef struct {
-    ngx_list_t                 headers;
-    
-    ngx_table_elt_t           *date;
-    ngx_table_elt_t           *server;
+    ngx_uint_t                   status;
+    ngx_uint_t                   status_count;
+    u_char                      *status_start;
+    u_char                      *status_end;
+} ngx_http_proxy_ctx_t;
 
-    ngx_table_elt_t           *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;
+#define NGX_HTTP_PROXY_PARSE_NO_HEADER  20
 
 
 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
+static ngx_int_t ngx_http_proxy_parse_status_line(ngx_http_request_t *r,
+    ngx_http_proxy_ctx_t *p);
 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
-static ngx_int_t ngx_http_proxy_send_header(ngx_http_request_t *r);
 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
     ngx_int_t rc);
 
-static ngx_int_t ngx_http_proxy_compile_header_start(ngx_table_elt_t *h,
-    ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value);
-static ngx_int_t ngx_http_proxy_compile_header_end(ngx_array_t *lengths,
-    ngx_array_t *values);
+static ngx_http_variable_value_t *
+    ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data);
+static ngx_http_variable_value_t *
+    ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data);
+static ngx_http_variable_value_t *
+    ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
+    uintptr_t data);
+static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
+    ngx_table_elt_t *h, size_t prefix);
 
-static ngx_int_t ngx_http_proxy_init(ngx_cycle_t *cycle);
-static ngx_http_variable_value_t *ngx_http_proxy_host_variable
-    (ngx_http_request_t *r, uintptr_t data);
+static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
     void *parent, void *child);
 
 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
-
-static char *ngx_http_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd,
+static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+
 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
 
+
 static ngx_conf_post_t  ngx_http_proxy_lowat_post =
-                                                { ngx_http_proxy_lowat_check };
+    { ngx_http_proxy_lowat_check };
+
+static ngx_conf_enum_t  ngx_http_proxy_set_methods[] = {
+    { ngx_string("get"), NGX_HTTP_GET },
+    { ngx_null_string, 0 }
+};
 
 static ngx_conf_bitmask_t  ngx_http_proxy_next_upstream_masks[] = {
     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
@@ -113,6 +124,13 @@
       0,
       NULL },
 
+    { ngx_string("proxy_redirect"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+      ngx_http_proxy_redirect,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("proxy_connect_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_msec_slot,
@@ -134,6 +152,13 @@
       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
       &ngx_http_proxy_lowat_post },
 
+    { ngx_string("proxy_redirect_errors"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.redirect_errors),
+      NULL },
+
     { ngx_string("proxy_pass_unparsed_uri"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -141,39 +166,32 @@
       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_unparsed_uri),
       NULL },
 
-    { ngx_string("proxy_preserve_host"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
+    { ngx_string("proxy_set_header"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+      ngx_conf_set_table_elt_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, preserve_host),
+      offsetof(ngx_http_proxy_loc_conf_t, headers_source),
       NULL },
 
-    { ngx_string("proxy_set_x_url"),
-      NGX_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_string("proxy_method"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_proxy_set_x_var,
+      ngx_conf_set_enum_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      0,
-      NULL },
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.method),
+      ngx_http_proxy_set_methods },
 
-    { ngx_string("proxy_add_x_forwarded_for"),
+    { ngx_string("proxy_pass_request_headers"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, add_x_forwarded_for),
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
+      NULL },
+
+    { ngx_string("proxy_pass_request_body"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
       NULL },
 
     { ngx_string("proxy_header_buffer_size"),
@@ -232,18 +250,25 @@
       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
       &ngx_http_proxy_next_upstream_masks },
 
+    { ngx_string("proxy_pass_x_powered_by"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_x_powered_by),
+      NULL },
+
     { ngx_string("proxy_pass_server"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, pass_server),
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_server),
       NULL },
 
     { ngx_string("proxy_pass_x_accel_expires"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_proxy_loc_conf_t, pass_x_accel_expires),
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_x_accel_expires),
       NULL },
 
       ngx_null_command
@@ -251,7 +276,8 @@
 
 
 ngx_http_module_t  ngx_http_proxy_module_ctx = {
-    NULL,                                  /* pre conf */
+    ngx_http_proxy_add_variables,          /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -265,25 +291,49 @@
 
 
 ngx_module_t  ngx_http_proxy_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_proxy_module_ctx,            /* module context */
     ngx_http_proxy_commands,               /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
-    ngx_http_proxy_init,                   /* init module */
+    NULL,                                  /* init module */
     NULL                                   /* init process */
 };
 
 
 static ngx_str_t ngx_http_proxy_methods[] = {
-    ngx_string("GET"),
-    ngx_string("HEAD"),
-    ngx_string("POST")
+    ngx_string("GET "),
+    ngx_string("HEAD "),
+    ngx_string("POST ")
 };
 
 
 static char  ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
 
-static ngx_str_t  ngx_http_proxy_host = ngx_string("PROXY_HOST");
+
+static ngx_table_elt_t  ngx_http_proxy_headers[] = {
+    { 0, ngx_string("Host"), ngx_string("$proxy_host"), },
+    { 0, ngx_string("Connection"), ngx_string("close"), },
+    { 0, ngx_null_string, ngx_null_string }
+};
+
+
+static ngx_http_variable_t  ngx_http_proxy_vars[] = {
+
+    { ngx_string("proxy_host"), ngx_http_proxy_host_variable, 0,
+      NGX_HTTP_VAR_CHANGABLE },
+
+    { ngx_string("proxy_port"), ngx_http_proxy_port_variable, 0,
+      NGX_HTTP_VAR_CHANGABLE },
+
+    { ngx_string("proxy_add_x_forwarded_for"),
+      ngx_http_proxy_add_x_forwarded_for_variable, 0, 0 },
+
+#if 0
+    { ngx_string("proxy_add_via"), NULL, 0, 0 },
+#endif
+
+    { ngx_null_string, NULL, 0, 0 }
+};
 
 
 #if (NGX_PCRE)
@@ -291,45 +341,6 @@
 #endif
 
 
-#if 0
-
-ngx_http_header_t ngx_http_proxy_headers_in[] = {
-    { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) },
-    { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) },
-
-    { ngx_string("Expires"), offsetof(ngx_http_proxy_headers_in_t, expires) },
-    { ngx_string("Cache-Control"),
-                 offsetof(ngx_http_proxy_headers_in_t, cache_control) },
-    { ngx_string("ETag"), offsetof(ngx_http_proxy_headers_in_t, etag) },
-    { ngx_string("X-Accel-Expires"),
-                 offsetof(ngx_http_proxy_headers_in_t, x_accel_expires) },
-
-    { ngx_string("Connection"),
-                 offsetof(ngx_http_proxy_headers_in_t, connection) },
-    { ngx_string("Content-Type"),
-                 offsetof(ngx_http_proxy_headers_in_t, content_type) },
-    { ngx_string("Content-Length"),
-                 offsetof(ngx_http_proxy_headers_in_t, content_length) },
-
-#if (NGX_HTTP_GZIP)
-    { ngx_string("Content-Encoding"),
-                 offsetof(ngx_http_proxy_headers_in_t, content_encoding) },
-#endif
-
-    { ngx_string("Last-Modified"),
-                 offsetof(ngx_http_proxy_headers_in_t, last_modified) },
-    { ngx_string("Location"),
-                 offsetof(ngx_http_proxy_headers_in_t, location) },
-    { ngx_string("Accept-Ranges"),
-                 offsetof(ngx_http_proxy_headers_in_t, accept_ranges) },
-    { ngx_string("X-Pad"), offsetof(ngx_http_proxy_headers_in_t, x_pad) },
-
-    { ngx_null_string, 0 }
-};
-
-#endif
-
-
 static ngx_int_t
 ngx_http_proxy_handler(ngx_http_request_t *r)
 {   
@@ -358,20 +369,17 @@
 
     u->create_request = ngx_http_proxy_create_request;
     u->reinit_request = ngx_http_proxy_reinit_request;
-    u->process_header = ngx_http_proxy_process_header;
-    u->send_header = ngx_http_proxy_send_header;
+    u->process_header = ngx_http_proxy_process_status_line;
     u->abort_request = ngx_http_proxy_abort_request;
     u->finalize_request = ngx_http_proxy_finalize_request;
 
+    if (plcf->redirects) {
+        u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
+    }
+
     u->pipe.input_filter = ngx_event_pipe_copy_input_filter;
 
-    u->log_ctx = r->connection->log->data;
-    u->log_handler = ngx_http_upstream_log_error;
-
-    u->schema0.len = sizeof("http://") - 1;
-    u->schema0.data = (u_char *) "http://";
-    u->uri0 = plcf->uri0;
-    u->location0 = plcf->location0;
+    u->accel = 1;
     
     r->upstream = u;
 
@@ -388,19 +396,19 @@
 static ngx_int_t
 ngx_http_proxy_create_request(ngx_http_request_t *r)
 {
-    size_t                          len;
-    ngx_uint_t                      i, key;
-    uintptr_t                       escape;
-    ngx_buf_t                      *b;
-    ngx_str_t                      *hh;
-    ngx_chain_t                    *cl;
-    ngx_list_part_t                *part;
-    ngx_table_elt_t                *header;
-    ngx_http_upstream_t            *u;
-    ngx_http_proxy_loc_conf_t      *plcf;
-    ngx_http_script_code_pt         code;
-    ngx_http_script_len_code_pt     lcode;
-    ngx_http_script_lite_engine_t   e;
+    size_t                        len, loc_len;
+    ngx_uint_t                    i, key;
+    uintptr_t                     escape;
+    ngx_buf_t                    *b;
+    ngx_str_t                    *hh;
+    ngx_chain_t                  *cl, *body;
+    ngx_list_part_t              *part;
+    ngx_table_elt_t              *header;
+    ngx_http_upstream_t          *u;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e, le;
+    ngx_http_proxy_loc_conf_t    *plcf;
+    ngx_http_script_len_code_pt   lcode;
 
     u = r->upstream;
 
@@ -409,65 +417,73 @@
     len = sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
 
     if (u->method) {
-        len += ngx_http_proxy_methods[u->method - 1].len + u->uri0.len;
+        len += ngx_http_proxy_methods[u->method - 1].len + u->conf->uri.len;
     } else {
-        len += r->method_name.len + u->uri0.len;
+        len += r->method_name.len + 1 + u->conf->uri.len;
     }
 
     escape = 0;
-    
+
+    loc_len = r->valid_location ? u->conf->location->len : 1;
+
     if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) {
         len += r->unparsed_uri.len - 1;
 
     } else {
         if (r->quoted_uri) {
-            escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location0->len,
-                                        r->uri.len - u->location0->len,
-                                        NGX_ESCAPE_URI);
+            escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
+                                        r->uri.len - loc_len, NGX_ESCAPE_URI);
         }
 
-        len += r->uri.len - u->location0->len + escape
-            + sizeof("?") - 1 + r->args.len;
+        len += r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len;
+    }
+
+    ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+    le.ip = plcf->headers_set_len->elts;
+    le.request = r;
+
+    while (*(uintptr_t *) le.ip) {
+        while (*(uintptr_t *) le.ip) {
+            lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            len += lcode(&le);
+        }
+        le.ip += sizeof(uintptr_t);
     }
 
 
-    e.ip = plcf->headers_set_len->elts;
-    e.request = r;
-
-    while (*(uintptr_t *) e.ip) {
-        lcode = *(ngx_http_script_len_code_pt *) e.ip;
-        len += lcode(&e);
-    }
-
-
-    part = &r->headers_in.headers.part;
-    header = part->elts;
     hh = (ngx_str_t *) plcf->headers_set_hash->buckets;
 
-    for (i = 0; /* void */; i++) {
+    if (plcf->upstream.pass_request_headers) {
+        part = &r->headers_in.headers.part;
+        header = part->elts;
 
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
+        for (i = 0; /* void */; i++) {
+
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0; 
             }
 
-            part = part->next;
-            header = part->elts;
-            i = 0; 
+            key = header[i].hash % plcf->headers_set_hash->hash_size;
+
+            if (hh[key].len == header[i].key.len
+                && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0)
+            {
+                continue;
+            }
+
+            len += header[i].key.len + sizeof(": ") - 1
+                + header[i].value.len + sizeof(CRLF) - 1;
         }
-
-        key = header[i].hash % plcf->headers_set_hash->hash_size;
-
-        if (hh[key].len == header[i].key.len
-            && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0)
-        {
-            continue;
-        }
-
-        len += header[i].key.len + sizeof(": ") - 1
-            + header[i].value.len + sizeof(CRLF) - 1;
     }
 
+
     b = ngx_create_temp_buf(r->pool, len);
     if (b == NULL) {
         return NGX_ERROR;
@@ -479,9 +495,6 @@
     }
 
     cl->buf = b;
-    cl->next = NULL;
-
-    r->request_body->bufs = cl;
 
 
     /* the request line */
@@ -491,23 +504,24 @@
                              ngx_http_proxy_methods[u->method - 1].data,
                              ngx_http_proxy_methods[u->method - 1].len);
     } else {
-        b->last = ngx_cpymem(b->last, r->method_name.data, r->method_name.len);
+        b->last = ngx_cpymem(b->last, r->method_name.data,
+                             r->method_name.len + 1);
     }
 
-    b->last = ngx_cpymem(b->last, u->uri0.data, u->uri0.len);
+    b->last = ngx_cpymem(b->last, u->conf->uri.data, u->conf->uri.len);
 
     if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) {
         b->last = ngx_cpymem(b->last, r->unparsed_uri.data + 1,
                              r->unparsed_uri.len - 1);
     } else {
         if (escape) {
-            ngx_escape_uri(b->last, r->uri.data + u->location0->len,
-                           r->uri.len - u->location0->len, NGX_ESCAPE_URI);
-            b->last += r->uri.len - u->location0->len + escape;
+            ngx_escape_uri(b->last, r->uri.data + loc_len,
+                           r->uri.len - loc_len, NGX_ESCAPE_URI);
+            b->last += r->uri.len - loc_len + escape;
 
         } else { 
-            b->last = ngx_cpymem(b->last, r->uri.data + u->location0->len,
-                                 r->uri.len - u->location0->len);
+            b->last = ngx_cpymem(b->last, r->uri.data + loc_len,
+                                 r->uri.len - loc_len);
         }
 
         if (r->args.len > 0) {
@@ -522,50 +536,76 @@
 
     e.ip = plcf->headers_set->elts;
     e.pos = b->last;
+    e.request = r;
 
-    while (*(uintptr_t *) e.ip) {
-        code = *(ngx_http_script_code_pt *) e.ip;
-        code((ngx_http_script_engine_t *) &e);
+    le.ip = plcf->headers_set_len->elts;
+
+    while (*(uintptr_t *) le.ip) {
+        lcode = *(ngx_http_script_len_code_pt *) le.ip;
+        lcode(&le);
+
+        if (*(ngx_http_script_len_code_pt *) le.ip) {
+
+            for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
+                lcode = *(ngx_http_script_len_code_pt *) le.ip;
+            }
+
+            e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
+
+        } else {
+            e.skip = 0;
+        }
+
+        le.ip += sizeof(uintptr_t);
+
+        while (*(uintptr_t *) e.ip) {
+            code = *(ngx_http_script_code_pt *) e.ip;
+            code((ngx_http_script_engine_t *) &e);
+        } 
+        e.ip += sizeof(uintptr_t);
     }
 
     b->last = e.pos;
 
 
-    part = &r->headers_in.headers.part;
-    header = part->elts;
+    if (plcf->upstream.pass_request_headers) {
+        part = &r->headers_in.headers.part;
+        header = part->elts;
     
-    for (i = 0; /* void */; i++) {
+        for (i = 0; /* void */; i++) {
 
-        if (i >= part->nelts) {
-            if (part->next == NULL) {
-                break;
+            if (i >= part->nelts) {
+                if (part->next == NULL) {
+                    break;
+                }
+
+                part = part->next;
+                header = part->elts;
+                i = 0; 
             }
 
-            part = part->next;
-            header = part->elts;
-            i = 0; 
+            key = header[i].hash % plcf->headers_set_hash->hash_size;
+
+            if (hh[key].len == header[i].key.len
+                && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0)
+            {
+                continue;
+            }
+
+            b->last = ngx_cpymem(b->last, header[i].key.data,
+                                 header[i].key.len);
+
+            *b->last++ = ':'; *b->last++ = ' ';
+
+            b->last = ngx_cpymem(b->last, header[i].value.data,
+                                 header[i].value.len);
+
+            *b->last++ = CR; *b->last++ = LF;
+
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http proxy header: \"%V: %V\"",
+                           &header[i].key, &header[i].value);
         }
-
-        key = header[i].hash % plcf->headers_set_hash->hash_size;
-
-        if (hh[key].len == header[i].key.len
-            && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0)
-        {
-            continue;
-        }
-
-        b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len);
-
-        *b->last++ = ':'; *b->last++ = ' ';
-
-        b->last = ngx_cpymem(b->last, header[i].value.data,
-                             header[i].value.len);
-
-        *b->last++ = CR; *b->last++ = LF;
-
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http proxy header: \"%V: %V\"",
-                       &header[i].key, &header[i].value);
     }
 
     /* add "\r\n" at the header end */
@@ -582,6 +622,36 @@
     }
 #endif
 
+    if (plcf->upstream.pass_request_body) {
+
+        body = u->request_bufs;
+        u->request_bufs = cl;
+
+        while (body) {
+            b = ngx_alloc_buf(r->pool);
+            if (b == NULL) {
+                return NGX_ERROR;
+            }
+
+            ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
+
+            cl->next = ngx_alloc_chain_link(r->pool);
+            if (cl->next == NULL) {
+                return NGX_ERROR;
+            }
+
+            cl = cl->next;
+            cl->buf = b;
+
+            body = body->next;
+        }
+
+    } else {
+        u->request_bufs = cl;
+    }
+
+    cl->next = NULL;
+
     return NGX_OK;
 }
 
@@ -589,6 +659,286 @@
 static ngx_int_t
 ngx_http_proxy_reinit_request(ngx_http_request_t *r)
 {
+    ngx_http_proxy_ctx_t  *p;
+
+    p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+    if (p == NULL) {
+        return NGX_OK;
+    }
+
+    p->status = 0;
+    p->status_count = 0;
+    p->status_start = NULL;
+    p->status_end = NULL;
+
+    r->upstream->process_header = ngx_http_proxy_process_status_line;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_process_status_line(ngx_http_request_t *r)
+{
+    ngx_int_t              rc;
+    ngx_http_upstream_t   *u;
+    ngx_http_proxy_ctx_t  *p;
+
+    p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+    if (p == NULL) {
+        p = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
+        if (p == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        ngx_http_set_ctx(r, p, ngx_http_proxy_module);
+    }
+
+    rc = ngx_http_proxy_parse_status_line(r, p);
+
+    if (rc == NGX_AGAIN) {
+        return rc;
+    }
+
+    u = r->upstream;
+
+    if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "upstream sent no valid HTTP/1.0 header"); 
+
+        if (u->accel) {
+            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+        }
+
+        r->http_version = NGX_HTTP_VERSION_9;
+        p->status = NGX_HTTP_OK;
+    
+        return NGX_OK;
+    }
+
+    r->headers_out.status = p->status;
+    u->state->status = p->status;
+
+    r->headers_out.status_line.len = p->status_end - p->status_start;
+    r->headers_out.status_line.data = ngx_palloc(r->pool,
+                                                r->headers_out.status_line.len);
+    if (r->headers_out.status_line.data == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+    ngx_memcpy(r->headers_out.status_line.data, p->status_start,
+               r->headers_out.status_line.len);
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http proxy status %ui \"%V\"",
+                   r->headers_out.status, &r->headers_out.status_line);
+
+    u->process_header = ngx_http_proxy_process_header;
+
+    return ngx_http_proxy_process_header(r);
+}
+
+
+static ngx_int_t
+ngx_http_proxy_parse_status_line(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p)
+{
+    u_char                ch;
+    u_char               *pos;
+    ngx_http_upstream_t  *u;
+    enum  {
+        sw_start = 0,
+        sw_H,
+        sw_HT,
+        sw_HTT,
+        sw_HTTP,
+        sw_first_major_digit,
+        sw_major_digit,
+        sw_first_minor_digit,
+        sw_minor_digit,
+        sw_status,
+        sw_space_after_status,
+        sw_status_text,
+        sw_almost_done
+    } state; 
+
+    u = r->upstream;
+
+    state = r->state;
+
+    for (pos = u->header_in.pos; pos < u->header_in.last; pos++) {
+        ch = *pos;
+
+        switch (state) {
+
+        /* "HTTP/" */
+        case sw_start:
+            switch (ch) {
+            case 'H': 
+                state = sw_H;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        case sw_H: 
+            switch (ch) {
+            case 'T': 
+                state = sw_HT;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        case sw_HT:
+            switch (ch) {
+            case 'T': 
+                state = sw_HTT;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        case sw_HTT:
+            switch (ch) {
+            case 'P': 
+                state = sw_HTTP;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        case sw_HTTP:
+            switch (ch) {
+            case '/': 
+                state = sw_first_major_digit;
+                break;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        /* the first digit of major HTTP version */
+        case sw_first_major_digit:
+            if (ch < '1' || ch > '9') {
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+
+            state = sw_major_digit;
+            break;
+
+        /* the major HTTP version or dot */
+        case sw_major_digit:
+            if (ch == '.') {
+                state = sw_first_minor_digit;
+                break;
+            }
+
+            if (ch < '0' || ch > '9') {
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+
+            break;
+
+        /* the first digit of minor HTTP version */
+        case sw_first_minor_digit:
+            if (ch < '0' || ch > '9') {
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+
+            state = sw_minor_digit;
+            break;
+
+        /* the minor HTTP version or the end of the request line */
+        case sw_minor_digit:
+            if (ch == ' ') {
+                state = sw_status;
+                break;
+            }
+
+            if (ch < '0' || ch > '9') {
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+
+            break;
+
+        /* HTTP status code */
+        case sw_status:
+            if (ch < '0' || ch > '9') {
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+
+            p->status = p->status * 10 + ch - '0';
+
+            if (++p->status_count == 3) {
+                state = sw_space_after_status;
+                p->status_start = pos - 2;
+            }
+
+            break;
+
+         /* space or end of line */
+         case sw_space_after_status:
+            switch (ch) {
+            case ' ': 
+                state = sw_status_text;
+                break;
+            case '.':                    /* IIS may send 403.1, 403.2, etc */
+                state = sw_status_text;
+                break;
+            case CR:
+                state = sw_almost_done;
+                break;
+            case LF:
+                goto done;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+            break;
+
+        /* any text until end of line */
+        case sw_status_text:
+            switch (ch) {
+            case CR:
+                state = sw_almost_done;
+
+                break;
+            case LF:
+                goto done;
+            }
+            break;
+
+        /* end of request line */
+        case sw_almost_done:
+            p->status_end = pos - 1;
+            switch (ch) {
+            case LF:
+                goto done;
+            default:
+                return NGX_HTTP_PROXY_PARSE_NO_HEADER;
+            }
+        }
+    }
+
+    u->header_in.pos = pos + 1;
+    r->state = state;
+
+    return NGX_AGAIN;
+
+done:
+
+    u->header_in.pos = pos + 1;
+
+    if (p->status_end == NULL) {
+        p->status_end = pos;
+    }
+
+    r->state = sw_start;
+
     return NGX_OK;
 }
 
@@ -596,14 +946,79 @@
 static ngx_int_t
 ngx_http_proxy_process_header(ngx_http_request_t *r)
 {
-    return NGX_OK;
-}
+    ngx_int_t                       rc;
+    ngx_uint_t                      key;
+    ngx_table_elt_t                *h;
+    ngx_http_upstream_header_t     *hh;
+    ngx_http_upstream_main_conf_t  *umcf;
 
+    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+    hh = (ngx_http_upstream_header_t *) umcf->headers_in_hash.buckets;
 
-static ngx_int_t
-ngx_http_proxy_send_header(ngx_http_request_t *r)
-{
-    return NGX_OK;
+    for ( ;;  ) {
+
+        rc = ngx_http_parse_header_line(r, &r->upstream->header_in);
+
+        if (rc == NGX_OK) {
+
+            /* a header line has been parsed successfully */
+
+            h = ngx_list_push(&r->upstream->headers_in.headers);
+            if (h == NULL) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            h->hash = r->header_hash;
+
+            h->key.len = r->header_name_end - r->header_name_start;
+            h->value.len = r->header_end - r->header_start;
+
+            h->key.data = ngx_palloc(r->pool,
+                                     h->key.len + 1 + h->value.len + 1);
+            if (h->key.data == NULL) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            h->value.data = h->key.data + h->key.len + 1;
+
+            ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
+            ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
+
+            key = h->hash % umcf->headers_in_hash.hash_size;
+
+            if (hh[key].name.len == h->key.len
+                && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0)
+            {
+                if (hh[key].handler(r, h, hh[key].offset) != NGX_OK) {
+                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                }
+            }
+
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http proxy header: \"%V: %V\"",
+                           &h->key, &h->value);
+
+            continue;
+        }
+
+        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
+
+            /* a whole header has been parsed successfully */
+
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http proxy header done");
+
+            return NGX_OK;
+        }
+
+        /* there was error while a header line parsing */
+
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      ngx_http_upstream_header_errors[rc
+                                               - NGX_HTTP_PARSE_HEADER_ERROR]);
+
+        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+    }
 }
 
 
@@ -627,57 +1042,222 @@
 }
 
 
-static ngx_int_t
-ngx_http_proxy_init(ngx_cycle_t *cycle)
-{
-#if 0
-    ngx_http_variable_t  *var;
-
-    var = ngx_http_add_variable(cf, &ngx_http_proxy_host, 1);
-    if (var == NULL) {
-        return NGX_ERROR;
-    }
-
-    var->handler = ngx_http_proxy_host_variable;
-#endif
-
-    return NGX_OK;
-
-#if 0
-    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;
-
-#endif
-}
-
-
 static ngx_http_variable_value_t *
 ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data)
 {
-    ngx_http_variable_value_t  *var;
+    ngx_http_variable_value_t  *vv;
     ngx_http_proxy_loc_conf_t  *plcf;
 
-    var = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
-    if (var == NULL) {
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
         return NULL;
     }
 
     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
 
-    var->value = 0;
-    var->text = plcf->host_header;
+    vv->value = 0;
+    vv->text = plcf->host_header;
 
-    return var;
+    return vv;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data)
+{
+    ngx_http_variable_value_t  *vv;
+    ngx_http_proxy_loc_conf_t  *plcf;
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+    vv->value = 0;
+    vv->text = plcf->port_text;
+
+    return vv;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
+    uintptr_t data)
+{
+    u_char                     *p;
+    ngx_http_variable_value_t  *vv;
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    vv->value = 0;
+
+    if (r->headers_in.x_forwarded_for == NULL) {
+        vv->text = r->connection->addr_text;
+        return vv;
+    }
+
+    vv->text.len = r->headers_in.x_forwarded_for->value.len
+                   + sizeof(", ") - 1 + r->connection->addr_text.len;
+
+    p = ngx_palloc(r->pool, vv->text.len);
+    if (p == NULL) {
+        return NULL;
+    }
+
+    vv->text.data = p;
+
+    p = ngx_cpymem(p, r->headers_in.x_forwarded_for->value.data,
+                   r->headers_in.x_forwarded_for->value.len);
+
+    *p++ = ','; *p++ = ' ';
+
+    ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
+
+    return vv;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
+    size_t prefix)
+{
+    ngx_int_t                   rc;
+    ngx_uint_t                  i;
+    ngx_http_proxy_loc_conf_t  *plcf;
+    ngx_http_proxy_redirect_t  *pr;
+
+    plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+    pr = plcf->redirects->elts;
+
+    if (pr == NULL) {
+        return NGX_DECLINED;
+    }
+
+    for (i = 0; i < plcf->redirects->nelts; i++) {
+        rc = pr->handler(r, h, prefix, pr);
+
+        if (rc != NGX_DECLINED) {
+            return rc;
+        }
+    }
+
+    return NGX_DECLINED;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h,
+    size_t prefix, ngx_http_proxy_redirect_t *pr)
+{
+    size_t   len;
+    u_char  *data, *p;
+
+    if (pr->redirect.len > h->value.len - prefix
+        || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
+                        pr->redirect.len) != 0)
+    {
+        return NGX_DECLINED;
+    }
+
+    len = prefix + pr->replacement.text.len + h->value.len - pr->redirect.len;
+
+    data = ngx_palloc(r->pool, len);
+    if (data == NULL) {
+        return NGX_ERROR;
+    }
+
+    p = data;
+
+    if (prefix) {
+        p = ngx_cpymem(p, h->value.data, prefix);
+    }
+
+    p = ngx_cpymem(p, pr->replacement.text.data, pr->replacement.text.len);
+
+    ngx_memcpy(p, h->value.data + prefix + pr->redirect.len,
+               h->value.len - pr->redirect.len - prefix);
+
+    h->value.len = len;
+    h->value.data = data;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t *r, ngx_table_elt_t *h,
+    size_t prefix, ngx_http_proxy_redirect_t *pr)
+{
+    size_t                        len;
+    u_char                       *data, *p;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e;
+    ngx_http_script_len_code_pt   lcode;
+
+    if (pr->redirect.len > h->value.len - prefix
+        || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
+                        pr->redirect.len) != 0)
+    {
+        return NGX_DECLINED;
+    }
+
+    ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+    e.ip = pr->replacement.vars.lengths;
+    e.request = r;
+
+    for (len = prefix; *(uintptr_t *) e.ip; len += lcode(&e)) {
+        lcode = *(ngx_http_script_len_code_pt *) e.ip;
+    }
+
+    data = ngx_palloc(r->pool, len);
+    if (data == NULL) {
+        return NGX_ERROR;
+    }
+
+    p = data;
+
+    if (prefix) {
+        p = ngx_cpymem(p, h->value.data, prefix);
+    }
+
+    e.ip = pr->replacement.vars.values;
+    e.pos = p;
+
+    while (*(uintptr_t *) e.ip) {
+        code = *(ngx_http_script_code_pt *) e.ip;
+        code(&e);
+    }
+
+    h->value.len = len;
+    h->value.data = data;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_add_variables(ngx_conf_t *cf)
+{
+    ngx_http_variable_t  *var, *v;
+
+    for (v = ngx_http_proxy_vars; v->name.len; v++) {
+        var = ngx_http_add_variable(cf, &v->name, v->flags);
+        if (var == NULL) {
+            return NGX_ERROR;
+        }
+
+        var->handler = v->handler;
+        var->data = v->data;
+    }
+
+    return NGX_OK;
 }
 
 
@@ -698,6 +1278,15 @@
      *     conf->upstream.path = NULL;
      *     conf->upstream.next_upstream = 0;
      *     conf->upstream.temp_path = NULL;
+     *     conf->upstream.schema = { 0, NULL };
+     *     conf->upstream.uri = { 0, NULL };
+     *     conf->upstream.location = NULL;
+     *
+     *     conf->headers_source = NULL;
+     *     conf->headers_set_len = NULL;
+     *     conf->headers_set = NULL;
+     *     conf->headers_set_hash = NULL;
+     *     conf->rewrite_locations = NULL;
      */
     
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
@@ -709,21 +1298,23 @@
     conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE;
     conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE;  
     conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE;
+
+    conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET;
+    conf->upstream.method = NGX_CONF_UNSET_UINT;
+    conf->upstream.pass_request_headers = NGX_CONF_UNSET;
+    conf->upstream.pass_request_body = NGX_CONF_UNSET;
     
     conf->upstream.redirect_errors = NGX_CONF_UNSET;
-    conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET;
-    conf->upstream.x_powered_by = NGX_CONF_UNSET;
 
     /* "proxy_cyclic_temp_file" is disabled */
     conf->upstream.cyclic_temp_file = 0;
 
-    conf->preserve_host = NGX_CONF_UNSET;
-    conf->set_x_url = NGX_CONF_UNSET;
-    conf->set_x_real_ip = NGX_CONF_UNSET;
-    conf->add_x_forwarded_for = NGX_CONF_UNSET;
+    conf->upstream.pass_x_powered_by = NGX_CONF_UNSET;
+    conf->upstream.pass_server = NGX_CONF_UNSET;
+    conf->upstream.pass_date = 0;
+    conf->upstream.pass_x_accel_expires = NGX_CONF_UNSET;
 
-    conf->pass_server = NGX_CONF_UNSET;
-    conf->pass_x_accel_expires = NGX_CONF_UNSET;
+    conf->redirect = NGX_CONF_UNSET;
 
     return conf;
 }
@@ -735,11 +1326,16 @@
     ngx_http_proxy_loc_conf_t *prev = parent;
     ngx_http_proxy_loc_conf_t *conf = child;
 
-    size_t            size;
-    ngx_str_t        *name;
-    ngx_table_elt_t  *src;
-    ngx_http_variable_t  *var;
-    
+    u_char                       *p;
+    size_t                        size;
+    uintptr_t                    *code;
+    ngx_str_t                    *name;
+    ngx_uint_t                    i;
+    ngx_table_elt_t              *src, *s, *h;
+    ngx_http_proxy_redirect_t    *pr;
+    ngx_http_script_compile_t     sc;
+    ngx_http_script_copy_code_t  *copy;
+
     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                               prev->upstream.connect_timeout, 60000);
 
@@ -841,241 +1437,297 @@
                                |NGX_HTTP_UPSTREAM_FT_ERROR
                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
 
-    ngx_conf_merge_msec_value(conf->upstream.redirect_errors,
-                              prev->upstream.redirect_errors, 0);
+    ngx_conf_merge_path_value(conf->upstream.temp_path,
+                              prev->upstream.temp_path,
+                              NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,
+                              ngx_garbage_collector_temp_handler, cf);
 
     ngx_conf_merge_msec_value(conf->upstream.pass_unparsed_uri,
                               prev->upstream.pass_unparsed_uri, 0);
 
-    if (conf->upstream.pass_unparsed_uri && conf->location0->len > 1) {
+    if (conf->upstream.pass_unparsed_uri && conf->upstream.location->len > 1) {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                       "\"proxy_pass_unparsed_uri\" can be set for "
                       "location \"/\" or given by regular expression.");
         return NGX_CONF_ERROR;
     }
 
-    ngx_conf_merge_msec_value(conf->upstream.x_powered_by,
-                              prev->upstream.x_powered_by, 1);
+    if (conf->upstream.method == NGX_CONF_UNSET_UINT) {
+        conf->upstream.method = prev->upstream.method;
+    }
 
-    ngx_conf_merge_value(conf->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_value(conf->upstream.pass_request_headers,
+                              prev->upstream.pass_request_headers, 1);
+    ngx_conf_merge_value(conf->upstream.pass_request_body,
+                              prev->upstream.pass_request_body, 1);
+
+    ngx_conf_merge_msec_value(conf->upstream.redirect_errors,
+                              prev->upstream.redirect_errors, 0);
+
+    ngx_conf_merge_msec_value(conf->upstream.pass_x_powered_by,
+                              prev->upstream.pass_x_powered_by, 1);
+    ngx_conf_merge_msec_value(conf->upstream.pass_server,
+                              prev->upstream.pass_server, 0);
+    ngx_conf_merge_msec_value(conf->upstream.pass_x_accel_expires,
+                              prev->upstream.pass_x_accel_expires, 0);
+
+
+    ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
+
+    if (conf->redirect) {
+
+        if (conf->redirects == NULL) {
+            conf->redirects = prev->redirects;
+        }
+
+        if (conf->redirects == NULL && conf->upstream.url.data) {
+
+            conf->redirects = ngx_array_create(cf->pool, 1,
+                                            sizeof(ngx_http_proxy_redirect_t));
+            if (conf->redirects == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            pr = ngx_array_push(conf->redirects);
+            if (pr == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            pr->handler = ngx_http_proxy_rewrite_redirect_text;
+            pr->redirect = conf->upstream.url;
+            pr->replacement.text = *conf->upstream.location;
+        }
+    }
+
 
     if (conf->peers == NULL) {
         conf->peers = prev->peers;
         conf->upstream = prev->upstream;
     }
 
-    if (conf->headers_set_hash == NULL) {
+    if (conf->headers_source == NULL) {
+        conf->headers_source = prev->headers_source;
         conf->headers_set_len = prev->headers_set_len;
         conf->headers_set = prev->headers_set;
         conf->headers_set_hash = prev->headers_set_hash;
     }
 
-    if (conf->headers_set_hash == NULL) {
-
-        if (conf->headers_names == NULL) {
-            conf->headers_names = ngx_array_create(cf->pool, 4,
-                                                   sizeof(ngx_str_t));
-            if (conf->headers_names == NULL) {
-                return NGX_CONF_ERROR;
-            }
-        }
-
-        if (conf->headers_sources == NULL) {
-            conf->headers_sources = ngx_array_create(cf->pool, 4,
-                                                     sizeof(ngx_table_elt_t));
-            if (conf->headers_sources == NULL) {
-                return NGX_CONF_ERROR;
-            }
-        }
-
-        /* STUB */
-        var = ngx_http_add_variable(cf, &ngx_http_proxy_host, 0);
-        if (var == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        var->handler = ngx_http_proxy_host_variable;
-        /**/
-
-
-        name = ngx_array_push(conf->headers_names);
-        if (name == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        name->len = sizeof("Host") - 1;
-        name->data = (u_char *) "Host";
-
-        src = ngx_array_push(conf->headers_sources);
-        if (src == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        src->hash = 0;
-        src->key.len = sizeof("Host") - 1;
-        src->key.data = (u_char *) "Host";
-        src->value.len = sizeof("$PROXY_HOST") - 1;
-        src->value.data = (u_char *) "$PROXY_HOST";
-
-
-        name = ngx_array_push(conf->headers_names);
-        if (name == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        name->len = sizeof("Connection") - 1;
-        name->data = (u_char *) "Connection";
-
-        src = ngx_array_push(conf->headers_sources);
-        if (src == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        src->hash = 0;
-        src->key.len = sizeof("Connection") - 1;
-        src->key.data = (u_char *) "Connection";
-        src->value.len = sizeof("close") - 1;
-        src->value.data = (u_char *) "close";
-
-
-        name = ngx_array_push(conf->headers_names);
-        if (name == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        name->len = 0;
-        name->data = NULL;
-
-
-        if (ngx_http_script_compile_lite(cf, conf->headers_sources,
-                &conf->headers_set_len, &conf->headers_set,
-                ngx_http_proxy_compile_header_start,
-                ngx_http_proxy_compile_header_end) != NGX_OK)
-        {
-            return NGX_CONF_ERROR;
-        }
-
-
-        conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash_t));
-        if (conf->headers_set_hash == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        conf->headers_set_hash->max_size = 100;
-        conf->headers_set_hash->bucket_limit = 1;
-        conf->headers_set_hash->bucket_size = sizeof(ngx_str_t);
-        conf->headers_set_hash->name = "proxy_headers";
-
-        if (ngx_hash_init(conf->headers_set_hash, cf->pool,
-                          conf->headers_names->elts) != NGX_OK)
-        {
-            return NGX_CONF_ERROR;
-        }
-
-#if 0
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
-#endif
-        ngx_log_error(NGX_LOG_NOTICE, cf->log, 0,
-                       "proxy_headers hash size: %ui, "
-                       "max buckets per entry: %ui",
-                       conf->headers_set_hash->hash_size,
-                       conf->headers_set_hash->min_buckets);
+    if (conf->headers_set_hash) {
+        return NGX_CONF_OK;
     }
 
+
+    conf->headers_names = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
+    if (conf->headers_names == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (conf->headers_source == NULL) {
+        conf->headers_source = ngx_array_create(cf->pool, 4,
+                                                sizeof(ngx_table_elt_t));
+        if (conf->headers_source == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
+    if (conf->headers_set_len == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->headers_set = ngx_array_create(cf->pool, 512, 1);
+    if (conf->headers_set == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+
+    src = conf->headers_source->elts;
+
+    for (h = ngx_http_proxy_headers; h->key.len; h++) {
+
+        for (i = 0; i < conf->headers_source->nelts; i++) {
+            if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
+                goto next;
+            }
+        }
+
+        s = ngx_array_push(conf->headers_source);
+        if (s == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *s = *h;
+
+    next:
+
+        continue;
+    }
+
+    for (i = 0; i < conf->headers_source->nelts; i++) {
+
+        name = ngx_array_push(conf->headers_names);
+        if (name == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *name = src[i].key;
+
+        if (ngx_http_script_variables_count(&src[i].value) == 0) {
+            copy = ngx_array_push_n(conf->headers_set_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                 ngx_http_script_copy_len_code;
+            copy->len = src[i].key.len + sizeof(": ") - 1
+                        + src[i].value.len + sizeof(CRLF) - 1;
+
+
+            size = (sizeof(ngx_http_script_copy_code_t)
+                       + src[i].key.len + sizeof(": ") - 1
+                       + src[i].value.len + sizeof(CRLF) - 1
+                       + sizeof(uintptr_t) - 1)
+                    & ~(sizeof(uintptr_t) - 1);
+
+            copy = ngx_array_push_n(conf->headers_set, size);
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = ngx_http_script_copy_code;
+            copy->len = src[i].key.len + sizeof(": ") - 1
+                        + src[i].value.len + sizeof(CRLF) - 1;
+
+            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+
+            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
+            *p++ = ':'; *p++ = ' ';
+            p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
+            *p++ = CR; *p = LF;
+
+        } else {
+            copy = ngx_array_push_n(conf->headers_set_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                 ngx_http_script_copy_len_code;
+            copy->len = src[i].key.len + sizeof(": ") - 1;
+
+
+            size = (sizeof(ngx_http_script_copy_code_t)
+                    + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
+                    & ~(sizeof(uintptr_t) - 1);
+
+            copy = ngx_array_push_n(conf->headers_set, size);
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = ngx_http_script_copy_code;
+            copy->len = src[i].key.len + sizeof(": ") - 1;
+
+            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+            p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
+            *p++ = ':'; *p = ' ';
+
+
+            ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+            sc.cf = cf;
+            sc.source = &src[i].value;
+            sc.lengths = &conf->headers_set_len;
+            sc.values = &conf->headers_set;
+
+            if (ngx_http_script_compile(&sc) != NGX_OK) {
+                return NGX_CONF_ERROR;
+            }
+
+
+            copy = ngx_array_push_n(conf->headers_set_len,
+                                    sizeof(ngx_http_script_copy_code_t));
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = (ngx_http_script_code_pt)
+                                                 ngx_http_script_copy_len_code;
+            copy->len = sizeof(CRLF) - 1;
+
+
+            size = (sizeof(ngx_http_script_copy_code_t)
+                    + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
+                    & ~(sizeof(uintptr_t) - 1);
+
+            copy = ngx_array_push_n(conf->headers_set, size);
+            if (copy == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            copy->code = ngx_http_script_copy_code;
+            copy->len = sizeof(CRLF) - 1;
+
+            p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+            *p++ = CR; *p = LF;
+        }
+
+        code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+
+        code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+    }
+
+    code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
+    if (code == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    *code = (uintptr_t) NULL;
+
+
+    conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash_t));
+    if (conf->headers_set_hash == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->headers_set_hash->max_size = 100;
+    conf->headers_set_hash->bucket_limit = 1;
+    conf->headers_set_hash->bucket_size = sizeof(ngx_str_t);
+    conf->headers_set_hash->name = "proxy_headers";
+
+    if (ngx_hash_init(conf->headers_set_hash, cf->pool,
+              conf->headers_names->elts, conf->headers_names->nelts) != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
+                   "proxy_headers hash size: %ui, "
+                   "max buckets per entry: %ui",
+                   conf->headers_set_hash->hash_size,
+                   conf->headers_set_hash->min_buckets);
+
     return NGX_CONF_OK;
 }
 
 
-static ngx_int_t
-ngx_http_proxy_compile_header_start(ngx_table_elt_t *h,
-    ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value)
-{
-    u_char                       *p;
-    size_t                        size;
-    ngx_http_script_copy_code_t  *copy;
-
-    copy = ngx_array_push_n(lengths, sizeof(ngx_http_script_copy_code_t));
-    if (copy == NULL) {
-        return NGX_ERROR;
-    }
-
-    copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len;
-    copy->len = h->key.len + sizeof(": ") - 1;
-
-    if (value) {
-        copy->len += h->value.len + sizeof(CRLF) - 1;
-    }
-
-    size = (copy->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
-
-    copy = ngx_array_push_n(values,
-                            sizeof(ngx_http_script_copy_code_t) + size);
-    if (copy == NULL) {
-        return NGX_ERROR;
-    }
-
-    copy->code = ngx_http_script_copy;
-    copy->len = h->key.len + sizeof(": ") - 1;
-
-    if (value) {
-        copy->len += h->value.len + sizeof(CRLF) - 1;
-    }
-
-    p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
-
-    p = ngx_cpymem(p, h->key.data, h->key.len);
-    p = ngx_cpymem(p, ": ", sizeof(": ") - 1);
-
-    if (value) {
-        p = ngx_cpymem(p, h->value.data, h->value.len);
-        ngx_memcpy(p, CRLF, sizeof(CRLF) - 1);
-    }
-
-    return NGX_OK;
-}
-
-
-static ngx_int_t
-ngx_http_proxy_compile_header_end(ngx_array_t *lengths, ngx_array_t *values)
-{
-    size_t                        size;
-    ngx_http_script_copy_code_t  *copy;
-
-    copy = ngx_array_push_n(lengths, sizeof(ngx_http_script_copy_code_t));
-    if (copy == NULL) {
-        return NGX_ERROR;
-    }
-
-    copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len;
-    copy->len = sizeof(CRLF) - 1;
-
-    size = (sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
-            & ~(sizeof(uintptr_t) - 1);
-
-    copy = ngx_array_push_n(values,
-                            sizeof(ngx_http_script_copy_code_t) + size);
-    if (copy == NULL) {
-        return NGX_ERROR;
-    }
-
-    copy->code = ngx_http_script_copy;
-    copy->len = sizeof(CRLF) - 1;
-
-    ngx_memcpy((u_char *) copy + sizeof(ngx_http_script_copy_code_t),
-               CRLF, sizeof(CRLF) - 1);
-
-    return NGX_OK;
-}
-
-
 static char *
 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_proxy_loc_conf_t *lcf = conf;
+    ngx_http_proxy_loc_conf_t *plcf = conf;
 
     ngx_uint_t                   i;
     ngx_str_t                   *value, *url;
@@ -1105,20 +1757,16 @@
         unix_upstream.url.data = url->data + 7;
         unix_upstream.uri_part = 1;
 
-        lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
-        if (lcf->peers == NULL) {
+        plcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
+        if (plcf->peers == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        lcf->peers->peer[0].uri_separator = ":";
+        plcf->peers->peer[0].uri_separator = ":";
 
-        lcf->host_header.len = sizeof("localhost") - 1;
-        lcf->host_header.data = (u_char *) "localhost";
-        lcf->uri0 = unix_upstream.uri;
-#if 0
-	STUB
-        lcf->upstream->default_port = 1;
-#endif
+        plcf->host_header.len = sizeof("localhost") - 1;
+        plcf->host_header.data = (u_char *) "localhost";
+        plcf->upstream.uri = unix_upstream.uri;
 
 #else
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -1137,34 +1785,35 @@
         inet_upstream.default_port_value = 80;
         inet_upstream.uri_part = 1;
 
-        lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
-        if (lcf->peers == NULL) {
+        plcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
+        if (plcf->peers == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        for (i = 0; i < lcf->peers->number; i++) {
-            lcf->peers->peer[i].uri_separator = ":";
+        for (i = 0; i < plcf->peers->number; i++) {
+            plcf->peers->peer[i].uri_separator = ":";
         }
 
-        lcf->host_header = inet_upstream.host_header;
-        lcf->uri0 = inet_upstream.uri;
-#if 0
-	STUB
-        lcf->port_text = inet_upstream.port_text;
-        lcf->upstream->default_port = inet_upstream.default_port;
-#endif
+        plcf->host_header = inet_upstream.host_header;
+        plcf->port_text = inet_upstream.port_text;
+        plcf->upstream.uri = inet_upstream.uri;
     }
 
+    plcf->upstream.schema.len = sizeof("http://") - 1;
+    plcf->upstream.schema.data = (u_char *) "http://";
+
     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
 
     clcf->handler = ngx_http_proxy_handler;
 
 #if (NGX_PCRE)
-    lcf->location0 = clcf->regex ? &ngx_http_proxy_uri : &clcf->name;
+    plcf->upstream.location = clcf->regex ? &ngx_http_proxy_uri : &clcf->name;
 #else
-    lcf->location0 = &clcf->name;
+    plcf->upstream.location = &clcf->name;
 #endif
 
+    plcf->upstream.url = *url;
+
     if (clcf->name.data[clcf->name.len - 1] == '/') {
         clcf->auto_redirect = 1;
     }
@@ -1174,8 +1823,84 @@
 
 
 static char *
-ngx_http_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
+    ngx_http_proxy_loc_conf_t *plcf = conf;
+
+    ngx_str_t                  *value;
+    ngx_array_t                *vars_lengths, *vars_values;
+    ngx_http_script_compile_t   sc;
+    ngx_http_proxy_redirect_t  *pr;
+
+    if (plcf->redirect == 0) {
+        return NGX_CONF_OK;
+    }
+
+    value = cf->args->elts;
+
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        plcf->redirect = 0;
+        plcf->redirects = NULL;
+        return NGX_CONF_OK;
+    }
+
+    if (plcf->redirects == NULL) {
+        plcf->redirects = ngx_array_create(cf->pool, 1,
+                                           sizeof(ngx_http_proxy_redirect_t));
+        if (plcf->redirects == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    pr = ngx_array_push(plcf->redirects);
+    if (pr == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "default") == 0) {
+        if (plcf->upstream.url.data == NULL) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "\"proxy_rewrite_location default\" must go "
+                               "after the \"proxy_pass\" directive");
+            return NGX_CONF_ERROR;
+        }
+
+        pr->handler = ngx_http_proxy_rewrite_redirect_text;
+        pr->redirect = plcf->upstream.url;
+        pr->replacement.text = *plcf->upstream.location;
+
+        return NGX_CONF_OK;
+    }
+
+    if (ngx_http_script_variables_count(&value[2]) == 0) {
+        pr->handler = ngx_http_proxy_rewrite_redirect_text;
+        pr->redirect = value[1];
+        pr->replacement.text = value[2];
+
+        return NGX_CONF_OK;
+    }
+
+    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+    vars_lengths = NULL;
+    vars_values = NULL;
+
+    sc.cf = cf;
+    sc.source = &value[2];
+    sc.lengths = &vars_lengths;
+    sc.values = &vars_values;
+    sc.complete_lengths = 1;
+    sc.complete_values = 1;
+
+    if (ngx_http_script_compile(&sc) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    pr->handler = ngx_http_proxy_rewrite_redirect_vars;
+    pr->redirect = value[1];
+    pr->replacement.vars.lengths = vars_lengths->elts;
+    pr->replacement.vars.values = vars_values->elts;
+
     return NGX_CONF_OK;
 }
 
diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c
index 84381c9..cfc23f6 100644
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -54,7 +54,8 @@
 
 
 static ngx_http_module_t  ngx_http_range_header_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -68,7 +69,7 @@
 
 
 ngx_module_t  ngx_http_range_header_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_range_header_filter_module_ctx, /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -78,7 +79,8 @@
 
 
 static ngx_http_module_t  ngx_http_range_body_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -92,7 +94,7 @@
 
 
 ngx_module_t  ngx_http_range_body_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_range_body_filter_module_ctx, /* module context */
     NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -120,6 +122,7 @@
 
     if (r->http_version < NGX_HTTP_VERSION_10
         || r->headers_out.status != NGX_HTTP_OK
+        || r->main
         || r->headers_out.content_length_n == -1
         || !r->filter_allow_ranges)
     {
@@ -136,6 +139,7 @@
             return NGX_ERROR;
         }
 
+        r->headers_out.accept_ranges->hash = 1;
         r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1;
         r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges";
         r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1;
@@ -269,6 +273,7 @@
 
         r->headers_out.content_range = content_range;
 
+        content_range->hash = 1;
         content_range->key.len = sizeof("Content-Range") - 1;
         content_range->key.data = (u_char *) "Content-Range";
 
@@ -303,6 +308,7 @@
 
         r->headers_out.content_range = content_range;
 
+        content_range->hash = 1;
         content_range->key.len = sizeof("Content-Range") - 1;
         content_range->key.data = (u_char *) "Content-Range";
 
@@ -338,7 +344,7 @@
 
     len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
           + sizeof(CRLF "Content-Type: ") - 1
-          + r->headers_out.content_type->value.len
+          + r->headers_out.content_type.len
           + sizeof(CRLF "Content-Range: bytes ") - 1;
 
     if (r->headers_out.charset.len) {
@@ -366,7 +372,7 @@
                                            "Content-Type: %V; charset=%V" CRLF
                                            "Content-Range: bytes ",
                                            boundary,
-                                           &r->headers_out.content_type->value,
+                                           &r->headers_out.content_type,
                                            &r->headers_out.charset)
                                    - ctx->boundary_header.data;
 
@@ -378,26 +384,26 @@
                                            "Content-Type: %V" CRLF
                                            "Content-Range: bytes ",
                                            boundary,
-                                           &r->headers_out.content_type->value)
+                                           &r->headers_out.content_type)
                                    - ctx->boundary_header.data;
     }
 
-    r->headers_out.content_type->value.data =
-         ngx_palloc(r->pool,
-                    sizeof("Content-Type: multipart/byteranges; boundary=") - 1
-                    + NGX_ATOMIC_T_LEN);
+    r->headers_out.content_type.data =
+        ngx_palloc(r->pool,
+                   sizeof("Content-Type: multipart/byteranges; boundary=") - 1
+                   + NGX_ATOMIC_T_LEN);
 
-    if (r->headers_out.content_type->value.data == NULL) {
+    if (r->headers_out.content_type.data == NULL) {
         return NGX_ERROR;
     }
 
     /* "Content-Type: multipart/byteranges; boundary=0123456789" */
 
-    r->headers_out.content_type->value.len =
-                           ngx_sprintf(r->headers_out.content_type->value.data,
+    r->headers_out.content_type.len =
+                           ngx_sprintf(r->headers_out.content_type.data,
                                        "multipart/byteranges; boundary=%0muA",
                                        boundary)
-                           - r->headers_out.content_type->value.data;
+                           - r->headers_out.content_type.data;
 
 
     /* the size of the last boundary CRLF "--0123456789--" CRLF */
diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c
index 1da475c..2dc7a7f 100644
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -9,136 +9,36 @@
 #include <ngx_http.h>
 
 
-typedef struct ngx_http_rewrite_engine_s  ngx_http_rewrite_engine_t;
-
-typedef void (*ngx_http_rewrite_code_pt) (ngx_http_rewrite_engine_t *e);
-
-
 typedef struct {
-    ngx_str_t                     name;
-    ngx_uint_t                    wildcard;
+    ngx_str_t                   name;
+    ngx_uint_t                  wildcard;
 } ngx_http_rewrite_referer_t;
 
 
 typedef struct {
-    ngx_str_t                    *name;
-    ngx_http_variable_value_t    *value;
+    ngx_str_t                  *name;
+    ngx_http_variable_value_t  *value;
 } ngx_http_rewrite_variable_t;
 
 
 typedef struct {
-    ngx_array_t                  *codes;        /* uintptr_t */
-    ngx_array_t                  *referers;     /* ngx_http_rewrite_referer_t */
+    ngx_array_t                *codes;        /* uintptr_t */
+    ngx_array_t                *referers;     /* ngx_http_rewrite_referer_t */
 
-    ngx_uint_t                    max_captures;
-    ngx_uint_t                    stack_size;
+    ngx_uint_t                  max_captures;
+    ngx_uint_t                  stack_size;
 
-    ngx_flag_t                    log;
+    ngx_flag_t                  log;
 
-    ngx_flag_t                    no_referer;
-    ngx_flag_t                    blocked_referer;
+    ngx_flag_t                  no_referer;
+    ngx_flag_t                  blocked_referer;
 } ngx_http_rewrite_loc_conf_t;
 
 
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    ngx_regex_t                  *regex;
-    uintptr_t                     size;
-    uintptr_t                     ncaptures;
-    uintptr_t                     status;
-    uintptr_t                     next;
-
-    uintptr_t                     test:1;
-    uintptr_t                     uri:1;
-
-    /* add the r->args to the new arguments */
-    uintptr_t                     args:1;
-
-    uintptr_t                     redirect:1;
-    uintptr_t                     break_cycle:1;
-
-    ngx_str_t                     name;
-} ngx_http_rewrite_regex_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-
-    uintptr_t                     uri:1;
-
-    /* add the r->args to the new arguments */
-    uintptr_t                     args:1;
-
-    uintptr_t                     redirect:1;
-} ngx_http_rewrite_regex_end_code_t;
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     n;
-} ngx_http_rewrite_copy_capture_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     len;
-} ngx_http_rewrite_copy_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     status;
-    uintptr_t                     null;
-} ngx_http_rewrite_return_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     next;
-    void                        **loc_conf;
-} ngx_http_rewrite_if_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     value;
-    uintptr_t                     text_len;
-    uintptr_t                     text_data;
-} ngx_http_rewrite_value_code_t;
-
-
-typedef struct {
-    ngx_http_rewrite_code_pt      code;
-    uintptr_t                     index;
-} ngx_http_rewrite_var_code_t;
-
-
-struct ngx_http_rewrite_engine_s {
-    u_char                       *ip;
-    ngx_http_variable_value_t    *sp;
-
-    ngx_str_t                     buf;
-    ngx_str_t                    *line;
-
-    u_char                       *pos;
-
-    /* the start of the rewritten arguments */
-    u_char                       *args;
-
-    unsigned                      quote:1;
-
-    ngx_int_t                     status;
-
-    int                          *captures;
-
-    ngx_http_request_t           *request;
-    ngx_http_rewrite_loc_conf_t  *conf;
-};
-
-
-static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle);
 static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
     void *parent, void *child);
+static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle);
 static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
@@ -150,12 +50,8 @@
     ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
 static char *ngx_http_rewrite_valid_referers(ngx_conf_t *cf,
     ngx_command_t *cmd, void *conf);
-static char * ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd,
+static char *ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
-static void *ngx_http_rewrite_start_code(ngx_pool_t *pool,
-    ngx_array_t **codes, size_t size);
-static void *ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size,
-    void *code);
 
 
 static ngx_command_t  ngx_http_rewrite_commands[] = {
@@ -211,7 +107,8 @@
 
 
 ngx_http_module_t  ngx_http_rewrite_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -225,7 +122,7 @@
 
 
 ngx_module_t  ngx_http_rewrite_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_rewrite_module_ctx,          /* module context */ 
     ngx_http_rewrite_commands,             /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -234,19 +131,15 @@
 };
 
 
-#define ngx_http_rewrite_exit  (u_char *) &ngx_http_rewrite_exit_code
-
-uintptr_t ngx_http_rewrite_exit_code = (uintptr_t) NULL;
-
 static ngx_http_variable_value_t  ngx_http_rewrite_null_value =
-                                                        { 0, ngx_string("") };
+    { 0, ngx_string("") };
 
 
 static ngx_int_t
 ngx_http_rewrite_handler(ngx_http_request_t *r)
 {
-    ngx_http_rewrite_code_pt      code;
-    ngx_http_rewrite_engine_t    *e;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t     *e;
     ngx_http_rewrite_loc_conf_t  *cf;
 
     cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
@@ -255,13 +148,13 @@
         return NGX_DECLINED;
     }
 
-    e = ngx_palloc(r->pool, sizeof(ngx_http_rewrite_engine_t));
+    e = ngx_pcalloc(r->pool, sizeof(ngx_http_script_engine_t));
     if (e == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    e->sp = ngx_palloc(r->pool,
-                       cf->stack_size * sizeof(ngx_http_variable_value_t));
+    e->sp = ngx_pcalloc(r->pool,
+                        cf->stack_size * sizeof(ngx_http_variable_value_t));
     if (e->sp == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -277,18 +170,13 @@
     }
 
     e->ip = cf->codes->elts;
-    e->buf.len = 0;
-    e->buf.data = NULL;
-    e->line = NULL;
-    e->pos = NULL;
-    e->args = NULL;
-    e->quote = 1;
-    e->status = NGX_DECLINED;
     e->request = r;
-    e->conf = cf;
+    e->quote = 1;
+    e->log = cf->log;
+    e->status = NGX_DECLINED;
 
     while (*(uintptr_t *) e->ip) {
-        code = *(ngx_http_rewrite_code_pt *) e->ip;
+        code = *(ngx_http_script_code_pt *) e->ip;
         code(e);
     }
 
@@ -297,392 +185,7 @@
 
 
 static void
-ngx_http_rewrite_regex_start_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_int_t                       rc;
-    ngx_uint_t                      n;
-    ngx_http_request_t             *r;
-    ngx_http_rewrite_regex_code_t  *code;
-
-    code = (ngx_http_rewrite_regex_code_t *) e->ip;
-
-    r = e->request;
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http rewrite regex: \"%V\"", &code->name);
-
-    if (code->uri) {
-        e->line = &r->uri;
-    } else {
-        e->sp--;
-        e->line = &e->sp->text;
-    }
-
-    rc = ngx_regex_exec(code->regex, e->line, e->captures, code->ncaptures);
-
-    if (rc == NGX_REGEX_NO_MATCHED) {
-        if (e->conf->log) {
-            ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                          "\"%V\" does not match \"%V\"", &code->name, e->line);
-        }
-
-        if (code->test) {
-            e->sp->value = 0;
-            e->sp->text.len = 0;
-            e->sp->text.data = (u_char *) "";
-            e->sp++;
-
-            e->ip += sizeof(ngx_http_rewrite_regex_code_t);
-            return;
-        }
-
-        e->ip += code->next;
-        return;
-    }
-
-    if (rc < 0) {
-        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                      ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
-                      rc, e->line, &code->name);
-
-        e->ip = ngx_http_rewrite_exit;
-        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-        return;
-    }
-
-    if (e->conf->log) {
-        ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                      "\"%V\" matches \"%V\"", &code->name, e->line);
-    }
-
-    if (code->test) {
-        e->sp->value = 1;
-        e->sp->text.len = 1;
-        e->sp->text.data = (u_char *) "1";
-        e->sp++;
-
-        e->ip += sizeof(ngx_http_rewrite_regex_code_t);
-        return;
-    }
-
-    if (code->status) {
-        e->status = code->status;
-
-        if (!code->redirect) {
-            e->ip = ngx_http_rewrite_exit;
-            return;
-        }
-    }
-
-    e->buf.len = code->size;
-
-    if (code->uri) {
-        if (!code->break_cycle) {
-            r->uri_changed = 1;
-            r->valid_unparsed_uri = 1;
-        }
-
-        if (rc && (r->quoted_uri || r->plus_in_uri)) {
-            e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
-                                             NGX_ESCAPE_ARGS);
-        }
-    }
-
-    for (n = 1; n < (ngx_uint_t) rc; n++) {
-        e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n];
-    }
-
-    if (code->args && r->args.len) {
-        e->buf.len += r->args.len + 1;
-    }
-
-    e->buf.data = ngx_palloc(r->pool, e->buf.len);
-    if (e->buf.data == NULL) {
-        e->ip = ngx_http_rewrite_exit;
-        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-        return;
-    }
-
-    e->quote = code->redirect;
-
-    e->pos = e->buf.data;
-
-    e->ip += sizeof(ngx_http_rewrite_regex_code_t);
-}
-
-
-static void
-ngx_http_rewrite_regex_end_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_request_t                 *r;
-    ngx_http_rewrite_regex_end_code_t  *code;
-
-    code = (ngx_http_rewrite_regex_end_code_t *) e->ip;
-
-    r = e->request;
-
-    e->quote = 0;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http rewrite regex end");
-
-    if (e->args) {
-        e->buf.len = e->args - e->buf.data;
-
-        if (code->args && r->args.len) {
-            *e->pos++ = '&';
-            e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len);
-        }
-
-        r->args.len = e->pos - e->args;
-        r->args.data = e->args;
-
-        e->args = NULL;
-
-    } else {
-        if (code->args && r->args.len) {
-            *e->pos++ = '?';
-            e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len);
-        }
-
-        e->buf.len = e->pos - e->buf.data;
-    }
-
-    if (!code->redirect) {
-        if (e->conf->log) {
-            ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                          "rewritten data: \"%V\", args: \"%V\"",
-                          &e->buf, &r->args);
-        }
-
-        if (code->uri) {
-            r->uri = e->buf;
-
-            if (ngx_http_set_exten(r) != NGX_OK) {
-                e->ip = ngx_http_rewrite_exit;
-                e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-                return;
-            }
-        }
-
-        e->ip += sizeof(ngx_http_rewrite_regex_end_code_t);
-        return;
-    }
-
-    ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                  "rewritten redirect: \"%V\"", &e->buf);
-
-    r->headers_out.location = ngx_list_push(&r->headers_out.headers);
-    if (r->headers_out.location == NULL) {
-        e->ip = ngx_http_rewrite_exit;
-        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-        return;
-    }
-
-    if (e->buf.data[0] != '/') {
-        r->headers_out.location->key.len = sizeof("Location") - 1;
-        r->headers_out.location->key.data = (u_char *) "Location";
-    }
-
-    r->headers_out.location->value = e->buf;
-
-    e->ip += sizeof(ngx_http_rewrite_regex_end_code_t);
-}
-
-
-static void
-ngx_http_rewrite_copy_capture_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_rewrite_copy_capture_code_t  *code;
-
-    code = (ngx_http_rewrite_copy_capture_code_t *) e->ip;
-
-    e->ip += sizeof(ngx_http_rewrite_copy_capture_code_t);
-
-    if ((e->args || e->quote)
-        && (e->request->quoted_uri || e->request->plus_in_uri))
-    {
-        e->pos = (u_char *) ngx_escape_uri(e->pos,
-                                &e->line->data[e->captures[code->n]],
-                                e->captures[code->n + 1] - e->captures[code->n],
-                                NGX_ESCAPE_ARGS);
-    } else {
-        e->pos = ngx_cpymem(e->pos, &e->line->data[e->captures[code->n]],
-                        e->captures[code->n + 1] - e->captures[code->n]);
-    }
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite capture: \"%V\"", &e->buf);
-}
-
-
-static void
-ngx_http_rewrite_copy_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_rewrite_copy_code_t  *code;
-
-    code = (ngx_http_rewrite_copy_code_t *) e->ip;
-
-    e->pos = ngx_cpymem(e->pos, e->ip + sizeof(ngx_http_rewrite_copy_code_t),
-                        code->len);
-
-    e->ip += sizeof(ngx_http_rewrite_copy_code_t)
-          + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite copy: \"%V\"", &e->buf);
-}
-
-
-static void
-ngx_http_rewrite_start_args_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite args");
-
-    e->args = e->pos;
-    e->ip += sizeof(uintptr_t);
-}
-
-
-static void
-ngx_http_rewrite_return_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_rewrite_return_code_t  *code;
-
-    code = (ngx_http_rewrite_return_code_t *) e->ip;
-
-    e->status = code->status;
-
-    e->ip += sizeof(ngx_http_rewrite_return_code_t) - sizeof(uintptr_t);
-}
-
-
-static void
-ngx_http_rewrite_if_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_rewrite_if_code_t  *code;
-
-    code = (ngx_http_rewrite_if_code_t *) e->ip;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite if");
-
-    e->sp--;
-
-    if (e->sp->value) {
-        if (code->loc_conf) {
-            e->request->loc_conf = code->loc_conf;
-        }
-
-        e->ip += sizeof(ngx_http_rewrite_if_code_t);
-        return;
-    }
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite if false");
-
-    e->ip += code->next;
-}
-
-
-static void
-ngx_http_rewrite_value_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_rewrite_value_code_t  *code;
-
-    code = (ngx_http_rewrite_value_code_t *) e->ip;
-
-    e->ip += sizeof(ngx_http_rewrite_value_code_t);
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite value");
-
-    e->sp->value = (ngx_uint_t) code->value;
-    e->sp->text.len = (size_t) code->text_len;
-    e->sp->text.data = (u_char *) code->text_data;
-    e->sp++;
-}
-
-
-static void
-ngx_http_rewrite_set_var_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_request_t           *r;
-    ngx_http_variable_value_t    *value;
-    ngx_http_core_main_conf_t    *cmcf;
-    ngx_http_rewrite_var_code_t  *code;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite set var");
-
-    code = (ngx_http_rewrite_var_code_t *) e->ip;
-
-    e->ip += sizeof(ngx_http_rewrite_var_code_t);
-
-    r = e->request;
-
-    if (r->variables == NULL) {
-        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-
-        r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts
-                                        * sizeof(ngx_http_variable_value_t *));
-        if (r->variables == NULL) {
-            e->ip = ngx_http_rewrite_exit;
-            e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-            return;
-        }
-    }
-
-    value = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
-    if (value == NULL) {
-        e->ip = ngx_http_rewrite_exit;
-        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-        return;
-    }
-
-    e->sp--;
-
-    *value = *e->sp;
-
-    r->variables[code->index] = value;
-}
-
-
-static void
-ngx_http_rewrite_var_code(ngx_http_rewrite_engine_t *e)
-{
-    ngx_http_variable_value_t    *value;
-    ngx_http_rewrite_var_code_t  *code;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite var");
-
-    code = (ngx_http_rewrite_var_code_t *) e->ip;
-
-    e->ip += sizeof(ngx_http_rewrite_var_code_t);
-
-    value = ngx_http_get_indexed_variable(e->request, code->index);
-
-    if (value == NULL || value == NGX_HTTP_VARIABLE_NOT_FOUND) {
-        e->sp->value = 0;
-        e->sp->text.len = 0;
-        e->sp->text.data = (u_char *) "";
-        e->sp++;
-
-        return;
-    }
-
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http rewrite var: %ui, \"%V\"", value->value, &value->text);
-
-    *e->sp = *value;
-    e->sp++;
-}
-
-
-static void
-ngx_http_rewrite_invalid_referer_code(ngx_http_rewrite_engine_t *e)
+ngx_http_rewrite_invalid_referer_code(ngx_http_script_engine_t *e)
 {
     u_char                       *ref;
     size_t                        len;
@@ -804,13 +307,6 @@
 }
 
 
-static void
-ngx_http_rewrite_nop_code(ngx_http_rewrite_engine_t *e)
-{
-    e->ip += sizeof(uintptr_t);
-}
-
-
 static ngx_http_variable_value_t *
 ngx_http_rewrite_var(ngx_http_request_t *r, uintptr_t data)
 {
@@ -834,25 +330,6 @@
 }
 
 
-static ngx_int_t
-ngx_http_rewrite_init(ngx_cycle_t *cycle)
-{   
-    ngx_http_handler_pt        *h;
-    ngx_http_core_main_conf_t  *cmcf;
-    
-    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
-
-    h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
-    if (h == NULL) {
-        return NGX_ERROR;
-    }
-    
-    *h = ngx_http_rewrite_handler;
-    
-    return NGX_OK;
-}   
-
-
 static void *
 ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
 {
@@ -878,8 +355,7 @@
     ngx_http_rewrite_loc_conf_t *prev = parent;
     ngx_http_rewrite_loc_conf_t *conf = child;
 
-    uintptr_t                      *code, *last;
-    ngx_http_rewrite_regex_code_t  *regex;
+    uintptr_t  *code;
 
     ngx_conf_merge_value(conf->log, prev->log, 0);
     ngx_conf_merge_unsigned_value(conf->stack_size, prev->stack_size, 10);
@@ -906,65 +382,6 @@
         return NGX_CONF_OK;
     }
 
-    code = conf->codes->elts;
-    last = (uintptr_t *) ((u_char *) code + conf->codes->nelts);
-
-    while (code < last) {
-        if (*code == (uintptr_t) NULL) {
-            return NGX_CONF_OK;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_regex_start_code) {
-            regex = (ngx_http_rewrite_regex_code_t *) code;
-            if (conf->max_captures < regex->ncaptures) {
-                conf->max_captures = regex->ncaptures;
-            }
-            code = (uintptr_t *) ((u_char *) code + regex->next);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_if_code) {
-            code += sizeof(ngx_http_rewrite_if_code_t) / sizeof(uintptr_t);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_return_code) {
-            code += sizeof(ngx_http_rewrite_return_code_t) / sizeof(uintptr_t);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_set_var_code) {
-            code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_var_code) {
-            code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_value_code) {
-            code += sizeof(ngx_http_rewrite_value_code_t) / sizeof(uintptr_t);
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_invalid_referer_code) {
-            code++;
-            continue;
-        }
-
-        if (*code == (uintptr_t) &ngx_http_rewrite_nop_code) {
-            code++;
-            continue;
-        }
-
-#if (NGX_DEBUG)
-        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                      "unknown rewrite code: %p", *code);
-        return NGX_CONF_ERROR;
-#endif
-    }
-
     code = ngx_array_push_n(conf->codes, sizeof(uintptr_t));
     if (code == NULL) {
         return NGX_CONF_ERROR;
@@ -976,29 +393,47 @@
 }
 
 
+static ngx_int_t
+ngx_http_rewrite_init(ngx_cycle_t *cycle)
+{   
+    ngx_http_handler_pt        *h;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
+
+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_rewrite_handler;
+
+    return NGX_OK;
+}   
+
+
 static char *
 ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_rewrite_loc_conf_t *lcf = conf;
     
-    u_char                                *data;
-    size_t                                 len, size;
-    ngx_str_t                             *value, err;
-    ngx_int_t                              n;
-    ngx_uint_t                             i, last;
-    ngx_http_rewrite_code_pt              *code;
-    ngx_http_rewrite_copy_code_t          *copy;
-    ngx_http_rewrite_regex_code_t         *regex;
-    ngx_http_rewrite_regex_end_code_t     *regex_end;
-    ngx_http_rewrite_copy_capture_code_t  *copy_capture;
-    u_char                                 errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_str_t                         *value, err;
+    ngx_int_t                          n;
+    ngx_uint_t                         last;
+    ngx_http_script_code_pt           *code;
+    ngx_http_script_compile_t          sc;
+    ngx_http_script_regex_code_t      *regex;
+    ngx_http_script_regex_end_code_t  *regex_end;
+    u_char                             errstr[NGX_MAX_CONF_ERRSTR];
 
-    regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                        sizeof(ngx_http_rewrite_regex_code_t));
+    regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                       sizeof(ngx_http_script_regex_code_t));
     if (regex == NULL) {
         return NGX_CONF_ERROR;
     }
 
+    ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
+
     value = cf->args->elts;
 
     err.len = NGX_MAX_CONF_ERRSTR;
@@ -1013,17 +448,19 @@
         return NGX_CONF_ERROR;
     }
 
-    regex->code = ngx_http_rewrite_regex_start_code;
-    regex->size = 0;
-    regex->ncaptures = 0;
-    regex->status = 0;
-    regex->test = 0;
+    regex->code = ngx_http_script_regex_start_code;
     regex->uri = 1;
-    regex->args = 1;
-    regex->redirect = 0;
-    regex->break_cycle = 0;
     regex->name = value[1];
 
+    if (value[2].data[value[2].len - 1] == '?') {
+
+        /* the last "?" drops the original arguments */
+        value[2].len--;
+
+    } else {
+        regex->add_args = 1;
+    }
+
     last = 0;
 
     if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0) {
@@ -1057,113 +494,29 @@
         }
     }
 
-    i = 0;
+    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
 
-    while (i < value[2].len) {
+    sc.cf = cf;
+    sc.source = &value[2];
+    sc.lengths = &regex->lengths;
+    sc.values = &lcf->codes;
+    sc.variables = ngx_http_script_variables_count(&value[2]);
+    sc.main = regex;
+    sc.complete_lengths = 1;
+    sc.compile_args = !regex->redirect;
 
-        data = &value[2].data[i];
+    if (ngx_http_script_compile(&sc) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
 
-        if (value[2].data[i] == '$' && i < value[2].len
-            && value[2].data[i + 1] >= '1' && value[2].data[i + 1] <= '9')
-        {
+    regex = sc.main;
 
-            /* the "$1" - "$9" captures */
+    regex->ncaptures = sc.ncaptures;
+    regex->size = sc.size;
+    regex->args = sc.args;
 
-            copy_capture = ngx_http_rewrite_add_code(lcf->codes,
-                                  sizeof(ngx_http_rewrite_copy_capture_code_t),
-                                  &regex);
-            if (copy_capture == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            i++;
-
-            copy_capture->code = ngx_http_rewrite_copy_capture_code;
-            copy_capture->n = value[2].data[i] - '0';
-
-            if (regex->ncaptures < copy_capture->n) {
-                regex->ncaptures = copy_capture->n;
-            }
-
-            copy_capture->n *= 2;
-
-            i++;
-
-            continue;
-        }
-
-        if (value[2].data[i] == '?') {
-
-            /* the arguments */
-
-            if (i == value[2].len - 1) {
-                /* the last "?" drops the original arguments */
-                regex->args = 0;
-                break;
-            }
-
-            if (!regex->redirect) {
-                code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t),
-                                                 &regex);
-                if (code == NULL) {
-                    return NGX_CONF_ERROR;
-                }
-
-                *code = ngx_http_rewrite_start_args_code;
-
-                i++;
-
-                continue;
-            }
-        }
-
-        i++;
-
-        /* the substituion strings */
-
-        while (i < value[2].len && value[2].data[i] != '$') {
-
-            if (value[2].data[i] == '?') {
-
-                if (i == value[2].len - 1) {
-                    /*
-                     * the last "?" drops the original arguments,
-                     * and it should not be copied to a substituion
-                     */
-                    regex->args = 0;
-                    break;
-                }
-
-                if (!regex->redirect) {
-                    break;
-                }
-            }
-
-            i++;
-        }
-
-        len = &value[2].data[i] - data;
-
-        if (len == 0) {
-            continue;
-        }
-
-        regex->size += len;
-
-        size = (len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
-
-        copy = ngx_http_rewrite_add_code(lcf->codes,
-                                   sizeof(ngx_http_rewrite_copy_code_t) + size,
-                                   &regex);
-        if (copy == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        copy->code = ngx_http_rewrite_copy_code;
-        copy->len = len;
-
-        ngx_memcpy((u_char *) copy + sizeof(ngx_http_rewrite_copy_code_t),
-                   data, len);
+    if (sc.variables == 0) {
+        regex->lengths = NULL;
     }
 
     n = ngx_regex_capture_count(regex->regex);
@@ -1191,21 +544,26 @@
         regex->ncaptures = (regex->ncaptures + 1) * 3;
     }
 
-    regex_end = ngx_http_rewrite_add_code(lcf->codes,
-                                     sizeof(ngx_http_rewrite_regex_end_code_t),
-                                     &regex);
+    if (lcf->max_captures < regex->ncaptures) {
+        lcf->max_captures = regex->ncaptures;
+    }
+
+    regex_end = ngx_http_script_add_code(lcf->codes,
+                                      sizeof(ngx_http_script_regex_end_code_t),
+                                      &regex);
     if (regex_end == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    regex_end->code = ngx_http_rewrite_regex_end_code;
+    regex_end->code = ngx_http_script_regex_end_code;
     regex_end->uri = regex->uri;
     regex_end->args = regex->args;
+    regex_end->add_args = regex->add_args;
     regex_end->redirect = regex->redirect;
 
     if (last) {
-        code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t),
-                                         &regex);
+        code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t),
+                                        &regex);
         if (code == NULL) {
             return NGX_CONF_ERROR;
         }
@@ -1225,18 +583,18 @@
 {
     ngx_http_rewrite_loc_conf_t *lcf = conf;
 
-    ngx_str_t                       *value;
-    ngx_http_rewrite_return_code_t  *ret;
+    ngx_str_t                      *value;
+    ngx_http_script_return_code_t  *ret;
 
-    ret = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                      sizeof(ngx_http_rewrite_return_code_t));
+    ret = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                     sizeof(ngx_http_script_return_code_t));
     if (ret == NULL) {
         return NGX_CONF_ERROR;
     }
 
     value = cf->args->elts;
 
-    ret->code = ngx_http_rewrite_return_code;
+    ret->code = ngx_http_script_return_code;
     ret->null = (uintptr_t) NULL;
 
     ret->status = ngx_atoi(value[1].data, value[1].len);
@@ -1262,7 +620,7 @@
     ngx_http_module_t            *module;
     ngx_http_conf_ctx_t          *ctx, *pctx;
     ngx_http_core_loc_conf_t     *clcf, *pclcf, **clcfp;
-    ngx_http_rewrite_if_code_t   *if_code;
+    ngx_http_script_if_code_t    *if_code;
     ngx_http_rewrite_loc_conf_t  *nlcf;
 
     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
@@ -1324,12 +682,12 @@
         return NGX_CONF_ERROR;
     }
 
-    if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_rewrite_if_code_t));
+    if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t));
     if (if_code == NULL) {
         return NULL;
     }
 
-    if_code->code = ngx_http_rewrite_if_code;
+    if_code->code = ngx_http_script_if_code;
 
     elts = lcf->codes->elts;
 
@@ -1362,7 +720,7 @@
 
 
     if (elts != lcf->codes->elts) {
-        if_code = (ngx_http_rewrite_if_code_t *)
+        if_code = (ngx_http_script_if_code_t *)
                    ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts));
     }
 
@@ -1376,10 +734,10 @@
 static char *
 ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf)
 {
-    ngx_str_t                      *value, err;
-    ngx_uint_t                      cur, last;
-    ngx_http_rewrite_regex_code_t  *regex;
-    u_char                          errstr[NGX_MAX_CONF_ERRSTR];
+    ngx_str_t                     *value, err;
+    ngx_uint_t                     cur, last;
+    ngx_http_script_regex_code_t  *regex;
+    u_char                         errstr[NGX_MAX_CONF_ERRSTR];
 
     value = cf->args->elts;
     last = cf->args->nelts - 1;
@@ -1440,12 +798,14 @@
             return NGX_CONF_ERROR;
         }
 
-        regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                        sizeof(ngx_http_rewrite_regex_code_t));
+        regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                         sizeof(ngx_http_script_regex_code_t));
         if (regex == NULL) {
             return NGX_CONF_ERROR;
         }
 
+        ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
+
         err.len = NGX_MAX_CONF_ERRSTR;
         err.data = errstr;
 
@@ -1458,16 +818,9 @@
             return NGX_CONF_ERROR;
         }
 
-        regex->code = ngx_http_rewrite_regex_start_code;
-        regex->size = 0;
-        regex->ncaptures = 0;
-        regex->status = 0;
-        regex->next = sizeof(ngx_http_rewrite_regex_code_t);
+        regex->code = ngx_http_script_regex_start_code;
+        regex->next = sizeof(ngx_http_script_regex_code_t);
         regex->test = 1;
-        regex->uri = 0;
-        regex->args = 0;
-        regex->redirect = 0;
-        regex->break_cycle = 0;
         regex->name = value[last];
 
         return NGX_CONF_OK;
@@ -1484,9 +837,9 @@
 ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
     ngx_str_t *value)
 {
-    ngx_http_variable_t          *var;
-    ngx_http_rewrite_code_pt     *code;
-    ngx_http_rewrite_var_code_t  *var_code;
+    ngx_int_t                    index;
+    ngx_http_script_code_pt     *code;
+    ngx_http_script_var_code_t  *var_code;
 
     value->len--;
     value->data++;
@@ -1495,8 +848,8 @@
         && ngx_strncmp(value->data, "invalid_referer",
                        sizeof("invalid_referer") - 1) == 0)
     {
-        code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                           sizeof(ngx_http_rewrite_code_pt));
+        code = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                          sizeof(ngx_http_script_code_pt));
         if (code == NULL) {
             return NGX_CONF_ERROR;
         }
@@ -1504,20 +857,20 @@
         *code = ngx_http_rewrite_invalid_referer_code;
 
     } else {
-        var = ngx_http_add_variable(cf, value, 0);
+        index = ngx_http_get_variable_index(cf, value);
 
-        if (var == NULL) {
+        if (index == NGX_ERROR) {
             return NGX_CONF_ERROR;
         }
 
-        var_code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                           sizeof(ngx_http_rewrite_var_code_t));
+        var_code = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                           sizeof(ngx_http_script_var_code_t));
         if (var_code == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        var_code->code = ngx_http_rewrite_var_code;
-        var_code->index = var->index;
+        var_code->code = ngx_http_script_var_code;
+        var_code->index = index;
     }
 
     return NGX_CONF_OK;
@@ -1624,11 +977,11 @@
 {
     ngx_http_rewrite_loc_conf_t *lcf = conf;
 
-    ngx_int_t                       n;
-    ngx_str_t                      *value;
-    ngx_http_variable_t            *v;
-    ngx_http_rewrite_var_code_t    *var;
-    ngx_http_rewrite_value_code_t  *val;
+    ngx_int_t                      n, index;
+    ngx_str_t                     *value;
+    ngx_http_variable_t           *v;
+    ngx_http_script_var_code_t    *var;
+    ngx_http_script_value_code_t  *val;
 
     value = cf->args->elts;
 
@@ -1641,16 +994,21 @@
     value[1].len--;
     value[1].data++;
 
-    v = ngx_http_add_variable(cf, &value[1], 1);
+    v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGABLE);
     if (v == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    v->handler = ngx_http_rewrite_var;
-    v->data = v->index;
+    index = ngx_http_get_variable_index(cf, &value[1]);
+    if (index == NGX_ERROR) {
+        return NGX_CONF_ERROR;
+    }
 
-    val = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                      sizeof(ngx_http_rewrite_value_code_t));
+    v->handler = ngx_http_rewrite_var;
+    v->data = index;
+
+    val = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                     sizeof(ngx_http_script_value_code_t));
     if (val == NULL) {
         return NGX_CONF_ERROR;
     }
@@ -1661,55 +1019,19 @@
         n = 0;
     }
 
-    val->code = ngx_http_rewrite_value_code;
+    val->code = ngx_http_script_value_code;
     val->value = (uintptr_t) n;
     val->text_len = (uintptr_t) value[2].len;
     val->text_data = (uintptr_t) value[2].data;
 
-    var = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
-                                      sizeof(ngx_http_rewrite_var_code_t));
+    var = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                     sizeof(ngx_http_script_var_code_t));
     if (var == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    var->code = ngx_http_rewrite_set_var_code;
-    var->index = (uintptr_t) v->index;
+    var->code = ngx_http_script_set_var_code;
+    var->index = (uintptr_t) index;
 
     return NGX_CONF_OK;
 }
-
-
-static void *
-ngx_http_rewrite_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size)
-{
-    if (*codes == NULL) {
-        *codes = ngx_array_create(pool, 256, 1);
-        if (*codes == NULL) {
-            return NULL;
-        }
-    }
-
-    return ngx_array_push_n(*codes, size);
-}
-
-
-static void *
-ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size, void *code)
-{
-    u_char  *elts, **p;
-    void    *new;
-
-    elts = codes->elts;
-
-    new = ngx_array_push_n(codes, size);
-    if (new == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    if (elts != codes->elts) {
-        p = code;
-        *p += (u_char *) codes->elts - elts;
-    }
-
-    return new;
-}
diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c
index a351747..acaeeed 100644
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -16,10 +16,13 @@
 
 #define NGX_HTTP_SSI_ERROR        1
 
+#define NGX_HTTP_SSI_DATE_LEN     2048
+
 
 typedef struct {
     ngx_flag_t        enable;
     ngx_flag_t        silent_errors;
+    ngx_flag_t        ignore_recycled_buffers;
 
     size_t            min_file_chunk;
     size_t            value_len;
@@ -50,6 +53,10 @@
     size_t             looked;
 
     size_t             value_len;
+
+    ngx_uint_t         output;        /* unsigned  output:1; */
+
+    ngx_str_t          timefmt;
 } ngx_http_ssi_ctx_t;
 
 
@@ -70,7 +77,8 @@
     ngx_http_ssi_command_pt   handler;
     ngx_http_ssi_param_t     *params;
 
-    ngx_uint_t                flush;    /* unsigned  flush:1; */
+    unsigned                  conditional:1;
+    unsigned                  flush:1;
 } ngx_http_ssi_command_t;
 
 
@@ -98,12 +106,28 @@
 } ngx_http_ssi_state_e;
 
 
+static ngx_int_t ngx_http_ssi_output(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx);
 static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx);
 
 static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r,
     ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
+static ngx_int_t ngx_http_ssi_config(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
+static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
+static ngx_int_t ngx_http_ssi_if(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
+static ngx_int_t ngx_http_ssi_else(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
+static ngx_int_t ngx_http_ssi_endif(ngx_http_request_t *r,
+    ngx_http_ssi_ctx_t *ctx, ngx_str_t **params);
 
+static ngx_http_variable_value_t *
+    ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt);
+
+static ngx_int_t ngx_http_ssi_add_variables(ngx_conf_t *cf);
 static void *ngx_http_ssi_create_conf(ngx_conf_t *cf);
 static char *ngx_http_ssi_merge_conf(ngx_conf_t *cf,
     void *parent, void *child);
@@ -126,6 +150,13 @@
       offsetof(ngx_http_ssi_conf_t, silent_errors),
       NULL },
 
+    { ngx_string("ssi_ignore_recycled_buffers"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_ssi_conf_t, ignore_recycled_buffers),
+      NULL },
+
     { ngx_string("ssi_min_file_chunk"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_size_slot,
@@ -139,7 +170,8 @@
 
     
 static ngx_http_module_t  ngx_http_ssi_filter_module_ctx = {
-    NULL,                                  /* pre conf */
+    ngx_http_ssi_add_variables,            /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -153,7 +185,7 @@
 
 
 ngx_module_t  ngx_http_ssi_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_ssi_filter_module_ctx,       /* module context */
     ngx_http_ssi_filter_commands,          /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -174,8 +206,16 @@
 static ngx_str_t ngx_http_ssi_none = ngx_string("(none)");
 
 
-#define  NGX_HTTP_SSI_ECHO_VAR      0
-#define  NGX_HTTP_SSI_ECHO_DEFAULT  1
+#define  NGX_HTTP_SSI_ECHO_VAR         0
+#define  NGX_HTTP_SSI_ECHO_DEFAULT     1
+
+#define  NGX_HTTP_SSI_CONFIG_TIMEFMT   0
+
+#define  NGX_HTTP_SSI_INCLUDE_VIRTUAL  0
+#define  NGX_HTTP_SSI_INCLUDE_FILE     1
+
+#define  NGX_HTTP_SSI_IF_EXPR          0
+
 
 static ngx_http_ssi_param_t  ngx_http_ssi_echo_params[] = {
     { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1 },
@@ -183,13 +223,60 @@
     { ngx_null_string, 0, 0 }
 };
 
+static ngx_http_ssi_param_t  ngx_http_ssi_include_params[] = {
+    { ngx_string("virtual"), NGX_HTTP_SSI_INCLUDE_VIRTUAL, 0 },
+#if 0
+    { ngx_string("file"), NGX_HTTP_SSI_INCLUDE_FILE, 0 },
+#endif
+    { ngx_null_string, 0, 0 }
+};
+
+
+static ngx_http_ssi_param_t  ngx_http_ssi_config_params[] = {
+    { ngx_string("timefmt"), NGX_HTTP_SSI_CONFIG_TIMEFMT, 0 },
+    { ngx_null_string, 0, 0 }
+};
+
+
+static ngx_http_ssi_param_t  ngx_http_ssi_if_params[] = {
+    { ngx_string("expr"), NGX_HTTP_SSI_IF_EXPR, 0 },
+    { ngx_null_string, 0, 0 }
+};
+
+
+static ngx_http_ssi_param_t  ngx_http_ssi_no_params[] = {
+    { ngx_null_string, 0, 0 }
+};
+
 
 static ngx_http_ssi_command_t  ngx_http_ssi_commands[] = {
-    { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0 },
-    { ngx_null_string, NULL, NULL, 0 }
+    { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0, 0 },
+    { ngx_string("config"), ngx_http_ssi_config,
+                       ngx_http_ssi_config_params, 0, 0 },
+    { ngx_string("include"), ngx_http_ssi_include,
+                       ngx_http_ssi_include_params, 0, 1 },
+
+    { ngx_string("if"), ngx_http_ssi_if, ngx_http_ssi_if_params, 0, 0 },
+    { ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params, 1, 0 },
+    { ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params, 1, 0 },
+
+    { ngx_null_string, NULL, NULL, 0, 0 }
 };
 
 
+static ngx_http_variable_t  ngx_http_ssi_vars[] = {
+
+    { ngx_string("date_local"), ngx_http_ssi_date_gmt_local_variable, 0,
+      NGX_HTTP_VAR_NOCACHABLE },
+
+    { ngx_string("date_gmt"), ngx_http_ssi_date_gmt_local_variable, 1,
+      NGX_HTTP_VAR_NOCACHABLE },
+
+    { ngx_null_string, NULL, 0, 0 }
+};
+
+
+
 static ngx_int_t
 ngx_http_ssi_header_filter(ngx_http_request_t *r)
 {
@@ -204,9 +291,9 @@
 
     /* TODO: "text/html" -> custom types */
 
-    if (r->headers_out.content_type
-        && ngx_strncasecmp(r->headers_out.content_type->value.data,
-                                                          "text/html", 5) != 0)
+    if (r->headers_out.content_type.len == 0
+        || ngx_strncasecmp(r->headers_out.content_type.data, "text/html", 5)
+           != 0)
     {
         return ngx_http_next_header_filter(r);
     }
@@ -223,26 +310,33 @@
     ctx->value_len = conf->value_len;
     ctx->last_out = &ctx->out;
 
+    ctx->output = 1;
+
     ctx->params.elts = ctx->params_array;
     ctx->params.size = sizeof(ngx_table_elt_t);
     ctx->params.nalloc = NGX_HTTP_SSI_PARAMS_N;
     ctx->params.pool = r->pool;
 
-    r->headers_out.content_length_n = -1;
-    if (r->headers_out.content_length) {
-        r->headers_out.content_length->key.len = 0;
-        r->headers_out.content_length = NULL;
-    }
-
-    r->headers_out.last_modified_time = -1;
-    if (r->headers_out.last_modified) {
-        r->headers_out.last_modified->key.len = 0;
-        r->headers_out.last_modified = NULL;
-    }
+    ctx->timefmt.len = sizeof("%A, %d-%b-%Y %H:%M:%S %Z") - 1;
+    ctx->timefmt.data = (u_char *) "%A, %d-%b-%Y %H:%M:%S %Z";
 
     r->filter_need_in_memory = 1;
     r->filter_ssi_need_in_memory = 1;
 
+    if (r->main == NULL) {
+        r->headers_out.content_length_n = -1;
+        if (r->headers_out.content_length) {
+            r->headers_out.content_length->hash = 0;
+            r->headers_out.content_length = NULL;
+        }
+
+        r->headers_out.last_modified_time = -1;
+        if (r->headers_out.last_modified) {
+            r->headers_out.last_modified->hash = 0;
+            r->headers_out.last_modified = NULL;
+        }
+    }
+
     return ngx_http_next_header_filter(r);
 }
 
@@ -277,8 +371,8 @@
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module);
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http ssi filter");
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http ssi filter \"%V\"", &r->uri);
 
     while (ctx->in || ctx->buf) {
 
@@ -312,19 +406,50 @@
 
             if (ctx->copy_start != ctx->copy_end) {
 
-                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                               "saved: %d", ctx->saved);
+                if (ctx->output) {
 
-                if (ctx->saved) {
+                    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                                   "saved: %d", ctx->saved);
+
+                    if (ctx->saved) {
+
+                        if (ctx->free) {
+                            cl = ctx->free;
+                            ctx->free = ctx->free->next;
+                            b = cl->buf;
+                            ngx_memzero(b, sizeof(ngx_buf_t));
+
+                        } else {
+                            b = ngx_calloc_buf(r->pool);
+                            if (b == NULL) {
+                                return NGX_ERROR;
+                            }
+
+                            cl = ngx_alloc_chain_link(r->pool);
+                            if (cl == NULL) {
+                                return NGX_ERROR;
+                            }
+
+                            cl->buf = b;
+                        }
+
+                        b->memory = 1;
+                        b->pos = ngx_http_ssi_string;
+                        b->last = ngx_http_ssi_string + ctx->saved;
+
+                        *ctx->last_out = cl;
+                        ctx->last_out = &cl->next;
+
+                        ctx->saved = 0;
+                    }
 
                     if (ctx->free) {
                         cl = ctx->free;
                         ctx->free = ctx->free->next;
                         b = cl->buf;
-                        ngx_memzero(b, sizeof(ngx_buf_t));
 
                     } else {
-                        b = ngx_calloc_buf(r->pool);
+                        b = ngx_alloc_buf(r->pool);
                         if (b == NULL) {
                             return NGX_ERROR;
                         }
@@ -337,56 +462,31 @@
                         cl->buf = b;
                     }
 
-                    b->memory = 1;
-                    b->pos = ngx_http_ssi_string;
-                    b->last = ngx_http_ssi_string + ctx->saved;
+                    ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));
 
+                    b->last_buf = 0;
+                    b->recycled = 0;
+                    b->pos = ctx->copy_start;
+                    b->last = ctx->copy_end;
+
+                    if (b->in_file) {
+                        if (conf->min_file_chunk < (size_t) (b->last - b->pos))
+                        {
+                            b->file_last = b->file_pos + (b->last - b->start);
+                            b->file_pos += b->pos - b->start;
+
+                        } else {
+                            b->in_file = 0;
+                        }
+                    }
+
+                    cl->next = NULL;
                     *ctx->last_out = cl;
                     ctx->last_out = &cl->next;
 
+                } else {
                     ctx->saved = 0;
                 }
-
-                if (ctx->free) {
-                    cl = ctx->free;
-                    ctx->free = ctx->free->next;
-                    b = cl->buf;
-
-                } else {
-                    b = ngx_alloc_buf(r->pool);
-                    if (b == NULL) {
-                        return NGX_ERROR;
-                    }
-
-                    cl = ngx_alloc_chain_link(r->pool);
-                    if (cl == NULL) {
-                        return NGX_ERROR;
-                    }
-
-                    cl->buf = b;
-                }
-
-                ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));
-
-                b->last_buf = 0;
-                b->recycled = 0;
-                b->pos = ctx->copy_start;
-                b->last = ctx->copy_end;
-
-                if (b->in_file) {
-
-                    if (conf->min_file_chunk < (size_t) (b->last - b->pos)) {
-                        b->file_last = b->file_pos + (b->last - b->start);
-                        b->file_pos += b->pos - b->start;
-
-                    } else {
-                        b->in_file = 0;
-                    }
-                }
-
-                cl->next = NULL;
-                *ctx->last_out = cl;
-                ctx->last_out = &cl->next;
             }
 
             if (ctx->state == ssi_start_state) {
@@ -420,12 +520,16 @@
                     break;
                 }
 
-                if (cmd->name.len == 0) {
+                if (cmd->name.len == 0 && ctx->output) {
                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                   "invalid SSI command: \"%V\"", &ctx->command);
                     goto ssi_error;
                 }
 
+                if (!ctx->output && !cmd->conditional) {
+                    continue;
+                }
+
                 ngx_memzero(params,
                             NGX_HTTP_SSI_MAX_PARAMS * sizeof(ngx_str_t *));
 
@@ -479,6 +583,14 @@
                     }
                 }
 
+                if (cmd->flush && ctx->out) {
+                    rc = ngx_http_ssi_output(r, ctx);
+
+                    if (rc == NGX_ERROR) {
+                        return NGX_ERROR;
+                    }
+                }
+
                 if (cmd->handler(r, ctx, params) == NGX_OK) {
                     continue;
                 }
@@ -525,9 +637,9 @@
             continue;
         }
 
-        if (ctx->buf->recycled || ctx->buf->last_buf) {
-            if (b == NULL) {
+        if (ctx->buf->last_buf || ctx->buf->recycled) {
 
+            if (b == NULL) {
                 if (ctx->free) {
                     cl = ctx->free;
                     ctx->free = ctx->free->next;
@@ -548,14 +660,19 @@
                     cl->buf = b;
                 }
 
+                b->sync = 1;
+
                 cl->next = NULL;
                 *ctx->last_out = cl;
                 ctx->last_out = &cl->next;
             }
 
             b->last_buf = ctx->buf->last_buf;
-            b->flush = ctx->buf->recycled;
             b->shadow = ctx->buf;
+
+            if (conf->ignore_recycled_buffers == 0)  {
+                b->recycled = ctx->buf->recycled;
+            }
         }
 
         ctx->buf = NULL;
@@ -567,6 +684,17 @@
         return NGX_OK;
     }
 
+    return ngx_http_ssi_output(r, ctx);
+}
+
+
+static ngx_int_t
+ngx_http_ssi_output(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx)
+{
+    ngx_int_t     rc;
+    ngx_buf_t    *b;
+    ngx_chain_t  *cl;
+
     rc = ngx_http_next_body_filter(r, ctx->out);
 
     if (ctx->busy == NULL) {
@@ -1154,7 +1282,7 @@
     var = params[NGX_HTTP_SSI_ECHO_VAR];
 
     for (i = 0; i < var->len; i++) {
-        var->data[i] = ngx_toupper(var->data[i]);
+        var->data[i] = ngx_tolower(var->data[i]);
     }
 
     vv = ngx_http_get_variable(r, var);
@@ -1163,7 +1291,7 @@
         return NGX_HTTP_SSI_ERROR;
     }
 
-    if (vv == NGX_HTTP_VARIABLE_NOT_FOUND) {
+    if (vv == NGX_HTTP_VAR_NOT_FOUND) {
         value = params[NGX_HTTP_SSI_ECHO_DEFAULT];
 
         if (value == NULL) {
@@ -1204,6 +1332,325 @@
 }
 
 
+static ngx_int_t
+ngx_http_ssi_config(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
+    ngx_str_t **params)
+{
+    ngx_str_t  *value;
+
+    value = params[NGX_HTTP_SSI_CONFIG_TIMEFMT];
+
+    if (value) {
+        ctx->timefmt = *value;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
+    ngx_str_t **params)
+{
+    u_char                      ch, *p, **value;
+    size_t                     *size, len;
+    ngx_uint_t                  i, j, n, bracket;
+    ngx_str_t                   uri, args, name;
+    ngx_array_t                 lengths, values;
+    ngx_http_variable_value_t  *vv;
+
+    /* TODO: file, virtual vs file */
+
+    uri = *params[NGX_HTTP_SSI_INCLUDE_VIRTUAL];
+    args.len = 0;
+    args.data = NULL;
+
+    n = ngx_http_script_variables_count(&uri);
+
+    if (n > 0) {
+
+        if (ngx_array_init(&lengths, r->pool, 8, sizeof(size_t *)) != NGX_OK) {
+            return NGX_HTTP_SSI_ERROR;
+        }
+
+        if (ngx_array_init(&values, r->pool, 8, sizeof(u_char *)) != NGX_OK) {
+            return NGX_HTTP_SSI_ERROR;
+        }
+
+        len = 0;
+
+        for (i = 0; i < uri.len; /* void */ ) {
+
+            name.len = 0;
+
+            if (uri.data[i] == '$') {
+
+                if (++i == uri.len) {
+                    goto invalid_variable;
+                }
+
+                if (uri.data[i] == '{') {
+                    bracket = 1;
+
+                    if (++i == uri.len) {
+                        goto invalid_variable;
+                    }
+
+                    name.data = &uri.data[i];
+
+                } else {
+                    bracket = 0;
+                    name.data = &uri.data[i];
+                }
+
+                for ( /* void */ ; i < uri.len; i++, name.len++) {
+                    ch = uri.data[i];
+
+                    if (ch == '}' && bracket) {
+                        i++;
+                        bracket = 0;
+                        break;
+                    }
+
+                    if ((ch >= 'A' && ch <= 'Z')
+                        || (ch >= 'a' && ch <= 'z')
+                        || (ch >= '0' && ch <= '9')
+                        || ch == '_')
+                    {
+                        continue;
+                    }
+
+                    break;
+                }
+
+                if (bracket) {
+                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                                  "the closing bracket in \"%V\" "
+                                  "variable is missing", &name);
+                    return NGX_HTTP_SSI_ERROR;
+                }
+
+                if (name.len == 0) {
+                    goto invalid_variable;
+                }
+
+                for (j = 0; j < name.len; j++) {
+                    name.data[j] = ngx_tolower(name.data[j]);
+                }
+
+                vv = ngx_http_get_variable(r, &name);
+
+                if (vv == NULL) {
+                    return NGX_HTTP_SSI_ERROR;
+                }
+
+                if (vv == NGX_HTTP_VAR_NOT_FOUND) {
+                    continue;
+                }
+
+                name = vv->text;
+
+            } else {
+                name.data = &uri.data[i];
+
+                while (i < uri.len && uri.data[i] != '$') {
+                    i++;
+                    name.len++;
+                }
+            }
+
+            len += name.len;
+
+            size = ngx_array_push(&lengths);
+            if (size == NULL) {
+                return NGX_HTTP_SSI_ERROR;
+            }
+
+            *size = name.len;
+
+            value = ngx_array_push(&values);
+            if (value == NULL) {
+                return NGX_HTTP_SSI_ERROR;
+            }
+
+            *value = name.data;
+        }
+
+        p = ngx_palloc(r->pool, len);
+        if (p == NULL) {
+            return NGX_HTTP_SSI_ERROR;
+        }
+
+        uri.len = len;
+        uri.data = p;
+
+        size = lengths.elts;
+        value = values.elts;
+
+        for (i = 0; i < values.nelts; i++) {
+            p = ngx_cpymem(p, value[i], size[i]);
+        }
+    }
+
+    for (i = 0; i < uri.len; i++) {
+        if (uri.data[i] == '?') {
+            args.len = uri.len - i - 1;
+            args.data = &uri.data[i + 1];
+            uri.len -= args.len + 1;
+
+            break;
+        }
+    }
+
+    if (ngx_http_subrequest(r, &uri, &args) != NGX_OK) {
+        return NGX_HTTP_SSI_ERROR;
+    }
+
+    return NGX_OK;
+
+invalid_variable:
+
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                  "invalid variable name in \"%V\"", &uri);
+
+    return NGX_ERROR;
+}
+
+
+static ngx_int_t
+ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
+    ngx_str_t **params)
+{
+    ngx_str_t                  *expr, var;
+    ngx_uint_t                  i;
+    ngx_http_variable_value_t  *vv;
+
+    expr = params[NGX_HTTP_SSI_IF_EXPR];
+
+    if (expr->data[0] != '$') {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "invalid variable name in \"%V\"", expr);
+        return NGX_HTTP_SSI_ERROR;
+    }
+
+    var.len = expr->len - 1;
+    var.data = expr->data + 1;
+
+    for (i = 0; i < var.len; i++) {
+        var.data[i] = ngx_tolower(var.data[i]);
+    }
+
+    vv = ngx_http_get_variable(r, &var);
+
+    if (vv == NULL) {
+        return NGX_HTTP_SSI_ERROR;
+    }
+
+    if (vv != NGX_HTTP_VAR_NOT_FOUND && vv->text.len != 0) {
+        ctx->output = 1;
+
+    } else {
+        ctx->output = 0;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_ssi_else(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
+    ngx_str_t **params)
+{
+    ctx->output = !ctx->output;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_ssi_endif(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
+    ngx_str_t **params)
+{
+    ctx->output = 1;
+
+    return NGX_OK;
+}
+
+
+static ngx_http_variable_value_t *
+ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt)
+{
+    ngx_http_ssi_ctx_t         *ctx;
+    ngx_http_variable_value_t  *vv;
+    struct tm                   tm;
+    char                        buf[NGX_HTTP_SSI_DATE_LEN];
+
+    vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+    if (vv == NULL) {
+        return NULL;
+    }
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module);
+
+    if (ctx->timefmt.len == sizeof("%s") - 1
+        && ctx->timefmt.data[0] == '%' && ctx->timefmt.data[1] == 's')
+    {
+        vv->value = ngx_time() + (gmt ? 0 : ngx_gmtoff);
+
+        vv->text.data = ngx_palloc(r->pool, NGX_TIME_T_LEN);
+        if (vv->text.data == NULL) {
+            return NULL;
+        }
+
+        vv->text.len = ngx_sprintf(vv->text.data, "%T", vv->value)
+                       - vv->text.data;
+        return vv;
+    }
+
+    if (gmt) {
+        ngx_libc_gmtime(&tm);
+    } else {
+        ngx_libc_localtime(&tm);
+    }
+
+    vv->value = ngx_time() + (gmt ? 0 : ngx_gmtoff);
+
+    vv->text.len = strftime(buf, NGX_HTTP_SSI_DATE_LEN,
+                            (char *) ctx->timefmt.data, &tm);
+    if (vv->text.len == 0) {
+        return NULL;
+    }
+
+    vv->text.data = ngx_palloc(r->pool, vv->text.len);
+    if (vv->text.data == NULL) {
+        return NULL;
+    }
+
+    ngx_memcpy(vv->text.data, buf, vv->text.len);
+
+    return vv;
+}
+
+
+static ngx_int_t
+ngx_http_ssi_add_variables(ngx_conf_t *cf)
+{
+    ngx_http_variable_t  *var, *v;
+
+    for (v = ngx_http_ssi_vars; v->name.len; v++) {
+        var = ngx_http_add_variable(cf, &v->name, v->flags);
+        if (var == NULL) {
+            return NGX_ERROR;
+        }
+
+        var->handler = v->handler;
+        var->data = v->data;
+    }
+
+    return NGX_OK; 
+}
+
+
 static void *
 ngx_http_ssi_create_conf(ngx_conf_t *cf)
 {
@@ -1216,6 +1663,7 @@
 
     conf->enable = NGX_CONF_UNSET;
     conf->silent_errors = NGX_CONF_UNSET;
+    conf->ignore_recycled_buffers = NGX_CONF_UNSET;
 
     conf->min_file_chunk = NGX_CONF_UNSET_SIZE;
     conf->value_len = NGX_CONF_UNSET_SIZE;
@@ -1232,6 +1680,8 @@
 
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
     ngx_conf_merge_value(conf->silent_errors, prev->silent_errors, 0);
+    ngx_conf_merge_value(conf->ignore_recycled_buffers,
+                         prev->ignore_recycled_buffers, 0);
 
     ngx_conf_merge_size_value(conf->min_file_chunk, prev->min_file_chunk, 1024);
     ngx_conf_merge_size_value(conf->value_len, prev->value_len, 256);
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index c18c493..04d4c91 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -64,7 +64,8 @@
 
 
 static ngx_http_module_t  ngx_http_ssl_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     ngx_http_ssl_create_main_conf,         /* create main configuration */
     ngx_http_ssl_init_main_conf,           /* init main configuration */
@@ -78,7 +79,7 @@
 
 
 ngx_module_t  ngx_http_ssl_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_ssl_module_ctx,              /* module context */
     ngx_http_ssl_commands,                 /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -197,6 +198,13 @@
         return NGX_CONF_ERROR;
     }
 
+    if (ngx_pool_cleanup_add(cf->pool, ngx_ssl_cleanup_ctx, conf->ssl_ctx)
+        == NULL)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+
 #if 0
     SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL);
     SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_NO_SSLv3);
diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c
index c2c4582..a84a70e 100644
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -17,7 +17,7 @@
 static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r);
 static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf,
-                                            void *parent, void *child);
+    void *parent, void *child);
 static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle);
 
 
@@ -38,9 +38,9 @@
 };
 
 
-
 ngx_http_module_t  ngx_http_static_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -54,7 +54,7 @@
 
 
 ngx_module_t  ngx_http_static_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_static_module_ctx,           /* module context */
     ngx_http_static_commands,              /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -63,7 +63,8 @@
 };
 
 
-static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r)
+static ngx_int_t
+ngx_http_static_handler(ngx_http_request_t *r)
 {
     u_char                      *last;
     ngx_fd_t                     fd;
@@ -75,16 +76,8 @@
     ngx_buf_t                   *b;
     ngx_chain_t                  out;
     ngx_file_info_t              fi;
-    ngx_http_cleanup_t          *file_cleanup;
-#if (NGX_HTTP_CACHE)
-    ngx_http_cleanup_t          *redirect_cleanup;
-#endif
+    ngx_pool_cleanup_file_t     *cln;
     ngx_http_core_loc_conf_t    *clcf;
-#if (NGX_HTTP_CACHE)
-    ngx_http_static_loc_conf_t  *slcf;
-    uint32_t                     file_crc, redirect_crc;
-    ngx_http_cache_t            *file, *redirect;
-#endif
 
     if (r->uri.data[r->uri.len - 1] == '/') {
         return NGX_DECLINED;
@@ -105,19 +98,6 @@
         return rc;
     }
 
-#if (NGX_HTTP_CACHE)
-
-    /*
-     * there is a valid cached open file, i.e by the index handler,
-     * and it should be already registered in r->cleanup
-     */
-
-    if (r->cache && !r->cache->expired) {
-        return ngx_http_send_cached(r);
-    }
-
-#endif
-
     log = r->connection->log;
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -127,7 +107,19 @@
      * in a possible redirect and for the last '\0'
      */
 
-    if (clcf->alias) {
+    if (!clcf->alias) {
+        name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2);
+        if (name.data == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len);
+        last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);
+
+        name.len = last - name.data;
+        location.len = last - location.data + 1;
+
+    } else {
         name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2
                                         - clcf->name.len);
         if (name.data == NULL) {
@@ -147,119 +139,16 @@
 
         last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);
 
-#if 0
-        /*
-         * aliases usually have trailling "/",
-         * set it in the start of the possible redirect
-         */
-
-        if (*location.data != '/') {
-            location.data--;
-        }
-#endif
-
-        location.len = last - location.data + 1;
-
-    } else {
-        name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2);
-        if (name.data == NULL) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len);
-        last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);
-
-        name.len = last - name.data;
         location.len = last - location.data + 1;
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                    "http filename: \"%s\"", name.data);
 
-
-    /* allocate cleanups */
-
-    file_cleanup = ngx_array_push(&r->cleanup);
-    if (file_cleanup == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-    file_cleanup->valid = 0;
-
-#if (NGX_HTTP_CACHE)
-
-    slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module);
-    if (slcf->redirect_cache) {
-        redirect_cleanup = ngx_array_push(&r->cleanup);
-        if (redirect_cleanup == NULL) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-        redirect_cleanup->valid = 0;
-
-    } else {
-        redirect_cleanup = NULL;
-    }
-
-    /* look up an open files cache */
-
-    if (clcf->open_files) {
-        file = ngx_http_cache_get(clcf->open_files, file_cleanup,
-                                  &name, &file_crc);
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                       "http open file cache get: %p", file);
-
-        if (file && !file->expired) {
-            r->cache = file;
-            return ngx_http_send_cached(r);
-        }
-
-    } else {
-        file = NULL;
-    }
-
-
-    /* look up an redirect cache */
-
-    if (slcf->redirect_cache) {
-        redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup,
-                                      &name, &redirect_crc);
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                       "http redirect cache get: %p", redirect);
-
-        if (redirect && !redirect->expired) {
-
-            /*
-             * We do not copy a cached value so the cache entry is locked
-             * until the end of the request.  In a single threaded model
-             * the redirected request should complete before other event
-             * will be processed.  In a multithreaded model this locking
-             * should keep more popular redirects in cache.
-             */
-
-            r->headers_out.location = ngx_http_add_header(&r->headers_out,
-                                                          ngx_http_headers_out);
-            if (r->headers_out.location == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
-
-            r->headers_out.location->value = redirect->data.value;
-
-            return NGX_HTTP_MOVED_PERMANENTLY;
-        }
-
-    } else {
-        redirect = NULL;
-    }
-
-#endif
-
     /* open file */
 
 #if (NGX_WIN9X)
 
-    /* TODO: redirect cache */
-
     if (ngx_win32_version < NGX_WIN_NT) {
 
         /*
@@ -285,9 +174,6 @@
         }
 
         if (ngx_is_dir(&fi)) {
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                           "HTTP DIR: \"%s\"", name.data);
-
             r->headers_out.location = ngx_http_add_header(&r->headers_out,
                                                           ngx_http_headers_out);
             if (r->headers_out.location == NULL) {
@@ -356,60 +242,18 @@
         *last++ = '/';
         *last = '\0';
 
-        r->headers_out.location = ngx_list_push(&r->headers_out.headers);
+        r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
         if (r->headers_out.location == NULL) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
+        /*
+         * we do not need to set the r->headers_out.location->hash and
+         * r->headers_out.location->key fields
+         */
+
         r->headers_out.location->value = location;
 
-#if (NGX_HTTP_CACHE)
-
-        if (slcf->redirect_cache) {
-            if (redirect) {
-                if (location.len == redirect->data.value.len
-                    && ngx_memcmp(redirect->data.value.data, location.data,
-                                                            location.len) == 0)
-                {
-                    redirect->accessed = ngx_cached_time;
-                    redirect->updated = ngx_cached_time;
-
-                    /*
-                     * we can unlock the cache entry because
-                     * we have the local copy anyway
-                     */
-
-                    ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
-                    redirect_cleanup->valid = 0;
-
-                    return NGX_HTTP_MOVED_PERMANENTLY;
-                }
-            }
-
-            location.len++;
-            redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect,
-                                            redirect_cleanup,
-                                            &name, redirect_crc,
-                                            &location, log);
-            location.len--;
-
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                           "http redirect cache alloc: %p", redirect);
-
-            if (redirect) {
-                redirect->fd = NGX_INVALID_FILE;
-                redirect->accessed = ngx_cached_time;
-                redirect->last_modified = 0;
-                redirect->updated = ngx_cached_time;
-                redirect->memory = 1;
-                ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
-                redirect_cleanup->valid = 0;
-            }
-
-        }
-
-#endif
-
         return NGX_HTTP_MOVED_PERMANENTLY;
     }
 
@@ -429,68 +273,20 @@
 
 #endif
 
-
-#if (NGX_HTTP_CACHE)
-
-    if (clcf->open_files) {
-
-#if (NGX_USE_HTTP_FILE_CACHE_UNIQ)
-
-        if (file && file->uniq == ngx_file_uniq(&fi)) {
-            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                              ngx_close_file_n " \"%s\" failed", name.data);
-            }
-            file->accessed = ngx_cached_time;
-            file->updated = ngx_cached_time;
-            file->expired = 0;
-            r->cache = file;
-
-            return ngx_http_send_cached(r);
-
-        } else {
-            if (file) {
-                ngx_http_cache_unlock(clcf->open_files, file, log);
-                file = NULL;
-            }
-
-            file = ngx_http_cache_alloc(clcf->open_files, file,
-                                        file_cleanup,
-                                        &name, file_crc, NULL, log);
-            if (file) {
-                file->uniq = ngx_file_uniq(&fi);
-            }
-        }
-
-#else
-        file = ngx_http_cache_alloc(clcf->open_files, file,
-                                    file_cleanup,
-                                    &name, file_crc, NULL, log);
-#endif
-
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                       "http open file cache alloc: %p", file);
-
-        if (file) {
-            file->fd = fd;
-            file->data.size = ngx_file_size(&fi);
-            file->accessed = ngx_cached_time;
-            file->last_modified = ngx_file_mtime(&fi);
-            file->updated = ngx_cached_time;
-            r->cache = file;
-        }
-
-        return ngx_http_send_cached(r);
-    }
-
-#endif
-
     log->action = "sending response to client";
 
-    file_cleanup->data.file.fd = fd;
-    file_cleanup->data.file.name = name.data;
-    file_cleanup->valid = 1;
-    file_cleanup->cache = 0;
+    cln = ngx_palloc(r->pool, sizeof(ngx_pool_cleanup_file_t));
+    if (cln == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    cln->fd = fd;
+    cln->name = name.data;
+    cln->log = r->pool->log;
+
+    if (ngx_pool_cleanup_add(r->pool, ngx_pool_cleanup_file, cln) == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
     r->headers_out.status = NGX_HTTP_OK;
     r->headers_out.content_length_n = ngx_file_size(&fi);
@@ -532,10 +328,12 @@
 
     b->in_file = 1;
 
-    if (!r->main) {
+    if (r->main == NULL) {
         b->last_buf = 1;
     }
 
+    b->last_in_chain = 1;
+
     b->file_pos = 0;
     b->file_last = ngx_file_size(&fi);
 
@@ -550,7 +348,8 @@
 }
 
 
-static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf)
+static void *
+ngx_http_static_create_loc_conf(ngx_conf_t *cf)
 {
     ngx_http_static_loc_conf_t  *conf;
 
@@ -565,8 +364,8 @@
 }
 
 
-static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf,
-                                            void *parent, void *child)
+static char *
+ngx_http_static_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
 {
     ngx_http_static_loc_conf_t  *prev = parent;
     ngx_http_static_loc_conf_t  *conf = child;
@@ -579,7 +378,8 @@
 }
 
 
-static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle)
+static ngx_int_t
+ngx_http_static_init(ngx_cycle_t *cycle)
 {
     ngx_http_handler_pt        *h;
     ngx_http_core_main_conf_t  *cmcf;
diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c
index 1a01bce..0f1a252 100644
--- a/src/http/modules/ngx_http_stub_status_module.c
+++ b/src/http/modules/ngx_http_stub_status_module.c
@@ -22,7 +22,8 @@
 
     
 ngx_http_module_t  ngx_http_stub_status_module_ctx = {
-    NULL,                                  /* pre conf */
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -36,7 +37,7 @@
 
 
 ngx_module_t  ngx_http_stub_status_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_stub_status_module_ctx,      /* module context */
     ngx_http_status_commands,              /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -63,15 +64,8 @@
         return rc;
     }
 
-    r->headers_out.content_type = ngx_list_push(&r->headers_out.headers);
-    if (r->headers_out.content_type == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    r->headers_out.content_type->key.len = 0;
-    r->headers_out.content_type->key.data = NULL;
-    r->headers_out.content_type->value.len = sizeof("text/plain") - 1;
-    r->headers_out.content_type->value.data = (u_char *) "text/plain";
+    r->headers_out.content_type.len = sizeof("text/plain") - 1;
+    r->headers_out.content_type.data = (u_char *) "text/plain";
 
     if (r->method == NGX_HTTP_HEAD) {
         r->headers_out.status = NGX_HTTP_OK;
@@ -103,14 +97,14 @@
     rd = *ngx_stat_reading;
     wr = *ngx_stat_writing;
 
-    b->last = ngx_sprintf(b->last, "Active connections: %A \n", ac);
+    b->last = ngx_sprintf(b->last, "Active connections: %uA \n", ac);
 
     b->last = ngx_cpymem(b->last, "server accepts handled requests\n",
                          sizeof("server accepts handled requests\n") - 1);
 
-    b->last = ngx_sprintf(b->last, " %A %A %A \n", ap, hn, rq);
+    b->last = ngx_sprintf(b->last, " %uA %uA %uA \n", ap, hn, rq);
 
-    b->last = ngx_sprintf(b->last, "Reading: %A Writing: %A Waiting: %A \n",
+    b->last = ngx_sprintf(b->last, "Reading: %uA Writing: %uA Waiting: %uA \n",
                           rd, wr, ac - (rd + wr));
 
     r->headers_out.status = NGX_HTTP_OK;
diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c
index 4889fbf..af60d80 100644
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -19,7 +19,7 @@
 
 
 typedef struct {
-    ngx_flag_t  enable;
+    ngx_uint_t  enable;
 
     ngx_int_t   service;
 
@@ -83,7 +83,7 @@
 
 
 static ngx_conf_post_handler_pt  ngx_http_userid_domain_p =
-                                                        ngx_http_userid_domain;
+    ngx_http_userid_domain;
 
 static ngx_conf_post_handler_pt  ngx_http_userid_path_p = ngx_http_userid_path;
 static ngx_conf_post_handler_pt  ngx_http_userid_p3p_p = ngx_http_userid_p3p;
@@ -145,7 +145,8 @@
 
 
 ngx_http_module_t  ngx_http_userid_filter_module_ctx = {
-    ngx_http_userid_add_log_formats,       /* pre conf */
+    ngx_http_userid_add_log_formats,       /* preconfiguration */
+    NULL,                                  /* postconfiguration */
 
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
@@ -159,7 +160,7 @@
 
 
 ngx_module_t  ngx_http_userid_filter_module = {
-    NGX_MODULE,
+    NGX_MODULE_V1,
     &ngx_http_userid_filter_module_ctx,    /* module context */
     ngx_http_userid_commands,              /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
@@ -186,6 +187,10 @@
     ngx_http_userid_ctx_t   *ctx;
     ngx_http_userid_conf_t  *conf;
 
+    if (r->main) {
+        return ngx_http_next_header_filter(r);
+    }
+
     conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
 
     if (conf->enable == NGX_HTTP_USERID_OFF) {
@@ -225,82 +230,47 @@
 ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
     ngx_http_userid_conf_t *conf)
 {
-    u_char            *start, *last, *end;
-    ngx_uint_t         i;
+    ngx_int_t          n;
     ngx_str_t          src, dst;
     ngx_table_elt_t  **cookies;
 
-    cookies = r->headers_in.cookies.elts;
-
-    for (i = 0; i < r->headers_in.cookies.nelts; i++) {
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "cookie: \"%V\"", &cookies[i]->value);
-
-        if (conf->name.len >= cookies[i]->value.len) {
-            continue;
-        }
-
-        start = cookies[i]->value.data;
-        end = cookies[i]->value.data + cookies[i]->value.len;
-
-        while (start < end) {
-
-            if (ngx_strncmp(start, conf->name.data, conf->name.len) != 0) {
-
-                while (start < end && *start++ != ';') { /* void */ }
-                while (start < end && *start == ' ') { start++; }
-
-                continue;
-            }
-
-            start += conf->name.len;
-
-            while (start < end && *start == ' ') { start++; }
-
-            if (start == end || *start++ != '=') {
-                /* the invalid "Cookie" header */
-                break;
-            }
-
-            while (start < end && *start == ' ') { start++; }
-
-            last = start;
-
-            while (last < end && *last++ != ';') { /* void */ }
-
-            if (last - start < 22) {
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "client sent too short userid cookie \"%V\"",
-                              &cookies[i]->value);
-                break;
-            }
-
-            /*
-             * we have to limit encoded string to 22 characters
-             * because there are already the millions cookies with a garbage
-             * instead of the correct base64 trail "=="
-             */
-
-            src.len = 22;
-            src.data = start;
-            dst.data = (u_char *) ctx->uid_got;
-
-            if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "client sent invalid userid cookie \"%V\"",
-                              &cookies[i]->value);
-                break;
-            }
-
-            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "uid: %08XD%08XD%08XD%08XD",
-                           ctx->uid_got[0], ctx->uid_got[1],
-                           ctx->uid_got[2], ctx->uid_got[3]);
-
-            return NGX_OK;
-        }
+    n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name,
+                                          &src);
+    if (n == NGX_DECLINED) {
+        return NGX_OK;
     }
 
+    if (src.len < 22) {
+        cookies = r->headers_in.cookies.elts;
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "client sent too short userid cookie \"%V\"",
+                      &cookies[n]->value);
+        return NGX_OK;
+    }
+
+    /*
+     * we have to limit encoded string to 22 characters
+     * because there are already the millions cookies with a garbage
+     * instead of the correct base64 trail "=="
+     */
+
+    src.len = 22;
+
+    dst.data = (u_char *) ctx->uid_got;
+
+    if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
+        cookies = r->headers_in.cookies.elts;
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "client sent invalid userid cookie \"%V\"",
+                      &cookies[n]->value);
+        return NGX_OK;
+    }
+
+    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "uid: %08XD%08XD%08XD%08XD",
+                   ctx->uid_got[0], ctx->uid_got[1],
+                   ctx->uid_got[2], ctx->uid_got[3]);
+
     return NGX_OK;
 }
 
@@ -404,6 +374,7 @@
         return NGX_ERROR;
     }
 
+    set_cookie->hash = 1;
     set_cookie->key.len = sizeof("Set-Cookie") - 1;
     set_cookie->key.data = (u_char *) "Set-Cookie";
     set_cookie->value.len = p - cookie;
@@ -421,6 +392,7 @@
         return NGX_ERROR;
     }
 
+    p3p->hash = 1;
     p3p->key.len = sizeof("P3P") - 1;
     p3p->key.data = (u_char *) "P3P";
     p3p->value = conf->p3p;
@@ -570,7 +542,7 @@
      *     conf->p3p.date = NULL;
      */
 
-    conf->enable = NGX_CONF_UNSET;
+    conf->enable = NGX_CONF_UNSET_UINT;
     conf->service = NGX_CONF_UNSET;
     conf->expires = NGX_CONF_UNSET;
 
@@ -584,7 +556,8 @@
     ngx_http_userid_conf_t *prev = parent;
     ngx_http_userid_conf_t *conf = child;
 
-    ngx_conf_merge_value(conf->enable, prev->enable, NGX_HTTP_USERID_OFF);
+    ngx_conf_merge_unsigned_value(conf->enable, prev->enable,
+                                  NGX_HTTP_USERID_OFF);
 
     ngx_conf_merge_str_value(conf->name, prev->name, "uid");
     ngx_conf_merge_str_value(conf->domain, prev->domain, "");
diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c
index 12d4171..bc91df9 100644
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -311,7 +311,7 @@
 
 
 
-ngx_http_header_t ngx_http_proxy_headers_in[] = {
+ngx_http_header0_t ngx_http_proxy_headers_in[] = {
     { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) },
     { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) },
 
@@ -490,13 +490,25 @@
 #endif
 
 
-void ngx_http_proxy_check_broken_connection(ngx_event_t *ev)
+void ngx_http_proxy_rd_check_broken_connection(ngx_http_request_t *r)
+{
+    ngx_http_proxy_check_broken_connection(r, r->connection->read);
+}
+
+
+void ngx_http_proxy_wr_check_broken_connection(ngx_http_request_t *r)
+{
+    ngx_http_proxy_check_broken_connection(r, r->connection->read);
+}
+
+
+void ngx_http_proxy_check_broken_connection(ngx_http_request_t *r,
+    ngx_event_t *ev)
 {
     int                    n;
     char                   buf[1];
     ngx_err_t              err;
     ngx_connection_t      *c;
-    ngx_http_request_t    *r;
     ngx_http_proxy_ctx_t  *p;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
@@ -510,8 +522,7 @@
             return;
         }
 
-        c = ev->data;
-        r = c->data;
+        c = r->connection;
         p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
         ev->eof = 1;
@@ -542,8 +553,7 @@
 
 #endif
 
-    c = ev->data;
-    r = c->data;
+    c = r->connection;
     p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
     n = recv(c->fd, buf, 1, MSG_PEEK);
@@ -712,13 +722,6 @@
                        p->cache->ctx.file.fd);
     }
 
-    if (p->upstream && p->upstream->event_pipe) {
-        r->file.fd = p->upstream->event_pipe->temp_file->file.fd;
-
-    } else if (p->cache) {
-        r->file.fd = p->cache->ctx.file.fd;
-    }
-
     if (rc == 0 && r->main == NULL) {
         rc = ngx_http_send_last(r);
     }
diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.h b/src/http/modules/proxy/ngx_http_proxy_handler.h
index 2c9210f..11c24b1 100644
--- a/src/http/modules/proxy/ngx_http_proxy_handler.h
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.h
@@ -249,7 +249,10 @@
 
 #endif
 
-void ngx_http_proxy_check_broken_connection(ngx_event_t *ev);
+void ngx_http_proxy_rd_check_broken_connection(ngx_http_request_t *r);
+void ngx_http_proxy_wr_check_broken_connection(ngx_http_request_t *r);
+void ngx_http_proxy_check_broken_connection(ngx_http_request_t *r,
+    ngx_event_t *ev);
 
 void ngx_http_proxy_busy_lock_handler(ngx_event_t *rev);
 void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p);
@@ -265,7 +268,7 @@
 
 
 extern ngx_module_t  ngx_http_proxy_module;
-extern ngx_http_header_t ngx_http_proxy_headers_in[];
+extern ngx_http_header0_t ngx_http_proxy_headers_in[];
 
 
 
diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c
index 107aba3..0f17b95 100644
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c
@@ -24,6 +24,7 @@
 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev);
 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *);
 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p);
+static void ngx_http_proxy_process_downstream(ngx_http_request_t *r);
 static void ngx_http_proxy_process_body(ngx_event_t *ev);
 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p,
                                          ngx_uint_t ft_type);
@@ -112,7 +113,7 @@
         len = http_methods[p->upstream->method - 1].len + uc->uri.len;
 
     } else {
-        len = r->method_name.len + uc->uri.len;
+        len = r->method_name.len + 1 + uc->uri.len;
     }
 
     if (p->lcf->pass_unparsed_uri && r->valid_unparsed_uri) {
@@ -261,7 +262,8 @@
                              http_methods[p->upstream->method - 1].data,
                              http_methods[p->upstream->method - 1].len);
     } else {
-        b->last = ngx_cpymem(b->last, r->method_name.data, r->method_name.len);
+        b->last = ngx_cpymem(b->last, r->method_name.data,
+                             r->method_name.len + 1);
     }
 
     b->last = ngx_cpymem(b->last, uc->uri.data, uc->uri.len);
@@ -502,12 +504,11 @@
         ngx_del_timer(r->connection->read);
     }
 
-    r->connection->read->event_handler = ngx_http_proxy_check_broken_connection;
+    r->read_event_handler = ngx_http_proxy_rd_check_broken_connection;
 
     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
 
-        r->connection->write->event_handler =
-                                        ngx_http_proxy_check_broken_connection;
+        r->write_event_handler = ngx_http_proxy_wr_check_broken_connection;
 
         if (!r->connection->write->active) {
             if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT,
@@ -770,8 +771,8 @@
     c = p->upstream->peer.connection;
 
     c->data = p;
-    c->write->event_handler = ngx_http_proxy_send_request_handler;
-    c->read->event_handler = ngx_http_proxy_process_upstream_status_line;
+    c->write->handler = ngx_http_proxy_send_request_handler;
+    c->read->handler = ngx_http_proxy_process_upstream_status_line;
 
     c->sendfile = r->connection->sendfile;
 
@@ -925,9 +926,9 @@
     }
 #endif
 
-    c->write->event_handler = ngx_http_proxy_dummy_handler;
+    c->write->handler = ngx_http_proxy_dummy_handler;
 
-    if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
+    if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
         ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
     }
@@ -1124,7 +1125,7 @@
     }
 
 
-    c->read->event_handler = ngx_http_proxy_process_upstream_headers;
+    c->read->handler = ngx_http_proxy_process_upstream_headers;
     ngx_http_proxy_process_upstream_headers(rev);
 }
 
@@ -1174,7 +1175,7 @@
 
         rc = ngx_http_parse_header_line(p->request, p->header_in);
 
-        if (rc == NGX_OK) {
+        if (rc == NGX_OK && !r->invalid_header) {
 
             /* a header line has been parsed successfully */
 
@@ -1241,6 +1242,10 @@
 
         } else if (rc != NGX_AGAIN) {
 
+            if (r->invalid_header) {
+                rc = NGX_HTTP_PARSE_INVALID_HEADER;
+            }
+
             /* there was error while a header line parsing */
 
             ngx_log_error(NGX_LOG_ERR, rev->log, 0,
@@ -1465,9 +1470,8 @@
     ep->send_timeout = clcf->send_timeout;
     ep->send_lowat = clcf->send_lowat;
 
-    p->upstream->peer.connection->read->event_handler =
-                                                   ngx_http_proxy_process_body;
-    r->connection->write->event_handler = ngx_http_proxy_process_body;
+    p->upstream->peer.connection->read->handler = ngx_http_proxy_process_body;
+    r->write_event_handler = ngx_http_proxy_process_downstream;
 
     ngx_http_proxy_process_body(p->upstream->peer.connection->read);
 
@@ -1475,6 +1479,12 @@
 }
 
 
+static void ngx_http_proxy_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;