]> git.kaiwu.me - nginx.git/commitdiff
nginx-0.1.17-RELEASE import release-0.1.17
authorIgor Sysoev <igor@sysoev.ru>
Thu, 3 Feb 2005 19:33:37 +0000 (19:33 +0000)
committerIgor Sysoev <igor@sysoev.ru>
Thu, 3 Feb 2005 19:33:37 +0000 (19:33 +0000)
    *) Change: the ngx_http_rewrite_module was rewritten from the scratch.
       Now it is possible to redirect, to return the error codes, to check
       the variables and referrers. The directives can be used inside
       locations. The redirect directive was canceled.

    *) Feature: the ngx_http_geo_module.

    *) Feature: the proxy_set_x_var and fastcgi_set_var directives.

    *) Bugfix: the location configuration with "=" modifier may be used in
       another location.

    *) Bugfix: the correct content type was set only for requests that use
       small caps letters in extension.

    *) Bugfix: if the proxy_pass or fastcgi_pass directives were set in the
       location, and access was denied, and the error was redirected to a
       static page, then the segmentation fault occurred.

    *) Bugfix: if in a proxied "Location" header was a relative URL, then a
       host name and a slash were added to them; the bug had appeared in
       0.1.14.

    *) Bugfix: the system error message was not logged on Linux.

35 files changed:
auto/cc/gcc
auto/modules
auto/options
auto/sources
auto/unix
docs/xml/nginx/changes.xml
src/core/nginx.h
src/core/ngx_array.c
src/core/ngx_array.h
src/core/ngx_conf_file.c
src/core/ngx_config.h
src/core/ngx_core.h
src/core/ngx_palloc.c
src/core/ngx_palloc.h
src/core/ngx_radix_tree.c
src/core/ngx_radix_tree.h
src/core/ngx_string.c
src/core/ngx_string.h
src/http/modules/ngx_http_access_handler.c
src/http/modules/ngx_http_fastcgi_handler.c
src/http/modules/ngx_http_geo_module.c [new file with mode: 0644]
src/http/modules/ngx_http_gzip_filter.c
src/http/modules/ngx_http_rewrite_handler.c
src/http/modules/ngx_http_ssl_module.c
src/http/modules/proxy/ngx_http_proxy_handler.c
src/http/modules/proxy/ngx_http_proxy_handler.h
src/http/modules/proxy/ngx_http_proxy_upstream.c
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_log_handler.c
src/http/ngx_http_parse.c
src/http/ngx_http_request.h
src/http/ngx_http_upstream.c

index d5bf1dc3d207a0db809bd25ba2d7ced71614e6e0..24b908d26a872740b7b6c8e2b61f8645a79dd962 100644 (file)
@@ -28,6 +28,7 @@ fi
 # optimizations
 
 #CFLAGS="$CFLAGS -O2 -fomit-frame-pointer"
+#CFLAGS="$CFLAGS -Os -fomit-frame-pointer"
 
 case $CPU in
     pentium)
index 3221e26f19ae44b33b6e352f369ab15a7d93c72e..375b755f0b32748c48ff91f47def3993a7b13484 100644 (file)
@@ -116,6 +116,12 @@ if [ $HTTP_STATUS = YES ]; then
     HTTP_SRCS="$HTTP_SRCS $HTTP_STATUS_SRCS"
 fi
 
+if [ $HTTP_GEO = YES ]; then
+    have=NGX_HTTP_GEO . auto/have
+    HTTP_MODULES="$HTTP_MODULES $HTTP_GEO_MODULE"
+    HTTP_SRCS="$HTTP_SRCS $HTTP_GEO_SRCS"
+fi
+
 if [ $HTTP_REWRITE = YES -a $USE_PCRE != DISABLED ]; then
     have=NGX_HTTP_REWRITE . auto/have
     USE_PCRE=YES
index 3d552df77b7c5ce0dbc4fa72c985c20fb245f5e2..9aff6e228182e3700b72d6568730042196f5c511 100644 (file)
@@ -53,6 +53,7 @@ HTTP_ACCESS=YES
 HTTP_USERID=YES
 HTTP_AUTOINDEX=YES
 HTTP_STATUS=NO
+HTTP_GEO=YES
 HTTP_REWRITE=YES
 HTTP_PROXY=YES
 HTTP_FASTCGI=YES
@@ -125,6 +126,7 @@ do
         --without-http_access_module)    HTTP_ACCESS=NO             ;;
         --without-http_autoindex_module) HTTP_AUTOINDEX=NO          ;;
         --without-http_status_module)    HTTP_STATUS=NO             ;;
+        --without-http_geo_module)       HTTP_GEO=NO                ;;
         --without-http_rewrite_module)   HTTP_REWRITE=NO            ;;
         --without-http_proxy_module)     HTTP_PROXY=NO              ;;
         --without-http_fastcgi_module)   HTTP_FASTCGI=NO            ;;
@@ -198,6 +200,7 @@ cat << END
   --without-http_userid_module       disable ngx_http_userid_module
   --without-http_access_module       disable ngx_http_access_module
   --without-http_autoindex_module    disable ngx_http_autoindex_module
+  --without-http_geo_module          disable ngx_http_geo_module
   --without-http_rewrite_module      disable ngx_http_rewrite_module
   --without-http_proxy_module        disable ngx_http_proxy_module
   --without-http_fastcgi_module      disable ngx_http_fastcgi_module
index c61d83af3327a708cfea453108d0ee3b59c4babc..ac177f1df989b5e53d378718ef059206d3dc2f1b 100644 (file)
@@ -21,14 +21,13 @@ CORE_DEPS="src/core/nginx.h \
            src/core/ngx_file.h \
            src/core/ngx_crc.h \
            src/core/ngx_rbtree.h \
+           src/core/ngx_radix_tree.h \
            src/core/ngx_times.h \
            src/core/ngx_connection.h \
            src/core/ngx_cycle.h \
            src/core/ngx_conf_file.h \
            src/core/ngx_garbage_collector.h"
 
-#           src/core/ngx_radix_tree.h \
-#           src/core/ngx_radix_tree.c \
 
 CORE_SRCS="src/core/nginx.c \
            src/core/ngx_log.c \
@@ -42,6 +41,7 @@ CORE_SRCS="src/core/nginx.c \
            src/core/ngx_inet.c \
            src/core/ngx_file.c \
            src/core/ngx_rbtree.c \
+           src/core/ngx_radix_tree.c \
            src/core/ngx_times.c \
            src/core/ngx_connection.c \
            src/core/ngx_cycle.c \
@@ -296,6 +296,10 @@ HTTP_STATUS_MODULE=ngx_http_status_module
 HTTP_STATUS_SRCS=src/http/modules/ngx_http_status_handler.c
 
 
+HTTP_GEO_MODULE=ngx_http_geo_module
+HTTP_GEO_SRCS=src/http/modules/ngx_http_geo_module.c
+
+
 HTTP_REWRITE_MODULE=ngx_http_rewrite_module
 HTTP_REWRITE_SRCS=src/http/modules/ngx_http_rewrite_handler.c
 
index 37bb5d2c61bd8e1898f8ed1163c212f99f01dbbb..406f2a23f578953d1f31ab0a637f0edb14130767 100755 (executable)
--- a/auto/unix
+++ b/auto/unix
@@ -94,8 +94,8 @@ ngx_feature_name="NGX_HAVE_STRERROR_R"
 ngx_feature_run=yes
 ngx_feature_incs="#include <string.h>"
 ngx_feature_libs=
-ngx_feature_test="char buf[32]; int n; n = strerror_r(1, buf, 32);
-                  if (n > 32) return 1;"
+ngx_feature_test="char buf[1024]; long n; n = strerror_r(1, buf, 1024);
+                  if (n < 0 || n > 1024) return 1;"
 . auto/feature
 
 
@@ -106,8 +106,8 @@ ngx_feature_name="NGX_HAVE_GNU_STRERROR_R"
 ngx_feature_run=yes
 ngx_feature_incs="#include <string.h>"
 ngx_feature_libs=
-ngx_feature_test="char buf[32]; int n; n = strerror_r(1, buf, 32);
-                  if (n < 32) return 1;"
+ngx_feature_test="char buf[1024]; long n; n = strerror_r(1, buf, 1024);
+                  if (n >= 0 && n < 1024) return 1;"
 . auto/feature
 
 
index eb466d82364c40304a6a343002e8505854813904..7323d48e95c676b5890c58c4f65cfce7658b8e4e 100644 (file)
@@ -9,6 +9,103 @@
 <title lang="en">nginx changelog</title>
 
 
+<changes ver="0.1.17" date="03.02.2005">
+
+<change type="feature">
+<para lang="ru">
+ÍÏÄÕÌØ ngx_http_rewrite_module ÐÏÌÎÏÓÔØÀ ÐÅÒÅÐÉÓÁÎ.
+ôÅÐÅÒØ ÍÏÖÎÏ ÄÅÌÁÔØ ÒÅÄÉÒÅËÔÙ, ×ÏÚ×ÒÁÝÁÔØ ËÏÄÙ ÏÛÉÂÏË
+É ÐÒÏ×ÅÒÑÔØ ÐÅÒÅÍÅÎÎÙÅ É ÒÅÆÅÒÅÒÙ.
+üÔÉ ÄÉÒÅËÔÉ×Ù ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ ×ÎÕÔÒÉ location.
+äÉÒÅËÔÉ×Á redirect ÕÐÒÁÚÄÎÅÎÁ.
+</para>
+<para lang="en">
+the ngx_http_rewrite_module was rewritten from the scratch.
+Now it is possible to redirect, to return the error codes,
+to check the variables and referrers. The directives can be used
+inside locations.
+The redirect directive was canceled.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÍÏÄÕÌØ ngx_http_geo_module.
+</para>
+<para lang="en">
+the ngx_http_geo_module.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+ÄÉÒÅËÔÉ×Ù proxy_set_x_var É fastcgi_set_var.
+</para>
+<para lang="en">
+the proxy_set_x_var and fastcgi_set_var directives.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ËÏÎÆÉÇÕÒÁÃÉÑ location Ó ÍÏÄÉÆÉËÁÔÏÒÏÍ "=" ÍÏÇÌÁ ÉÓÐÏÌØÚÏ×ÁÔØÓÑ
+× ÄÒÕÇÏÍ location.
+</para>
+<para lang="en">
+the location configuration with "=" modifier may be used in another
+location.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÐÒÁ×ÉÌØÎÙÊ ÔÉРÏÔ×ÅÔÁ ×ÙÓÔÁ×ÌÑÌÓÑ ÔÏÌØËÏ ÄÌÑ ÚÁÐÒÏÓÏ×, Õ ËÏÔÏÒÙÈ × ÒÁÓÛÉÒÅÎÉÉ
+ÂÙÌÉ ÔÏÌØËÏ ÍÁÌÅÎØËÉÅ ÂÕË×Ù.
+</para>
+<para lang="en">
+the correct content type was set only for requests that use small caps letters
+in extension.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÅÓÌÉ ÄÌÑ location ÕÓÔÁÎÏ×ÌÅΠproxy_pass ÉÌÉ fastcgi_pass, É ÄÏÓÔÕÐ
+Ë ÎÅÍÕ ÚÁÐÒÅÝÁÌÓÑ, Á ÏÛÉÂËÁ ÐÅÒÅÎÁÐÒÁ×ÌÑÌÁÓØ ÎÁ ÓÔÁÔÉÞÅÓËÕÀ ÓÔÒÁÎÉÃÕ,
+ÔÏ ÐÒÏÉÓÈÏÄÉÌ segmentation fault.
+</para>
+<para lang="en">
+if the proxy_pass or fastcgi_pass directives were set in the location,
+and access was denied, and the error was redirected to a static page,
+then the segmentation fault occurred.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÅÓÌÉ × ÐÒÏËÓÉÒÏ×ÁÎÎÏÍ ÏÔ×ÅÔÅ × ÚÁÇÏÌÏ×ËÅ "Location" ÐÅÒÅÄÁ×ÁÌÓÑ
+ÏÔÎÏÓÉÔÅÌØÎÙÊ URL, ÔÏ Ë ÎÅÍÕ ÄÏÂÁ×ÌÑÌÏÓØ ÉÍÑ ÈÏÓÔÁ É ÓÌÜÛ;
+ÏÛÉÂËÁ ÐÏÑ×ÉÌÁÓØ × 0.1.14.
+</para>
+<para lang="en">
+if in a proxied "Location" header was a relative URL,
+then a host name and a slash were added to them;
+bug appeared in 0.1.14.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+ÎÁ Linux × ÌÏÇ ÎÅ ÚÁÐÉÓÙ×ÁÌÓÑ ÔÅËÓÔ ÓÉÓÔÅÍÎÏÊ ÏÛÉÂËÉ.
+</para>
+<para lang="en">
+the system error message was not logged on Linux.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="0.1.16" date="25.01.2005">
 
 <change type="bugfix">
index 0b9d9905cc881e27ef018d8ae5ec7699c7795642..c6afc459918b2c409bd20b4620cdbf5e4988ccb8 100644 (file)
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.1.16"
+#define NGINX_VER          "nginx/0.1.17"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_NEWPID_EXT     ".newbin"
index 6eae76ffdf4572ed52ff9e2d2ac1eb003ceda54d..82d5d1db816b7132e22a278df36e7bfaaf322c99 100644 (file)
 #include <ngx_core.h>
 
 
-ngx_array_t *ngx_create_array(ngx_pool_t *p, ngx_uint_t n, size_t size)
+ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
 {
     ngx_array_t *a;
 
-    ngx_test_null(a, ngx_palloc(p, sizeof(ngx_array_t)), NULL);
+    if (!(a = ngx_palloc(p, sizeof(ngx_array_t)))) {
+        return NULL;
+    }
 
-    ngx_test_null(a->elts, ngx_palloc(p, n * size), NULL);
+    if (!(a->elts = ngx_palloc(p, n * size))) {
+        return NULL;
+    }
 
-    a->pool = p;
     a->nelts = 0;
-    a->nalloc = n;
     a->size = size;
+    a->nalloc = n;
+    a->pool = p;
 
     return a;
 }
 
 
-void ngx_destroy_array(ngx_array_t *a)
+void ngx_array_destroy(ngx_array_t *a)
 {
     ngx_pool_t  *p;
 
     p = a->pool;
 
-    if ((char *) a->elts + a->size * a->nalloc == p->last) {
+    if ((u_char *) a->elts + a->size * a->nalloc == p->last) {
         p->last -= a->size * a->nalloc;
     }
 
-    if ((char *) a + sizeof(ngx_array_t) == p->last) {
-        p->last = (char *) a;
+    if ((u_char *) a + sizeof(ngx_array_t) == p->last) {
+        p->last = (u_char *) a;
     }
 }
 
 
-void *ngx_push_array(ngx_array_t *a)
+void *ngx_array_push(ngx_array_t *a)
 {
     void        *elt, *new;
+    size_t       size;
     ngx_pool_t  *p;
 
-    /* array is full */
     if (a->nelts == a->nalloc) {
+
+        /* the array is full */
+
+        size = a->size * a->nalloc;
+
         p = a->pool;
 
-        /* array allocation is the last in the pool */
-        if ((char *) a->elts + a->size * a->nelts == p->last
-            && (unsigned) (p->end - p->last) >= a->size)
+        if ((u_char *) a->elts + size == p->last && p->last + a->size <= p->end)
         {
+            /*
+             * the array allocation is the last in the pool
+             * and there is space for new allocation
+             */
+
             p->last += a->size;
             a->nalloc++;
 
-        /* allocate new array */
         } else {
-            ngx_test_null(new, ngx_palloc(p, 2 * a->nalloc * a->size), NULL);
+            /* allocate a new array */
+
+            if (!(new = ngx_palloc(p, 2 * size))) {
+                return NULL;
+            }
 
-            ngx_memcpy(new, a->elts, a->nalloc * a->size);
+            ngx_memcpy(new, a->elts, size);
             a->elts = new;
             a->nalloc *= 2;
         }
     }
 
-    elt = (char *) a->elts + a->size * a->nelts;
+    elt = (u_char *) a->elts + a->size * a->nelts;
     a->nelts++;
 
     return elt;
 }
+
+
+void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
+{
+    void        *elt, *new;
+    size_t       size;
+    ngx_uint_t   nalloc;
+    ngx_pool_t  *p;
+
+    size = n * a->size;
+
+    if (a->nelts + n > a->nalloc) {
+
+        /* the array is full */
+
+        p = a->pool;
+
+        if ((u_char *) a->elts + a->size * a->nalloc == p->last
+            && p->last + size <= p->end)
+        {
+            /*
+             * the array allocation is the last in the pool
+             * and there is space for new allocation
+             */
+
+            p->last += size;
+            a->nalloc += n;
+
+        } else {
+            /* allocate a new array */
+
+            nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);
+
+            if (!(new = ngx_palloc(p, nalloc * a->size))) {
+                return NULL;
+            }
+
+            ngx_memcpy(new, a->elts, a->nelts * a->size);
+            a->elts = new;
+            a->nalloc = nalloc;
+        }
+    }
+
+    elt = (u_char *) a->elts + a->size * a->nelts;
+    a->nelts += n;
+
+    return elt;
+}
index 931c7fb50a2204a988fc48f7a29b24b4bc3a5bc5..d90cf76f07862a6c9bcf65b397ed0ddb4c1bea90 100644 (file)
@@ -21,9 +21,10 @@ struct ngx_array_s {
 };
 
 
-ngx_array_t *ngx_create_array(ngx_pool_t *p, ngx_uint_t n, size_t size);
-void ngx_destroy_array(ngx_array_t *a);
-void *ngx_push_array(ngx_array_t *a);
+ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
+void ngx_array_destroy(ngx_array_t *a);
+void *ngx_array_push(ngx_array_t *a);
+void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
 
 
 static ngx_inline ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool,
@@ -42,13 +43,14 @@ static ngx_inline ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool,
 }
 
 
-
+/* STUB */
 #define ngx_init_array(a, p, n, s, rc)                                       \
     ngx_test_null(a.elts, ngx_palloc(p, n * s), rc);                         \
     a.nelts = 0; a.size = s; a.nalloc = n; a.pool = p;
 
-#define ngx_array_create  ngx_create_array
-#define ngx_array_push    ngx_push_array
+#define ngx_create_array  ngx_array_create
+#define ngx_push_array    ngx_array_push
+/**/
 
 
 #endif /* _NGX_ARRAY_H_INCLUDED_ */
index 19a567f688870c9bc9e6a0e5138cc8442441b41b..e9cc24de52986570911d0b473e95b66e54f5ce13 100644 (file)
@@ -87,7 +87,8 @@ char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
                           ngx_fd_info_n " \"%s\" failed", filename->data);
         }
 
-        if (!(cf->conf_file->buffer = ngx_create_temp_buf(cf->pool, 1024))) {
+        cf->conf_file->buffer = ngx_create_temp_buf(cf->pool, ngx_pagesize);
+        if (cf->conf_file->buffer == NULL) {
             return NGX_CONF_ERROR;
         }
 
index fcef373c3e68ead80883fe0b7c74ea3bfe6ff0bb..dc791d406dd1f58e6915fa6511819339f48a3ec6 100644 (file)
@@ -105,7 +105,7 @@ typedef long               ngx_flag_t;
 
 #endif
 
-#define ngx_align(p)    (char *) ((NGX_ALIGN_CAST p + NGX_ALIGN) & ~NGX_ALIGN)
+#define ngx_align(p)    (u_char *) ((NGX_ALIGN_CAST p + NGX_ALIGN) & ~NGX_ALIGN)
 
 
 /* TODO: auto_conf: ngx_inline   inline __inline __inline__ */
index db43a4438b011bd6215b0c67a19aad126253c82b..13053f2003e1a2857786b5a06333c44927b24347 100644 (file)
@@ -59,6 +59,7 @@ typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
 #include <ngx_regex.h>
 #endif
 #include <ngx_rbtree.h>
+#include <ngx_radix_tree.h>
 #include <ngx_times.h>
 #include <ngx_inet.h>
 #if (NGX_HAVE_UNIX_DOMAIN)
index c1b55e552f736e8a2159502e7509715aba365e32..fc6f36e839c982678d459099795ff62a864dd358 100644 (file)
@@ -16,8 +16,8 @@ ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log)
        return NULL;
     }
 
-    p->last = (char *) p + sizeof(ngx_pool_t);
-    p->end = (char *) p + size;
+    p->last = (u_char *) p + sizeof(ngx_pool_t);
+    p->end = (u_char *) p + size;
     p->next = NULL;
     p->large = NULL;
     p->log = log;
@@ -70,12 +70,12 @@ void ngx_destroy_pool(ngx_pool_t *pool)
 
 void *ngx_palloc(ngx_pool_t *pool, size_t size)
 {
-    char              *m;
+    u_char            *m;
     ngx_pool_t        *p, *n;
     ngx_pool_large_t  *large, *last;
 
     if (size <= (size_t) NGX_MAX_ALLOC_FROM_POOL
-        && size <= (size_t) (pool->end - (char *) pool)
+        && size <= (size_t) (pool->end - (u_char *) pool)
                                      - (size_t) ngx_align(sizeof(ngx_pool_t)))
     {
         for (p = pool, n = pool->next; /* void */; p = n, n = n->next) {
@@ -94,7 +94,7 @@ void *ngx_palloc(ngx_pool_t *pool, size_t size)
 
         /* allocate a new pool block */
 
-        if (!(n = ngx_create_pool((size_t) (p->end - (char *) p), p->log))) {
+        if (!(n = ngx_create_pool((size_t) (p->end - (u_char *) p), p->log))) {
             return NULL;
         }
 
index 53448f4f3f22b63d8bf5bb750fb491cc7c26c722..71be7424ed9e48f0c83ca1c9723e2a05014c6041 100644 (file)
@@ -33,8 +33,8 @@ struct ngx_pool_large_s {
 
 
 struct ngx_pool_s {
-    char              *last;
-    char              *end;
+    u_char            *last;
+    u_char            *end;
     ngx_pool_t        *next;
     ngx_pool_large_t  *large;
     ngx_log_t         *log;
index c1d349e0253ba14a524bde690a9769a64443af25..9493bab8ad65a4ee15c1dd665d73e4ed584fcddf 100644 (file)
@@ -8,7 +8,7 @@
 #include <ngx_core.h>
 
 
-static void *ngx_radix_alloc(ngx_radix_tree_t *tree, size_t size);
+static void *ngx_radix_alloc(ngx_radix_tree_t *tree);
 
 
 ngx_radix_tree_t *ngx_radix_tree_create(ngx_pool_t *pool)
@@ -24,14 +24,14 @@ ngx_radix_tree_t *ngx_radix_tree_create(ngx_pool_t *pool)
     tree->start = NULL;
     tree->size = 0;
 
-    if (!(tree->root = ngx_radix_alloc(tree, sizeof(ngx_radix_node_t)))) {
+    if (!(tree->root = ngx_radix_alloc(tree))) {
         return NULL;
     }
 
-    tree->root->value = (uintptr_t) 0;
     tree->root->right = NULL;
     tree->root->left = NULL;
     tree->root->parent = NULL;
+    tree->root->value = NGX_RADIX_NO_VALUE;
 
     return tree;
 }
@@ -44,8 +44,9 @@ ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree,
     ngx_radix_node_t  *node, *next;
 
     bit = 0x80000000;
+
     node = tree->root;
-    next = NULL;
+    next = tree->root;
 
     while (bit & mask) {
         if (key & bit) {
@@ -55,17 +56,16 @@ ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree,
             next = node->left;
         }
 
-        bit >>= 1;
-
         if (next == NULL) {
             break;
         }
 
+        bit >>= 1;
         node = next;
     }
 
     if (next) {
-        if (node->value) {
+        if (node->value != NGX_RADIX_NO_VALUE) {
             return NGX_BUSY;
         }
 
@@ -74,14 +74,14 @@ ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree,
     }
 
     while (bit & mask) {
-        if (!(next = ngx_radix_alloc(tree, sizeof(ngx_radix_node_t)))) {
+        if (!(next = ngx_radix_alloc(tree))) {
             return NGX_ERROR;
         }
 
-        next->value = value;
         next->right = NULL;
         next->left = NULL;
         next->parent = node;
+        next->value = NGX_RADIX_NO_VALUE;
 
         if (key & bit) {
             node->right = next;
@@ -94,6 +94,8 @@ ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree,
         node = next;
     }
 
+    node->value = value;
+
     return NGX_OK;
 }
 
@@ -123,8 +125,12 @@ ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree,
     }
 
     if (node->right || node->left) {
-        node->value = (uintptr_t) 0;
-        return NGX_OK;
+        if (node->value != NGX_RADIX_NO_VALUE) {
+            node->value = NGX_RADIX_NO_VALUE;
+            return NGX_OK;
+        }
+
+        return NGX_ERROR;
     }
 
     for ( ;; ) {
@@ -139,7 +145,11 @@ ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree,
 
         node = node->parent;
 
-        if (node->right || node->left || node->value || node->parent == NULL) {
+        if (node->right
+            || node->left
+            || node->value != NGX_RADIX_NO_VALUE
+            || node->parent == NULL)
+        {
             break;
         }
     }
@@ -155,11 +165,11 @@ uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key)
     ngx_radix_node_t  *node;
 
     bit = 0x80000000;
-    value = (uintptr_t) 0;
+    value = NGX_RADIX_NO_VALUE;
     node = tree->root;
 
     while (node) {
-        if (node->value) {
+        if (node->value != NGX_RADIX_NO_VALUE) {
             value = node->value;
         }
 
@@ -177,7 +187,7 @@ uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key)
 }
 
 
-static void *ngx_radix_alloc(ngx_radix_tree_t *tree, size_t size)
+static void *ngx_radix_alloc(ngx_radix_tree_t *tree)
 {
     char  *p;
 
@@ -187,7 +197,7 @@ static void *ngx_radix_alloc(ngx_radix_tree_t *tree, size_t size)
         return p;
     }
 
-    if (tree->size < size) {
+    if (tree->size < sizeof(ngx_radix_node_t)) {
         if (!(tree->start = ngx_palloc(tree->pool, ngx_pagesize))) {
             return NULL;
         }
@@ -196,8 +206,8 @@ static void *ngx_radix_alloc(ngx_radix_tree_t *tree, size_t size)
     }
 
     p = tree->start;
-    tree->start += size;
-    tree->size -= size;
+    tree->start += sizeof(ngx_radix_node_t);
+    tree->size -= sizeof(ngx_radix_node_t);
 
     return p;
 }
index 5398d06eb59eec9976141995ddf5c3360603f394..c2d8a36a2645531525c0ea459589db5a0c4f0a37 100644 (file)
@@ -12,6 +12,8 @@
 #include <ngx_core.h>
 
 
+#define NGX_RADIX_NO_VALUE   (uintptr_t) -1
+
 typedef struct ngx_radix_node_s  ngx_radix_node_t;
 
 struct ngx_radix_node_s {
index 37a75aab31c818c4f552f5af1d8ddd129939039b..d63a238505813ede829958bd40b34118b7b243b5 100644 (file)
@@ -28,6 +28,20 @@ u_char *ngx_cpystrn(u_char *dst, u_char *src, size_t n)
 }
 
 
+u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
+{
+    u_char  *dst;
+
+    if (!(dst = ngx_palloc(pool, src->len))) {
+        return NULL;
+    }
+
+    ngx_memcpy(dst, src->data, src->len);
+
+    return dst;
+}
+
+
 /*
  * supported formats:
  *    %[0][width][x][X]O        off_t
@@ -602,13 +616,14 @@ ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
 }
 
 
-ngx_uint_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
-                          ngx_uint_t type)
+uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
 {
     ngx_uint_t        i, n;
     uint32_t         *escape;
     static u_char     hex[] = "0123456789abcdef";
 
+                      /* " ", "%", "?", %00-%1F, %7F-%FF */
+
     static uint32_t   uri[] =
         { 0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
 
@@ -626,6 +641,27 @@ ngx_uint_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
           0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
           0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */ };
 
+                      /* " ", "%", "+", "?", %00-%1F, %7F-%FF */
+
+    static uint32_t   args[] =
+        { 0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+
+                      /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
+          0x80000821, /* 1000 0000 0000 0000  0000 1000 0010 0001 */
+
+                      /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
+          0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
+
+                      /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
+          0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */
+
+          0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+          0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+          0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+          0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */ };
+
+                      /* " ", """, "%", "'", %00-%1F, %7F-%FF */
+
     static uint32_t   html[] =
         { 0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
 
@@ -644,11 +680,16 @@ ngx_uint_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
           0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */ };
 
 
-    if (type == NGX_ESCAPE_HTML) {
+    switch (type) {
+    case NGX_ESCAPE_HTML:
         escape = html;
-
-    } else {
+        break;
+    case NGX_ESCAPE_ARGS:
+        escape = args;
+        break;
+    default:
         escape = uri;
+        break;
     }
 
     if (dst == NULL) {
@@ -664,7 +705,7 @@ ngx_uint_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
             src++;
         }
 
-        return n;
+        return (uintptr_t) n;
     }
 
     for (i = 0; i < size; i++) {
@@ -679,5 +720,5 @@ ngx_uint_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
         }
     }
 
-    return 0;
+    return (uintptr_t) dst;
 }
index abef82d45181bec6eb2e3721026264ed7f6d4c17..766880738b1ae03065d18297dbd9a85531556b9c 100644 (file)
@@ -72,6 +72,7 @@ typedef struct {
 
 
 u_char *ngx_cpystrn(u_char *dst, u_char *src, size_t n);
+u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src);
 u_char *ngx_sprintf(u_char *buf, const char *fmt, ...);
 u_char *ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...);
 u_char *ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args);
@@ -93,10 +94,11 @@ ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src);
 
 
 #define NGX_ESCAPE_URI   0
-#define NGX_ESCAPE_HTML  1
+#define NGX_ESCAPE_ARGS  1
+#define NGX_ESCAPE_HTML  2
 
-ngx_uint_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
-                          ngx_uint_t type);
+uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
+                         ngx_uint_t type);
 
 
 #define  ngx_qsort                qsort
index 01796897f51c7f9e6231a5e64811dc26b0c238c5..832f9c2ed231d27f556f9240ecede7da15293d9d 100644 (file)
@@ -158,7 +158,7 @@ static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,
     }
 
     if (ngx_ptocidr(&value[1], &in_cidr) == NGX_ERROR) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid paramter \"%V\"",
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
                            &value[1]);
         return NGX_CONF_ERROR;
     }
index 9f5016a45fa5d5d2e05258e8cc40838bcfdbd4e4..828f7accca5f0b32d9d56618baf6bd238c9749dc 100644 (file)
@@ -20,6 +20,8 @@ typedef struct {
     ngx_str_t                       root;
     ngx_str_t                       index;
 
+    ngx_array_t                     vars;
+
     ngx_str_t                      *location;
 } ngx_http_fastcgi_loc_conf_t;
 
@@ -130,6 +132,8 @@ static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r,
 
 static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
                                    void *conf);
+static char *ngx_http_fastcgi_set_var(ngx_conf_t *cf, ngx_command_t *cmd,
+                                      void *conf);
 static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
                                           void *data);
 static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf);
@@ -306,6 +310,13 @@ static ngx_command_t  ngx_http_fastcgi_commands[] = {
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
       &ngx_http_fastcgi_next_upstream_masks },
 
+    { ngx_string("fastcgi_set_var"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_fastcgi_set_var,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("fastcgi_params"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
       ngx_conf_set_bitmask_slot,
@@ -405,14 +416,18 @@ static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r)
     ngx_buf_t                         *b;
     socklen_t                          slen;
     ngx_chain_t                       *cl, *body;
-    ngx_uint_t                         i, n, next;
+    ngx_uint_t                         i, n, next, *vindex;
     ngx_list_part_t                   *part;
     ngx_table_elt_t                   *header;
     struct sockaddr_in                 sin;
+    ngx_http_variable_t               *var;
+    ngx_http_variable_value_t         *value;
+    ngx_http_core_main_conf_t         *cmcf;
     ngx_http_fastcgi_header_t         *h;
     ngx_http_fastcgi_loc_conf_t       *flcf;
     ngx_http_fastcgi_begin_request_t  *br;
 
+
     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
 
     if ((flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) && r->in_addr == 0) {
@@ -518,6 +533,23 @@ static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r)
     }
 
 
+    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+    var = cmcf->variables.elts;
+    vindex = flcf->vars.elts;
+
+    for (i = 0; i < flcf->vars.nelts; i++) {
+
+        if (!(value = ngx_http_get_variable(r, vindex[i]))) {
+            continue;
+        }
+
+        if (value->text.len) {
+            len += 1 + 1 + var[vindex[i]].name.len + value->text.len;
+        }
+    }
+
+
     part = &r->headers_in.headers.part;
     header = part->elts;
 
@@ -850,6 +882,26 @@ static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r)
     }
 
 
+    for (i = 0; i < flcf->vars.nelts; i++) {
+
+        if (!(value = ngx_http_get_variable(r, vindex[i]))) {
+            continue;
+        }
+
+        if (value->text.len == 0) {
+            continue;
+        }
+
+        *b->last++ = (u_char) var[vindex[i]].name.len;
+        *b->last++ = (u_char) value->text.len;
+
+        b->last = ngx_cpymem(b->last, var[vindex[i]].name.data,
+                             var[vindex[i]].name.len);
+
+        b->last = ngx_cpymem(b->last, value->text.data, value->text.len);
+    }
+
+
     part = &r->headers_in.headers.part;
     header = part->elts;
 
@@ -1763,7 +1815,11 @@ static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
 
     clcf->handler = ngx_http_fastcgi_handler;
 
+#if (NGX_PCRE)
     lcf->location = clcf->regex ? &ngx_http_fastcgi_uri: &clcf->name;
+#else
+    lcf->location = &clcf->name;
+#endif
 
     if (clcf->name.data[clcf->name.len - 1] == '/') {
         clcf->auto_redirect = 1;
@@ -1773,6 +1829,47 @@ static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
 }
 
 
+static char *ngx_http_fastcgi_set_var(ngx_conf_t *cf, ngx_command_t *cmd,
+                                      void *conf)
+{
+    ngx_http_fastcgi_loc_conf_t *lcf = conf;
+
+    ngx_uint_t                  i, *index;
+    ngx_str_t                  *value;
+    ngx_http_variable_t        *var;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    if (lcf->vars.elts == NULL) {
+        if (ngx_array_init(&lcf->vars, cf->pool, 4,
+                           sizeof(ngx_http_variable_t *)) == NGX_ERROR)
+        {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    value = cf->args->elts;
+
+    var = cmcf->variables.elts;
+    for (i = 0; i < cmcf->variables.nelts; i++) {
+        if (ngx_strcasecmp(var[i].name.data, value[1].data) == 0) {
+
+            if (!(index = ngx_array_push(&lcf->vars))) {
+                return NGX_CONF_ERROR;
+            }
+
+            *index = var[i].index;
+            return NGX_CONF_OK;
+        }
+    }
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "unknown variable name \"%V\"", &value[1]);
+    return NGX_CONF_ERROR;
+}
+
+
 static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
                                           void *data)
 {
diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c
new file mode 100644 (file)
index 0000000..cd77489
--- /dev/null
@@ -0,0 +1,252 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+    ngx_radix_tree_t           *tree;
+    ngx_pool_t                 *pool;
+    ngx_array_t                 values;
+} ngx_http_geo_conf_t;
+
+
+static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
+
+
+static ngx_command_t  ngx_http_geo_commands[] = {
+
+    { ngx_string("geo"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
+      ngx_http_geo_block,
+      NGX_HTTP_MAIN_CONF_OFFSET,
+      0,
+      NULL },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_geo_module_ctx = {
+    NULL,                                  /* pre conf */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    NULL,                                  /* create location configuration */
+    NULL                                   /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_geo_module = {
+    NGX_MODULE,
+    &ngx_http_geo_module_ctx,              /* module context */
+    ngx_http_geo_commands,                 /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init module */
+    NULL                                   /* init process */
+};
+
+
+static ngx_http_variable_value_t  ngx_http_geo_null_value =
+                                                        { 0, ngx_string("0") };
+
+
+/* AF_INET only */
+
+static ngx_http_variable_value_t *ngx_http_geo_variable(ngx_http_request_t *r,
+                                                        void *data)
+{
+    ngx_radix_tree_t *tree = data;
+
+    struct sockaddr_in  *sin;
+
+    sin = (struct sockaddr_in *) r->connection->sockaddr;
+
+    return (ngx_http_variable_value_t *)
+                       ngx_radix32tree_find(tree, ntohl(sin->sin_addr.s_addr));
+}
+
+
+static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char                 *rv;
+    ngx_str_t            *value;
+    ngx_conf_t            save;
+    ngx_pool_t           *pool;
+    ngx_radix_tree_t     *tree;
+    ngx_http_geo_conf_t   geo;
+    ngx_http_variable_t  *var;
+
+    if (!(var = ngx_http_add_variable(cf))) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (!(tree = ngx_radix_tree_create(cf->pool))) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    var->name = value[1];
+    var->handler = ngx_http_geo_variable;
+    var->data = tree;
+
+    /*
+     * create the temporary pool of a huge initial size
+     * to process quickly a large number of geo lines
+     */
+
+    if (!(pool = ngx_create_pool(512 * 1024, cf->log))) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (ngx_array_init(&geo.values, pool, 512,
+                       sizeof(ngx_http_variable_value_t *)) == NGX_ERROR)
+    {
+        ngx_destroy_pool(pool);
+        return NGX_CONF_ERROR;
+    }
+
+    geo.tree = tree;
+    geo.pool = cf->pool;
+
+    save = *cf;
+    cf->pool = pool;
+    cf->ctx = &geo;
+    cf->handler = ngx_http_geo;
+    cf->handler_conf = conf;
+
+    rv = ngx_conf_parse(cf, NULL);
+
+    *cf = save;
+
+    ngx_destroy_pool(pool);
+
+    if (ngx_radix32tree_find(tree, 0) != NGX_RADIX_NO_VALUE) {
+        return rv;
+    }
+
+    if (ngx_radix32tree_insert(tree, 0, 0,
+                            (uintptr_t) &ngx_http_geo_null_value) == NGX_ERROR)
+    {
+        return NGX_CONF_ERROR;
+    }
+
+    return rv;
+}
+
+
+/* AF_INET only */
+
+static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
+{
+    ngx_int_t                   rc, n;
+    ngx_uint_t                  i;
+    ngx_str_t                  *value, file;
+    ngx_inet_cidr_t             cidrin;
+    ngx_http_geo_conf_t        *geo;
+    ngx_http_variable_value_t  *var, **v;
+
+    geo = cf->ctx;
+
+    if (cf->args->nelts != 2) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid number of the geo parameters");
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    if (ngx_strcmp(value[0].data, "include") == 0) {
+        file = value[1];
+
+        if (ngx_conf_full_name(cf->cycle, &file) == NGX_ERROR){
+            return NGX_CONF_ERROR;
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
+
+        return ngx_conf_parse(cf, &file);
+    }
+
+    if (ngx_strcmp(value[0].data, "default") == 0) {
+        cidrin.addr = 0;
+        cidrin.mask = 0;
+
+    } else {
+        if (ngx_ptocidr(&value[0], &cidrin) == NGX_ERROR) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid parameter \"%V\"", &value[0]);
+            return NGX_CONF_ERROR;
+        }
+
+        cidrin.addr = ntohl(cidrin.addr);
+        cidrin.mask = ntohl(cidrin.mask);
+    }
+
+    n = ngx_atoi(value[1].data, value[1].len);
+
+    var = NULL;
+    v = geo->values.elts;
+
+    if (n == NGX_ERROR) {
+        for (i = 0; i < geo->values.nelts; i++) {
+            if (ngx_strcmp(value[1].data, v[i]->text.data) == 0) {
+                var = v[i];
+                break;
+            }
+        }
+
+    } else {
+        for (i = 0; i < geo->values.nelts; i++) {
+            if (v[i]->value == (ngx_uint_t) n) {
+                var = v[i];
+                break;
+            }
+        }
+    }
+
+    if (i == geo->values.nelts) {
+        var = ngx_palloc(geo->pool, sizeof(ngx_http_variable_value_t));
+        if (var == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        var->text.len = value[1].len;
+        if (!(var->text.data = ngx_pstrdup(geo->pool, &value[1]))) {
+            return NGX_CONF_ERROR;
+        }
+
+        var->value = (n == NGX_ERROR) ? 0 : n;
+
+        if (!(v = ngx_array_push(&geo->values))) {
+            return NGX_CONF_ERROR;
+        }
+
+        *v = var;
+    }
+
+    rc = ngx_radix32tree_insert(geo->tree, cidrin.addr, cidrin.mask,
+                                (uintptr_t) var);
+    if (rc == NGX_ERROR) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (rc == NGX_BUSY) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate parameter \"%V\"",
+                           &value[0]);
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
index cda9ca31e26f9fcc7ee937d748aa705cf6896a71..ccf5dc4beb885c8655a6d65f1d230c5a80042bb4 100644 (file)
@@ -132,7 +132,8 @@ static ngx_conf_bitmask_t  ngx_http_gzip_proxied_mask[] = {
 static ngx_command_t  ngx_http_gzip_filter_commands[] = {
 
     { ngx_string("gzip"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      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_gzip_conf_t, enable),
index 636331bc421c6b05a28e638b9de0291cf85c44b1..b1f591c975e15a916c688b29ae76a0f3fecf9cb0 100644 (file)
 #include <ngx_http.h>
 
 
-#define NGX_HTTP_REWRITE_COPY_CAPTURE  0
-#define NGX_HTTP_REWRITE_COPY_SHORT    1
-#define NGX_HTTP_REWRITE_COPY_LONG     2
-#define NGX_HTTP_REWRITE_START_ARGS    3
+typedef struct ngx_http_rewrite_engine_s  ngx_http_rewrite_engine_t;
+
+typedef void (*ngx_http_rewrite_code_pt) (ngx_http_rewrite_engine_t *e);
 
 
 typedef struct {
-    ngx_int_t    op;
-    size_t       len;
-    uintptr_t    data;
-} ngx_http_rewrite_op_t;
+    ngx_str_t                     name;
+    ngx_uint_t                    wildcard;
+} ngx_http_rewrite_referer_t;
 
 
 typedef struct {
-    ngx_regex_t  *regex;
-    ngx_uint_t    ncaptures;
+    ngx_array_t                  *codes;        /* uintptr_t */
+    ngx_array_t                  *referers;     /* ngx_http_rewrite_referer_t */
 
-    ngx_array_t   ops;
-    ngx_uint_t    size;
+    ngx_uint_t                    max_captures;
+    ngx_uint_t                    stack_size;
 
-    ngx_str_t     re_name;
-    ngx_str_t     s_name;
+    ngx_flag_t                    log;
 
-    ngx_uint_t    status;
-    unsigned      last:1;
-} ngx_http_rewrite_rule_t;
+    ngx_flag_t                    no_referer;
+} ngx_http_rewrite_loc_conf_t;
 
 
 typedef struct {
-    ngx_array_t   rules;
-    ngx_flag_t    log;
-} ngx_http_rewrite_srv_conf_t;
+    ngx_http_rewrite_code_pt      code;
+    ngx_regex_t                  *regex;
+    uintptr_t                     size;
+    uintptr_t                     ncaptures;
+    uintptr_t                     status;
+    uintptr_t                     next;
+
+    uintptr_t                     uri:1;
+
+    /* add the r->args to the new arguments */
+    uintptr_t                     args:1;
+
+    uintptr_t                     redirect:1;
+
+    ngx_str_t                     name;
+} ngx_http_rewrite_regex_code_t;
 
 
 typedef struct {
-    ngx_str_t     redirect;
-} ngx_http_rewrite_loc_conf_t;
+    ngx_http_rewrite_code_pt      code;
 
+    uintptr_t                     uri:1;
 
-static void *ngx_http_rewrite_create_srv_conf(ngx_conf_t *cf);
-static char *ngx_http_rewrite_merge_srv_conf(ngx_conf_t *cf,
-                                             void *parent, void *child);
-static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
-static char *ngx_http_rewrite_rule(ngx_conf_t *cf, ngx_command_t *cmd,
-                                   void *conf);
-static char *ngx_http_redirect(ngx_conf_t *cf, void *post, void *data);
-static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle);
+    /* add the r->args to the new arguments */
+    uintptr_t                     args:1;
+
+    uintptr_t                     redirect:1;
+} ngx_http_rewrite_regex_end_code_t;
+
+typedef struct {
+    ngx_http_rewrite_code_pt      code;
+    uintptr_t                     n;
+} ngx_http_rewrite_copy_capture_code_t;
+
+
+typedef struct {
+    ngx_http_rewrite_code_pt      code;
+    uintptr_t                     len;
+} ngx_http_rewrite_copy_code_t;
+
+
+typedef struct {
+    ngx_http_rewrite_code_pt      code;
+    uintptr_t                     status;
+    uintptr_t                     null;
+} ngx_http_rewrite_return_code_t;
 
 
-static ngx_conf_post_handler_pt  ngx_http_redirect_p = ngx_http_redirect;
+typedef struct {
+    ngx_http_rewrite_code_pt      code;
+    uintptr_t                     next;
+    void                        **loc_conf;
+} ngx_http_rewrite_if_code_t;
+
+
+typedef struct {
+    ngx_http_rewrite_code_pt      code;
+    uintptr_t                     index;
+} ngx_http_rewrite_var_code_t;
+
+
+struct ngx_http_rewrite_engine_s {
+    u_char                       *ip;
+    uintptr_t                    *sp;
+
+    ngx_str_t                     buf;
+    ngx_str_t                    *line;
+
+    u_char                       *pos;
+
+    /* the start of the rewritten arguments */
+    u_char                       *args;
+
+    unsigned                      quote:1;
+
+    ngx_int_t                     status;
+
+    int                          *captures;
+
+    ngx_http_request_t           *request;
+    ngx_http_rewrite_loc_conf_t  *conf;
+};
+
+
+static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle);
+static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
+                                             void *parent, void *child);
+static 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_if(ngx_conf_t *cf, ngx_command_t *cmd,
+                                 void *conf);
+static char *ngx_http_rewrite_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd,
+                                             void *conf);
+static void *ngx_http_rewrite_start_code(ngx_pool_t *pool,
+                                         ngx_array_t **codes, size_t size);
+static void *ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size,
+                                       u_char **main);
 
 
 static ngx_command_t  ngx_http_rewrite_commands[] = {
 
     { ngx_string("rewrite"),
-      NGX_HTTP_SRV_CONF|NGX_CONF_TAKE23,
-      ngx_http_rewrite_rule,
-      NGX_HTTP_SRV_CONF_OFFSET,
+      NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                       |NGX_CONF_TAKE23,
+      ngx_http_rewrite,
+      NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
 
-    { ngx_string("redirect"),
-      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
+    { ngx_string("return"),
+      NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                       |NGX_CONF_TAKE1,
+      ngx_http_rewrite_return,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
-      &ngx_http_redirect_p },
+      NULL },
+
+    { ngx_string("if"),
+      NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
+      ngx_http_rewrite_if,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("valid_referers"),
+      NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_rewrite_valid_referers,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
 
     { ngx_string("rewrite_log"),
-      NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                       |NGX_CONF_TAKE1,
       ngx_conf_set_flag_slot,
-      NGX_HTTP_SRV_CONF_OFFSET,
-      offsetof(ngx_http_rewrite_srv_conf_t, log),
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_rewrite_loc_conf_t, log),
       NULL },
 
       ngx_null_command
@@ -94,217 +185,468 @@ ngx_http_module_t  ngx_http_rewrite_module_ctx = {
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
 
-    ngx_http_rewrite_create_srv_conf,      /* create server configuration */
-    ngx_http_rewrite_merge_srv_conf,       /* merge server configuration */
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
 
     ngx_http_rewrite_create_loc_conf,      /* create location configration */
-    NULL,                                  /* merge location configration */
+    ngx_http_rewrite_merge_loc_conf        /* merge location configration */
 };
 
 
 ngx_module_t  ngx_http_rewrite_module = {
     NGX_MODULE,
-    &ngx_http_rewrite_module_ctx,          /* module context */
+    &ngx_http_rewrite_module_ctx,          /* module context */ 
     ngx_http_rewrite_commands,             /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
     ngx_http_rewrite_init,                 /* init module */
-    NULL                                   /* init child */
+    NULL                                   /* init process */
 };
 
 
+#define ngx_http_rewrite_exit  (u_char *) &ngx_http_rewrite_exit_code
+
+uintptr_t ngx_http_rewrite_exit_code = (uintptr_t) NULL;
+
+
 static ngx_int_t ngx_http_rewrite_handler(ngx_http_request_t *r)
 {
-    int                          *captures;
-    u_char                       *p;
-    size_t                        len;
-    uintptr_t                     data;
-    ngx_int_t                     rc;
-    ngx_uint_t                    i, m, n;
-    ngx_str_t                     uri, args;
-    ngx_http_rewrite_op_t        *op;
-    ngx_http_rewrite_rule_t      *rule;
-    ngx_http_rewrite_srv_conf_t  *scf;
+    ngx_http_rewrite_code_pt      code;
+    ngx_http_rewrite_engine_t    *e;
+    ngx_http_rewrite_loc_conf_t  *cf;
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http rewrite handler");
+    cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
 
-    scf = ngx_http_get_module_srv_conf(r, ngx_http_rewrite_module);
+    if (cf->codes == NULL) {
+        return NGX_DECLINED;
+    }
 
-    rule = scf->rules.elts;
-    for (i = 0; i < scf->rules.nelts; i++) {
+    if (!(e = ngx_palloc(r->pool, sizeof(ngx_http_rewrite_engine_t)))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
-        if (rule[i].ncaptures) {
-            captures = ngx_palloc(r->pool, rule[i].ncaptures * sizeof(int));
-            if (captures == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
+    e->sp = ngx_palloc(r->pool, cf->stack_size * sizeof(ngx_int_t));
+    if (e->sp == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
 
-        } else {
-            captures = NULL;
+    if (cf->max_captures) {
+        e->captures = ngx_palloc(r->pool, cf->max_captures * sizeof(int));
+        if (e->captures == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        rc = ngx_regex_exec(rule[i].regex, &r->uri,
-                            captures, rule[i].ncaptures);
+    } else {
+        e->captures = NULL;
+    }
 
-        if (rc == NGX_REGEX_NO_MATCHED) {
-            if (scf->log) {
-                ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                              "\"%V\" does not match \"%V\"",
-                              &rule[i].re_name, &r->uri);
-            }
+    e->ip = cf->codes->elts;
+    e->buf.len = 0;
+    e->buf.data = NULL;
+    e->line = NULL;
+    e->pos = NULL;
+    e->args = NULL;
+    e->quote = 1;
+    e->status = NGX_DECLINED;
+    e->request = r;
+    e->conf = cf;
+
+    while (*(uintptr_t *) e->ip) {
+        code = *(ngx_http_rewrite_code_pt *) e->ip;
+        code(e);
+    }
 
-            continue;
-        }
+    return e->status;
+}
 
-        if (rc < 0) {
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                          ngx_regex_exec_n
-                          " failed: %d on \"%V\" using \"%V\"",
-                          rc, &r->uri, &rule[i].re_name);
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
 
-        if (scf->log) {
+static void ngx_http_rewrite_regex_start_code(ngx_http_rewrite_engine_t *e)
+{
+    ngx_int_t                       rc;
+    ngx_uint_t                      n;
+    ngx_http_request_t             *r;
+    ngx_http_rewrite_regex_code_t  *code;
+
+    code = (ngx_http_rewrite_regex_code_t *) e->ip;
+
+    r = e->request;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http rewrite start: \"%V\"", &code->name);
+
+    if (code->uri) {
+        e->line = &r->uri;
+    } else {
+        e->line = *(ngx_str_t **) e->sp--;
+    }
+
+    rc = ngx_regex_exec(code->regex, e->line, e->captures, code->ncaptures);
+
+    if (rc == NGX_REGEX_NO_MATCHED) {
+        if (e->conf->log) {
             ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                          "\"%V\" matches \"%V\"",
-                          &rule[i].re_name, &r->uri);
+                          "\"%V\" does not match \"%V\"", &code->name, e->line);
         }
 
-        if (rule[i].status) {
-            return rule[i].status;
-        }
+        e->ip += code->next;
+        return;
+    }
+
+    if (rc < 0) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
+                      rc, e->line, &code->name);
+
+        e->ip = ngx_http_rewrite_exit;
+        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+        return;
+    }
+
+    if (e->conf->log) {
+        ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
+                      "\"%V\" matches \"%V\"", &code->name, e->line);
+    }
 
-        uri.len = rule[i].size;
+    if (code->status) {
+        e->status = code->status;
 
-        for (n = 1; n < (ngx_uint_t) rc; n++) {
-            uri.len += captures[2 * n + 1] - captures[2 * n];
+        if (!code->redirect) {
+            e->ip = ngx_http_rewrite_exit;
+            return;
         }
+    }
 
-        if (!(uri.data = ngx_palloc(r->pool, uri.len))) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    e->buf.len = code->size;
+
+    if (code->uri) {
+        r->uri_changed = 1;
+
+        if (rc && (r->quoted_uri || r->plus_in_uri)) {
+            e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
+                                             NGX_ESCAPE_ARGS);
         }
+    }
 
-        args.data = NULL;
-        p = uri.data;
+    for (n = 1; n < (ngx_uint_t) rc; n++) {
+        e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n];
+    }
 
-        op = rule[i].ops.elts;
-        for (n = 0; n < rule[i].ops.nelts; n++) {
-            if (op[n].op == NGX_HTTP_REWRITE_COPY_SHORT) {
-                len = op[n].len;
-                data = op[n].data;
-                while (len--) {
-                    *p++ = (char) (data & 0xff);
-                    data >>= 8;
-                }
+    if (code->args && r->args.len) {
+        e->buf.len += r->args.len + 1;
+    }
 
-            } else if (op[n].op == NGX_HTTP_REWRITE_COPY_LONG) {
-                p = ngx_cpymem(p, (void *) op[n].data, op[n].len);
+    if (!(e->buf.data = ngx_palloc(r->pool, e->buf.len))) {
+        e->ip = ngx_http_rewrite_exit;
+        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+        return;
+    }
 
-            } else if (op[n].op == NGX_HTTP_REWRITE_START_ARGS) {
-                args.data = p;
+    e->quote = code->redirect;
 
-            } else { /* NGX_HTTP_REWRITE_COPY_CAPTURE */
-                m = 2 * op[n].data;
-                p = ngx_cpymem(p, &r->uri.data[captures[m]],
-                               captures[m + 1] - captures[m]);
-            }
+    e->pos = e->buf.data;
+
+    e->ip += sizeof(ngx_http_rewrite_regex_code_t);
+}
+
+
+static void ngx_http_rewrite_regex_end_code(ngx_http_rewrite_engine_t *e)
+{
+    ngx_http_request_t                 *r;
+    ngx_http_rewrite_regex_end_code_t  *code;
+
+    code = (ngx_http_rewrite_regex_end_code_t *) e->ip;
+
+    r = e->request;
+
+    e->quote = 0;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http rewrite end");
+
+    if (e->args) {
+        e->buf.len = e->args - e->buf.data;
+
+        if (code->args && r->args.len) {
+            *e->pos++ = '&';
+            e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len);
         }
 
-        if (args.data) {
-            uri.len = args.data - uri.data;
-            args.len = p - args.data;
+        r->args.len = e->pos - e->args;
+        r->args.data = e->args;
 
-            r->args = args;
+        e->args = NULL;
 
-        } else {
-            uri.len = p - uri.data;
-            args.len = 0;
+    } else {
+        if (code->args && r->args.len) {
+            *e->pos++ = '&';
+            e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len);
         }
 
-        r->uri = uri;
+        e->buf.len = e->pos - e->buf.data;
+    }
 
-        if (scf->log) {
+    if (!code->redirect) {
+        if (e->conf->log) {
             ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
-                          "rewritten uri: \"%V\", args: \"%V\"", &uri, &args);
+                          "rewritten data: \"%V\", args: \"%V\"",
+                          &e->buf, &r->args);
         }
 
-        if (ngx_http_set_exten(r) != NGX_OK) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
+        if (code->uri) {
+            r->uri = e->buf;
 
-        if (rule[i].last) {
-            return NGX_DECLINED;
+            if (ngx_http_set_exten(r) != NGX_OK) {
+                e->ip = ngx_http_rewrite_exit;
+                e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+                return;
+            }
         }
+
+        e->ip += sizeof(ngx_http_rewrite_regex_end_code_t);
+        return;
     }
 
-    return NGX_DECLINED;
+    ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
+                  "rewritten redirect: \"%V\"", &e->buf);
+
+    if (!(r->headers_out.location = ngx_list_push(&r->headers_out.headers))) {
+        e->ip = ngx_http_rewrite_exit;
+        e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+        return;
+    }
+
+    if (e->buf.data[0] != '/') {
+        r->headers_out.location->key.len = sizeof("Location") - 1;
+        r->headers_out.location->key.data = (u_char *) "Location";
+    }
+
+    r->headers_out.location->value = e->buf;
+
+    e->ip += sizeof(ngx_http_rewrite_regex_end_code_t);
 }
 
 
-static ngx_int_t ngx_http_redirect_handler(ngx_http_request_t *r)
+static void ngx_http_rewrite_copy_capture_code(ngx_http_rewrite_engine_t *e)
 {
-    u_char                       *p;
-    ngx_http_rewrite_loc_conf_t  *rlcf;
+    ngx_http_rewrite_copy_capture_code_t  *code;
+
+    code = (ngx_http_rewrite_copy_capture_code_t *) e->ip;
+
+    e->ip += sizeof(ngx_http_rewrite_copy_capture_code_t);
+
+    if ((e->args || e->quote)
+        && (e->request->quoted_uri || e->request->plus_in_uri))
+    {
+        e->pos = (u_char *) ngx_escape_uri(e->pos,
+                                &e->line->data[e->captures[code->n]],
+                                e->captures[code->n + 1] - e->captures[code->n],
+                                NGX_ESCAPE_ARGS);
+    } else {
+        e->pos = ngx_cpymem(e->pos, &e->line->data[e->captures[code->n]],
+                        e->captures[code->n + 1] - e->captures[code->n]);
+    }
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http redirect handler");
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http rewrite capture: \"%V\"", &e->buf);
+}
 
-    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
 
-    r->headers_out.location = ngx_list_push(&r->headers_out.headers);
-    if (r->headers_out.location == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
+static void ngx_http_rewrite_copy_code(ngx_http_rewrite_engine_t *e)
+{
+    ngx_http_rewrite_copy_code_t  *code;
 
-    if (rlcf->redirect.data[0] != '/') {
-        r->headers_out.location->key.len = sizeof("Location") - 1;
-        r->headers_out.location->key.data = (u_char *) "Location";
+    code = (ngx_http_rewrite_copy_code_t *) e->ip;
+
+    e->pos = ngx_cpymem(e->pos, e->ip + sizeof(ngx_http_rewrite_copy_code_t),
+                        code->len);
+
+    e->ip += sizeof(ngx_http_rewrite_copy_code_t)
+             + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http rewrite copy: \"%V\"", &e->buf);
+}
+
+
+static void ngx_http_rewrite_start_args_code(ngx_http_rewrite_engine_t *e)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http rewrite args");
+
+    e->args = e->pos;
+    e->ip += sizeof(uintptr_t);
+}
+
+
+static void ngx_http_rewrite_return_code(ngx_http_rewrite_engine_t *e)
+{
+    ngx_http_rewrite_return_code_t  *code;
+
+    code = (ngx_http_rewrite_return_code_t *) e->ip;
+
+    e->status = code->status;
+
+    e->ip += sizeof(ngx_http_rewrite_return_code_t) - sizeof(uintptr_t);
+}
+
+
+static void ngx_http_rewrite_if_code(ngx_http_rewrite_engine_t *e)
+{
+    ngx_http_rewrite_if_code_t  *code;
+
+    code = (ngx_http_rewrite_if_code_t *) e->ip;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http rewrite if");
+
+    if (*e->sp--) {
+        if (code->loc_conf) {
+            e->request->loc_conf = code->loc_conf;
+        }
+
+        e->ip += sizeof(ngx_http_rewrite_if_code_t);
+        return;
     }
 
-    r->headers_out.location->value.len =  rlcf->redirect.len
-                                          + r->unparsed_uri.len;
-    r->headers_out.location->value.data = ngx_palloc(r->pool,
-                                           r->headers_out.location->value.len);
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http rewrite if false");
 
-    if (r->headers_out.location->value.data == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    e->ip += code->next;
+}
+
+
+static void ngx_http_rewrite_var_code(ngx_http_rewrite_engine_t *e)
+{
+    ngx_http_variable_value_t    *value;
+    ngx_http_rewrite_var_code_t  *code;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http rewrite var");
+
+    code = (ngx_http_rewrite_var_code_t *) e->ip;
+
+    e->sp++;
+
+    e->ip += sizeof(ngx_http_rewrite_var_code_t);
+
+    if (!(value = ngx_http_get_variable(e->request, code->index))) {
+        *e->sp = (uintptr_t) 0;
+        return;
     }
 
-    p = ngx_cpymem(r->headers_out.location->value.data, rlcf->redirect.data,
-                   rlcf->redirect.len);
-    p = ngx_cpystrn(p, r->unparsed_uri.data + 1, r->unparsed_uri.len);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http rewrite var: %p", value->value);
 
-    return NGX_HTTP_MOVED_TEMPORARILY;
+    *e->sp = value->value;
 }
 
 
-static void *ngx_http_rewrite_create_srv_conf(ngx_conf_t *cf)
+static void ngx_http_rewrite_invalid_referer_code(ngx_http_rewrite_engine_t *e)
 {
-    ngx_http_rewrite_srv_conf_t  *conf;
+    u_char                       *ref;
+    size_t                        len;
+    ngx_uint_t                    i, n;
+    ngx_http_request_t           *r;
+    ngx_http_rewrite_referer_t   *refs;
+    ngx_http_rewrite_loc_conf_t  *cf;
 
-    if (!(conf = ngx_palloc(cf->pool, sizeof(ngx_http_rewrite_srv_conf_t)))) {
-        return NGX_CONF_ERROR;
+    r = e->request;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http rewrite invalid referer");
+
+    cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
+
+    e->sp++;
+    e->ip += sizeof(uintptr_t);
+
+    if (cf->referers == NULL) {
+        *e->sp = (uintptr_t) 0;
+        return;
+    }
+
+    if (r->headers_in.referer == NULL) {
+        if (cf->no_referer) {
+            *e->sp = (uintptr_t) 0;
+            return;
+        } else {
+            *e->sp = (uintptr_t) 1;
+            return;
+        }
     }
 
-    ngx_init_array(conf->rules, cf->pool, 5, sizeof(ngx_http_rewrite_rule_t),
-                   NGX_CONF_ERROR);
+    len = r->headers_in.referer->value.len;
+    ref = r->headers_in.referer->value.data;
 
-    conf->log = NGX_CONF_UNSET;
+    if (len < sizeof("http://i.ru") - 1
+        || (ngx_strncasecmp(ref, "http://", 7) != 0))
+    {
+        *e->sp = (uintptr_t) 1;
+        return;
+    }
 
-    return conf;
+    len -= 7;
+    ref += 7;
+
+    refs = cf->referers->elts;
+    for (i = 0; i < cf->referers->nelts; i++ ){
+
+        if (refs[i].name.len > len) {
+            continue;
+        }
+
+        if (refs[i].wildcard) {
+            for (n = 0; n < len; n++) {
+                if (ref[n] == '/' || ref[n] == ':') {
+                    break;
+                }
+
+                if (ref[n] != '.') {
+                    continue;
+                }
+
+                if (ngx_strncmp(&ref[n], refs[i].name.data,
+                                refs[i].name.len) == 0)
+                {
+                    *e->sp = (uintptr_t) 0;
+                    return;
+                }
+            }
+
+        } else {
+            if (ngx_strncasecmp(refs[i].name.data, ref, refs[i].name.len) == 0)
+            {
+                *e->sp = (uintptr_t) 0;
+                return;
+            }
+        }
+    }
+
+    *e->sp = (uintptr_t) 1;
 }
 
 
-static char *ngx_http_rewrite_merge_srv_conf(ngx_conf_t *cf,
-                                             void *parent, void *child)
+static void ngx_http_rewrite_nop_code(ngx_http_rewrite_engine_t *e)
 {
-    ngx_http_rewrite_srv_conf_t *prev = parent;
-    ngx_http_rewrite_srv_conf_t *conf = child;
+    e->ip += sizeof(uintptr_t);
+}
 
-    ngx_conf_merge_value(conf->log, prev->log, 0);
 
-    return NGX_CONF_OK;
-}
+static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle)
+{   
+    ngx_http_handler_pt        *h;
+    ngx_http_core_main_conf_t  *cmcf;
+    
+    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
+
+    h = ngx_push_array(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+    
+    *h = ngx_http_rewrite_handler;
+    
+    return NGX_OK;
+}   
 
 
 static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
@@ -315,198 +657,643 @@ static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
         return NGX_CONF_ERROR;
     }
 
+    conf->stack_size = NGX_CONF_UNSET_UINT;
+    conf->log = NGX_CONF_UNSET;
+    conf->no_referer = NGX_CONF_UNSET;
+
     return conf;
 }
 
 
-static char *ngx_http_rewrite_rule(ngx_conf_t *cf, ngx_command_t *cmd,
-                                   void *conf)
+static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
+                                             void *parent, void *child)
 {
-    ngx_http_rewrite_srv_conf_t *scf = conf;
+    ngx_http_rewrite_loc_conf_t *prev = parent;
+    ngx_http_rewrite_loc_conf_t *conf = child;
 
-    u_char                   *data, *p;
-    size_t                    len;
-    ngx_str_t                *value, err;
-    ngx_uint_t                i, n;
-    ngx_http_rewrite_op_t    *op;
-    ngx_http_rewrite_rule_t  *rule;
-    u_char                    errstr[NGX_MAX_CONF_ERRSTR];
+    uintptr_t                      *code, *last;
+    ngx_http_rewrite_regex_code_t  *regex;
 
-    if (!(rule = ngx_push_array(&scf->rules))) {
-        return NGX_CONF_ERROR;
+    ngx_conf_merge_value(conf->log, prev->log, 0);
+    ngx_conf_merge_unsigned_value(conf->stack_size, prev->stack_size, 10);
+
+    if (conf->referers == NULL) {
+        conf->referers = prev->referers;
+        ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0);
     }
 
-    ngx_init_array(rule->ops, cf->pool, 5, sizeof(ngx_http_rewrite_op_t),
-                   NGX_CONF_ERROR);
+    if (conf->codes == NULL) {
+        return NGX_CONF_OK;
+    }
 
-    rule->ncaptures = 0;
-    rule->size = 0;
-    rule->status = 0;
-    rule->last = 0;
+    if (conf->codes == prev->codes) {
+        return NGX_CONF_OK;
+    }
 
-    value = cf->args->elts;
+    code = conf->codes->elts;
+    last = (uintptr_t *) ((u_char *) code + conf->codes->nelts);
 
-    /* STUB */ {
-        err.len = NGX_MAX_CONF_ERRSTR;
-        err.data = errstr;
+    while (code < last) {
+        if (*code == (uintptr_t) NULL) {
+            return NGX_CONF_OK;
+        }
 
-        rule->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err);
-    
-        if (rule->regex == NULL) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
-            return NGX_CONF_ERROR;
+        if (*code == (uintptr_t) &ngx_http_rewrite_regex_start_code) {
+            regex = (ngx_http_rewrite_regex_code_t *) code;
+            if (conf->max_captures < regex->ncaptures) {
+                conf->max_captures = regex->ncaptures;
+            }
+            code = (uintptr_t *) ((u_char *) code + regex->next);
         }
+
+        if (*code == (uintptr_t) &ngx_http_rewrite_if_code) {
+            code += sizeof(ngx_http_rewrite_if_code_t) / sizeof(uintptr_t);
+        }
+
+        if (*code == (uintptr_t) &ngx_http_rewrite_return_code) {
+            code += sizeof(ngx_http_rewrite_return_code_t) / sizeof(uintptr_t);
+        }
+
+        if (*code == (uintptr_t) &ngx_http_rewrite_var_code) {
+            code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t);
+        }
+
+        if (*code == (uintptr_t) &ngx_http_rewrite_invalid_referer_code) {
+            code++;
+        }
+
+        if (*code == (uintptr_t) &ngx_http_rewrite_nop_code) {
+            code++;
+        }
+    }
+
+    if (!(code = ngx_array_push_n(conf->codes, sizeof(uintptr_t)))) {
+        return NGX_CONF_ERROR;
+    }
+
+    *code = (uintptr_t) NULL;
+
+    return NGX_CONF_OK;
+}
+
+
+static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_rewrite_loc_conf_t *lcf = conf;
     
-        rule->re_name = value[1];
-        rule->s_name = value[2];
+    u_char                                *data;
+    size_t                                 len, size;
+    ngx_str_t                             *value, err;
+    ngx_uint_t                             i, n, last;
+    ngx_http_rewrite_code_pt              *code;
+    ngx_http_rewrite_copy_code_t          *copy;
+    ngx_http_rewrite_regex_code_t         *regex;
+    ngx_http_rewrite_regex_end_code_t     *regex_end;
+    ngx_http_rewrite_copy_capture_code_t  *copy_capture;
+    u_char                                 errstr[NGX_MAX_CONF_ERRSTR];
+
+    regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
+                                        sizeof(ngx_http_rewrite_regex_code_t));
+    if (regex == NULL) {
+        return NGX_CONF_ERROR;
+    }
 
-        if (ngx_strcasecmp(value[2].data, "forbidden:") == 0) {
+    value = cf->args->elts;
 
-            if (cf->args->nelts == 3) {
-                rule->status = NGX_HTTP_FORBIDDEN;
-                rule->last = 1;
-                return NGX_CONF_OK;
-            }
+    err.len = NGX_MAX_CONF_ERRSTR;
+    err.data = errstr;
+
+    /* TODO: NGX_REGEX_CASELESS */
+
+    regex->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err);
+
+    if (regex->regex == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
+        return NGX_CONF_ERROR;
+    }
+
+    regex->code = ngx_http_rewrite_regex_start_code;
+    regex->size = 0;
+    regex->ncaptures = 0;
+    regex->status = 0;
+    regex->uri = 1;
+    regex->args = 1;
+    regex->redirect = 0;
+    regex->name = value[1];
+
+    last = 0;
+
+    if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0) {
+        regex->status = NGX_HTTP_MOVED_TEMPORARILY;
+        regex->redirect = 1;
+        last = 1;
+    }
 
+    if (cf->args->nelts == 4) {
+        if (ngx_strcmp(value[3].data, "last") == 0) {
+            last = 1;
+
+        } else if (ngx_strcmp(value[3].data, "redirect") == 0) {
+            regex->status = NGX_HTTP_MOVED_TEMPORARILY;
+            regex->redirect = 1;
+            last = 1;
+
+        } else if (ngx_strcmp(value[3].data, "permanent") == 0) {
+            regex->status = NGX_HTTP_MOVED_PERMANENTLY;
+            regex->redirect = 1;
+            last = 1;
+
+        } else {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "invalid parameter \"%V\"", &value[3]);
             return NGX_CONF_ERROR;
         }
+    }
+
+    i = 0;
+
+    while (i < value[2].len) {
+
+        data = &value[2].data[i];
 
-        i = 0;
+        if (value[2].data[i] == '$' && i < value[2].len
+            && value[2].data[i + 1] >= '1' && value[2].data[i + 1] <= '9')
+        {
 
-        while (i < value[2].len) {
+            /* the "$1" - "$9" captures */
 
-            if (!(op = ngx_push_array(&rule->ops))) {
+            copy_capture = ngx_http_rewrite_add_code(lcf->codes,
+                                  sizeof(ngx_http_rewrite_copy_capture_code_t),
+                                  (u_char **) &regex);
+            if (copy_capture == NULL) {
                 return NGX_CONF_ERROR;
             }
 
-            data = &value[2].data[i];
+            i++;
 
-            if (value[2].data[i] == '$'
-                && i < value[2].len
-                && value[2].data[i + 1] >= '1'
-                && value[2].data[i + 1] <= '9')
-            {
-                op->op = NGX_HTTP_REWRITE_COPY_CAPTURE; 
-                op->len = 0;
-                op->data = value[2].data[++i] - '0';
+            copy_capture->code = ngx_http_rewrite_copy_capture_code;
+            copy_capture->n = value[2].data[i] - '0';
+
+            if (regex->ncaptures < copy_capture->n) {
+                regex->ncaptures = copy_capture->n;
+            }
+
+            copy_capture->n *= 2;
+
+            i++;
 
-                if (rule->ncaptures < op->data) {
-                    rule->ncaptures = op->data;
+            continue;
+        }
+
+        if (value[2].data[i] == '?') {
+
+            /* the arguments */
+
+            if (i == value[2].len - 1) {
+                /* the last "?" drops the original arguments */
+                regex->args = 0;
+                break;
+            }
+
+            if (!regex->redirect) {
+                code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t),
+                                                 (u_char **) &regex);
+                if (code == NULL) {
+                    return NGX_CONF_ERROR;
                 }
 
+                *code = ngx_http_rewrite_start_args_code;
+
                 i++;
 
                 continue;
             }
+        }
+
+        i++;
+
+        /* the substituion strings */
+
+        while (i < value[2].len && value[2].data[i] != '$') {
 
             if (value[2].data[i] == '?') {
-                op->op = NGX_HTTP_REWRITE_START_ARGS; 
-                op->len = 0;
-                op->data = 0;
 
-                i++;
+                if (i == value[2].len - 1) {
+                    /*
+                     * the last "?" drops the original arguments,
+                     * and it should not be copied to a substituion
+                     */
+                    regex->args = 0;
+                    break;
+                }
 
-                continue;
+                if (!regex->redirect) {
+                    break;
+                }
             }
 
             i++;
+        }
 
-            while (i < value[2].len
-                   && value[2].data[i] != '$'
-                   && value[2].data[i] != '?')
-            {
-                i++;
-            }
+        len = &value[2].data[i] - data;
 
-            len = &value[2].data[i] - data;
-            rule->size += len;
+        if (len == 0) {
+            continue;
+        }
 
-            if (len) {
+        regex->size += len;
 
-                op->len = len;
+        size = (len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
 
-                if (len <= sizeof(uintptr_t)) {
-                    op->op = NGX_HTTP_REWRITE_COPY_SHORT; 
-                    op->data = 0;
+        copy = ngx_http_rewrite_add_code(lcf->codes,
+                                   sizeof(ngx_http_rewrite_copy_code_t) + size,
+                                   (u_char **) &regex);
+        if (copy == NULL) {
+            return NGX_CONF_ERROR;
+        }
 
-                    while (len--) {
-                        op->data <<= 8;
-                        op->data |= data[len];
-                    }
+        copy->code = ngx_http_rewrite_copy_code;
+        copy->len = len;
 
-                } else {
-                    op->op = NGX_HTTP_REWRITE_COPY_LONG;
+        ngx_memcpy((u_char *) copy + sizeof(ngx_http_rewrite_copy_code_t),
+                   data, len);
+    }
 
-                    if (!(p = ngx_palloc(cf->pool, len))) {
-                        return NGX_CONF_ERROR;
-                    }
+    n = ngx_regex_capture_count(regex->regex);
 
-                    ngx_memcpy(p, data, len);
-                    op->data = (uintptr_t) p;
-                }
+    if (regex->ncaptures > n) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "pattern \"%V\" has less captures "
+                           "than referrenced in substitution \"%V\"",
+                           &value[1], &value[2]);
+        return NGX_CONF_ERROR;
+    }
+
+    if (regex->ncaptures < n) {
+        regex->ncaptures = n;
+    }
+
+    if (regex->ncaptures) {
+        regex->ncaptures = (regex->ncaptures + 1) * 3;
+    }
+
+    regex_end = ngx_http_rewrite_add_code(lcf->codes,
+                                     sizeof(ngx_http_rewrite_regex_end_code_t),
+                                     (u_char **) &regex);
+    if (regex_end == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    regex_end->code = ngx_http_rewrite_regex_end_code;
+    regex_end->uri = regex->uri;
+    regex_end->args = regex->args;
+    regex_end->redirect = regex->redirect;
+
+    if (last) {
+        code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t),
+                                         (u_char **) &regex);
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *code = (uintptr_t) NULL;
+    }
+
+    regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
+                                              - (u_char *) regex;
+
+    return NGX_CONF_OK;
+}
+
+
+
+static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
+                                     void *conf)
+{
+    ngx_http_rewrite_loc_conf_t *lcf = conf;
+
+    ngx_str_t                       *value;
+    ngx_http_rewrite_return_code_t  *ret;
+
+    ret = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
+                                      sizeof(ngx_http_rewrite_return_code_t));
+    if (ret == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    ret->code = ngx_http_rewrite_return_code;
+    ret->null = (uintptr_t) NULL;
+
+    ret->status = ngx_atoi(value[1].data, value[1].len);
+
+    if (ret->status == (uintptr_t) NGX_ERROR) {
+        return NGX_CONF_ERROR;
+    }
+
+    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;
+
+    void                         *mconf;
+    char                         *rv;
+    u_char                       *elts;
+    ngx_str_t                    *value;
+    ngx_uint_t                    i;
+    ngx_conf_t                    save;
+    ngx_http_rewrite_code_pt     *code;
+    ngx_http_module_t            *module;
+    ngx_http_conf_ctx_t          *ctx, *pctx;
+    ngx_http_variable_t          *var;
+    ngx_http_core_loc_conf_t     *clcf, *pclcf, **clcfp;
+    ngx_http_core_main_conf_t    *cmcf;
+    ngx_http_rewrite_if_code_t   *if_code;
+    ngx_http_rewrite_var_code_t  *var_code;
+    ngx_http_rewrite_loc_conf_t  *nlcf;
+
+    if (!(ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)))) {
+        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) {
+
+            if (!(mconf = module->create_loc_conf(cf))) {
+                 return NGX_CONF_ERROR;
             }
+
+            ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
         }
+    }
 
-        n = ngx_regex_capture_count(rule->regex);
+    pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
 
-        if (rule->ncaptures > n) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "pattern \"%V\" has less captures "
-                               "than referrenced in substitution \"%V\"",
-                               &value[1], &value[2]);
+    clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
+    clcf->loc_conf = ctx->loc_conf;
+    clcf->name = pclcf->name;
+    clcf->noname = 1;
+
+    if (pclcf->locations.elts == NULL) {
+        if (ngx_array_init(&pclcf->locations, cf->pool, 4, sizeof(void *))
+                                                                  == NGX_ERROR)
+        {
             return NGX_CONF_ERROR;
         }
+    }
 
-        if (rule->ncaptures < n) {
-            rule->ncaptures = n;
-        }
+    if (!(clcfp = ngx_push_array(&pclcf->locations))) {
+        return NGX_CONF_ERROR;
+    }
+
+    *clcfp = clcf;
 
-        if (rule->ncaptures) {
-            rule->ncaptures = (rule->ncaptures + 1) * 3;
+
+    /* STUB: "if ($var)" */
+
+    value = cf->args->elts;
+
+    if (value[1].len < 2
+        || value[1].data[0] != '('
+        || value[1].data[1] != '$'
+        || value[1].data[value[1].len - 1] != ')')
+    {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid condition \"%V\"", &value[1]);
+        return NGX_CONF_ERROR;
+    }
+
+    value[1].len -= 3;
+    value[1].data += 2;
+
+    if (value[1].len == sizeof("invalid_referer") - 1
+        && ngx_strncmp(value[1].data, "invalid_referer",
+                       sizeof("invalid_referer") - 1) == 0)
+    {
+        code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
+                                           sizeof(ngx_http_rewrite_code_pt));
+        if (code == NULL) {
+            return NGX_CONF_ERROR;
         }
 
-        if (cf->args->nelts > 3) {
-            if (ngx_strcmp(value[3].data, "last") == 0) {
-                rule->last = 1;
+        *code = ngx_http_rewrite_invalid_referer_code;
 
-            } else {
-                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                                   "invalid parameter \"%V\"", &value[3]);
-                return NGX_CONF_ERROR;
+    } else {
+
+        cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+        var = cmcf->variables.elts;
+        for (i = 0; i < cmcf->variables.nelts; i++) {
+            if (var[i].name.len != value[1].len) {
+                continue;
+            }
+
+            if (ngx_strncasecmp(var[i].name.data, value[1].data,
+                                var[i].name.len) == 0)
+            {
+                break;
             }
         }
+
+        if (i == cmcf->variables.nelts) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "unknown variable name \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+        var_code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
+                                           sizeof(ngx_http_rewrite_var_code_t));
+        if (var_code == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        var_code->code = ngx_http_rewrite_var_code;
+        var_code->index = var[i].index;
+    }
+
+    if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_rewrite_if_code_t));
+    if (if_code == NULL) {
+        return NULL;
+    }
+
+    if_code->code = ngx_http_rewrite_if_code;
+
+    elts = lcf->codes->elts;
+
+
+    /* the inside directives must compile to the same code array */
+
+    nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index];
+    nlcf->codes = lcf->codes;
+
+
+    save = *cf;
+    cf->ctx = ctx;
+
+    if (pclcf->name.len == 0) {
+        if_code->loc_conf = NULL;
+        cf->cmd_type = NGX_HTTP_SIF_CONF;
+
+    } else {
+        if_code->loc_conf = ctx->loc_conf;
+        cf->cmd_type = NGX_HTTP_LIF_CONF;
+    }
+
+    rv = ngx_conf_parse(cf, NULL);
+
+    *cf = save;
+
+    if (rv != NGX_CONF_OK) {
+        return rv;
+    }
+
+
+    if (elts != lcf->codes->elts) {
+        if_code = (ngx_http_rewrite_if_code_t *)
+                   ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts));
     }
 
+    if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
+                                                - (u_char *) if_code;
+
     return NGX_CONF_OK;
 }
 
 
-static char *ngx_http_redirect(ngx_conf_t *cf, void *post, void *data)
+static char *ngx_http_rewrite_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd,
+                                             void *conf)
 {
-    ngx_http_core_loc_conf_t  *clcf;
+    ngx_http_rewrite_loc_conf_t *lcf = conf;
+
+    ngx_uint_t                   i, server_names;
+    ngx_str_t                   *value;
+    ngx_http_server_name_t      *sn;
+    ngx_http_core_srv_conf_t    *cscf;
+    ngx_http_rewrite_referer_t  *ref;
+
+    cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
+
+    if (lcf->referers == NULL) {
+        lcf->referers = ngx_array_create(cf->pool,
+                                    cf->args->nelts + cscf->server_names.nelts,
+                                    sizeof(ngx_http_rewrite_referer_t));
+        if (lcf->referers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    value = cf->args->elts;
+    server_names = 0;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+        if (value[i].len == 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid referer \"%V\"", &value[i]);
+            return NGX_CONF_ERROR;
+        }
+
+        if (ngx_strcmp(value[i].data, "none") == 0) {
+            lcf->no_referer = 1;
+            continue;
+        }
+
+        if (ngx_strcmp(value[i].data, "server_names") == 0) {
+            server_names = 1;
+            continue;
+        }
+
+        if (!(ref = ngx_array_push(lcf->referers))) {
+            return NGX_CONF_ERROR;
+        }
+
+        if (value[i].data[0] != '*') {
+            ref->name = value[i];
+            ref->wildcard = 0;
+            continue;
+        }
+
+        if (value[i].data[1] != '.') {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid wildcard referer \"%V\"", &value[i]);
+            return NGX_CONF_ERROR;
+        }
 
-    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
-    clcf->handler = ngx_http_redirect_handler;
+        ref->name.len = value[i].len - 1;
+        ref->name.data = value[i].data + 1;
+        ref->wildcard = 1;
+    }
+
+    if (!server_names) {
+        return NGX_CONF_OK;
+    }
+
+    sn = cscf->server_names.elts;
+    for (i = 0; i < cscf->server_names.nelts; i++) {
+        if (!(ref = ngx_array_push(lcf->referers))) {
+            return NGX_CONF_ERROR;
+        }
+
+        ref->name.len = sn[i].name.len + 1;
+        if (!(ref->name.data = ngx_palloc(cf->pool, ref->name.len))) {
+            return NGX_CONF_ERROR;
+        }
+
+        ngx_memcpy(ref->name.data, sn[i].name.data, sn[i].name.len);
+        ref->name.data[sn[i].name.len] = '/';
+        ref->wildcard = sn[i].wildcard;
+    }
 
     return NGX_CONF_OK;
 }
 
 
-static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle)
+static void *ngx_http_rewrite_start_code(ngx_pool_t *pool,
+                                         ngx_array_t **codes, size_t size)
 {
-    ngx_http_handler_pt        *h;
-    ngx_http_core_main_conf_t  *cmcf;
+    if (*codes == NULL) {
+        if (!(*codes = ngx_array_create(pool, 256, 1))) {
+            return NULL;
+        }
+    }
 
-    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
+    return ngx_array_push_n(*codes, size);
+}
 
-    h = ngx_push_array(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
-    if (h == NULL) {
-        return NGX_ERROR;
+
+static void *ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size,
+                                       u_char **main)
+{
+    u_char  *elts;
+    void    *new;
+
+    elts = codes->elts;
+
+    if (!(new = ngx_array_push_n(codes, size))) {
+        return NGX_CONF_ERROR;
     }
 
-    *h = ngx_http_rewrite_handler;
+    if (elts != codes->elts) {
+        *main += (u_char *) codes->elts - elts;
+    }
 
-    return NGX_OK;
+    return new;
 }
index 9cb6e171d8a6677b1c773edfff74b2aaa99dfb23..883e44fbcd9e08df0f8e865dc2f83142bf44a1e1 100644 (file)
@@ -73,7 +73,7 @@ static ngx_http_module_t  ngx_http_ssl_module_ctx = {
     ngx_http_ssl_merge_srv_conf,           /* merge server configuration */
 
     NULL,                                  /* create location configuration */
-    NULL,                                  /* merge location configuration */
+    NULL                                   /* merge location configuration */
 };
 
 
index ea3a0ca4333c52f38075b9cc3bf87f56e1a76cab..a195b45e4421ef32aaea7914939c6de8516ac19a 100644 (file)
@@ -36,6 +36,8 @@ static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
 static char *ngx_http_proxy_parse_upstream(ngx_str_t *url,
                                            ngx_http_proxy_upstream_conf_t *u);
 
+static char *ngx_http_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd,
+                                      void *conf);
 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
 
 static ngx_conf_post_t  ngx_http_proxy_lowat_post =
@@ -119,6 +121,13 @@ static ngx_command_t  ngx_http_proxy_commands[] = {
       offsetof(ngx_http_proxy_loc_conf_t, set_x_real_ip),
       NULL },
 
+    { ngx_string("proxy_set_x_var"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_proxy_set_x_var,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("proxy_add_x_forwarded_for"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -1063,9 +1072,9 @@ static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
 {
     ngx_http_proxy_loc_conf_t  *conf;
 
-    ngx_test_null(conf,
-                  ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)),
-                  NGX_CONF_ERROR);
+    if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)))) {
+        return NGX_CONF_ERROR;
+    }
 
     /*
      * set by ngx_pcalloc():
@@ -1078,6 +1087,7 @@ static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
      *    conf->peers = NULL;
      *    conf->cache_path = NULL;
      *    conf->temp_path = NULL;
+     *    conf->x_vars;
      *    conf->busy_lock = NULL;
      */
 
@@ -1305,6 +1315,8 @@ static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
         return NGX_CONF_ERROR;
     }
 
+    lcf->upstream->url = *url;
+
     if (ngx_strncasecmp(url->data + 7, "unix:", 5) == 0) {
 
 #if (NGX_HAVE_UNIX_DOMAIN)
@@ -1367,6 +1379,47 @@ static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
 }
 
 
+static char *ngx_http_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd,
+                                      void *conf)
+{
+    ngx_http_proxy_loc_conf_t *lcf = conf;
+
+    ngx_uint_t                  i, *index;
+    ngx_str_t                  *value;
+    ngx_http_variable_t        *var;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    if (lcf->x_vars.elts == NULL) {
+        if (ngx_array_init(&lcf->x_vars, cf->pool, 4,
+                           sizeof(ngx_http_variable_t *)) == NGX_ERROR)
+        {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    value = cf->args->elts;
+
+    var = cmcf->variables.elts;
+    for (i = 0; i < cmcf->variables.nelts; i++) {
+        if (ngx_strcasecmp(var[i].name.data, value[1].data) == 0) {
+
+            if (!(index = ngx_array_push(&lcf->x_vars))) {
+                return NGX_CONF_ERROR;
+            }
+
+            *index = var[i].index;
+            return NGX_CONF_OK;
+        }
+    }
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "unknown variable name \"%V\"", &value[1]);
+    return NGX_CONF_ERROR;
+}
+
+
 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
 {
 #if (NGX_FREEBSD)
index 4dd97c22ce986241fa547a3f40058cc9a0643ce2..28d7971dfb91208275b3b7045616e1fea1aab359 100644 (file)
@@ -87,6 +87,8 @@ typedef struct {
     ngx_path_t                      *cache_path;
     ngx_path_t                      *temp_path;
 
+    ngx_array_t                      x_vars;
+
     ngx_http_busy_lock_t            *busy_lock;
 
     ngx_http_proxy_upstream_conf_t  *upstream;
index 4dfd4e6d1979d1ae3e6601fff2a938907149d1f4..cf5195368132d8d5300bd6f425ec8aae3e969f3f 100644 (file)
@@ -86,13 +86,15 @@ int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p)
 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
 {
     size_t                           len;
-    ngx_int_t                        escape;
-    ngx_uint_t                       i;
+    ngx_uint_t                       i, escape, *index;
     ngx_buf_t                       *b;
     ngx_chain_t                     *chain;
     ngx_list_part_t                 *part;
     ngx_table_elt_t                 *header;
     ngx_http_request_t              *r;
+    ngx_http_variable_t             *var;
+    ngx_http_variable_value_t       *value;
+    ngx_http_core_main_conf_t       *cmcf;
     ngx_http_proxy_upstream_conf_t  *uc;
 
     r = p->request;
@@ -115,18 +117,18 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
 
     len += uc->uri.len
         + r->uri.len - uc->location->len + escape
-        + 1 + r->args.len                                   /* 1 is for "?" */
+        + sizeof("?") - 1 + r->args.len
         + sizeof(http_version) - 1
         + sizeof(connection_close_header) - 1
-        + 2;                           /* 2 is for "\r\n" at the header end */
+        + sizeof(CRLF) - 1;
 
 
     if (p->lcf->set_x_url) {
         len += sizeof(x_url_header) - 1
-            + 4                                          /* 4 is for "s://" */
+            + sizeof("s://") - 1
             + r->port_text->len
             + r->unparsed_uri.len
-            + 2;                        /* 2 is for "\r\n" at the header end */
+            + sizeof(CRLF) - 1;
 
         if (r->headers_in.host) {
             len += r->headers_in.host_name_len;
@@ -140,17 +142,17 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
 
     if (p->lcf->preserve_host && r->headers_in.host) {
         len += sizeof(host_header) - 1
-            + r->headers_in.host_name_len
-            + 1                                              /* 1 is for ":" */
-            + uc->port_text.len
-            + 2;                                          /* 2 is for "\r\n" */
-    } else {                                              /* 2 is for "\r\n" */
-        len += sizeof(host_header) - 1 + uc->host_header.len + 2;
+            + r->headers_in.host_name_len + sizeof(":") - 1 + uc->port_text.len
+            + sizeof(CRLF) - 1;
+    } else {
+        len += sizeof(host_header) - 1 + uc->host_header.len
+            + sizeof(CRLF) - 1;
     }
 
 
-    if (p->lcf->set_x_real_ip) {                          /* 2 is for "\r\n" */
-        len += sizeof(x_real_ip_header) - 1 + INET_ADDRSTRLEN - 1 + 2;
+    if (p->lcf->set_x_real_ip) {
+        len += sizeof(x_real_ip_header) - 1 + INET_ADDRSTRLEN - 1
+            + sizeof(CRLF) - 1;
     }
 
 
@@ -158,12 +160,29 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
         if (r->headers_in.x_forwarded_for) {
             len += sizeof(x_forwarded_for_header) - 1
                 + r->headers_in.x_forwarded_for->value.len
-                + 2                                         /* 2 is ofr ", " */
-                + INET_ADDRSTRLEN - 1
-                + 2;                                      /* 2 is for "\r\n" */
+                + sizeof(", ") - 1 + INET_ADDRSTRLEN - 1 + sizeof(CRLF) - 1;
+
         } else {
-            len += sizeof(x_forwarded_for_header) - 1 + INET_ADDRSTRLEN - 1 + 2;
-                                                          /* 2 is for "\r\n" */
+            len += sizeof(x_forwarded_for_header) - 1 + INET_ADDRSTRLEN - 1
+                + sizeof(CRLF) - 1;
+        }
+    }
+
+
+    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+    var = cmcf->variables.elts;
+    index = p->lcf->x_vars.elts;
+
+    for (i = 0; i < p->lcf->x_vars.nelts; i++) {
+
+        if (!(value = ngx_http_get_variable(r, index[i]))) {
+            continue;
+        }
+
+        if (value->text.len) {
+            len += sizeof("X-") - 1 + var[index[i]].name.len + sizeof(": ") - 1
+                + value->text.len + sizeof(CRLF) - 1;
         }
     }
 
@@ -191,16 +210,24 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
             continue;
         }
 
-        /* 2 is for ": " and 2 is for "\r\n" */
-        len += header[i].key.len + 2 + header[i].value.len + 2;
+        len += header[i].key.len + sizeof(": ") - 1
+            + header[i].value.len + sizeof(CRLF) - 1;
     }
 
 #if (NGX_DEBUG)
     len++;
 #endif
 
-    ngx_test_null(b, ngx_create_temp_buf(r->pool, len), NULL);
-    ngx_alloc_link_and_set_buf(chain, b, r->pool, NULL);
+    if (!(b = ngx_create_temp_buf(r->pool, len))) {
+        return NULL;
+    }
+
+    if (!(chain = ngx_alloc_chain_link(r->pool))) {
+        return NULL;
+    }
+
+    chain->buf = b;
+    chain->next = NULL;
 
 
     /* the request line */
@@ -227,7 +254,7 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
     }
 
     if (r->args.len > 0) {
-        *(b->last++) = '?';
+        *b->last++ = '?';
         b->last = ngx_cpymem(b->last, r->args.data, r->args.len);
     }
 
@@ -249,7 +276,7 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
                              r->headers_in.host_name_len);
 
         if (!uc->default_port) {
-            *(b->last++) = ':';
+            *b->last++ = ':';
             b->last = ngx_cpymem(b->last, uc->port_text.data,
                                  uc->port_text.len);
         }
@@ -258,7 +285,7 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
         b->last = ngx_cpymem(b->last, uc->host_header.data,
                              uc->host_header.len);
     }
-    *(b->last++) = CR; *(b->last++) = LF;
+    *b->last++ = CR; *b->last++ = LF;
 
 
     /* the "X-URL" header */
@@ -271,12 +298,12 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
 #if (NGX_OPENSSL)
 
         if (r->connection->ssl) {
-            *(b->last++) = 's';
+            *b->last++ = 's';
         }
 
 #endif
 
-        *(b->last++) = ':'; *(b->last++) = '/'; *(b->last++) = '/';
+        *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/';
 
         if (r->headers_in.host) {
             b->last = ngx_cpymem(b->last, r->headers_in.host->value.data,
@@ -290,7 +317,7 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
         b->last = ngx_cpymem(b->last, r->unparsed_uri.data,
                              r->unparsed_uri.len);
 
-        *(b->last++) = CR; *(b->last++) = LF;
+        *b->last++ = CR; *b->last++ = LF;
     }
 
 
@@ -301,7 +328,7 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
                              sizeof(x_real_ip_header) - 1);
         b->last = ngx_cpymem(b->last, r->connection->addr_text.data,
                              r->connection->addr_text.len);
-        *(b->last++) = CR; *(b->last++) = LF;
+        *b->last++ = CR; *b->last++ = LF;
     }
 
 
@@ -316,7 +343,7 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
                                  r->headers_in.x_forwarded_for->value.data,
                                  r->headers_in.x_forwarded_for->value.len);
 
-            *(b->last++) = ','; *(b->last++) = ' ';
+            *b->last++ = ','; *b->last++ = ' ';
 
         } else {
             b->last = ngx_cpymem(b->last, x_forwarded_for_header,
@@ -325,7 +352,30 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
 
         b->last = ngx_cpymem(b->last, r->connection->addr_text.data,
                              r->connection->addr_text.len);
-        *(b->last++) = CR; *(b->last++) = LF;
+        *b->last++ = CR; *b->last++ = LF;
+    }
+
+
+    for (i = 0; i < p->lcf->x_vars.nelts; i++) {
+
+        if (!(value = ngx_http_get_variable(r, index[i]))) {
+            continue;
+        }
+
+        if (value->text.len == 0) {
+            continue;
+        }
+
+        *b->last++ = 'X'; *b->last++ = '-';
+
+        b->last = ngx_cpymem(b->last, var[index[i]].name.data,
+                             var[index[i]].name.len);
+
+        *b->last++ = ':'; *b->last++ = ' ';
+
+        b->last = ngx_cpymem(b->last, value->text.data, value->text.len);
+
+        *b->last++ = CR; *b->last++ = LF;
     }
 
 
@@ -372,12 +422,12 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
 
         b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len);
 
-        *(b->last++) = ':'; *(b->last++) = ' ';
+        *b->last++ = ':'; *b->last++ = ' ';
 
         b->last = ngx_cpymem(b->last, header[i].value.data,
                              header[i].value.len);
 
-        *(b->last++) = CR; *(b->last++) = LF;
+        *b->last++ = CR; *b->last++ = LF;
 
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "http proxy header: \"%V: %V\"",
@@ -385,10 +435,10 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
     }
 
     /* add "\r\n" at the header end */
-    *(b->last++) = CR; *(b->last++) = LF;
+    *b->last++ = CR; *b->last++ = LF;
 
 #if (NGX_DEBUG)
-    *(b->last) = '\0';
+    *b->last = '\0';
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http proxy header:\n\"%s\"", b->pos);
 #endif
index 21d2e5543f7952cfb40d1d0173033b9aceacfb3d..26f1cb416fc34f37f76f1ace56ecbfdef317e927 100644 (file)
@@ -26,7 +26,7 @@ static char *ngx_http_merge_locations(ngx_conf_t *cf,
                                       ngx_http_module_t *module,
                                       ngx_uint_t ctx_index);
 
-int         ngx_http_max_module;
+ngx_uint_t  ngx_http_max_module;
 
 ngx_uint_t  ngx_http_total_requests;
 uint64_t    ngx_http_total_sent;
@@ -89,19 +89,20 @@ static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 #endif
 
 #if (NGX_SUPPRESS_WARN)
-    /* MSVC thinks 'in_ports' may be used without having been initialized */
+    /* MSVC thinks "in_ports" may be used without having been initialized */
     ngx_memzero(&in_ports, sizeof(ngx_array_t));
 #endif
 
 
     /* the main http context */
 
-    ngx_test_null(ctx,
-                  ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)),
-                  NGX_CONF_ERROR);
+    if (!(ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)))) {
+        return NGX_CONF_ERROR;
+    }
 
     *(ngx_http_conf_ctx_t **) conf = ctx;
 
+
     /* count the number of the http modules and set up their indices */
 
     ngx_http_max_module = 0;
@@ -113,24 +114,42 @@ static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         ngx_modules[m]->ctx_index = ngx_http_max_module++;
     }
 
-    /* the main http main_conf, it's the same in the all http contexts */
 
-    ngx_test_null(ctx->main_conf,
-                  ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
-                  NGX_CONF_ERROR);
+    /* the http main_conf context, it is the same in the all http contexts */
+
+    ctx->main_conf = ngx_pcalloc(cf->pool,
+                                 sizeof(void *) * ngx_http_max_module);
+    if (ctx->main_conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
 
-    /* the http null srv_conf, it's used to merge the server{}s' srv_conf's */
-    ngx_test_null(ctx->srv_conf,
-                  ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
-                  NGX_CONF_ERROR);
+    /*
+     * the http null srv_conf context, it is used to merge
+     * the server{}s' srv_conf's
+     */
 
-    /* the http null loc_conf, it's used to merge the server{}s' loc_conf's */
-    ngx_test_null(ctx->loc_conf,
-                  ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
-                  NGX_CONF_ERROR);
+    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
+    if (ctx->srv_conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
 
 
-    /* create the main_conf, srv_conf and loc_conf in all http modules */
+    /*
+     * the http null loc_conf context, it is used to merge
+     * the server{}s' loc_conf's
+     */
+
+    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
+    if (ctx->loc_conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+
+    /*
+     * create the main_conf's, the null srv_conf's, and the null loc_conf's
+     * of the all http modules
+     */
 
     for (m = 0; ngx_modules[m]; m++) {
         if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
@@ -147,21 +166,25 @@ static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         }
 
         if (module->create_main_conf) {
-            ngx_test_null(ctx->main_conf[mi], module->create_main_conf(cf),
-                          NGX_CONF_ERROR);
+            if (!(ctx->main_conf[mi] = module->create_main_conf(cf))) {
+                return NGX_CONF_ERROR;
+            }
         }
 
         if (module->create_srv_conf) {
-            ngx_test_null(ctx->srv_conf[mi], module->create_srv_conf(cf),
-                          NGX_CONF_ERROR);
+            if (!(ctx->srv_conf[mi] = module->create_srv_conf(cf))) {
+                return NGX_CONF_ERROR;
+            }
         }
 
         if (module->create_loc_conf) {
-            ngx_test_null(ctx->loc_conf[mi], module->create_loc_conf(cf),
-                          NGX_CONF_ERROR);
+            if (!(ctx->loc_conf[mi] = module->create_loc_conf(cf))) {
+                return NGX_CONF_ERROR;
+            }
         }
     }
 
+
     /* parse inside the http{} block */
 
     pcf = *cf;
@@ -236,57 +259,59 @@ static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                     *cf = pcf;
                     return rv;
                 }
-
-#if 0
-                clcfp = (ngx_http_core_loc_conf_t **) cscfp[s]->locations.elts;
-
-                for (l = 0; l < cscfp[s]->locations.nelts; l++) {
-                    rv = module->merge_loc_conf(cf,
-                                                cscfp[s]->ctx->loc_conf[mi],
-                                                clcfp[l]->loc_conf[mi]);
-                    if (rv != NGX_CONF_OK) {
-                        *cf = pcf;
-                        return rv;
-                    }
-                }
-#endif
             }
         }
     }
 
-    /* we needed "http"'s cf->ctx while merging configuration */
+
+    /* we needed http{}'s cf->ctx while the merging configuration */
     *cf = pcf;
 
+
     /* init lists of the handlers */
 
-    ngx_init_array(cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
-                   cf->cycle->pool, 10, sizeof(ngx_http_handler_pt),
-                   NGX_CONF_ERROR);
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
+                       cf->pool, 1, sizeof(ngx_http_handler_pt)) == NGX_ERROR)
+    {
+        return NGX_CONF_ERROR;
+    }
+
     cmcf->phases[NGX_HTTP_REWRITE_PHASE].type = NGX_OK;
 
 
-    /* the special find config phase for single handler */
+    /* the special find config phase for a single handler */
+
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers,
+                       cf->pool, 1, sizeof(ngx_http_handler_pt)) == NGX_ERROR)
+    {
+        return NGX_CONF_ERROR;
+    }
 
-    ngx_init_array(cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers,
-                   cf->cycle->pool, 1, sizeof(ngx_http_handler_pt),
-                   NGX_CONF_ERROR);
     cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].type = NGX_OK;
 
-    ngx_test_null(h, ngx_push_array(
-                           &cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers),
-                  NGX_CONF_ERROR);
+    h = ngx_push_array(&cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
     *h = ngx_http_find_location_config;
 
 
-    ngx_init_array(cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,
-                   cf->cycle->pool, 10, sizeof(ngx_http_handler_pt),
-                   NGX_CONF_ERROR);
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,
+                       cf->pool, 1, sizeof(ngx_http_handler_pt)) == NGX_ERROR)
+    {
+        return NGX_CONF_ERROR;
+    }
+
     cmcf->phases[NGX_HTTP_ACCESS_PHASE].type = NGX_DECLINED;
 
 
-    ngx_init_array(cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
-                   cf->cycle->pool, 10, sizeof(ngx_http_handler_pt),
-                   NGX_CONF_ERROR);
+    if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
+                       cf->pool, 4, sizeof(ngx_http_handler_pt)) == NGX_ERROR)
+    {
+        return NGX_CONF_ERROR;
+    }
+
     cmcf->phases[NGX_HTTP_CONTENT_PHASE].type = NGX_OK;
 
 
index be0052e590f7fb98128ff2b1ac966614d69eca8f..85be911a6357d48aba7b8781bb22ce11dc93ff26 100644 (file)
@@ -38,6 +38,9 @@ typedef struct {
 #define NGX_HTTP_MAIN_CONF        0x02000000
 #define NGX_HTTP_SRV_CONF         0x04000000
 #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_MAIN_CONF_OFFSET  offsetof(ngx_http_conf_ctx_t, main_conf)
index bf455d86797ae28ad0519b1c6ef8db4399598f16..10fcb8790a02322081692293894c5c52896c0751 100644 (file)
 #define NGX_HTTP_LOCATION_REGEX           4
 
 
-static void ngx_http_phase_event_handler(ngx_event_t *rev);
-static void ngx_http_run_phases(ngx_http_request_t *r);
-static ngx_int_t ngx_http_find_location(ngx_http_request_t *r,
-                                        ngx_array_t *locations, size_t len);
+static void ngx_http_core_phase_event_handler(ngx_event_t *rev);
+static void ngx_http_core_run_phases(ngx_http_request_t *r);
+static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r,
+                                            ngx_array_t *locations, size_t len);
 
 static void *ngx_http_core_create_main_conf(ngx_conf_t *cf);
 static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf);
@@ -31,23 +31,33 @@ static void *ngx_http_core_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf,
                                           void *parent, void *child);
 
-static char *ngx_server_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
-static int ngx_cmp_locations(const void *first, const void *second);
-static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd,
-                                void *dummy);
-static char *ngx_types_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-static char *ngx_set_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
-static char *ngx_http_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-static char *ngx_set_server_name(ngx_conf_t *cf, ngx_command_t *cmd,
+static char *ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
+                                  void *dummy);
+static char *ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd,
+                                    void *dummy);
+static int ngx_http_core_cmp_locations(const void *first, const void *second);
+
+static char *ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd,
                                  void *conf);
-static char *ngx_set_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-static char *ngx_set_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-static char *ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-static char *ngx_set_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy,
+                                void *conf);
+
+static char *ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
+                                  void *conf);
+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_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,
+                                     void *conf);
+static char *ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
+                                     void *conf);
 
-static char *ngx_http_lowat_check(ngx_conf_t *cf, void *post, void *data);
+static char *ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data);
 
-static ngx_conf_post_t  ngx_http_lowat_post = { ngx_http_lowat_check } ;
+static ngx_conf_post_t  ngx_http_core_lowat_post =
+                                                 { ngx_http_core_lowat_check };
 
 
 static ngx_conf_enum_t  ngx_http_restrict_host_names[] = {
@@ -76,7 +86,7 @@ static ngx_command_t  ngx_http_core_commands[] = {
 
     { ngx_string("server"),
       NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
-      ngx_server_block,
+      ngx_http_core_server,
       0,
       0,
       NULL },
@@ -132,7 +142,7 @@ static ngx_command_t  ngx_http_core_commands[] = {
 
     { ngx_string("location"),
       NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
-      ngx_location_block,
+      ngx_http_core_location,
       NGX_HTTP_SRV_CONF_OFFSET,
       0,
       NULL },
@@ -143,14 +153,14 @@ static ngx_command_t  ngx_http_core_commands[] = {
 #else
       NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
 #endif
-      ngx_http_listen,
+      ngx_http_core_listen,
       NGX_HTTP_SRV_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("server_name"),
       NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
-      ngx_set_server_name,
+      ngx_http_core_server_name,
       NGX_HTTP_SRV_CONF_OFFSET,
       0,
       NULL },
@@ -158,7 +168,7 @@ static ngx_command_t  ngx_http_core_commands[] = {
     { ngx_string("types"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
                                           |NGX_CONF_BLOCK|NGX_CONF_NOARGS,
-      ngx_types_block,
+      ngx_http_core_types,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
@@ -172,14 +182,14 @@ static ngx_command_t  ngx_http_core_commands[] = {
 
     { ngx_string("root"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_set_root,
+      ngx_http_core_root,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("alias"),
       NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_set_root,
+      ngx_http_core_root,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
@@ -245,7 +255,7 @@ static ngx_command_t  ngx_http_core_commands[] = {
       ngx_conf_set_size_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_core_loc_conf_t, send_lowat),
-      &ngx_http_lowat_post },
+      &ngx_http_core_lowat_post },
 
     { ngx_string("postpone_output"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
@@ -255,7 +265,8 @@ static ngx_command_t  ngx_http_core_commands[] = {
       NULL },
 
     { ngx_string("limit_rate"),
-      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_LIF_CONF
+                        |NGX_CONF_TAKE1,
       ngx_conf_set_size_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_core_loc_conf_t, limit_rate),
@@ -263,7 +274,7 @@ static ngx_command_t  ngx_http_core_commands[] = {
 
     { ngx_string("keepalive_timeout"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
-      ngx_set_keepalive,
+      ngx_http_core_keepalive,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
@@ -298,14 +309,14 @@ static ngx_command_t  ngx_http_core_commands[] = {
 
     { ngx_string("error_page"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
-      ngx_set_error_page,
+      ngx_http_core_error_page,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("error_log"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
-      ngx_set_error_log,
+      ngx_http_core_error_log,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
       NULL },
@@ -399,15 +410,18 @@ void ngx_http_handler(ngx_http_request_t *r)
     /* TEST STUB */ r->lingering_close = 1;
 #endif
 
-    r->connection->write->event_handler = ngx_http_phase_event_handler;
+    r->connection->write->event_handler = ngx_http_core_phase_event_handler;
 
-    ngx_http_run_phases(r);
+    r->uri_changed = 1;
+    r->uri_changes = 11;
+
+    ngx_http_core_run_phases(r);
 
     return;
 }
 
 
-static void ngx_http_phase_event_handler(ngx_event_t *ev)
+static void ngx_http_core_phase_event_handler(ngx_event_t *ev)
 {
     ngx_connection_t    *c;
     ngx_http_request_t  *r;
@@ -417,15 +431,14 @@ static void ngx_http_phase_event_handler(ngx_event_t *ev)
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "phase event handler");
 
-    ngx_http_run_phases(r);
+    ngx_http_core_run_phases(r);
 
     return;
 }
 
 
-static void ngx_http_run_phases(ngx_http_request_t *r)
+static void ngx_http_core_run_phases(ngx_http_request_t *r)
 {
-    char                       *path;
     ngx_int_t                   rc;
     ngx_http_handler_pt        *h;
     ngx_http_core_loc_conf_t   *clcf;
@@ -435,10 +448,38 @@ static void ngx_http_run_phases(ngx_http_request_t *r)
 
     for (/* void */; r->phase < NGX_HTTP_LAST_PHASE; r->phase++) {
 
+        if (r->phase == NGX_HTTP_FIND_CONFIG_PHASE && !r->uri_changed) {
+            continue;
+        }
+
+        if (r->phase == NGX_HTTP_FIND_CONFIG_PHASE + 1 && r->uri_changed) {
+
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "uri changes: %d", r->uri_changes);
+
+            /*
+             * gcc before 3.3 compiles the broken code for
+             *     if (r->uri_changes-- == 0)
+             * if the r->uri_changes is defined as
+             *     unsigned  uri_changes:4
+             */
+
+            r->uri_changes--;
+
+            if (r->uri_changes == 0) {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                              "rewrite cycle");
+                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+                return;
+            }
+
+            r->uri_changed = 0;
+            r->phase = NGX_HTTP_REWRITE_PHASE;
+        }
+
         if (r->phase == NGX_HTTP_CONTENT_PHASE && r->content_handler) {
             r->connection->write->event_handler = ngx_http_empty_handler;
-            rc = r->content_handler(r);
-            ngx_http_finalize_request(r, rc);
+            ngx_http_finalize_request(r, r->content_handler(r));
             return;
         }
 
@@ -483,21 +524,15 @@ static void ngx_http_run_phases(ngx_http_request_t *r)
         }
     }
 
+    /* no content handler was found */
 
     if (r->uri.data[r->uri.len - 1] == '/') {
 
         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-        if (!(path = ngx_palloc(r->pool, clcf->root.len + r->uri.len))) {
-            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-            return;
-        }
-    
-        ngx_cpystrn(ngx_cpymem(path, clcf->root.data, clcf->root.len),
-                    r->uri.data, r->uri.len + 1);
-    
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "directory index of \"%s\" is forbidden", path);
+                      "directory index of \"%V%V\" is forbidden",
+                      &clcf->root, &r->uri);
 
         ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN);
         return;
@@ -518,7 +553,7 @@ ngx_int_t ngx_http_find_location_config(ngx_http_request_t *r)
 
     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
 
-    rc = ngx_http_find_location(r, &cscf->locations, 0);
+    rc = ngx_http_core_find_location(r, &cscf->locations, 0);
 
     if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
         return rc;
@@ -583,8 +618,8 @@ ngx_int_t ngx_http_find_location_config(ngx_http_request_t *r)
 }
 
 
-static ngx_int_t ngx_http_find_location(ngx_http_request_t *r,
-                                        ngx_array_t *locations, size_t len)
+static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r,
+                                            ngx_array_t *locations, size_t len)
 {
     ngx_int_t                  n, rc;
     ngx_uint_t                 i, found, noregex;
@@ -604,6 +639,10 @@ static ngx_int_t ngx_http_find_location(ngx_http_request_t *r,
         }
 #endif
 
+        if (clcfp[i]->noname) {
+            break;
+        }
+
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "find location: %s\"%V\"",
                        clcfp[i]->exact_match ? "= " : "", &clcfp[i]->name);
@@ -632,9 +671,14 @@ static ngx_int_t ngx_http_find_location(ngx_http_request_t *r,
         }
 
         if (n == 0) {
-            if (clcfp[i]->exact_match && r->uri.len == clcfp[i]->name.len) {
-                r->loc_conf = clcfp[i]->loc_conf;
-                return NGX_HTTP_LOCATION_EXACT;
+            if (clcfp[i]->exact_match) {
+
+                if (r->uri.len == clcfp[i]->name.len) {
+                    r->loc_conf = clcfp[i]->loc_conf;
+                    return NGX_HTTP_LOCATION_EXACT;
+                }
+
+                continue;
             }
 
             if (len > clcfp[i]->name.len) {
@@ -652,7 +696,7 @@ static ngx_int_t ngx_http_find_location(ngx_http_request_t *r,
         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
         if (clcf->locations.nelts) {
-            rc = ngx_http_find_location(r, &clcf->locations, len);
+            rc = ngx_http_core_find_location(r, &clcf->locations, len);
 
             if (rc != NGX_OK) {
                 return rc;
@@ -674,6 +718,10 @@ static ngx_int_t ngx_http_find_location(ngx_http_request_t *r,
             continue;
         }
 
+        if (clcfp[i]->noname) {
+            break;
+        }
+
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "find location: ~ \"%V\"", &clcfp[i]->name);
 
@@ -706,6 +754,7 @@ static ngx_int_t ngx_http_find_location(ngx_http_request_t *r,
 
 ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r)
 {
+    u_char                     c, *p, *exten;
     uint32_t                   key;
     ngx_uint_t                 i;
     ngx_http_type_t           *type;
@@ -724,6 +773,37 @@ ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r)
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (r->exten.len) {
+
+        if (!r->low_case_exten) {
+            for (i = 0; i < r->exten.len; i++) {
+                c = r->exten.data[i];
+                if (c >= 'A' && c <= 'Z') {
+                    break;
+                }
+            }
+
+            if (i < r->exten.len) {
+                if (!(p = ngx_palloc(r->pool, r->exten.len))) {
+                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                }
+
+                exten = p;
+
+                for (i = 0; i < r->exten.len; i++) {
+                    c = r->exten.data[i];
+                    if (c >= 'A' && c <= 'Z') {
+                        *p++ = (u_char) (c | 0x20);
+                    } else {
+                        *p++ = c;
+                    }
+                }
+
+                r->exten.data = exten;
+            }
+
+            r->low_case_exten = 1;
+        }
+
 #if 0
         key = ngx_crc(r->exten.data, r->exten.key);
 #endif
@@ -826,6 +906,8 @@ ngx_int_t ngx_http_set_exten(ngx_http_request_t *r)
         }
     }
 
+    r->low_case_exten = 0;
+
     return NGX_OK;
 }
 
@@ -864,6 +946,7 @@ ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r,
 
     r->phase = 0;
     r->phase_handler = 0;
+    r->content_handler = NULL;
 
     ngx_http_handler(r);
 
@@ -893,48 +976,60 @@ int ngx_http_delay_handler(ngx_http_request_t *r)
 #endif
 
 
-#if 0
-
-static ngx_int_t ngx_http_core_init_process(ngx_cycle_t *cycle)
+ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf)
 {
-    ngx_uint_t                   i;
-    ngx_http_core_srv_conf_t   **cscfp;
-    ngx_http_core_main_conf_t   *cmcf;
+    ngx_http_variable_t        *var;
+    ngx_http_core_main_conf_t  *cmcf;
 
-    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
 
-#if 0
-    ngx_http_core_init_module:
+    if (cmcf->variables.elts == NULL) {
+        if (ngx_array_init(&cmcf->variables, cf->pool, 5,
+                           sizeof(ngx_http_variable_t)) == NGX_ERROR)
+        {
+            return NULL;
+        }
+    }
 
-    ngx_http_handler_pt         *h;
+    if (!(var = ngx_array_push(&cmcf->variables))) {
+        return NULL;
+    }
 
-    ngx_test_null(h, ngx_push_array(
-                             &cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].handlers),
-                  NGX_ERROR);
-    *h = ngx_http_delay_handler;
-#endif
+    var->index = cmcf->variables.nelts - 1;
+
+    return var;
+}
 
-    cscfp = cmcf->servers.elts;
 
-    for (i = 0; i < cmcf->servers.nelts; i++) {
-        if (cscfp[i]->recv == NULL) {
-            cscfp[i]->recv = ngx_io.recv;
-            cscfp[i]->send_chain = ngx_io.send_chain;
-        }
+ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
+                                                 ngx_uint_t index)
+{
+    ngx_http_variable_t        *v;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    /* TODO: cached variables */
+
+    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+    if (cmcf->variables.elts == NULL || cmcf->variables.nelts <= index) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      "unknown variable index: %d", index);
+        return NULL;
     }
 
-    return NGX_OK;
-}
+    v = cmcf->variables.elts;    
 
-#endif
+    return v[index].handler(r, v[index].data);
+}
 
 
-static char *ngx_server_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
+static char *ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
+                                  void *dummy)
 {
     int                          m;
     char                        *rv;
     ngx_http_module_t           *module;
-    ngx_conf_t                   pvcf;
+    ngx_conf_t                   save;
     ngx_http_conf_ctx_t         *ctx, *http_ctx;
     ngx_http_core_main_conf_t   *cmcf;
     ngx_http_core_srv_conf_t    *cscf, **cscfp;
@@ -989,67 +1084,32 @@ static char *ngx_server_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
 
     /* parse inside server{} */
 
-    pvcf = *cf;
+    save = *cf;
     cf->ctx = ctx;
     cf->cmd_type = NGX_HTTP_SRV_CONF;
+
     rv = ngx_conf_parse(cf, NULL);
-    *cf = pvcf;
+
+    *cf = save;
 
     if (rv != NGX_CONF_OK) {
         return rv;
     }
 
     ngx_qsort(cscf->locations.elts, (size_t) cscf->locations.nelts,
-              sizeof(ngx_http_core_loc_conf_t *), ngx_cmp_locations);
+              sizeof(ngx_http_core_loc_conf_t *), ngx_http_core_cmp_locations);
 
     return rv;
 }
 
 
-static int ngx_cmp_locations(const void *one, const void *two)
-{
-    ngx_int_t                  rc;
-    ngx_http_core_loc_conf_t  *first, *second;
-
-    first = *(ngx_http_core_loc_conf_t **) one;
-    second = *(ngx_http_core_loc_conf_t **) two;
-
-#if (NGX_PCRE)
-
-    if (first->regex && !second->regex) {
-        /* shift the regex matches to the end */
-        return 1;
-    }
-
-    if (!first->regex && second->regex) {
-        /* shift the regex matches to the end */
-        return -1;
-    }
-
-    if (first->regex || second->regex) {
-        /* do not sort the regex matches */
-        return 0;
-    }
-
-#endif
-
-    rc = ngx_strcmp(first->name.data, second->name.data);
-
-    if (rc == 0 && second->exact_match) {
-        /* an exact match must be before the same inclusive one */
-        return 1;
-    }
-
-    return (int) rc;
-}
-
-
-static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
+static char *ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd,
+                                    void *dummy)
 {
     char                      *rv;
     ngx_int_t                  m;
     ngx_str_t                 *value;
-    ngx_conf_t                 pcf;
+    ngx_conf_t                 save;
     ngx_http_module_t         *module;
     ngx_http_conf_ctx_t       *ctx, *pctx;
     ngx_http_core_srv_conf_t  *cscf;
@@ -1150,7 +1210,9 @@ static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
         }
 
     } else {
+#if 0
         clcf->prev_location = pclcf;
+#endif
 
         if (pclcf->exact_match) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -1176,7 +1238,7 @@ static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
         }
 
         if (pclcf->locations.elts == NULL) {
-            ngx_init_array(pclcf->locations, cf->pool, 5, sizeof(void *),
+            ngx_init_array(pclcf->locations, cf->pool, 4, sizeof(void *),
                            NGX_CONF_ERROR);
         }
 
@@ -1187,38 +1249,103 @@ static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
 
     *clcfp = clcf;
 
-    pcf = *cf;
+    save = *cf;
     cf->ctx = ctx;
     cf->cmd_type = NGX_HTTP_LOC_CONF;
+
     rv = ngx_conf_parse(cf, NULL);
-    *cf = pcf;
+
+    *cf = save;
+
+    if (rv != NGX_CONF_OK) {
+        return rv;
+    }
+
+    ngx_qsort(clcf->locations.elts, (size_t) clcf->locations.nelts,
+              sizeof(ngx_http_core_loc_conf_t *), ngx_http_core_cmp_locations);
 
     return rv;
 }
 
 
-static char *ngx_types_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+static int ngx_http_core_cmp_locations(const void *one, const void *two)
+{
+    ngx_int_t                  rc;
+    ngx_http_core_loc_conf_t  *first, *second;
+
+    first = *(ngx_http_core_loc_conf_t **) one;
+    second = *(ngx_http_core_loc_conf_t **) two;
+
+    if (first->noname && !second->noname) {
+        /* shift no named locations to the end */
+        return 1;
+    }
+
+    if (!first->noname && second->noname) {
+        /* shift no named locations to the end */
+        return -1;
+    }
+
+    if (first->noname || second->noname) {
+        /* do not sort no named locations */
+        return 0;
+    }
+
+#if (NGX_PCRE)
+
+    if (first->regex && !second->regex) {
+        /* shift the regex matches to the end */
+        return 1;
+    }
+
+    if (!first->regex && second->regex) {
+        /* shift the regex matches to the end */
+        return -1;
+    }
+
+    if (first->regex || second->regex) {
+        /* do not sort the regex matches */
+        return 0;
+    }
+
+#endif
+
+    rc = ngx_strcmp(first->name.data, second->name.data);
+
+    if (rc == 0 && second->exact_match) {
+        /* an exact match must be before the same inclusive one */
+        return 1;
+    }
+
+    return (int) rc;
+}
+
+
+static char *ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char        *rv;
-    ngx_conf_t   pcf;
+    ngx_conf_t   save;
 
-    pcf = *cf;
-    cf->handler = ngx_set_type;
+    save = *cf;
+    cf->handler = ngx_http_core_type;
     cf->handler_conf = conf;
+
     rv = ngx_conf_parse(cf, NULL);
-    *cf = pcf;
+
+    *cf = save;
 
     return rv;
 }
 
 
-static char *ngx_set_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
+static char *ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy,
+                                void *conf)
 {
     ngx_http_core_loc_conf_t *lcf = conf;
 
     uint32_t          key;
     ngx_uint_t        i;
-    ngx_str_t        *args;
+    ngx_str_t        *value;
     ngx_http_type_t  *type;
 
     if (lcf->types == NULL) {
@@ -1237,17 +1364,17 @@ static char *ngx_set_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
         }
     }
 
-    args = (ngx_str_t *) cf->args->elts;
+    value = cf->args->elts;
 
     for (i = 1; i < cf->args->nelts; i++) {
-        ngx_http_types_hash_key(key, args[i]);
+        ngx_http_types_hash_key(key, value[i]);
 
         if (!(type = ngx_array_push(&lcf->types[key]))) {
             return NGX_CONF_ERROR;
         }
 
-        type->exten = args[i];
-        type->type = args[0];
+        type->exten = value[i];
+        type->type = value[0];
     }
 
     return NGX_CONF_OK;
@@ -1256,15 +1383,17 @@ static char *ngx_set_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
 
 static void *ngx_http_core_create_main_conf(ngx_conf_t *cf)
 {
-    ngx_http_core_main_conf_t *cmcf;
+    ngx_http_core_main_conf_t  *cmcf;
 
-    ngx_test_null(cmcf,
-                  ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t)),
-                  NGX_CONF_ERROR);
+    if (!(cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t)))) {
+        return NGX_CONF_ERROR;
+    }
 
-    ngx_init_array(cmcf->servers, cf->pool,
-                   5, sizeof(ngx_http_core_srv_conf_t *),
-                   NGX_CONF_ERROR);
+    if (ngx_array_init(&cmcf->servers, cf->pool, 5,
+                       sizeof(ngx_http_core_srv_conf_t *)) == NGX_ERROR)
+    {
+        return NGX_CONF_ERROR;
+    }
 
     cmcf->server_names_hash = NGX_CONF_UNSET_UINT;
     cmcf->server_names_hash_threshold = NGX_CONF_UNSET_UINT;
@@ -1396,7 +1525,7 @@ static char *ngx_http_core_merge_srv_conf(ngx_conf_t *cf,
 
 static void *ngx_http_core_create_loc_conf(ngx_conf_t *cf)
 {
-    ngx_http_core_loc_conf_t *lcf;
+    ngx_http_core_loc_conf_t  *lcf;
 
     ngx_test_null(lcf,
                   ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)),
@@ -1547,7 +1676,8 @@ static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf,
 }
 
 
-static char *ngx_http_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+static char *ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
+                                  void *conf)
 {
     ngx_http_core_srv_conf_t *scf = conf;
 
@@ -1633,7 +1763,8 @@ static char *ngx_http_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 }
 
 
-static char *ngx_set_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+static char *ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd,
+                                       void *conf)
 {
     ngx_http_core_srv_conf_t *scf = conf;
 
@@ -1683,7 +1814,7 @@ static char *ngx_set_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 }
 
 
-static char *ngx_set_root(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)
 {
     ngx_http_core_loc_conf_t *lcf = conf;
 
@@ -1723,7 +1854,8 @@ static char *ngx_set_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 }
 
 
-static char *ngx_set_error_page(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)
 {
     ngx_http_core_loc_conf_t *lcf = conf;
 
@@ -1793,7 +1925,8 @@ static char *ngx_set_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 }
 
 
-static char *ngx_set_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+static char *ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
+                                     void *conf)
 {
     ngx_http_core_loc_conf_t *lcf = conf;
 
@@ -1831,7 +1964,8 @@ static char *ngx_set_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 }
 
 
-static char *ngx_set_error_log(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,
+                                     void *conf)
 {
     ngx_http_core_loc_conf_t *lcf = conf;
 
@@ -1843,7 +1977,7 @@ static char *ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 }
 
 
-static char *ngx_http_lowat_check(ngx_conf_t *cf, void *post, void *data)
+static char *ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data)
 {
 #if (NGX_FREEBSD)
     ssize_t *np = data;
index eee43bcb05abccf6d8d43485163dfa5819f7df7e..1c60991af4b9bb73005163caf1be7926b8c8020b 100644 (file)
@@ -36,6 +36,27 @@ typedef enum {
 } ngx_http_phases;
 
 
+typedef struct {
+    ngx_uint_t                 value;
+    ngx_str_t                  text;
+} ngx_http_variable_value_t;
+
+
+typedef struct ngx_http_variable_s  ngx_http_variable_t;
+
+typedef ngx_http_variable_value_t
+               *(*ngx_http_get_variable_pt) (ngx_http_request_t *r, void *var);
+
+
+struct ngx_http_variable_s {
+    ngx_str_t                  name;
+    ngx_uint_t                 index;
+    ngx_http_get_variable_pt   handler;
+    void                      *data;
+    ngx_uint_t                 uses;
+};
+
+
 typedef struct {
     ngx_array_t                handlers;
     ngx_int_t                  type;                /* NGX_OK, NGX_DECLINED */
@@ -43,7 +64,7 @@ typedef struct {
 
 
 typedef struct {
-    ngx_array_t                servers; /* array of ngx_http_core_srv_conf_t */
+    ngx_array_t                servers;         /* ngx_http_core_srv_conf_t */
 
     ngx_http_phase_t           phases[NGX_HTTP_LAST_PHASE];
     ngx_array_t                index_handlers;
@@ -52,20 +73,22 @@ typedef struct {
     ngx_uint_t                 server_names_hash_threshold;
 
     size_t                     max_server_name_len;
+
+    ngx_array_t                variables;        /* ngx_http_variable_t */
 } ngx_http_core_main_conf_t;
 
 
 typedef struct {
     /*
-     * array of ngx_http_core_loc_conf_t, used in the translation handler
-     * and in the merge phase
+     * array of the ngx_http_core_loc_conf_t,
+     * used in the translation handler and in the merge phase
      */
     ngx_array_t                locations;
 
-    /* "listen", array of ngx_http_listen_t */
+    /* array of the ngx_http_listen_t, "listen" directive */
     ngx_array_t                listen;
 
-    /* "server_name", array of ngx_http_server_name_t */
+    /* array of the ngx_http_server_name_t, "server_name" directive */
     ngx_array_t                server_names;
 
     /* server ctx */
@@ -158,6 +181,8 @@ struct ngx_http_core_loc_conf_s {
     ngx_regex_t  *regex;
 #endif
 
+    unsigned      noname:1;   /* "if () {}" block */
+
     unsigned      exact_match:1;
     unsigned      noregex:1;
 
@@ -205,19 +230,21 @@ struct ngx_http_core_loc_conf_s {
 
     ngx_log_t    *err_log;
 
+#if 0
     ngx_http_core_loc_conf_t  *prev_location;
+#endif
 };
 
 
+
 extern ngx_http_module_t  ngx_http_core_module_ctx;
 extern ngx_module_t  ngx_http_core_module;
 
-extern int ngx_http_max_module;
+extern ngx_uint_t ngx_http_max_module;
 
 
 
 ngx_int_t ngx_http_find_location_config(ngx_http_request_t *r);
-ngx_int_t ngx_http_core_translate_handler(ngx_http_request_t *r);
 
 ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r);
 ngx_int_t ngx_http_set_exten(ngx_http_request_t *r);
@@ -225,6 +252,10 @@ ngx_int_t ngx_http_set_exten(ngx_http_request_t *r);
 ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r,
                                      ngx_str_t *uri, ngx_str_t *args);
 
+ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf);
+ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
+                                                 ngx_uint_t index);
+
 
 typedef ngx_int_t (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r);
 typedef ngx_int_t (*ngx_http_output_body_filter_pt)
index 142010739af8fb8c179be9fb160ef3cccaf09707..d4f906f1ab5f0f0412d2a028d36075f6c649ad54 100644 (file)
@@ -893,8 +893,8 @@ static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
 
     fmt->name = value[1];
 
-    if (!(fmt->ops = ngx_create_array(cf->pool, 20,
-                                      sizeof(ngx_http_log_op_t)))) {
+    if (!(fmt->ops = ngx_array_create(cf->pool, 20, sizeof(ngx_http_log_op_t))))
+    {
         return NGX_CONF_ERROR;
     }
 
index b17c2008eae739a3dbe8c69597c2d244152c8e33..f5912ac6046f9e68830c72e7cd352efb50e20d7c 100644 (file)
@@ -229,6 +229,9 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
             case '/':
                 r->complex_uri = 1;
                 break;
+            case '+':
+                r->plus_in_uri = 1;
+                break;
             case '?':
                 r->args_start = p + 1;
                 state = sw_uri;
@@ -268,6 +271,9 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
                 r->uri_ext = NULL;
                 state = sw_after_slash_in_uri;
                 break;
+            case '+':
+                r->plus_in_uri = 1;
+                break;
             case '%':
                 r->quoted_uri = 1;
                 state = sw_uri;
@@ -291,6 +297,9 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
                 r->uri_end = p;
                 r->http_minor = 9;
                 goto done;
+            case '+':
+                r->plus_in_uri = 1;
+                break;
             case ' ':
                 r->uri_end = p;
                 state = sw_http_09;
index 14121d1ffde33eb1b883e11e55d1bf3fd06c590d..a4e3d0e5a0bfa31c1cc8f95f7803d4d6ce58af44 100644 (file)
@@ -298,6 +298,9 @@ struct ngx_http_request_s {
     ngx_int_t            phase_handler;
     ngx_http_handler_pt  content_handler;
 
+    ngx_uint_t           nvariables;
+    void               **variables;
+
     ngx_array_t          cleanup;
 
     /* used to learn the Apache compatible response length without a header */
@@ -313,14 +316,19 @@ struct ngx_http_request_s {
 
     unsigned             http_state:4;
 
-#if 0
-    /* URI is not started with '/' - "GET http://" */
-    unsigned             unusual_uri:1;
-#endif
     /* URI with "/." and on Win32 with "//" */
     unsigned             complex_uri:1;
+
     /* URI with "%" */
     unsigned             quoted_uri:1;
+
+    /* URI with "+" */
+    unsigned             plus_in_uri:1;
+
+    unsigned             uri_changed:1;
+    unsigned             uri_changes:4;
+
+    unsigned             low_case_exten:1;
     unsigned             header_timeout_set:1;
 
     unsigned             proxy:1;
index dae82692689e885e10fdc3b316a1e2bb07e29a23..11e0f3105021de29c1010ae558ad997de6719b04 100644 (file)
@@ -664,13 +664,14 @@ static void ngx_http_upstream_process_header(ngx_event_t *rev)
 static void ngx_http_upstream_send_response(ngx_http_request_t *r,
                                             ngx_http_upstream_t *u)
 {
+    ngx_int_t                  rc;
     ngx_event_pipe_t          *p;
     ngx_http_core_loc_conf_t  *clcf;
 
+    rc = u->send_header(r);
 
-    if (u->send_header(r) == NGX_HTTP_INTERNAL_SERVER_ERROR) {
-        ngx_http_upstream_finalize_request(r, u,
-                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
+    if (rc == NGX_ERROR || rc > NGX_OK) {
+        ngx_http_upstream_finalize_request(r, u, rc);
         return;
     }