changeset 180:4cd3e70c4d60 NGINX_0_3_37

nginx 0.3.37 *) Feature: the "limit_except" directive. *) Feature: the "if" directive supports the "!~", "!~*", "-f", and "!-f" operators. *) Feature: the ngx_http_perl_module supports the $r->request_body method. *) Bugfix: in the ngx_http_addition_filter_module.
author Igor Sysoev <http://sysoev.ru>
date Fri, 07 Apr 2006 00:00:00 +0400
parents 654cbdc0401d
children de8983d10e75
files CHANGES CHANGES.ru auto/cc/msvc src/core/nginx.h src/core/ngx_hash.c src/core/ngx_inet.c src/http/modules/ngx_http_access_module.c src/http/modules/ngx_http_addition_filter_module.c src/http/modules/ngx_http_auth_basic_module.c src/http/modules/ngx_http_referer_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/perl/nginx.xs src/http/ngx_http.c src/http/ngx_http_config.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_parse.c.orig src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_script.c src/http/ngx_http_script.h
diffstat 21 files changed, 414 insertions(+), 1217 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,16 @@
+
+Changes with nginx 0.3.37                                        07 Apr 2006
+
+    *) Feature: the "limit_except" directive.
+
+    *) Feature: the "if" directive supports the "!~", "!~*", "-f", and 
+       "!-f" operators.
+
+    *) Feature: the ngx_http_perl_module supports the $r->request_body 
+       method.
+
+    *) Bugfix: in the ngx_http_addition_filter_module.
+
 
 Changes with nginx 0.3.36                                        05 Apr 2006
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,17 @@
 
+Изменения в nginx 0.3.37                                          07.04.2006
+
+    *) Добавление: директива limit_except.
+
+    *) Добавление: директива if поддерживает операторы "!~", "!~*", "-f" и 
+       "!-f".
+
+    *) Добавление: модуль ngx_http_perl_module поддерживает метод 
+       $r->request_body.
+
+    *) Исправление: в модуле ngx_http_addition_filter_module.
+
+
 Изменения в nginx 0.3.36                                          05.04.2006
 
     *) Добавление: модуль ngx_http_addition_filter_module.
--- a/auto/cc/msvc
+++ b/auto/cc/msvc
@@ -116,6 +116,12 @@ ngx_binout="-Fe"
 ngx_objext="obj"
 ngx_binext=".exe"
 
+# Borland make
+#ngx_long_start='@&&|
+#        '
+#ngx_long_end='|'
+
+# MS nmake
 ngx_long_start='@<<
         '
 ngx_long_end='<<'
@@ -123,6 +129,6 @@ ngx_long_regex_cont=' \
 	'
 ngx_long_cont='
 	'
-
+# MSVC understand / in path
 #ngx_regex_dirsep='\\'
 #ngx_dirsep="\\"
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.36"
+#define NGINX_VER          "nginx/0.3.37"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -164,10 +164,14 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng
         return NGX_ERROR;
     }
 
-    start = nelts / (ngx_cacheline_size / (2 * sizeof(void *)) - 1);
+    bucket_size = hinit->bucket_size - sizeof(void *);
+
+    start = nelts / (bucket_size / (2 * sizeof(void *)) - 1);
     start = start ? start : 1;
 
-    bucket_size = hinit->bucket_size - sizeof(void *);
+    if (hinit->max_size > 10000 && hinit->max_size / nelts < 100) {
+        start = hinit->max_size - 1000;
+    }
 
     for (size = start; size < hinit->max_size; size++) {
 
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -21,8 +21,8 @@
  */
 
 
-static
-ngx_inline size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len)
+static ngx_inline size_t
+ngx_sprint_uchar(u_char *text, u_char c, size_t len)
 {
     size_t      n;
     ngx_uint_t  c1, c2;
--- a/src/http/modules/ngx_http_access_module.c
+++ b/src/http/modules/ngx_http_access_module.c
@@ -35,14 +35,16 @@ static ngx_int_t ngx_http_access_init(ng
 static ngx_command_t  ngx_http_access_commands[] = {
 
     { ngx_string("allow"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
+                        |NGX_CONF_TAKE1,
       ngx_http_access_rule,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("deny"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
+                        |NGX_CONF_TAKE1,
       ngx_http_access_rule,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
--- a/src/http/modules/ngx_http_addition_filter_module.c
+++ b/src/http/modules/ngx_http_addition_filter_module.c
@@ -16,8 +16,7 @@ typedef struct {
 
 
 typedef struct {
-    unsigned    before_body_sent:1;
-    unsigned    after_body_sent:1;
+    ngx_uint_t  before_body_sent;
 } ngx_http_addition_ctx_t;
 
 
@@ -92,6 +91,12 @@ ngx_http_addition_header_filter(ngx_http
         return ngx_http_next_header_filter(r);
     }
 
+    conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);
+
+    if (conf->before_body.len == 0 && conf->after_body.len == 0) {
+        return ngx_http_next_header_filter(r);
+    }
+
     if (ngx_strncasecmp(r->headers_out.content_type.data, "text/html",
                         sizeof("text/html") - 1)
         != 0)
@@ -99,12 +104,6 @@ ngx_http_addition_header_filter(ngx_http
         return ngx_http_next_header_filter(r);
     }
 
-    conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module);
-
-    if (conf->before_body.len == 0 && conf->after_body.len == 0) {
-        return ngx_http_next_header_filter(r);
-    }
-
     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_addition_ctx_t));
     if (ctx == NULL) {
         return NGX_ERROR;
@@ -155,17 +154,14 @@ ngx_http_addition_body_filter(ngx_http_r
     for (cl = in; cl; cl = cl->next) {
         if (cl->buf->last_buf) {
             cl->buf->last_buf = 0;
+            cl->buf->sync = 1;
             last = 1;
         }
     }
 
     rc = ngx_http_next_body_filter(r, in);
 
-    if (rc == NGX_ERROR
-        || !last
-        || ctx->after_body_sent
-        || conf->after_body.len == 0)
-    {
+    if (rc == NGX_ERROR || !last || conf->after_body.len == 0) {
         return rc;
     }
 
@@ -173,7 +169,7 @@ ngx_http_addition_body_filter(ngx_http_r
         return NGX_ERROR;
     }
 
-    ctx->after_body_sent = 1;
+    ngx_http_set_ctx(r, NULL, ngx_http_addition_filter_module);
 
     return ngx_http_send_special(r, NGX_HTTP_LAST);
 }
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -41,14 +41,16 @@ static ngx_conf_post_handler_pt  ngx_htt
 static ngx_command_t  ngx_http_auth_basic_commands[] = {
 
     { ngx_string("auth_basic"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
+                        |NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_auth_basic_loc_conf_t, realm),
       &ngx_http_auth_basic_p },
 
     { ngx_string("auth_basic_user_file"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
+                        |NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_auth_basic_loc_conf_t, user_file),
@@ -58,7 +60,6 @@ static ngx_command_t  ngx_http_auth_basi
 };
 
 
-
 ngx_http_module_t  ngx_http_auth_basic_module_ctx = {
     NULL,                                  /* preconfiguration */
     NULL,                                  /* postconfiguration */
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -217,7 +217,7 @@ ngx_http_referer_merge_conf(ngx_conf_t *
     }
 
     if ((conf->no_referer == 1 || conf->blocked_referer == 1)
-        && conf->keys->keys.nelts == 0 && conf->keys->dns_wildcards.nelts)
+        && conf->keys->keys.nelts == 0 && conf->keys->dns_wildcards.nelts == 0)
     {
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                       "the \"none\" or \"blocked\" referers are specified "
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -578,7 +578,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_
     elts = lcf->codes->elts;
 
 
-    /* the inside directives must compile to the same code array */
+    /* the inner directives must be compiled to the same code array */
 
     nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index];
     nlcf->codes = lcf->codes;
@@ -629,9 +629,12 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_
 static char *
 ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf)
 {
+    u_char                        *p;
+    size_t                         len;
     ngx_str_t                     *value, err;
     ngx_uint_t                     cur, last, n;
     ngx_http_script_code_pt       *code;
+    ngx_http_script_file_code_t   *fop;
     ngx_http_script_regex_code_t  *regex;
     u_char                         errstr[NGX_MAX_CONF_ERRSTR];
 
@@ -667,11 +670,14 @@ ngx_http_rewrite_if_condition(ngx_conf_t
         value[last].data[value[last].len] = '\0';
     }
 
-    if (value[cur].len > 1 && value[cur].data[0] == '$') {
+    len = value[cur].len;
+    p = value[cur].data;
+
+    if (len > 1 && p[0] == '$') {
 
         if (cur != last && cur + 2 != last) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "invalid condition \"%V\"", &value[cur]);
+                               "invalid condition \"%V\"", &value[cur]);
             return NGX_CONF_ERROR;
         }
 
@@ -685,7 +691,10 @@ ngx_http_rewrite_if_condition(ngx_conf_t
 
         cur++;
 
-        if (value[cur].len == 1 && value[cur].data[0] == '=') {
+        len = value[cur].len;
+        p = value[cur].data;
+
+        if (len == 1 && p[0] == '=') {
 
             if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
                 return NGX_CONF_ERROR;
@@ -702,9 +711,8 @@ ngx_http_rewrite_if_condition(ngx_conf_t
             return NGX_CONF_OK;
         }
 
-        if (value[cur].len == 2
-            && value[cur].data[0] == '!' && value[cur].data[1] == '=')
-        {
+        if (len == 2 && p[0] == '!' && p[1] == '=') {
+
             if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
                 return NGX_CONF_ERROR;
             }
@@ -719,9 +727,10 @@ ngx_http_rewrite_if_condition(ngx_conf_t
             return NGX_CONF_OK;
         }
 
-        if ((value[cur].len == 1 && value[cur].data[0] == '~')
-            || (value[cur].len == 2
-                && value[cur].data[0] == '~' && value[cur].data[1] == '*'))
+        if ((len == 1 && p[0] == '~')
+            || (len == 2 && p[0] == '~' && p[1] == '*')
+            || (len == 2 && p[0] == '!' && p[1] == '~')
+            || (len == 3 && p[0] == '!' && p[1] == '~' && p[2] == '*'))
         {
             regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
                                          sizeof(ngx_http_script_regex_code_t));
@@ -735,8 +744,8 @@ ngx_http_rewrite_if_condition(ngx_conf_t
             err.data = errstr;
 
             regex->regex = ngx_regex_compile(&value[last],
-                                 (value[cur].len == 2) ? NGX_REGEX_CASELESS : 0,
-                                 cf->pool, &err);
+                                  (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0,
+                                   cf->pool, &err);
 
             if (regex->regex == NULL) {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
@@ -746,6 +755,9 @@ ngx_http_rewrite_if_condition(ngx_conf_t
             regex->code = ngx_http_script_regex_start_code;
             regex->next = sizeof(ngx_http_script_regex_code_t);
             regex->test = 1;
+            if (p[0] == '!') {
+                regex->negative_test = 1;
+            }
             regex->name = value[last];
 
             n = ngx_regex_capture_count(regex->regex);
@@ -764,6 +776,46 @@ ngx_http_rewrite_if_condition(ngx_conf_t
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "unexpected \"%V\" in condition", &value[cur]);
         return NGX_CONF_ERROR;
+
+    } else if ((len == 2 && p[0] == '-')
+               || (len == 3 && p[0] == '!' && p[1] == '-'))
+    {
+        if (cur + 1 != last) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid condition \"%V\"", &value[cur]);
+            return NGX_CONF_ERROR;
+        }
+
+        value[last].data[value[last].len] = '\0';
+        value[last].len++;
+
+        if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
+            return NGX_CONF_ERROR;
+        }
+
+        fop = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                          sizeof(ngx_http_script_file_code_t));
+        if (fop == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        fop->code = ngx_http_script_file_code;
+
+        if (p[1] == 'f') {
+            fop->op = ngx_http_script_file_plain;
+            return NGX_CONF_OK;
+        }
+
+        if (p[0] == '!') {
+            if (p[2] == 'f') {
+                fop->op = ngx_http_script_file_not_plain;
+                return NGX_CONF_OK;
+            }
+        }
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid condition \"%V\"", &value[cur]);
+        return NGX_CONF_ERROR;
     }
 
     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -261,6 +261,41 @@ header_in(r, key)
     RETVAL
 
 
+SV *
+request_body(r)
+    nginx         r
+
+    PREINIT:
+
+    STRLEN        len;
+    ngx_chain_t  *cl;
+
+    CODE:
+
+    len = 0;
+
+    for (cl = r->request_body->bufs; cl; cl = cl->next) {
+        if (cl->buf->in_file) {
+            XSRETURN_UNDEF;
+        }
+
+        len += cl->buf->last - cl->buf->pos;
+    }
+
+    if (len == 0) {
+        XSRETURN_UNDEF;
+    }
+
+    RETVAL = newSV(len);
+
+    for (cl = r->request_body->bufs; cl; cl = cl->next) {
+        sv_catpvn(RETVAL, cl->buf->pos, cl->buf->last - cl->buf->pos);
+    }
+
+    OUTPUT:
+    RETVAL
+
+
 int
 header_out(r, key, value)
     nginx             r
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -595,8 +595,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
 
                 if (rc == NGX_BUSY) {
                     ngx_log_error(NGX_LOG_WARN, cf->log, 0,
-                                  "conflicting server name \"%V\", ignored",
-                                  &name[s].name);
+                                "conflicting server name \"%V\" on %s, ignored",
+                                &name[s].name, in_addr[a].listen_conf->addr);
                 }
             }
 
@@ -617,8 +617,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
 
                 if (rc == NGX_BUSY) {
                     ngx_log_error(NGX_LOG_WARN, cf->log, 0,
-                                  "conflicting server name \"%V\", ignored",
-                                  &name[s].name);
+                                "conflicting server name \"%V\" on %s, ignored",
+                                &name[s].name, in_addr[a].listen_conf->addr);
                 }
             }
 
--- a/src/http/ngx_http_config.h
+++ b/src/http/ngx_http_config.h
@@ -42,7 +42,8 @@ typedef struct {
 #define NGX_HTTP_LOC_CONF         0x08000000
 #define NGX_HTTP_UPS_CONF         0x10000000
 #define NGX_HTTP_SIF_CONF         0x20000000
-#define NGX_HTTP_LIF_CONF         0x80000000
+#define NGX_HTTP_LIF_CONF         0x40000000
+#define NGX_HTTP_LMT_CONF         0x80000000
 
 
 #define NGX_HTTP_MAIN_CONF_OFFSET  offsetof(ngx_http_conf_ctx_t, main_conf)
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -11,6 +11,12 @@
 #include <nginx.h>
 
 
+typedef struct {
+    char      *name;
+    uint32_t   method;
+} ngx_http_method_name_t;
+
+
 #define NGX_HTTP_LOCATION_EXACT           1
 #define NGX_HTTP_LOCATION_AUTO_REDIRECT   2
 #define NGX_HTTP_LOCATION_NOREGEX         3
@@ -48,6 +54,8 @@ static char *ngx_http_core_listen(ngx_co
 static char *ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 static char *ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 static char *ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -225,6 +233,13 @@ static ngx_command_t  ngx_http_core_comm
       0,
       NULL },
 
+    { ngx_string("limit_except"),
+      NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
+      ngx_http_core_limit_except,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("client_max_body_size"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_size_slot,
@@ -711,6 +726,11 @@ ngx_http_update_location_config(ngx_http
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
+    if (r->method & clcf->limit_except) {
+        r->loc_conf = clcf->limit_except_loc_conf;
+        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+    }
+
     r->connection->log->file = clcf->err_log->file;
     if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
         r->connection->log->log_level = clcf->err_log->log_level;
@@ -1949,6 +1969,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
      * set by ngx_pcalloc():
      *
      *     lcf->root = { 0, NULL };
+     *     lcf->limit_except = 0;
      *     lcf->post_action = { 0, NULL };
      *     lcf->types = NULL;
      *     lcf->default_type = { 0, NULL };
@@ -2245,6 +2266,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
         ls->addr = INADDR_ANY;
     }
 
+    n = ngx_inet_ntop(AF_INET, &ls->addr, ls->conf.addr, INET_ADDRSTRLEN + 6);
+    ngx_sprintf(&ls->conf.addr[n], ":%ui", ls->port);
+
     if (cf->args->nelts == 2) {
         return NGX_CONF_OK;
     }
@@ -2480,6 +2504,124 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
 }
 
 
+static ngx_http_method_name_t  ngx_methods_names[] = {
+   { "GET",  (uint32_t) ~NGX_HTTP_GET },
+   { "HEAD", (uint32_t) ~NGX_HTTP_HEAD },
+   { NULL, 0 }
+};
+
+
+static char *
+ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_core_loc_conf_t *clcf = conf;
+
+    char                      *rv;
+    void                      *mconf;
+    ngx_str_t                 *value;
+    ngx_uint_t                 i;
+    ngx_conf_t                 save;
+    ngx_http_module_t         *module;
+    ngx_http_conf_ctx_t       *ctx, *pctx;
+    ngx_http_method_name_t    *name;
+    ngx_http_core_loc_conf_t  *lcf, **clcfp;
+
+    if (clcf->limit_except) {
+        return "duplicate";
+    }
+
+    clcf->limit_except = 0xffffffff;
+
+    value = cf->args->elts;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+        for (name = ngx_methods_names; name->name; name++) {
+
+            if (ngx_strcasecmp(value[i].data, name->name) == 0) {
+                clcf->limit_except &= name->method;
+                goto next;
+            }
+        }
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid method \"%V\"", &value[i]);
+        return NGX_CONF_ERROR;
+
+    next:
+        continue;
+    }
+
+    if (!(clcf->limit_except & NGX_HTTP_GET)) {
+        clcf->limit_except &= (uint32_t) ~NGX_HTTP_HEAD;
+    }
+
+    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
+    if (ctx == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    pctx = cf->ctx;
+    ctx->main_conf = pctx->main_conf;
+    ctx->srv_conf = pctx->srv_conf;
+
+    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
+    if (ctx->loc_conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    for (i = 0; ngx_modules[i]; i++) {
+        if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
+            continue;
+        }
+
+        module = ngx_modules[i]->ctx;
+
+        if (module->create_loc_conf) {
+
+            mconf = module->create_loc_conf(cf);
+            if (mconf == NULL) {
+                 return NGX_CONF_ERROR;
+            }
+
+            ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
+        }
+    }
+
+
+    lcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
+    clcf->limit_except_loc_conf = ctx->loc_conf;
+    lcf->loc_conf = ctx->loc_conf;
+    lcf->name = clcf->name;
+    lcf->noname = 1;
+
+    if (clcf->locations.elts == NULL) {
+        if (ngx_array_init(&clcf->locations, cf->pool, 4, sizeof(void *))
+            == NGX_ERROR)
+        {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    clcfp = ngx_array_push(&clcf->locations);
+    if (clcfp == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    *clcfp = lcf;
+
+
+    save = *cf;
+    cf->ctx = ctx;
+    cf->cmd_type = NGX_HTTP_LMT_CONF;
+
+    rv = ngx_conf_parse(cf, NULL);
+
+    *cf = save;
+
+    return rv;
+}
+
+
 static char *
 ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -28,6 +28,8 @@ typedef struct {
     ngx_uint_t                 deferred_accept;
 #endif
 
+    u_char                     addr[INET_ADDRSTRLEN + 6];
+
 } ngx_http_listen_conf_t;
 
 
@@ -196,6 +198,9 @@ struct ngx_http_core_loc_conf_s {
     /* pointer to the modules' loc_conf */
     void        **loc_conf ;
 
+    uint32_t      limit_except;
+    void        **limit_except_loc_conf ;
+
     ngx_http_handler_pt  handler;
 
     ngx_str_t     root;                    /* root, alias */
deleted file mode 100644
--- a/src/http/ngx_http_parse.c.orig
+++ /dev/null
@@ -1,1166 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-
-
-ngx_int_t
-ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
-{
-    u_char  c, ch, *p, *m;
-    enum {
-        sw_start = 0,
-        sw_method,
-        sw_space_after_method,
-        sw_spaces_before_uri,
-        sw_schema,
-        sw_schema_slash,
-        sw_schema_slash_slash,
-        sw_host,
-        sw_port,
-        sw_after_slash_in_uri,
-        sw_check_uri,
-        sw_uri,
-        sw_http_09,
-        sw_http_H,
-        sw_http_HT,
-        sw_http_HTT,
-        sw_http_HTTP,
-        sw_first_major_digit,
-        sw_major_digit,
-        sw_first_minor_digit,
-        sw_minor_digit,
-        sw_almost_done
-    } state;
-
-    state = r->state;
-
-    for (p = b->pos; p < b->last; p++) {
-        ch = *p;
-
-        /* gcc 2.95.2 and msvc 6.0 compile this switch as an jump table */
-
-        switch (state) {
-
-        /* HTTP methods: GET, HEAD, POST */
-        case sw_start:
-            r->request_start = p;
-
-            if (ch == CR || ch == LF) {
-                break;
-            }
-
-            if (ch < 'A' || ch > 'Z') {
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-
-            state = sw_method;
-            break;
-
-        case sw_method:
-            if (ch == ' ') {
-                r->method_end = p - 1;
-                m = r->request_start;
-
-                if (p - m == 3) {
-
-                    if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') {
-                        r->method = NGX_HTTP_GET;
-                    }
-
-                } else if (p - m == 4) {
-
-                    if (m[0] == 'P' && m[1] == 'O'
-                        && m[2] == 'S' && m[3] == 'T')
-                    {
-                        r->method = NGX_HTTP_POST;
-
-                    } else if (m[0] == 'H' && m[1] == 'E'
-                               && m[2] == 'A' && m[3] == 'D')
-                    {
-                        r->method = NGX_HTTP_HEAD;
-                    }
-                }
-
-                state = sw_spaces_before_uri;
-                break;
-            }
-
-            if (ch < 'A' || ch > 'Z') {
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-
-            break;
-
-        /* single space after method */
-        case sw_space_after_method:
-            switch (ch) {
-            case ' ':
-                state = sw_spaces_before_uri;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-            break;
-
-        /* space* before URI */
-        case sw_spaces_before_uri:
-
-            c = (u_char) (ch | 0x20);
-            if (c >= 'a' && c <= 'z') {
-                r->schema_start = p;
-                state = sw_schema;
-                break;
-            }
-
-            switch (ch) {
-            case '/':
-                r->uri_start = p;
-                state = sw_after_slash_in_uri;
-                break;
-            case ' ':
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        case sw_schema:
-
-            c = (u_char) (ch | 0x20);
-            if (c >= 'a' && c <= 'z') {
-                break;
-            }
-
-            switch (ch) {
-            case ':':
-                r->schema_end = p;
-                state = sw_schema_slash;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        case sw_schema_slash:
-            switch (ch) {
-            case '/':
-                state = sw_schema_slash_slash;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        case sw_schema_slash_slash:
-            switch (ch) {
-            case '/':
-                r->host_start = p;
-                state = sw_host;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        case sw_host:
-
-            c = (u_char) (ch | 0x20);
-            if (c >= 'a' && c <= 'z') {
-                break;
-            }
-
-            if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-')
-            {
-                break;
-            }
-
-            switch (ch) {
-            case ':':
-                r->host_end = p;
-                state = sw_port;
-                break;
-            case '/':
-                r->host_end = p;
-                r->uri_start = p;
-                state = sw_after_slash_in_uri;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        case sw_port:
-            if (ch >= '0' && ch <= '9') {
-                break;
-            }
-
-            switch (ch) {
-            case '/':
-                r->port_end = p;
-                r->uri_start = p;
-                state = sw_after_slash_in_uri;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        /* check "/.", "//", "%", and "\" (Win32) in URI */
-        case sw_after_slash_in_uri:
-
-            c = (u_char) (ch | 0x20);
-            if (c >= 'a' && c <= 'z') {
-                state = sw_check_uri;
-                break;
-            }
-
-            if (ch >= '0' && ch <= '9') {
-                state = sw_check_uri;
-                break;
-            }
-
-            switch (ch) {
-            case ' ':
-                r->uri_end = p;
-                state = sw_http_09;
-                break;
-            case CR:
-                r->uri_end = p;
-                r->http_minor = 9;
-                state = sw_almost_done;
-                break;
-            case LF:
-                r->uri_end = p;
-                r->http_minor = 9;
-                goto done;
-            case '.':
-                r->complex_uri = 1;
-                state = sw_uri;
-                break;
-            case '%':
-                r->quoted_uri = 1;
-                state = sw_uri;
-                break;
-            case '/':
-                r->complex_uri = 1;
-                state = sw_uri;
-                break;
-#if (NGX_WIN32)
-            case '\\':
-                r->complex_uri = 1;
-                state = sw_uri;
-                break;
-#endif
-            case '?':
-                r->args_start = p + 1;
-                state = sw_uri;
-                break;
-            case '+':
-                r->plus_in_uri = 1;
-                break;
-            case '\0':
-                r->zero_in_uri = 1;
-                break;
-            default:
-                state = sw_check_uri;
-                break;
-            }
-            break;
-
-        /* check "/", "%" and "\" (Win32) in URI */
-        case sw_check_uri:
-
-            c = (u_char) (ch | 0x20);
-            if (c >= 'a' && c <= 'z') {
-                break;
-            }
-
-            if (ch >= '0' && ch <= '9') {
-                break;
-            }
-
-            switch (ch) {
-            case '/':
-                r->uri_ext = NULL;
-                state = sw_after_slash_in_uri;
-                break;
-            case '.':
-                r->uri_ext = p + 1;
-                break;
-            case ' ':
-                r->uri_end = p;
-                state = sw_http_09;
-                break;
-            case CR:
-                r->uri_end = p;
-                r->http_minor = 9;
-                state = sw_almost_done;
-                break;
-            case LF:
-                r->uri_end = p;
-                r->http_minor = 9;
-                goto done;
-#if (NGX_WIN32)
-            case '\\':
-                r->complex_uri = 1;
-                state = sw_after_slash_in_uri;
-                break;
-#endif
-            case '%':
-                r->quoted_uri = 1;
-                state = sw_uri;
-                break;
-            case '+':
-                r->plus_in_uri = 1;
-                break;
-            case '?':
-                r->args_start = p + 1;
-                state = sw_uri;
-                break;
-            case '\0':
-                r->zero_in_uri = 1;
-                break;
-            }
-            break;
-
-        /* URI */
-        case sw_uri:
-            switch (ch) {
-            case ' ':
-                r->uri_end = p;
-                state = sw_http_09;
-                break;
-            case CR:
-                r->uri_end = p;
-                r->http_minor = 9;
-                state = sw_almost_done;
-                break;
-            case LF:
-                r->uri_end = p;
-                r->http_minor = 9;
-                goto done;
-            case '+':
-                r->plus_in_uri = 1;
-                break;
-            case '\0':
-                r->zero_in_uri = 1;
-                break;
-            }
-            break;
-
-        /* space+ after URI */
-        case sw_http_09:
-            switch (ch) {
-            case ' ':
-                break;
-            case CR:
-                r->http_minor = 9;
-                state = sw_almost_done;
-                break;
-            case LF:
-                r->http_minor = 9;
-                goto done;
-            case 'H':
-                r->http_protocol.data = p;
-                state = sw_http_H;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        case sw_http_H:
-            switch (ch) {
-            case 'T':
-                state = sw_http_HT;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        case sw_http_HT:
-            switch (ch) {
-            case 'T':
-                state = sw_http_HTT;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        case sw_http_HTT:
-            switch (ch) {
-            case 'P':
-                state = sw_http_HTTP;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        case sw_http_HTTP:
-            switch (ch) {
-            case '/':
-                state = sw_first_major_digit;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-            break;
-
-        /* first digit of major HTTP version */
-        case sw_first_major_digit:
-            if (ch < '1' || ch > '9') {
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-
-            r->http_major = ch - '0';
-            state = sw_major_digit;
-            break;
-
-        /* 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_PARSE_INVALID_REQUEST;
-            }
-
-            r->http_major = r->http_major * 10 + ch - '0';
-            break;
-
-        /* first digit of minor HTTP version */
-        case sw_first_minor_digit:
-            if (ch < '0' || ch > '9') {
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-
-            r->http_minor = ch - '0';
-            state = sw_minor_digit;
-            break;
-
-        /* minor HTTP version or end of request line */
-        case sw_minor_digit:
-            if (ch == CR) {
-                state = sw_almost_done;
-                break;
-            }
-
-            if (ch == LF) {
-                goto done;
-            }
-
-            if (ch < '0' || ch > '9') {
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-
-            r->http_minor = r->http_minor * 10 + ch - '0';
-            break;
-
-        /* end of request line */
-        case sw_almost_done:
-            r->request_end = p - 1;
-            switch (ch) {
-            case LF:
-                goto done;
-            default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
-            }
-        }
-    }
-
-    b->pos = p;
-    r->state = state;
-
-    return NGX_AGAIN;
-
-done:
-
-    b->pos = p + 1;
-
-    if (r->request_end == NULL) {
-        r->request_end = p;
-    }
-
-    r->http_version = r->http_major * 1000 + r->http_minor;
-    r->state = sw_start;
-
-    if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
-        return NGX_HTTP_PARSE_INVALID_09_METHOD;
-    }
-
-    return NGX_OK;
-}
-
-
-ngx_int_t
-ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b)
-{
-    u_char      c, ch, *p;
-    ngx_uint_t  hash;
-    enum {
-        sw_start = 0,
-        sw_name,
-        sw_space_before_value,
-        sw_value,
-        sw_space_after_value,
-        sw_ignore_line,
-        sw_almost_done,
-        sw_header_almost_done
-    } state;
-
-    state = r->state;
-    hash = r->header_hash;
-
-    for (p = b->pos; p < b->last; p++) {
-        ch = *p;
-
-        switch (state) {
-
-        /* first char */
-        case sw_start:
-            r->invalid_header = 0;
-
-            switch (ch) {
-            case CR:
-                r->header_end = p;
-                state = sw_header_almost_done;
-                break;
-            case LF:
-                r->header_end = p;
-                goto header_done;
-            default:
-                state = sw_name;
-                r->header_name_start = p;
-
-                c = (u_char) (ch | 0x20);
-                if (c >= 'a' && c <= 'z') {
-                    hash = c;
-                    break;
-                }
-
-                if (ch >= '0' && ch <= '9') {
-                    hash = ch;
-                    break;
-                }
-
-                r->invalid_header = 1;
-
-                break;
-
-            }
-            break;
-
-        /* header name */
-        case sw_name:
-            c = (u_char) (ch | 0x20);
-            if (c >= 'a' && c <= 'z') {
-                hash += c;
-                break;
-            }
-
-            if (ch == ':') {
-                r->header_name_end = p;
-                state = sw_space_before_value;
-                break;
-            }
-
-            if (ch == '-') {
-                hash += ch;
-                break;
-            }
-
-            if (ch >= '0' && ch <= '9') {
-                hash += ch;
-                break;
-            }
-
-            if (ch == CR) {
-                r->header_name_end = p;
-                r->header_start = p;
-                r->header_end = p;
-                state = sw_almost_done;
-                break;
-            }
-
-            if (ch == LF) {
-                r->header_name_end = p;
-                r->header_start = p;
-                r->header_end = p;
-                goto done;
-            }
-
-            /* IIS may send the duplicate "HTTP/1.1 ..." lines */
-            if (ch == '/'
-                && r->upstream
-                && p - r->header_name_start == 4
-                && ngx_strncmp(r->header_name_start, "HTTP", 4) == 0)
-            {
-                state = sw_ignore_line;
-                break;
-            }
-
-            r->invalid_header = 1;
-
-            break;
-
-        /* space* before header value */
-        case sw_space_before_value:
-            switch (ch) {
-            case ' ':
-                break;
-            case CR:
-                r->header_start = p;
-                r->header_end = p;
-                state = sw_almost_done;
-                break;
-            case LF:
-                r->header_start = p;
-                r->header_end = p;
-                goto done;
-            default:
-                r->header_start = p;
-                state = sw_value;
-                break;
-            }
-            break;
-
-        /* header value */
-        case sw_value:
-            switch (ch) {
-            case ' ':
-                r->header_end = p;
-                state = sw_space_after_value;
-                break;
-            case CR:
-                r->header_end = p;
-                state = sw_almost_done;
-                break;
-            case LF:
-                r->header_end = p;
-                goto done;
-            }
-            break;
-
-        /* space* before end of header line */
-        case sw_space_after_value:
-            switch (ch) {
-            case ' ':
-                break;
-            case CR:
-                state = sw_almost_done;
-                break;
-            case LF:
-                goto done;
-            default:
-                state = sw_value;
-                break;
-            }
-            break;
-
-        /* ignore header line */
-        case sw_ignore_line:
-            switch (ch) {
-            case LF:
-                state = sw_start;
-                break;
-            default:
-                break;
-            }
-            break;
-
-        /* end of header line */
-        case sw_almost_done:
-            switch (ch) {
-            case CR:
-                break;
-            case LF:
-                goto done;
-            default:
-                return NGX_HTTP_PARSE_INVALID_HEADER;
-            }
-
-        /* end of header */
-        case sw_header_almost_done:
-            switch (ch) {
-            case LF:
-                goto header_done;
-            default:
-                return NGX_HTTP_PARSE_INVALID_HEADER;
-            }
-        }
-    }
-
-    b->pos = p;
-    r->state = state;
-    r->header_hash = hash;
-
-    return NGX_AGAIN;
-
-done:
-
-    b->pos = p + 1;
-    r->state = sw_start;
-    r->header_hash = hash;
-
-    return NGX_OK;
-
-header_done:
-
-    b->pos = p + 1;
-    r->state = sw_start;
-
-    return NGX_HTTP_PARSE_HEADER_DONE;
-}
-
-
-ngx_int_t
-ngx_http_parse_complex_uri(ngx_http_request_t *r)
-{
-    u_char  c, ch, decoded, *p, *u;
-    enum {
-        sw_usual = 0,
-        sw_slash,
-        sw_dot,
-        sw_dot_dot,
-#if (NGX_WIN32)
-        sw_dot_dot_dot,
-#endif
-        sw_quoted,
-        sw_quoted_second
-    } state, quoted_state;
-
-#if (NGX_SUPPRESS_WARN)
-    decoded = '\0';
-    quoted_state = sw_usual;
-#endif
-
-    state = sw_usual;
-    p = r->uri_start;
-    u = r->uri.data;
-    r->uri_ext = NULL;
-    r->args_start = NULL;
-
-    ch = *p++;
-
-    while (p <= r->uri_end) {
-
-        /*
-         * we use "ch = *p++" inside the cycle, but this operation is safe,
-         * because after the URI there is always at least one charcter:
-         * the line feed
-         */
-
-        ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "s:%d in:'%Xd:%c', out:'%c'", state, ch, ch, *u);
-
-        switch (state) {
-
-        case sw_usual:
-            switch(ch) {
-#if (NGX_WIN32)
-            case '\\':
-                r->uri_ext = NULL;
-
-                if (p == r->uri_start + r->uri.len) {
-
-                    /*
-                     * we omit the last "\" to cause redirect because
-                     * the browsers do not treat "\" as "/" in relative URL path
-                     */
-
-                    break;
-                }
-
-                state = sw_slash;
-                *u++ = '/';
-                break;
-#endif
-            case '/':
-                r->uri_ext = NULL;
-                state = sw_slash;
-                *u++ = ch;
-                break;
-            case '%':
-                quoted_state = state;
-                state = sw_quoted;
-                break;
-            case '?':
-                r->args_start = p;
-                goto done;
-            case '.':
-                r->uri_ext = u + 1;
-                *u++ = ch;
-                break;
-            default:
-                *u++ = ch;
-                break;
-            }
-            ch = *p++;
-            break;
-
-        case sw_slash:
-            switch(ch) {
-#if (NGX_WIN32)
-            case '\\':
-#endif
-            case '/':
-                break;
-            case '.':
-                state = sw_dot;
-                *u++ = ch;
-                break;
-            case '%':
-                quoted_state = state;
-                state = sw_quoted;
-                break;
-            case '?':
-                r->args_start = p;
-                goto done;
-            default:
-                state = sw_usual;
-                *u++ = ch;
-                break;
-            }
-            ch = *p++;
-            break;
-
-        case sw_dot:
-            switch(ch) {
-#if (NGX_WIN32)
-            case '\\':
-#endif
-            case '/':
-                state = sw_slash;
-                u--;
-                break;
-            case '.':
-                state = sw_dot_dot;
-                *u++ = ch;
-                break;
-            case '%':
-                quoted_state = state;
-                state = sw_quoted;
-                break;
-            case '?':
-                r->args_start = p;
-                goto done;
-            default:
-                state = sw_usual;
-                *u++ = ch;
-                break;
-            }
-            ch = *p++;
-            break;
-
-        case sw_dot_dot:
-            switch(ch) {
-#if (NGX_WIN32)
-            case '\\':
-#endif
-            case '/':
-                state = sw_slash;
-                u -= 4;
-                if (u < r->uri.data) {
-                    return NGX_HTTP_PARSE_INVALID_REQUEST;
-                }
-                while (*(u - 1) != '/') {
-                    u--;
-                }
-                break;
-            case '%':
-                quoted_state = state;
-                state = sw_quoted;
-                break;
-            case '?':
-                r->args_start = p;
-                goto done;
-#if (NGX_WIN32)
-            case '.':
-                state = sw_dot_dot_dot;
-                *u++ = ch;
-                break;
-#endif
-            default:
-                state = sw_usual;
-                *u++ = ch;
-                break;
-            }
-            ch = *p++;
-            break;
-
-#if (NGX_WIN32)
-        case sw_dot_dot_dot:
-            switch(ch) {
-            case '\\':
-            case '/':
-                state = sw_slash;
-                u -= 5;
-                if (u < r->uri.data) {
-                    return NGX_HTTP_PARSE_INVALID_REQUEST;
-                }
-                while (*u != '/') {
-                    u--;
-                }
-                if (u < r->uri.data) {
-                    return NGX_HTTP_PARSE_INVALID_REQUEST;
-                }
-                while (*(u - 1) != '/') {
-                    u--;
-                }
-                break;
-            case '%':
-                quoted_state = state;
-                state = sw_quoted;
-                break;
-            case '?':
-                r->args_start = p;
-                goto done;
-            default:
-                state = sw_usual;
-                *u++ = ch;
-                break;
-            }
-            ch = *p++;
-            break;
-#endif
-
-        case sw_quoted:
-            if (ch >= '0' && ch <= '9') {
-                decoded = (u_char) (ch - '0');
-                state = sw_quoted_second;
-                ch = *p++;
-                break;
-            }
-
-            c = (u_char) (ch | 0x20);
-            if (c >= 'a' && c <= 'f') {
-                decoded = (u_char) (c - 'a' + 10);
-                state = sw_quoted_second;
-                ch = *p++;
-                break;
-            }
-
-            return NGX_HTTP_PARSE_INVALID_REQUEST;
-
-        case sw_quoted_second:
-            if (ch >= '0' && ch <= '9') {
-                ch = (u_char) ((decoded << 4) + ch - '0');
-
-                if (ch == '%') {
-                    state = sw_usual;
-                    *u++ = ch;
-                    ch = *p++;
-                    break;
-                }
-
-                if (ch == '\0') {
-                    r->zero_in_uri = 1;
-                    *u++ = ch;
-                    ch = *p++;
-                }
-
-                state = quoted_state;
-                break;
-            }
-
-            c = (u_char) (ch | 0x20);
-            if (c >= 'a' && c <= 'f') {
-                ch = (u_char) ((decoded << 4) + c - 'a' + 10);
-                if (ch == '?') {
-                    *u++ = ch;
-                    ch = *p++;
-                }
-                state = quoted_state;
-                break;
-            }
-
-            return NGX_HTTP_PARSE_INVALID_REQUEST;
-        }
-    }
-
-done:
-
-    r->uri.len = u - r->uri.data;
-    r->uri.data[r->uri.len] = '\0';
-
-    if (r->uri_ext) {
-        r->exten.len = u - r->uri_ext;
-        r->exten.data = r->uri_ext;
-    }
-
-    r->uri_ext = NULL;
-
-    return NGX_OK;
-}
-
-
-ngx_int_t
-ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
-    ngx_str_t *args, ngx_uint_t *flags)
-{
-    u_char  ch, *p;
-    size_t  len;
-
-    len = uri->len;
-    p = uri->data;
-
-    if (len == 0 || p[0] == '?') {
-        goto unsafe;
-    }
-
-    if (p[0] == '.' && len == 3 && p[1] == '.' && (p[2] == '/'
-#if (NGX_WIN32)
-                                                   || p[2] == '\\'
-#endif
-        ))
-    {
-        goto unsafe;
-    }
-
-    for ( /* void */ ; len; len--) {
-
-        ch = *p++;
-
-        if (ch == '?') {
-            args->len = len - 1;
-            args->data = p;
-            uri->len -= len;
-
-            return NGX_OK;
-        }
-
-        if (ch == '\0') {
-            *flags |= NGX_HTTP_ZERO_IN_URI;
-            continue;
-        }
-
-        if (ch != '/'
-#if (NGX_WIN32)
-            && ch != '\\'
-#endif
-            )
-        {
-            continue;
-        }
-
-        if (len > 2) {
-
-            /* detect "/../" */
-
-            if (p[0] == '.' && p[1] == '.' && p[2] == '/') {
-                goto unsafe;
-            }
-
-#if (NGX_WIN32)
-
-            if (p[2] == '\\') {
-                goto unsafe;
-            }
-
-            if (len > 3) {
-
-                /* detect "/.../" */
-
-                if (p[0] == '.' && p[1] == '.' && p[2] == '.'
-                    && (p[3] == '/' || p[3] == '\\'))
-                {
-                    goto unsafe;
-                }
-            }
-#endif
-        }
-    }
-
-    return NGX_OK;
-
-unsafe:
-
-    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                  "unsafe URI \"%V\" was detected", uri);
-
-    return NGX_ERROR;
-}
-
-
-ngx_int_t
-ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
-    ngx_str_t *value)
-{
-    ngx_uint_t         i;
-    u_char            *start, *last, *end, ch;
-    ngx_table_elt_t  **h;
-
-    h = headers->elts;
-
-    for (i = 0; i < headers->nelts; i++) {
-
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0,
-                       "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
-
-        if (name->len > h[i]->value.len) {
-            continue;
-        }
-
-        start = h[i]->value.data;
-        end = h[i]->value.data + h[i]->value.len;
-
-        while (start < end) {
-
-            if (ngx_strncasecmp(start, name->data, name->len) != 0) {
-                goto skip;
-            }
-
-            for (start += name->len; start < end && *start == ' '; start++) {
-                /* void */
-            }
-
-            if (value == NULL) {
-                if (start == end || *start == ',') {
-                    return i;
-                }
-
-                goto skip;
-            }
-
-            if (start == end || *start++ != '=') {
-                /* the invalid header value */
-                goto skip;
-            }
-
-            while (start < end && *start == ' ') { start++; }
-
-            for (last = start; last < end && *last != ';'; last++) {
-                /* void */
-            }
-
-            value->len = last - start;
-            value->data = start;
-
-            return i;
-
-        skip:
-
-            while (start < end) {
-                ch = *start++;
-                if (ch == ';' || ch == ',') {
-                    break;
-                }
-            }
-
-            while (start < end && *start == ' ') { start++; }
-        }
-    }
-
-    return NGX_DECLINED;
-}
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -410,6 +410,8 @@ void ngx_http_init_request(ngx_event_t *
 
     r->start_time = ngx_time();
 
+    r->method = NGX_HTTP_UNKNOWN;
+
     r->headers_in.content_length_n = -1;
     r->headers_in.keep_alive_n = -1;
     r->headers_out.content_length_n = -1;
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -19,9 +19,10 @@
 #define NGX_HTTP_VERSION_10                1000
 #define NGX_HTTP_VERSION_11                1001
 
-#define NGX_HTTP_GET                       1
-#define NGX_HTTP_HEAD                      2
-#define NGX_HTTP_POST                      3
+#define NGX_HTTP_UNKNOWN                   1
+#define NGX_HTTP_GET                       2
+#define NGX_HTTP_HEAD                      4
+#define NGX_HTTP_POST                      8
 
 #define NGX_HTTP_CONNECTION_CLOSE          1
 #define NGX_HTTP_CONNECTION_KEEP_ALIVE     2
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -588,8 +588,15 @@ ngx_http_script_regex_start_code(ngx_htt
         e->ncaptures = 0;
 
         if (code->test) {
-            e->sp->len = 0;
-            e->sp->data = (u_char *) "";
+            if (code->negative_test) {
+                e->sp->len = 1;
+                e->sp->data = (u_char *) "1";
+
+            } else {
+                e->sp->len = 0;
+                e->sp->data = (u_char *) "";
+            }
+
             e->sp++;
 
             e->ip += sizeof(ngx_http_script_regex_code_t);
@@ -618,8 +625,15 @@ ngx_http_script_regex_start_code(ngx_htt
     e->ncaptures = code->ncaptures;
 
     if (code->test) {
-        e->sp->len = 1;
-        e->sp->data = (u_char *) "1";
+        if (code->negative_test) {
+            e->sp->len = 0;
+            e->sp->data = (u_char *) "";
+
+        } else {
+            e->sp->len = 1;
+            e->sp->data = (u_char *) "1";
+        }
+
         e->sp++;
 
         e->ip += sizeof(ngx_http_script_regex_code_t);
@@ -911,6 +925,69 @@ ngx_http_script_not_equal_code(ngx_http_
 
 
 void
+ngx_http_script_file_code(ngx_http_script_engine_t *e)
+{
+    ngx_err_t                     err;
+    ngx_file_info_t               fi;
+    ngx_http_variable_value_t    *value;
+    ngx_http_script_file_code_t  *code;
+
+    value = e->sp - 1;
+
+    code = (ngx_http_script_file_code_t *) e->ip;
+    e->ip += sizeof(ngx_http_script_file_code_t);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script file op %p", code->op);
+
+    if (ngx_file_info(value->data, &fi) == -1) {
+        err = ngx_errno;
+
+        if (err != NGX_ENOENT && err != NGX_ENOTDIR) {
+            ngx_log_error(NGX_LOG_CRIT, e->request->connection->log, err,
+                          ngx_file_info_n " \"%s\" failed", value->data);
+        }
+
+        switch (code->op) {
+        case ngx_http_script_file_plain:
+             goto false;
+        case ngx_http_script_file_not_plain:
+             goto true;
+        }
+
+        goto false;
+    }
+
+    switch (code->op) {
+    case ngx_http_script_file_plain:
+        if (ngx_is_file(&fi)) {
+             goto true;
+        }
+        goto false;
+
+    case ngx_http_script_file_not_plain:
+        if (ngx_is_file(&fi)) {
+            goto false;
+        }
+        goto true;
+    }
+
+false:
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script file op false");
+
+    *value = ngx_http_variable_null_value;
+    return;
+
+true:
+
+    *value = ngx_http_variable_true_value;
+    return;
+}
+
+
+void
 ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
 {
     size_t                                 len;
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -52,7 +52,6 @@ typedef struct {
     void                       *main;
 
     unsigned                    compile_args:1;
-    unsigned                    compile_null:1;
     unsigned                    complete_lengths:1;
     unsigned                    complete_values:1;
 
@@ -94,6 +93,7 @@ typedef struct {
     uintptr_t                        next;
 
     uintptr_t                        test:1;
+    uintptr_t                        negative_test:1;
     uintptr_t                        uri:1;
     uintptr_t                        args:1;
 
@@ -129,6 +129,18 @@ typedef struct {
 } ngx_http_script_return_code_t;
 
 
+typedef enum {
+    ngx_http_script_file_plain = 0,
+    ngx_http_script_file_not_plain
+} ngx_http_script_file_op_e;
+
+
+typedef struct {
+    ngx_http_script_code_pt          code;
+    uintptr_t                        op;
+} ngx_http_script_file_code_t;
+
+
 typedef struct {
     ngx_http_script_code_pt          code;
     uintptr_t                        next;
@@ -177,6 +189,7 @@ void ngx_http_script_break_code(ngx_http
 void ngx_http_script_if_code(ngx_http_script_engine_t *e);
 void ngx_http_script_equal_code(ngx_http_script_engine_t *e);
 void ngx_http_script_not_equal_code(ngx_http_script_engine_t *e);
+void ngx_http_script_file_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);
 void ngx_http_script_set_var_code(ngx_http_script_engine_t *e);