changeset 635:18268abd340c release-0.3.39

nginx-0.3.39-RELEASE import *) Feature: the "uninitialized_variable_warn" directive; the logging level of the "uninitialized variable" message was lowered from "alert" to "warn". *) Feature: the "override_charset" directive. *) Change: now if the unknown variable is used in the "echo" and "if expr='$name'" SSI-commands, then the "unknown variable" message is not logged. *) Bugfix: the active connection counter increased on the exceeding of the connection limit specified by the "worker_connections" directive; the bug had appeared in 0.2.0. *) Bugfix: the limit rate might not work on some condition; the bug had appeared in 0.3.38.
author Igor Sysoev <igor@sysoev.ru>
date Mon, 17 Apr 2006 19:55:41 +0000
parents af8e20368022
children 21003753acbf
files auto/options docs/xml/nginx/changes.xml src/core/nginx.h src/core/ngx_connection.c src/event/ngx_event_accept.c src/http/modules/ngx_http_charset_filter_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/http/ngx_http_variables.c src/http/ngx_http_variables.h src/http/ngx_http_write_filter_module.c
diffstat 14 files changed, 320 insertions(+), 118 deletions(-) [+]
line wrap: on
line diff
--- a/auto/options
+++ b/auto/options
@@ -236,6 +236,9 @@ cat << END
 
   --with-http_ssl_module             enable ngx_http_ssl_module
   --with-http_realip_module          enable ngx_http_realip_module
+  --with-http_addition_module        enable ngx_http_addition_module
+  --with-http_dav_module             enable ngx_http_dav_module
+
   --without-http_charset_module      disable ngx_http_charset_module
   --without-http_gzip_module         disable ngx_http_gzip_module
   --without-http_ssi_module          disable ngx_http_ssi_module
@@ -257,11 +260,10 @@ cat << END
 
   --http-log-path=PATH               set path to the http access log
   --http-client-body-temp-path=PATH  set path to the http client request body
-                                     temporary files path
-  --http-proxy-temp-path=PATH        set path to the http proxy temporary
-                                     files path
+                                     temporary files
+  --http-proxy-temp-path=PATH        set path to the http proxy temporary files
   --http-fastcgi-temp-path=PATH      set path to the http fastcgi temporary
-                                     files path
+                                     files
 
   --without-http                     disable HTTP server
 
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -9,6 +9,66 @@
 <title lang="en">nginx changelog</title>
 
 
+<changes ver="0.3.39" date="17.04.2006">
+
+<change type="feature">
+<para lang="ru">
+директива uninitialized_variable_warn; уровень логгирования сообщения
+о неинициализированной переменной понижен с уровня alert на warn.
+</para>
+<para lang="en">
+the "uninitialized_variable_warn" directive; the logging level of the
+"uninitialized variable" message was lowered from "alert" to "warn".
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива override_charset.
+</para>
+<para lang="en">
+the "override_charset" directive.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+при использовании неизвестной переменной в SSI-командах echo и if expr='$name'
+теперь не записывается в лог сообщение о неизвестной переменной.
+</para>
+<para lang="en">
+now if the unknown variable is used in the "echo" and "if expr='$name'"
+SSI-commands, then the "unknown variable" message is not logged.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+счётчик активных соединений рос при превышении лимита соединений,
+заданного директивой worker_connections;
+ошибка появилась в 0.2.0.
+</para>
+<para lang="en">
+the active connection counter increased on the exceeding of the connection
+limit specified by the "worker_connections" directive;
+bug appeared in 0.2.0.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при некоторых условия ограничение скорости соединения могло не работать;
+ошибка появилась в 0.3.38.
+</para>
+<para lang="en">
+the limit rate might not work on some condition;
+bug appeared in 0.3.38.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="0.3.38" date="14.04.2006">
 
 <change type="feature">
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.38"
+#define NGINX_VER          "nginx/0.3.39"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -386,6 +386,21 @@ ngx_configure_listening_socket(ngx_cycle
             }
         }
 
+#if 0
+        if (1) {
+            int tcp_nodelay = 1;
+
+            if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_NODELAY,
+                       (const void *) &tcp_nodelay, sizeof(int))
+                == -1)
+            {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+                              "setsockopt(TCP_NODELAY) %V failed, ignored",
+                              &ls[i].addr_text);
+            }
+        }
+#endif
+
         if (ls[i].listen) {
             if (listen(ls[i].fd, ls[i].backlog) == -1) {
                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -78,7 +78,6 @@ ngx_event_accept(ngx_event_t *ev)
 
 #if (NGX_STAT_STUB)
         ngx_atomic_fetch_add(ngx_stat_accepted, 1);
-        ngx_atomic_fetch_add(ngx_stat_active, 1);
 #endif
 
         ngx_accept_disabled = NGX_ACCEPT_THRESHOLD
@@ -95,6 +94,10 @@ ngx_event_accept(ngx_event_t *ev)
             return;
         }
 
+#if (NGX_STAT_STUB)
+        ngx_atomic_fetch_add(ngx_stat_active, 1);
+#endif
+
         c->pool = ngx_create_pool(ls->pool_size, ev->log);
         if (c->pool == NULL) {
             ngx_close_accepted_connection(c);
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -13,47 +13,48 @@
 
 
 typedef struct {
-    char       **tables;
-    ngx_str_t    name;
+    u_char     **tables;
+    ngx_str_t     name;
 
-    ngx_uint_t   utf8;   /* unsigned     utf8:1; */
+    ngx_uint_t    utf8;   /* unsigned     utf8:1; */
 } ngx_http_charset_t;
 
 
 typedef struct {
-    ngx_int_t    src;
-    ngx_int_t    dst;
+    ngx_int_t     src;
+    ngx_int_t     dst;
 } ngx_http_charset_recode_t;
 
 
 typedef struct {
-    ngx_int_t    src;
-    ngx_int_t    dst;
-    char        *src2dst;
-    char        *dst2src;
+    ngx_int_t     src;
+    ngx_int_t     dst;
+    u_char       *src2dst;
+    u_char       *dst2src;
 } ngx_http_charset_tables_t;
 
 
 typedef struct {
-    ngx_array_t  charsets;               /* ngx_http_charset_t */
-    ngx_array_t  tables;                 /* ngx_http_charset_tables_t */
-    ngx_array_t  recodes;                /* ngx_http_charset_recode_t */
+    ngx_array_t   charsets;               /* ngx_http_charset_t */
+    ngx_array_t   tables;                 /* ngx_http_charset_tables_t */
+    ngx_array_t   recodes;                /* ngx_http_charset_recode_t */
 } ngx_http_charset_main_conf_t;
 
 
 typedef struct {
-    ngx_int_t    charset;
-    ngx_int_t    source_charset;
+    ngx_int_t     charset;
+    ngx_int_t     source_charset;
+    ngx_flag_t    override_charset;
 } ngx_http_charset_loc_conf_t;
 
 
 typedef struct {
-    ngx_int_t    server;
-    ngx_int_t    client;
+    u_char       *table;
+    ngx_int_t     charset;
 } ngx_http_charset_ctx_t;
 
 
-static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, char *table);
+static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, u_char *table);
 
 static char *ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
@@ -90,6 +91,14 @@ static ngx_command_t  ngx_http_charset_f
       offsetof(ngx_http_charset_loc_conf_t, source_charset),
       NULL },
 
+    { ngx_string("override_charset"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
+                        |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_charset_loc_conf_t, override_charset),
+      NULL },
+
     { ngx_string("charset_map"),
       NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2,
       ngx_charset_map_block,
@@ -139,16 +148,30 @@ static ngx_http_output_body_filter_pt   
 static ngx_int_t
 ngx_http_charset_header_filter(ngx_http_request_t *r)
 {
+    size_t                         len;
+    u_char                        *p;
+    ngx_int_t                      charset, source_charset;
+    ngx_uint_t                     i;
     ngx_http_charset_t            *charsets;
     ngx_http_charset_ctx_t        *ctx;
     ngx_http_charset_loc_conf_t   *lcf;
     ngx_http_charset_main_conf_t  *mcf;
 
     mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
-    lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
+
+    ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module);
 
-    if (lcf->charset == NGX_HTTP_NO_CHARSET) {
-        return ngx_http_next_header_filter(r);
+    if (ctx == NULL) {
+        lcf = ngx_http_get_module_loc_conf(r->main,
+                                           ngx_http_charset_filter_module);
+        charset = lcf->charset;
+
+        if (charset == NGX_HTTP_NO_CHARSET) {
+            return ngx_http_next_header_filter(r);
+        }
+
+    } else {
+        charset = ctx->charset;
     }
 
     if (r->headers_out.content_type.len == 0) {
@@ -162,9 +185,72 @@ ngx_http_charset_header_filter(ngx_http_
         return ngx_http_next_header_filter(r);
     }
 
-    if (r == r->main
-        && ngx_strstr(r->headers_out.content_type.data, "charset") != NULL)
-    {
+    charsets = mcf->charsets.elts;
+
+    lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
+
+    len = 0;
+
+    for (p = r->headers_out.content_type.data; *p; p++) {
+        if (*p == ';') {
+            len = p - r->headers_out.content_type.data;
+        }
+
+        if (ngx_strncasecmp(p, "charset=", 8) != 0) {
+            continue;
+        }
+
+        p += 8;
+
+        for (i = 0; i < mcf->charsets.nelts; i++) {
+
+            if (ngx_strcasecmp(p, charsets[i].name.data) == 0) {
+
+                if (r == r->main && lcf->override_charset == 0) {
+                    ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
+                    if (ctx == NULL) {
+                        return NGX_ERROR;
+                    }
+
+                    ngx_http_set_ctx(r, ctx, ngx_http_charset_filter_module);
+
+                    ctx->charset = i;
+
+                    return ngx_http_next_header_filter(r);
+                }
+
+                if (i != (ngx_uint_t) charset
+                    && (charsets[i].tables == NULL
+                        || charsets[i].tables[charset] == NULL))
+                {
+                    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                                  "no \"charset_map\" between the charsets "
+                                  "\"%V\" and \"%V\"",
+                                  &charsets[i].name, &charsets[charset].name);
+
+                    return ngx_http_next_header_filter(r);
+                }
+
+                r->headers_out.content_type.len = len;
+
+                if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY
+                    || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY)
+                {
+                    /*
+                     * do not set charset for the redirect because NN 4.x
+                     * uses this charset instead of the next page charset
+                     */
+
+                    r->headers_out.charset.len = 0;
+                    return ngx_http_next_header_filter(r);
+                }
+
+                source_charset = i;
+
+                goto found;
+            }
+        }
+
         return ngx_http_next_header_filter(r);
     }
 
@@ -172,8 +258,8 @@ ngx_http_charset_header_filter(ngx_http_
         || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY)
     {
         /*
-         * do not set charset for the redirect because NN 4.x uses this
-         * charset instead of the next page charset
+         * do not set charset for the redirect because NN 4.x
+         * use this charset instead of the next page charset
          */
 
         r->headers_out.charset.len = 0;
@@ -184,17 +270,17 @@ ngx_http_charset_header_filter(ngx_http_
         return ngx_http_next_header_filter(r);
     }
 
-    charsets = mcf->charsets.elts;
-    r->headers_out.charset = charsets[lcf->charset].name;
-    r->utf8 = charsets[lcf->charset].utf8;
+    source_charset = lcf->source_charset;
+
+found:
 
-    if (lcf->source_charset == NGX_CONF_UNSET
-        || lcf->source_charset == lcf->charset)
-    {
+    r->headers_out.charset = charsets[charset].name;
+    r->utf8 = charsets[charset].utf8;
+
+    if (source_charset == NGX_CONF_UNSET || source_charset == charset) {
         return ngx_http_next_header_filter(r);
     }
 
-
     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t));
     if (ctx == NULL) {
         return NGX_ERROR;
@@ -202,6 +288,8 @@ ngx_http_charset_header_filter(ngx_http_
 
     ngx_http_set_ctx(r, ctx, ngx_http_charset_filter_module);
 
+    ctx->table = charsets[source_charset].tables[charset];
+    ctx->charset = charset;
 
     r->filter_need_in_memory = 1;
 
@@ -212,27 +300,17 @@ ngx_http_charset_header_filter(ngx_http_
 static ngx_int_t
 ngx_http_charset_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
 {
-    char                          *table;
-    ngx_chain_t                   *cl;
-    ngx_http_charset_t            *charsets;
-    ngx_http_charset_ctx_t        *ctx;
-    ngx_http_charset_loc_conf_t   *lcf;
-    ngx_http_charset_main_conf_t  *mcf;
+    ngx_chain_t             *cl;
+    ngx_http_charset_ctx_t  *ctx;
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_charset_filter_module);
 
-    if (ctx == NULL) {
+    if (ctx == NULL || ctx->table == NULL) {
         return ngx_http_next_body_filter(r, in);
     }
 
-    mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
-    lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
-
-    charsets = mcf->charsets.elts;
-    table = charsets[lcf->source_charset].tables[lcf->charset];
-
     for (cl = in; cl; cl = cl->next) {
-        ngx_http_charset_recode(cl->buf, table);
+        (void) ngx_http_charset_recode(cl->buf, ctx->table);
     }
 
     return ngx_http_next_body_filter(r, in);
@@ -240,21 +318,15 @@ ngx_http_charset_body_filter(ngx_http_re
 
 
 static ngx_uint_t
-ngx_http_charset_recode(ngx_buf_t *b, char *table)
+ngx_http_charset_recode(ngx_buf_t *b, u_char *table)
 {
-    u_char      *p;
-    ngx_uint_t   change;
-
-    change = 0;
+    u_char  *p;
 
     for (p = b->pos; p < b->last; p++) {
-        if (*p != table[*p]) {
-            change = 1;
-            break;
+
+        if (*p == table[*p]) {
+            continue;
         }
-    }
-
-    if (change) {
 
         while (p < b->last) {
             *p = table[*p];
@@ -262,9 +334,11 @@ ngx_http_charset_recode(ngx_buf_t *b, ch
         }
 
         b->in_file = 0;
+
+        return 1;
     }
 
-    return change;
+    return 0;
 }
 
 
@@ -330,8 +404,8 @@ ngx_charset_map_block(ngx_conf_t *cf, ng
     }
 
     for (i = 0; i < 128; i++) {
-        table->src2dst[i] = (char) i;
-        table->dst2src[i] = (char) i;
+        table->src2dst[i] = (u_char) i;
+        table->dst2src[i] = (u_char) i;
     }
 
     for (/* void */; i < 256; i++) {
@@ -382,8 +456,8 @@ ngx_charset_map(ngx_conf_t *cf, ngx_comm
 
     table = cf->ctx;
 
-    table->src2dst[src] = (char) dst;
-    table->dst2src[dst] = (char) src;
+    table->src2dst[src] = (u_char) dst;
+    table->dst2src[dst] = (u_char) src;
 
     return NGX_CONF_OK;
 }
@@ -519,6 +593,7 @@ ngx_http_charset_create_loc_conf(ngx_con
 
     lcf->charset = NGX_CONF_UNSET;
     lcf->source_charset = NGX_CONF_UNSET;
+    lcf->override_charset = NGX_CONF_UNSET;
 
     return lcf;
 }
@@ -534,6 +609,7 @@ ngx_http_charset_merge_loc_conf(ngx_conf
     ngx_http_charset_recode_t     *recode;
     ngx_http_charset_main_conf_t  *mcf;
 
+    ngx_conf_merge_value(conf->override_charset, prev->override_charset, 0);
     ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_NO_CHARSET);
 
     if (conf->source_charset == NGX_CONF_UNSET) {
@@ -573,6 +649,7 @@ ngx_http_charset_merge_loc_conf(ngx_conf
 static ngx_int_t
 ngx_http_charset_postconfiguration(ngx_conf_t *cf)
 {
+    u_char                       **src, **dst;
     ngx_int_t                      c;
     ngx_uint_t                     i, t;
     ngx_http_charset_t            *charset;
@@ -591,21 +668,13 @@ ngx_http_charset_postconfiguration(ngx_c
 
         c = recode[i].src;
 
-        charset[c].tables = ngx_pcalloc(cf->pool,
-                                        sizeof(char *) * mcf->charsets.nelts);
-        if (charset[c].tables == NULL) {
-            return NGX_ERROR;
-        }
-
         for (t = 0; t < mcf->tables.nelts; t++) {
 
             if (c == tables[t].src && recode[i].dst == tables[t].dst) {
-                charset[c].tables[tables[t].dst] = tables[t].src2dst;
                 goto next;
             }
 
             if (c == tables[t].dst && recode[i].dst == tables[t].src) {
-                charset[c].tables[tables[t].src] = tables[t].dst2src;
                 goto next;
             }
         }
@@ -620,5 +689,34 @@ ngx_http_charset_postconfiguration(ngx_c
         continue;
     }
 
+
+    for (t = 0; t < mcf->tables.nelts; t++) {
+
+        src = charset[tables[t].src].tables;
+
+        if (src == NULL) {
+            src = ngx_pcalloc(cf->pool, sizeof(u_char *) * mcf->charsets.nelts);
+            if (src == NULL) {
+                return NGX_ERROR;
+            }
+
+            charset[tables[t].src].tables = src;
+        }
+
+        dst = charset[tables[t].dst].tables;
+
+        if (dst == NULL) {
+            dst = ngx_pcalloc(cf->pool, sizeof(u_char *) * mcf->charsets.nelts);
+            if (dst == NULL) {
+                return NGX_ERROR;
+            }
+
+            charset[tables[t].dst].tables = dst;
+        }
+
+        src[tables[t].dst] = tables[t].src2dst;
+        dst[tables[t].src] = tables[t].dst2src;
+    }
+
     return NGX_OK;
 }
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -16,6 +16,7 @@ typedef struct {
     ngx_uint_t    stack_size;
 
     ngx_flag_t    log;
+    ngx_flag_t    uninitialized_variable_warn;
 } ngx_http_rewrite_loc_conf_t;
 
 
@@ -91,13 +92,21 @@ static ngx_command_t  ngx_http_rewrite_c
       NULL },
 
     { ngx_string("rewrite_log"),
-      NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
-                       |NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
+                        |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_rewrite_loc_conf_t, log),
       NULL },
 
+    { ngx_string("uninitialized_variable_warn"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
+                        |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_rewrite_loc_conf_t, uninitialized_variable_warn),
+      NULL },
+
       ngx_null_command
 };
 
@@ -138,11 +147,11 @@ ngx_http_rewrite_handler(ngx_http_reques
 {
     ngx_http_script_code_pt       code;
     ngx_http_script_engine_t     *e;
-    ngx_http_rewrite_loc_conf_t  *cf;
+    ngx_http_rewrite_loc_conf_t  *rlcf;
 
-    cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
+    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
 
-    if (cf->codes == NULL) {
+    if (rlcf->codes == NULL) {
         return NGX_DECLINED;
     }
 
@@ -152,13 +161,13 @@ ngx_http_rewrite_handler(ngx_http_reques
     }
 
     e->sp = ngx_pcalloc(r->pool,
-                        cf->stack_size * sizeof(ngx_http_variable_value_t));
+                        rlcf->stack_size * sizeof(ngx_http_variable_value_t));
     if (e->sp == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    if (cf->captures) {
-        e->captures = ngx_palloc(r->pool, cf->captures * sizeof(int));
+    if (rlcf->captures) {
+        e->captures = ngx_palloc(r->pool, rlcf->captures * sizeof(int));
         if (e->captures == NULL) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
@@ -167,10 +176,10 @@ ngx_http_rewrite_handler(ngx_http_reques
         e->captures = NULL;
     }
 
-    e->ip = cf->codes->elts;
+    e->ip = rlcf->codes->elts;
     e->request = r;
     e->quote = 1;
-    e->log = cf->log;
+    e->log = rlcf->log;
     e->status = NGX_DECLINED;
 
     while (*(uintptr_t *) e->ip) {
@@ -186,8 +195,16 @@ static ngx_int_t
 ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v,
     uintptr_t data)
 {
-    ngx_http_variable_t        *var;
-    ngx_http_core_main_conf_t  *cmcf;
+    ngx_http_variable_t          *var;
+    ngx_http_core_main_conf_t    *cmcf;
+    ngx_http_rewrite_loc_conf_t  *rlcf;
+
+    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
+
+    if (rlcf->uninitialized_variable_warn == 0) {
+        *v = ngx_http_variable_null_value;
+        return NGX_OK;
+    }
 
     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
 
@@ -199,7 +216,7 @@ ngx_http_rewrite_var(ngx_http_request_t 
      * so the handler is called only if the variable is not initialized
      */
 
-    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+    ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
                   "using uninitialized \"%V\" variable", &var[data].name);
 
     *v = ngx_http_variable_null_value;
@@ -220,6 +237,7 @@ ngx_http_rewrite_create_loc_conf(ngx_con
 
     conf->stack_size = NGX_CONF_UNSET_UINT;
     conf->log = NGX_CONF_UNSET;
+    conf->uninitialized_variable_warn = NGX_CONF_UNSET;
 
     return conf;
 }
@@ -234,6 +252,8 @@ ngx_http_rewrite_merge_loc_conf(ngx_conf
     uintptr_t  *code;
 
     ngx_conf_merge_value(conf->log, prev->log, 0);
+    ngx_conf_merge_value(conf->uninitialized_variable_warn,
+                         prev->uninitialized_variable_warn, 1);
     ngx_conf_merge_unsigned_value(conf->stack_size, prev->stack_size, 10);
 
     if (conf->codes == NULL) {
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -14,6 +14,7 @@
 
 #define NGX_HTTP_SSI_ADD_PREFIX     1
 #define NGX_HTTP_SSI_ADD_ZERO       2
+#define NGX_HTTP_SSI_EXPR_TEST      4
 
 
 typedef struct {
@@ -1502,8 +1503,8 @@ ngx_http_ssi_evaluate_string(ngx_http_re
             val = ngx_http_ssi_get_variable(r, &var, key);
 
             if (val == NULL) {
-                vv = ngx_http_get_variable(r, &var, key);
-
+                vv = ngx_http_get_variable(r, &var, key,
+                                           flags & NGX_HTTP_SSI_EXPR_TEST);
                 if (vv == NULL) {
                     return NGX_ERROR;
                 }
@@ -1681,7 +1682,7 @@ ngx_http_ssi_echo(ngx_http_request_t *r,
     value = ngx_http_ssi_get_variable(r, var, key);
 
     if (value == NULL) {
-        vv = ngx_http_get_variable(r, var, key);
+        vv = ngx_http_get_variable(r, var, key, 1);
 
         if (vv == NULL) {
             return NGX_HTTP_SSI_ERROR;
@@ -1873,10 +1874,12 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
         p++;
     }
 
+    flags = (p == last) ? NGX_HTTP_SSI_EXPR_TEST : 0;
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "left: \"%V\"", &left);
 
-    if (ngx_http_ssi_evaluate_string(r, ctx, &left, 0) != NGX_OK) {
+    if (ngx_http_ssi_evaluate_string(r, ctx, &left, flags) != NGX_OK) {
         return NGX_HTTP_SSI_ERROR;
     }
 
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -188,6 +188,7 @@ ngx_http_perl_handler(ngx_http_request_t
 
     r->request_body_in_single_buf = 1;
     r->request_body_in_persistent_file = 1;
+    r->request_body_delete_incomplete_file = 1;
 
     rc = ngx_http_read_client_request_body(r, ngx_http_perl_handle_request);
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -486,8 +486,8 @@ ngx_http_handler(ngx_http_request_t *r)
         if (r->keepalive && r->headers_in.msie && r->method == NGX_HTTP_POST) {
 
             /*
-             * MSIE may wait for some time if the response for the POST request
-             * is sent over the keepalive connection
+             * MSIE may wait for some time if the response for
+             * the POST request is sent over the keepalive connection
              */
 
             r->keepalive = 0;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1473,21 +1473,6 @@ ngx_http_finalize_request(ngx_http_reque
                            &pr->uri, &pr->args);
 
             pr->write_event_handler(pr);
-
-#if 0
-            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "http request: \"%V?%V\" still has postponed",
-                           &pr->uri, &pr->args);
-
-            if (pr->done || pr->postponed->out) {
-                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                               "http wake parent request: \"%V?%V\"",
-                               &pr->uri, &pr->args);
-
-                pr->write_event_handler(pr);
-            }
-#endif
-
         }
 
         return;
@@ -1856,7 +1841,8 @@ ngx_http_set_keepalive(ngx_http_request_
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
 
         if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
-                           (const void *) &tcp_nodelay, sizeof(int)) == -1)
+                       (const void *) &tcp_nodelay, sizeof(int))
+            == -1)
         {
             ngx_connection_error(c, ngx_socket_errno,
                                  "setsockopt(TCP_NODELAY) failed");
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -324,7 +324,8 @@ ngx_http_get_flushed_variable(ngx_http_r
 
 
 ngx_http_variable_value_t *
-ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
+ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key,
+    ngx_uint_t nowarn)
 {
     ngx_http_variable_t        *v;
     ngx_http_variable_value_t  *vv;
@@ -377,10 +378,12 @@ ngx_http_get_variable(ngx_http_request_t
         return NULL;
     }
 
-    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                  "unknown \"%V\" variable", name);
+    vv->not_found = 1;
 
-    vv->not_found = 1;
+    if (nowarn == 0) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "unknown \"%V\" variable", name);
+    }
 
     return vv;
 }
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -56,7 +56,7 @@ ngx_http_variable_value_t *ngx_http_get_
     ngx_uint_t index);
 
 ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
-    ngx_str_t *name, ngx_uint_t key);
+    ngx_str_t *name, ngx_uint_t key, ngx_uint_t nowarn);
 
 #define ngx_http_clear_variable(r, index) r->variables0[index].text.data = NULL;
 
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -209,9 +209,20 @@ ngx_http_write_filter(ngx_http_request_t
         return NGX_ERROR;
     }
 
-    to_send = r->limit_rate * (ngx_time() - r->start_time + 1) - c->sent;
+    if (r->limit_rate) {
+        to_send = r->limit_rate * (ngx_time() - r->start_time + 1) - c->sent;
 
-    if (to_send < 0) {
+        if (to_send <= 0) {
+            c->write->delayed = 1;
+            ngx_add_timer(r->connection->write,
+                       (ngx_msec_t) (- to_send * 1000 / r->limit_rate));
+
+            c->buffered |= NGX_HTTP_WRITE_BUFFERED;
+
+            return NGX_AGAIN;
+        }
+
+    } else {
         to_send = 0;
     }