nginx-0.1.17-RELEASE import

    *) 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.
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 0b9d990..c6afc45 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -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"
diff --git a/src/core/ngx_array.c b/src/core/ngx_array.c
index 6eae76f..82d5d1d 100644
--- a/src/core/ngx_array.c
+++ b/src/core/ngx_array.c
@@ -8,67 +8,130 @@
 #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 */
 
-            ngx_memcpy(new, a->elts, a->nalloc * a->size);
+            if (!(new = ngx_palloc(p, 2 * size))) {
+                return NULL;
+            }
+
+            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;
+}
diff --git a/src/core/ngx_array.h b/src/core/ngx_array.h
index 931c7fb..d90cf76 100644
--- a/src/core/ngx_array.h
+++ b/src/core/ngx_array.h
@@ -21,9 +21,10 @@
 };
 
 
-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 @@
 }
 
 
-
+/* 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_ */
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index 19a567f..e9cc24d 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -87,7 +87,8 @@
                           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;
         }
 
diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h
index fcef373..dc791d4 100644
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -105,7 +105,7 @@
 
 #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__ */
diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h
index db43a44..13053f2 100644
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -59,6 +59,7 @@
 #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)
diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c
index c1b55e5..fc6f36e 100644
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -16,8 +16,8 @@
        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_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 @@
 
         /* 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;
         }
 
diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h
index 53448f4..71be742 100644
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -33,8 +33,8 @@
 
 
 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;
diff --git a/src/core/ngx_radix_tree.c b/src/core/ngx_radix_tree.c
index c1d349e..9493bab 100644
--- a/src/core/ngx_radix_tree.c
+++ b/src/core/ngx_radix_tree.c
@@ -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 @@
     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_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 @@
             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 @@
     }
 
     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 @@
         node = next;
     }
 
+    node->value = value;
+
     return NGX_OK;
 }
 
@@ -123,8 +125,12 @@
     }
 
     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 @@
 
         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 @@
     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 @@
 }
 
 
-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 @@
         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 @@
     }
 
     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;
 }
diff --git a/src/core/ngx_radix_tree.h b/src/core/ngx_radix_tree.h
index 5398d06..c2d8a36 100644
--- a/src/core/ngx_radix_tree.h
+++ b/src/core/ngx_radix_tree.h
@@ -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 {
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index 37a75aa..d63a238 100644
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -28,6 +28,20 @@
 }
 
 
+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_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 @@
           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 @@
           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 @@
             src++;
         }
 
-        return n;
+        return (uintptr_t) n;
     }
 
     for (i = 0; i < size; i++) {
@@ -679,5 +720,5 @@
         }
     }
 
-    return 0;
+    return (uintptr_t) dst;
 }
diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h
index abef82d..7668807 100644
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -72,6 +72,7 @@
 
 
 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 @@
 
 
 #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