nginx-0.1.38-RELEASE import

    *) Feature: the "limit_rate" directive is supported in in proxy and
       FastCGI mode.

    *) Feature: the "X-Accel-Limit-Rate" response header line is supported
       in proxy and FastCGI mode.

    *) Feature: the "break" directive.

    *) Feature: the "log_not_found" directive.

    *) Bugfix: the response status code was not changed when request was
       redirected by the ""X-Accel-Redirect" header line.

    *) Bugfix: the variables set by the "set" directive could not be used
       in SSI.

    *) Bugfix: the segmentation fault may occurred if the SSI page has more
       than one remote subrequest.

    *) Bugfix: nginx treated the backend response as invalid if the status
       line in the header was transferred in two packets; the bug had
       appeared in 0.1.29.

    *) Feature: the "ssi_types" directive.

    *) Feature: the "autoindex_exact_size" directive.

    *) Bugfix: the ngx_http_autoindex_module did not support the long file
       names in UTF-8.

    *) Feature: the IMAP/POP3 proxy.
diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c
index e26d294..d128340 100644
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -35,6 +35,7 @@
 typedef struct {
     ngx_flag_t     enable;
     ngx_flag_t     localtime;
+    ngx_flag_t     exact_size;
 } ngx_http_autoindex_loc_conf_t;
 
 
@@ -67,6 +68,13 @@
       offsetof(ngx_http_autoindex_loc_conf_t, localtime),
       NULL },
 
+    { ngx_string("autoindex_exact_size"),
+      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_autoindex_loc_conf_t, exact_size),
+      NULL },
+
       ngx_null_command
 };
 
@@ -117,10 +125,11 @@
 static ngx_int_t
 ngx_http_autoindex_handler(ngx_http_request_t *r)
 {
-    u_char                         *last;
-    size_t                          len;
+    u_char                         *last, scale;
+    off_t                           length;
+    size_t                          len, copy;
     ngx_tm_t                        tm;
-    ngx_int_t                       rc;
+    ngx_int_t                       rc, size;
     ngx_uint_t                      i, level;
     ngx_err_t                       err;
     ngx_buf_t                      *b;
@@ -351,7 +360,7 @@
             + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2
             + sizeof("</a>") - 1
             + sizeof(" 28-Sep-1970 12:00 ") - 1
-            + 19
+            + 20
             + 2;
     }
 
@@ -396,14 +405,27 @@
         *b->last++ = '"';
         *b->last++ = '>';
 
-        b->last = ngx_cpystrn(b->last, entry[i].name.data,
-                              NGX_HTTP_AUTOINDEX_NAME_LEN + 1);
-
         len = entry[i].utf_len;
 
+        if (len) {
+            if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
+                copy = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1;
+
+            } else {
+                copy = NGX_HTTP_AUTOINDEX_NAME_LEN + 1;
+            }
+
+            b->last = ngx_utf_cpystrn(b->last, entry[i].name.data, copy);
+            last = b->last;
+
+        } else {
+            b->last = ngx_cpystrn(b->last, entry[i].name.data,
+                                  NGX_HTTP_AUTOINDEX_NAME_LEN + 1);
+            last = b->last - 3;
+        }
+
         if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
-            b->last = ngx_cpymem(b->last - 3, "..&gt;</a>",
-                                 sizeof("..&gt;</a>") - 1);
+            b->last = ngx_cpymem(last, "..&gt;</a>", sizeof("..&gt;</a>") - 1);
 
         } else {
             if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
@@ -427,12 +449,55 @@
                               tm.ngx_tm_hour,
                               tm.ngx_tm_min);
 
-        if (entry[i].dir) {
-            b->last = ngx_cpymem(b->last,  "                  -",
-                                 sizeof("                  -") - 1);
+        if (alcf->exact_size) {
+            if (entry[i].dir) {
+                b->last = ngx_cpymem(b->last,  "                  -",
+                                     sizeof("                  -") - 1);
+            } else {
+                b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
+            } 
 
         } else {
-            b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
+            if (entry[i].dir) {
+                b->last = ngx_cpymem(b->last,  "     -", sizeof("     -") - 1);
+
+            } else {
+                length = entry[i].size;
+
+                if (length > 1024 * 1024 * 1024 - 1) {
+                    size = (ngx_int_t) (length / (1024 * 1024 * 1024));
+                    if ((length % (1024 * 1024 * 1024))
+                                                > (1024 * 1024 * 1024 / 2 - 1))
+                    { 
+                        size++;
+                    }
+                    scale = 'G';
+
+                } else if (length > 1024 * 1024 - 1) {
+                    size = (ngx_int_t) (length / (1024 * 1024));
+                    if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) {
+                        size++;
+                    }
+                    scale = 'M';
+
+                } else if (length > 9999) {
+                    size = (ngx_int_t) (length / 1024);
+                    if (length % 1024 > 511) {
+                        size++;
+                    }
+                    scale = 'K';
+
+                } else {
+                    size = (ngx_int_t) length;
+                    scale = ' ';
+                }
+
+                b->last = ngx_sprintf(b->last, "%6i", size);
+
+                if (scale != ' ') {
+                    *b->last++ = scale;
+                }
+            }
         }
 
         *b->last++ = CR;
@@ -559,6 +624,7 @@
 
     conf->enable = NGX_CONF_UNSET;
     conf->localtime = NGX_CONF_UNSET;
+    conf->exact_size = NGX_CONF_UNSET;
 
     return conf;
 }
@@ -572,6 +638,7 @@
 
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
     ngx_conf_merge_value(conf->localtime, prev->localtime, 0);
+    ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1);
 
     return NGX_CONF_OK;
 }
diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c
index f7cb92c..596e524 100644
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -15,7 +15,7 @@
     ngx_flag_t           enable;
     ngx_flag_t           no_buffer;
 
-    ngx_array_t         *types;     /* array of ngx_http_gzip_type_t */
+    ngx_array_t         *types;     /* array of ngx_str_t */
 
     ngx_bufs_t           bufs;
 
@@ -29,12 +29,6 @@
 } ngx_http_gzip_conf_t;
 
 
-typedef struct {
-    ngx_str_t            name;
-    ngx_uint_t           enable;
-} ngx_http_gzip_type_t;
-
-
 #define NGX_HTTP_GZIP_PROXIED_OFF       0x0002
 #define NGX_HTTP_GZIP_PROXIED_EXPIRED   0x0004
 #define NGX_HTTP_GZIP_PROXIED_NO_CACHE  0x0008
@@ -91,20 +85,18 @@
 static void *ngx_http_gzip_create_conf(ngx_conf_t *cf);
 static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf,
     void *parent, void *child);
-static char *ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd,
+static char *ngx_http_gzip_types(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
-static char *ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data);
-static char *ngx_http_gzip_set_hash(ngx_conf_t *cf, void *post, void *data);
+static char *ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data);
+static char *ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data);
 
 
 static ngx_conf_num_bounds_t  ngx_http_gzip_comp_level_bounds = {
     ngx_conf_check_num_bounds, 1, 9
 };
 
-static ngx_conf_post_handler_pt  ngx_http_gzip_set_window_p =
-                                                      ngx_http_gzip_set_window;
-static ngx_conf_post_handler_pt  ngx_http_gzip_set_hash_p =
-                                                        ngx_http_gzip_set_hash;
+static ngx_conf_post_handler_pt  ngx_http_gzip_window_p = ngx_http_gzip_window;
+static ngx_conf_post_handler_pt  ngx_http_gzip_hash_p = ngx_http_gzip_hash;
 
 
 
@@ -148,7 +140,7 @@
 
     { ngx_string("gzip_types"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
-      ngx_http_gzip_set_types,
+      ngx_http_gzip_types,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
@@ -165,14 +157,14 @@
       ngx_conf_set_size_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_gzip_conf_t, wbits),
-      &ngx_http_gzip_set_window_p },
+      &ngx_http_gzip_window_p },
 
     { ngx_string("gzip_hash"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_size_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_gzip_conf_t, memlevel),
-      &ngx_http_gzip_set_hash_p },
+      &ngx_http_gzip_hash_p },
 
     { ngx_string("gzip_no_buffer"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
@@ -270,10 +262,10 @@
 static ngx_int_t
 ngx_http_gzip_header_filter(ngx_http_request_t *r)
 {
-    ngx_uint_t             i, found;
+    ngx_str_t             *type;
+    ngx_uint_t             i;
     ngx_http_gzip_ctx_t   *ctx;
     ngx_http_gzip_conf_t  *conf;
-    ngx_http_gzip_type_t  *type;
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
@@ -297,24 +289,21 @@
     }
 
 
-    found = 0;
     type = conf->types->elts;
-
     for (i = 0; i < conf->types->nelts; i++) {
-        if (r->headers_out.content_type.len >= type[i].name.len
+        if (r->headers_out.content_type.len >= type[i].len
             && ngx_strncasecmp(r->headers_out.content_type.data, 
-                               type[i].name.data, type[i].name.len) == 0)
+                               type[i].data, type[i].len) == 0)
         {
-            found = 1;
-            break;
+            goto found;
         }
     }
 
-    if (!found) {
-        return ngx_http_next_header_filter(r);
-    }
+    return ngx_http_next_header_filter(r);
 
 
+found:
+
     if (r->headers_in.via) {
         if (conf->proxied & NGX_HTTP_GZIP_PROXIED_OFF) {
             return ngx_http_next_header_filter(r);
@@ -1031,7 +1020,7 @@
     ngx_http_gzip_conf_t *prev = parent;
     ngx_http_gzip_conf_t *conf = child;
 
-    ngx_http_gzip_type_t  *type;
+    ngx_str_t  *type;
 
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
 
@@ -1051,8 +1040,7 @@
 
     if (conf->types == NULL) {
         if (prev->types == NULL) {
-            conf->types = ngx_array_create(cf->pool, 1,
-                                           sizeof(ngx_http_gzip_type_t));
+            conf->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
             if (conf->types == NULL) {
                 return NGX_CONF_ERROR;
             }
@@ -1062,9 +1050,8 @@
                 return NGX_CONF_ERROR;
             }
 
-            type->name.len = sizeof("text/html") - 1;
-            type->name.data = (u_char *) "text/html";
-            type->enable = 1;
+            type->len = sizeof("text/html") - 1;
+            type->data = (u_char *) "text/html";
 
         } else {
             conf->types = prev->types;
@@ -1076,17 +1063,15 @@
 
 
 static char *
-ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+ngx_http_gzip_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_gzip_conf_t *gcf = conf;
 
-    ngx_str_t             *value;
-    ngx_uint_t             i;
-    ngx_http_gzip_type_t  *type;
+    ngx_str_t   *value, *type;
+    ngx_uint_t   i;
 
     if (gcf->types == NULL) {
-        gcf->types = ngx_array_create(cf->pool, 4,
-                                      sizeof(ngx_http_gzip_type_t));
+        gcf->types = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
         if (gcf->types == NULL) {
             return NGX_CONF_ERROR;
         }
@@ -1096,9 +1081,8 @@
             return NGX_CONF_ERROR;
         }
 
-        type->name.len = sizeof("text/html") - 1;
-        type->name.data = (u_char *) "text/html";
-        type->enable = 1;
+        type->len = sizeof("text/html") - 1;
+        type->data = (u_char *) "text/html";
     }
 
     value = cf->args->elts;
@@ -1114,14 +1098,14 @@
             return NGX_CONF_ERROR;
         }
 
-        type->name.len = value[i].len;
+        type->len = value[i].len;
 
-        type->name.data = ngx_palloc(cf->pool, type->name.len + 1);
-        if (type->name.data == NULL) {
+        type->data = ngx_palloc(cf->pool, type->len + 1);
+        if (type->data == NULL) {
             return NGX_CONF_ERROR;
         }
 
-        ngx_cpystrn(type->name.data, value[i].data, type->name.len + 1);
+        ngx_cpystrn(type->data, value[i].data, type->len + 1);
     }
 
     return NGX_CONF_OK;
@@ -1129,7 +1113,7 @@
 
 
 static char *
-ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data)
+ngx_http_gzip_window(ngx_conf_t *cf, void *post, void *data)
 {
     int *np = data;
 
@@ -1153,7 +1137,7 @@
 
 
 static char *
-ngx_http_gzip_set_hash(ngx_conf_t *cf, void *post, void *data)
+ngx_http_gzip_hash(ngx_conf_t *cf, void *post, void *data)
 {
     int *np = data;
 
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 83625be..85503d0 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -914,7 +914,7 @@
             }
             break;
 
-        /* end of request line */
+        /* end of status line */
         case sw_almost_done:
             p->status_end = pos - 1;
             switch (ch) {
@@ -926,7 +926,7 @@
         }
     }
 
-    u->header_in.pos = pos + 1;
+    u->header_in.pos = pos;
     r->state = state;
 
     return NGX_AGAIN;
@@ -1803,7 +1803,7 @@
         }
 
         for (i = 0; i < plcf->peers->number; i++) {
-            plcf->peers->peer[i].uri_separator = ":";
+            plcf->peers->peer[i].uri_separator = "";
         }
 
         plcf->host_header = inet_upstream.host_header;
diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c
index ed7abd6..5f73c02 100644
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -36,6 +36,8 @@
 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);
+static char *ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf,
@@ -66,6 +68,14 @@
       0,
       NULL },
 
+    { ngx_string("break"),
+      NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                       |NGX_CONF_NOARGS,
+      ngx_http_rewrite_break,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("if"),
       NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
       ngx_http_rewrite_if,
@@ -601,6 +611,24 @@
 
 
 static char *
+ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_rewrite_loc_conf_t *lcf = conf;
+
+    ngx_http_script_code_pt  *code;
+
+    code = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(uintptr_t));
+    if (code == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    *code = ngx_http_script_break_code;
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
 ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_rewrite_loc_conf_t *lcf = conf;
diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c
index 2992ff5..856726a 100644
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -24,6 +24,8 @@
     ngx_flag_t        silent_errors;
     ngx_flag_t        ignore_recycled_buffers;
 
+    ngx_array_t      *types;     /* array of ngx_str_t */
+
     size_t            min_file_chunk;
     size_t            value_len;
 } ngx_http_ssi_conf_t;
@@ -127,6 +129,8 @@
 static ngx_http_variable_value_t *
     ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt);
 
+static char *ngx_http_ssi_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+
 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,
@@ -164,6 +168,13 @@
       offsetof(ngx_http_ssi_conf_t, min_file_chunk),
       NULL },
 
+    { ngx_string("ssi_types"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_ssi_types,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
       ngx_null_command
 };
 
@@ -201,7 +212,7 @@
 
 static u_char ngx_http_ssi_string[] = "<!--";
 static u_char ngx_http_ssi_error_string[] =
-                          "[an error occurred while processing the directive]";
+    "[an error occurred while processing the directive]";
 
 static ngx_str_t ngx_http_ssi_none = ngx_string("(none)");
 
@@ -280,25 +291,35 @@
 static ngx_int_t
 ngx_http_ssi_header_filter(ngx_http_request_t *r)
 {
+    ngx_uint_t            i;
+    ngx_str_t            *type;
     ngx_http_ssi_ctx_t   *ctx;
     ngx_http_ssi_conf_t  *conf;
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module);
 
-    if (!conf->enable) {
-        return ngx_http_next_header_filter(r);
-    }
-
-    /* TODO: "text/html" -> custom types */
-
-    if (r->headers_out.content_type.len == 0
-        || ngx_strncasecmp(r->headers_out.content_type.data, "text/html", 5)
-           != 0)
+    if (!conf->enable
+        || r->headers_out.content_type.len == 0)
     {
         return ngx_http_next_header_filter(r);
     }
 
 
+    type = conf->types->elts;
+    for (i = 0; i < conf->types->nelts; i++) {
+        if (r->headers_out.content_type.len >= type[i].len
+            && ngx_strncasecmp(r->headers_out.content_type.data,
+                               type[i].data, type[i].len) == 0)
+        {
+            goto found;
+        }
+    }
+
+    return ngx_http_next_header_filter(r);
+
+
+found:
+
     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_ssi_ctx_t));
     if (ctx == NULL) {
         return NGX_ERROR;
@@ -1632,6 +1653,56 @@
 }
 
 
+static char *
+ngx_http_ssi_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_ssi_conf_t *scf = conf;
+
+    ngx_str_t   *value, *type;
+    ngx_uint_t   i;
+
+    if (scf->types == NULL) {
+        scf->types = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
+        if (scf->types == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        type = ngx_array_push(scf->types);
+        if (type == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        type->len = sizeof("text/html") - 1;
+        type->data = (u_char *) "text/html";
+    }
+
+    value = cf->args->elts;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+
+        if (ngx_strcmp(value[i].data, "text/html") == 0) {
+            continue;
+        }
+
+        type = ngx_array_push(scf->types);
+        if (type == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        type->len = value[i].len;
+
+        type->data = ngx_palloc(cf->pool, type->len + 1);
+        if (type->data == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        ngx_cpystrn(type->data, value[i].data, type->len + 1);
+    }
+
+    return NGX_CONF_OK;
+}
+
+
 static ngx_int_t
 ngx_http_ssi_add_variables(ngx_conf_t *cf)
 {
@@ -1661,6 +1732,12 @@
         return NGX_CONF_ERROR;
     }
 
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     conf->types = NULL;
+     */
+
     conf->enable = NGX_CONF_UNSET;
     conf->silent_errors = NGX_CONF_UNSET;
     conf->ignore_recycled_buffers = NGX_CONF_UNSET;
@@ -1678,6 +1755,8 @@
     ngx_http_ssi_conf_t *prev = parent;
     ngx_http_ssi_conf_t *conf = child;
 
+    ngx_str_t  *type;
+
     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,
@@ -1686,6 +1765,26 @@
     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);
 
+    if (conf->types == NULL) {
+        if (prev->types == NULL) {
+            conf->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
+            if (conf->types == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            type = ngx_array_push(conf->types);
+            if (type == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            type->len = sizeof("text/html") - 1;
+            type->data = (u_char *) "text/html";
+
+        } else {
+            conf->types = prev->types;
+        }
+    }
+
     return NGX_CONF_OK;
 }
 
diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c
index a84a70e..54e624f 100644
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -210,8 +210,10 @@
             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        ngx_log_error(level, log, err,
-                      ngx_open_file_n " \"%s\" failed", name.data);
+        if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
+            ngx_log_error(level, log, err,
+                          ngx_open_file_n " \"%s\" failed", name.data);
+        }
 
         return rc;
     }
diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c
index 5561134..4671548 100644
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -68,13 +68,17 @@
     ngx_output_chain_ctx_t       *ctx;
     ngx_http_copy_filter_conf_t  *conf;
 
-    if (r->connection->write->error) {
-        return NGX_ERROR;
-    }
-
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "copy filter: \"%V\"", &r->uri);
 
+    if (r->connection->closed) {
+        rc = ngx_http_next_filter(r, in);
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "copy closed filter: %i \"%V\"", rc, &r->uri);
+        return rc;
+    }
+
     ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module);
 
     if (ctx == NULL) {
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 1d39970..ad50585 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -326,6 +326,13 @@
       offsetof(ngx_http_core_loc_conf_t, msie_padding),
       NULL },
 
+    { ngx_string("log_not_found"),
+      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_core_loc_conf_t, log_not_found),
+      NULL },
+
     { ngx_string("error_page"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                         |NGX_CONF_2MORE,
@@ -633,6 +640,8 @@
         return NGX_HTTP_MOVED_PERMANENTLY;
     }
 
+    r->limit_rate = clcf->limit_rate;
+
     if (clcf->handler) {
         r->content_handler = clcf->handler;
     }
@@ -862,10 +871,6 @@
 {
     ngx_int_t  rc;
 
-    if (r->connection->write->error) {
-        return NGX_ERROR;
-    }
-
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http output filter \"%V\"", &r->uri);
 
@@ -873,7 +878,7 @@
 
     if (rc == NGX_ERROR) {
         /* NGX_ERROR may be returned by any filter */
-        r->connection->write->error = 1;
+        r->connection->closed = 1;
     }
 
     return rc;
@@ -1727,6 +1732,7 @@
     lcf->reset_timedout_connection = NGX_CONF_UNSET;
     lcf->port_in_redirect = NGX_CONF_UNSET;
     lcf->msie_padding = NGX_CONF_UNSET;
+    lcf->log_not_found = NGX_CONF_UNSET;
 
     return lcf;
 }
@@ -1841,6 +1847,7 @@
                               prev->reset_timedout_connection, 0);
     ngx_conf_merge_value(conf->port_in_redirect, prev->port_in_redirect, 1);
     ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1);
+    ngx_conf_merge_value(conf->log_not_found, prev->log_not_found, 1);
 
     if (conf->open_files == NULL) {
         conf->open_files = prev->open_files;
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index 1164046..1f6b185 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -224,6 +224,7 @@
     ngx_flag_t    reset_timedout_connection; /* reset_timedout_connection */
     ngx_flag_t    port_in_redirect;        /* port_in_redirect */
     ngx_flag_t    msie_padding;            /* msie_padding */
+    ngx_flag_t    log_not_found;           /* log_not_found */
 
     ngx_array_t  *error_pages;             /* error_page */
 
diff --git a/src/http/ngx_http_postpone_filter_module.c b/src/http/ngx_http_postpone_filter_module.c
index 8e47816..d7d338f 100644
--- a/src/http/ngx_http_postpone_filter_module.c
+++ b/src/http/ngx_http_postpone_filter_module.c
@@ -48,13 +48,18 @@
     ngx_http_request_t            *mr;
     ngx_http_postponed_request_t  *pr, **ppr;
 
-    if (r->connection->write->error) {
-        return NGX_ERROR;
-    }
-
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http postpone filter \"%V\" %p", &r->uri, in);
 
+    if (r->connection->closed) {
+
+        if (r->postponed) {
+            r->postponed = r->postponed->next;
+        }
+
+        return NGX_ERROR;
+    }
+
     if (r != r->connection->data || (r->postponed && in)) {
 
         if (r->postponed) {
@@ -112,7 +117,7 @@
 
     if (rc == NGX_ERROR) {
         /* NGX_ERROR may be returned by any filter */
-        r->connection->write->error = 1;
+        r->connection->closed = 1;
     }
 
     return rc;
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 9ced028..f41a891 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -90,11 +90,6 @@
     { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range),
                  ngx_http_process_header_line },
 
-#if 0
-    { ngx_string("If-Range"), offsetof(ngx_http_headers_in_t, if_range),
-                 ngx_http_process_header_line },
-#endif
-
 #if (NGX_HTTP_GZIP)
     { ngx_string("Accept-Encoding"),
                  offsetof(ngx_http_headers_in_t, accept_encoding),
@@ -1441,6 +1436,8 @@
     r->done = 1;
 
     if (r != r->connection->data) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http finalize non-active request: \"%V\"", &r->uri);
         return;
     }
 
@@ -1448,12 +1445,18 @@
 
         pr = r->parent;
 
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http parent request: \"%V\"", &pr->uri);
+
         if (rc != NGX_AGAIN) {
             pr->connection->data = pr;
         }
 
         if (pr->postponed) {
 
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http request: \"%V\" has postponed", &pr->uri);
+
             if (rc != NGX_AGAIN && pr->postponed->request == r) {
                 pr->postponed = pr->postponed->next;
 
@@ -1462,9 +1465,13 @@
                 }
             }
 
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "http request: \"%V\" still has postponed",
+                           &pr->uri);
+
             if (pr->done) {
                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                               "http wake request: \"%V\"", &pr->uri);
+                               "http wake parent request: \"%V\"", &pr->uri);
 
                 pr->write_event_handler(pr);
             }
@@ -1483,7 +1490,7 @@
             ngx_del_timer(r->connection->write);
         }
 
-        if (rc == NGX_HTTP_CLIENT_CLOSED_REQUEST || r->closed) {
+        if (r->connection->closed) {
             ngx_http_close_request(r, 0);
             ngx_http_close_connection(r->connection);
             return;
@@ -1492,13 +1499,15 @@
         ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc));
 
         return;
+    }
 
-    } else if (rc == NGX_ERROR) {
+    if (rc == NGX_ERROR || r->connection->closed) {
         ngx_http_close_request(r, 0);
         ngx_http_close_connection(r->connection);
         return;
+    }
 
-    } else if (rc == NGX_AGAIN || r->out) {
+    if (rc == NGX_AGAIN || r->out) {
         (void) ngx_http_set_write_handler(r);
         return;
     }
@@ -1553,6 +1562,10 @@
 
     r->write_event_handler = ngx_http_writer;
 
+    if (r->connection->closed) {
+        return NGX_OK;
+    }
+
     wev = r->connection->write;
 
     if (wev->ready && wev->delayed) {
@@ -1673,6 +1686,9 @@
 ngx_http_postponed_handler(ngx_http_request_t *r)
 {
     ngx_int_t                      rc;
+#if 0
+    ngx_http_request_t            *mr;
+#endif
     ngx_http_postponed_request_t  *pr;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -1687,20 +1703,16 @@
         rc = ngx_http_output_filter(r, NULL);
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "http postponed output filter: %d", rc);
+                       "http postponed output filter: %d", rc);
 
         if (rc == NGX_AGAIN) {
             return rc;
         }
 
-        if (rc == NGX_ERROR) {
-            /* NGX_ERROR may be returned by any filter */
-            r->connection->write->error = 1;
-
-            ngx_http_finalize_request(r, rc);
-
-            return NGX_DONE;
-        }
+        /*
+         * we treat NGX_ERROR as NGX_OK, because we need to complete
+         * all postponed requests
+         */
 
         pr = r->postponed;
 
@@ -1713,7 +1725,7 @@
     r->connection->data = r;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http postponed request \"%V\"", &r->uri);
+                   "http wake child request \"%V\"", &r->uri);
 
     r->write_event_handler(r);
 
@@ -1833,7 +1845,7 @@
 
     if (n == NGX_ERROR) {
 
-        r->closed = 1;
+        r->connection->closed = 1;
 
         /*
          * if a client request body is discarded then we already set
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 470f584..d1ba774 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -310,6 +310,8 @@
 
     ngx_http_variable_value_t       **variables;
 
+    size_t                            limit_rate;
+
     /* used to learn the Apache compatible response length without a header */
     size_t                            header_size;
 
@@ -361,7 +363,6 @@
     unsigned                          keepalive:1;
     unsigned                          lingering_close:1;
     unsigned                          internal:1;
-    unsigned                          closed:1;
     unsigned                          done:1;
     unsigned                          utf8:1;
 
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index 42edfef..eb2e6a5 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -236,7 +236,7 @@
         }
 
         if (n == 0 || n == NGX_ERROR) {
-            r->closed = 1;
+            c->closed = 1;
             return NGX_HTTP_BAD_REQUEST;
         }
 
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index 89256b3..716a6f0 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -558,6 +558,7 @@
 
         if (code->break_cycle) {
             r->valid_location = 0;
+            r->uri_changed = 0;
 
         } else {
             r->uri_changed = 1;
@@ -713,6 +714,15 @@
 
 
 void
+ngx_http_script_break_code(ngx_http_script_engine_t *e)
+{
+    e->request->uri_changed = 0;
+
+    e->ip = ngx_http_script_exit;
+}
+
+
+void
 ngx_http_script_if_code(ngx_http_script_engine_t *e)
 {
     ngx_http_script_if_code_t  *code;
diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h
index eb6f17e..2162542 100644
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -166,6 +166,7 @@
 void ngx_http_script_regex_end_code(ngx_http_script_engine_t *e);
 #endif
 void ngx_http_script_return_code(ngx_http_script_engine_t *e);
+void ngx_http_script_break_code(ngx_http_script_engine_t *e);
 void ngx_http_script_if_code(ngx_http_script_engine_t *e);
 void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e);
 void ngx_http_script_value_code(ngx_http_script_engine_t *e);
diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c
index 7a34159..14d4c80 100644
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -244,6 +244,9 @@
     ngx_http_err_page_t       *err_page;
     ngx_http_core_loc_conf_t  *clcf;
 
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http special response: %d, \"%V\"", error, &r->uri);
+
     rc = ngx_http_discard_body(r);
 
     if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index d7ee08f..8571b86 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -39,6 +39,8 @@
     ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
+    ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
 static ngx_int_t
@@ -143,6 +145,10 @@
                  offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
                  ngx_http_upstream_ignore_header_line, 0, 0 },
 
+    { ngx_string("X-Accel-Limit-Rate"),
+                 ngx_http_upstream_process_limit_rate, 0,
+                 ngx_http_upstream_ignore_header_line, 0, 0 },
+
 #if (NGX_HTTP_GZIP)
     { ngx_string("Content-Encoding"),
                  ngx_http_upstream_process_header_line,
@@ -299,12 +305,19 @@
     ngx_connection_t     *c;
     ngx_http_upstream_t  *u;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
-                   "http upstream check client, write event:%d", ev->write);
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
+                   "http upstream check client, write event:%d, \"%V\"",
+                   ev->write, &r->uri);
 
     c = r->connection;
     u = r->upstream;
 
+    if (c->closed) {
+        ngx_http_upstream_finalize_request(r, u,
+                                           NGX_HTTP_CLIENT_CLOSED_REQUEST);
+        return;
+    }
+
     if (u->peer.connection == NULL) {
         return;
     }
@@ -318,6 +331,7 @@
         }
 
         ev->eof = 1;
+        c->closed = 1;
 
         if (ev->kq_errno) {
             ev->error = 1;
@@ -325,9 +339,8 @@
 
         if (!u->cachable && u->peer.connection) {
             ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
-                          "kevent() reported that client closed "
-                          "prematurely connection, "
-                          "so upstream connection is closed too");
+                          "kevent() reported that client closed prematurely "
+                          "connection, so upstream connection is closed too");
             ngx_http_upstream_finalize_request(r, u,
                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
             return;
@@ -374,6 +387,7 @@
     }
 
     ev->eof = 1;
+    c->closed = 1;
 
     if (n == -1) {
         if (err == NGX_EAGAIN) {
@@ -924,6 +938,8 @@
             }
         }
 
+        r->headers_out.status_line.len = 0;
+
         ngx_http_internal_redirect(r,
                               &r->upstream->headers_in.x_accel_redirect->value,
                               NULL);
@@ -1155,9 +1171,33 @@
 
     if (ev->timedout) {
         if (ev->write) {
-            p->downstream_error = 1;
-            ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
-                          "client timed out");
+            if (ev->delayed) {
+
+                ev->timedout = 0;
+                ev->delayed = 0;
+
+                if (!ev->ready) {
+                    ngx_add_timer(ev, p->send_timeout);
+
+                    if (ngx_handle_write_event(ev, p->send_lowat) == NGX_ERROR)
+                    {
+                        ngx_http_upstream_finalize_request(r, u, 0);
+                        return;
+                    }
+
+                    return;
+                }
+
+                if (ngx_event_pipe(p, ev->write) == NGX_ABORT) {
+                    ngx_http_upstream_finalize_request(r, u, 0);
+                    return;
+                }
+
+            } else {
+                p->downstream_error = 1;
+                ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
+                              "client timed out");
+            }
 
         } else {
             p->upstream_error = 1; 
@@ -1166,6 +1206,17 @@
         }
 
     } else {
+        if (ev->write && ev->delayed) {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                           "http downstream delayed");
+
+            if (ngx_handle_write_event(ev, p->send_lowat) == NGX_ERROR) {
+                return;
+            }
+
+            return;
+        }
+
         if (ngx_event_pipe(p, ev->write) == NGX_ABORT) {
             ngx_http_upstream_finalize_request(r, u, 0);
             return;
@@ -1281,6 +1332,7 @@
     }
 
     if (r->connection->write->eof) {
+        r->connection->closed = 1;
         ngx_http_upstream_finalize_request(r, u,
                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
         return;
@@ -1432,6 +1484,24 @@
 
 
 static ngx_int_t
+ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
+    ngx_uint_t offset)
+{   
+    ngx_int_t  n;
+
+    r->upstream->headers_in.x_accel_limit_rate = h;
+
+    n = ngx_atoi(h->value.data, h->value.len);
+
+    if (n != NGX_ERROR) {
+        r->limit_rate = (size_t) n;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
 {
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index 00a64ac..428253c 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -48,6 +48,7 @@
     ngx_msec_t                      connect_timeout;
     ngx_msec_t                      send_timeout;
     ngx_msec_t                      read_timeout;
+    ngx_msec_t                      timeout;
 
     size_t                          send_lowat;
     size_t                          header_buffer_size;
@@ -103,6 +104,7 @@
     ngx_table_elt_t                *etag;
     ngx_table_elt_t                *x_accel_expires;
     ngx_table_elt_t                *x_accel_redirect;
+    ngx_table_elt_t                *x_accel_limit_rate;
 
     ngx_table_elt_t                *content_type;
     ngx_table_elt_t                *content_length;
@@ -120,8 +122,6 @@
 
 
 struct ngx_http_upstream_s {
-    ngx_http_request_t             *request;
-
     ngx_peer_connection_t           peer;
 
     ngx_event_pipe_t                pipe;
@@ -146,6 +146,8 @@
     ngx_int_t                     (*rewrite_redirect)(ngx_http_request_t *r,
                                         ngx_table_elt_t *h, size_t prefix);
 
+    ngx_msec_t                      timeout;
+
     ngx_uint_t                      method;
 
     ngx_http_log_handler_pt         saved_log_handler;
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index d66f0dc..2a5cf7d 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -706,7 +706,9 @@
             {
                 v[i].handler = av[n].handler;
                 v[i].data = av[n].data;
-                v[i].flags = av[n].flags | NGX_HTTP_VAR_INDEXED;
+
+                av[n].flags |= NGX_HTTP_VAR_INDEXED;
+                v[i].flags = av[n].flags;
 
                 goto next;
             }
diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c
index b872f3d..af95c99 100644
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -47,6 +47,12 @@
     ngx_connection_t          *c;
     ngx_http_core_loc_conf_t  *clcf;
 
+    c = r->connection;
+
+    if (c->closed) {
+        return NGX_ERROR;
+    }
+
     size = 0;
     flush = 0;
     last = 0;
@@ -151,8 +157,6 @@
 
     *ll = NULL;
 
-    c = r->connection;
-
     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http write filter: l:%d f:%d s:%O", last, flush, size);
 
@@ -197,19 +201,20 @@
 
     sent = c->sent;
 
-    chain = c->send_chain(c, r->out, clcf->limit_rate);
+    chain = c->send_chain(c, r->out, r->limit_rate);
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http write filter %p", chain);
 
-    if (clcf->limit_rate) {
+    if (r->limit_rate) {
         sent = c->sent - sent;
         c->write->delayed = 1;
         ngx_add_timer(r->connection->write,
-                      (ngx_msec_t) (sent * 1000 / clcf->limit_rate));
+                      (ngx_msec_t) (sent * 1000 / r->limit_rate));
     }
 
     if (chain == NGX_CHAIN_ERROR) {
+        c->closed = 1;
         return NGX_ERROR;
     }