changeset 144:e1c6ac408b68 NGINX_0_3_19

nginx 0.3.19 *) Feature: the "path" and "alias" directives support the variables. *) Change: now the "valid_referers" directive again checks the URI part. *) Bugfix: in SSI handling.
author Igor Sysoev <http://sysoev.ru>
date Wed, 28 Dec 2005 00:00:00 +0300
parents c2fa0caa07f2
children 85a84f8da62b
files CHANGES CHANGES.ru auto/cc/icc src/core/nginx.h src/core/ngx_buf.h src/core/ngx_hash.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_referer_module.c src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_postpone_filter_module.c src/http/ngx_http_request.h
diffstat 13 files changed, 235 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,12 @@
+
+Changes with nginx 0.3.19                                        28 Dec 2005
+
+    *) Feature: the "path" and "alias" directives support the variables.
+
+    *) Change: now the "valid_referers" directive again checks the URI part.
+
+    *) Bugfix: in SSI handling.
+
 
 Changes with nginx 0.3.18                                        26 Dec 2005
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,3 +1,12 @@
+
+Изменения в nginx 0.3.19                                          28.12.2005
+
+    *) Добавление: директивы path и alias поддерживают переменные.
+
+    *) Изменение: теперь директива valid_referers опять учитывает URI.
+
+    *) Исправление: ошибки в обработке SSI.
+
 
 Изменения в nginx 0.3.18                                          26.12.2005
 
--- a/auto/cc/icc
+++ b/auto/cc/icc
@@ -114,11 +114,17 @@ case "$NGX_ICC_VER" in
         # conversion from pointer to same-sized integral type,
         # warning on offsetof()
         CFLAGS="$CFLAGS -wd1684"
+        # floating-point equality and inequality comparisons are unreliable,
+        # warning on SvTRUE()
+        CFLAGS="$CFLAGS -wd1572"
     ;;
 
     8.*)
         # "cc" clobber ignored, warnings for Liunx's htonl()/htons()
         CFLAGS="$CFLAGS -wd1469"
+        # floating-point equality and inequality comparisons are unreliable,
+        # warning on SvTRUE()
+        CFLAGS="$CFLAGS -wd1572"
     ;;
 
     *)
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.18"
+#define NGINX_VER          "nginx/0.3.19"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_buf.h
+++ b/src/core/ngx_buf.h
@@ -105,10 +105,15 @@ typedef struct {
 
 #define ngx_buf_in_memory(b)        (b->temporary || b->memory || b->mmap)
 #define ngx_buf_in_memory_only(b)   (ngx_buf_in_memory(b) && !b->in_file)
+
 #define ngx_buf_special(b)                                                   \
     ((b->flush || b->last_buf || b->sync)                                    \
      && !ngx_buf_in_memory(b) && !b->in_file)
 
+#define ngx_buf_sync_only(b)                                                 \
+    (b->sync                                                                 \
+     && !ngx_buf_in_memory(b) && !b->in_file && !b->flush && !b->last_buf)
+
 #define ngx_buf_size(b)                                                      \
     (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos):                      \
                             (b->file_last - b->file_pos))
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -129,13 +129,14 @@ ngx_hash_find_wildcard(ngx_hash_wildcard
 
 
 #define NGX_HASH_ELT_SIZE(name)                                               \
-            sizeof(void *) + ngx_align((name)->key.len + 1, sizeof(void *))
+    (sizeof(void *) + ngx_align((name)->key.len + 1, sizeof(void *)))
 
 ngx_int_t
 ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
 {
     u_char          *elts;
-    size_t          *test, len;
+    size_t           len;
+    u_short         *test;
     ngx_uint_t       i, n, key, size, start, bucket_size;
     ngx_hash_elt_t  *elt, **buckets;
 
@@ -151,14 +152,14 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng
         if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
         {
             ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
-                          "could not build the %s hash, you should "
+                          "could not build the %s, you should "
                           "increase %s_bucket_size: %i",
                           hinit->name, hinit->name, hinit->bucket_size);
             return NGX_ERROR;
         }
     }
 
-    test = ngx_alloc(hinit->max_size * sizeof(size_t), hinit->pool->log);
+    test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log);
     if (test == NULL) {
         return NGX_ERROR;
     }
@@ -170,7 +171,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng
 
     for (size = start; size < hinit->max_size; size++) {
 
-        ngx_memzero(test, size * sizeof(size_t));
+        ngx_memzero(test, size * sizeof(u_short));
 
         for (n = 0; n < nelts; n++) {
             if (names[n].key.data == NULL) {
@@ -178,7 +179,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng
             }
 
             key = names[n].key_hash % size;
-            test[key] += NGX_HASH_ELT_SIZE(&names[n]);
+            test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
 
 #if 0
             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
@@ -186,7 +187,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng
                           size, key, test[key], &names[n].key);
 #endif
 
-            if (test[key] > bucket_size) {
+            if (test[key] > (u_short) bucket_size) {
                 goto next;
             }
         }
@@ -199,7 +200,7 @@ ngx_hash_init(ngx_hash_init_t *hinit, ng
     }
 
     ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
-                  "could not build the %s hash, you should increase "
+                  "could not build the %s, you should increase "
                   "either %s_max_size: %i or %s_bucket_size: %i",
                   hinit->name, hinit->name, hinit->max_size,
                   hinit->name, hinit->bucket_size);
@@ -220,7 +221,7 @@ found:
         }
 
         key = names[n].key_hash % size;
-        test[key] += NGX_HASH_ELT_SIZE(&names[n]);
+        test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
     }
 
     len = 0;
@@ -230,7 +231,7 @@ found:
             continue;
         }
 
-        test[i] = ngx_align(test[i], ngx_cacheline_size);
+        test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size));
 
         len += test[i];
     }
@@ -291,7 +292,7 @@ found:
             elt->name[i] = ngx_tolower(names[n].key.data[i]);
         }
 
-        test[key] += NGX_HASH_ELT_SIZE(&names[n]);
+        test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
     }
 
     for (i = 0; i < size; i++) {
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -291,7 +291,7 @@ ngx_http_index_handler(ngx_http_request_
         uri.len = r->uri.len + ctx->index.len - 1;
 
         if (!clcf->alias) {
-            uri.data = ctx->path.data + clcf->root.len;
+            uri.data = ctx->path.data + r->root_length;
 
         } else {
             uri.data = ngx_palloc(r->pool, uri.len);
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -9,6 +9,8 @@
 #include <ngx_http.h>
 
 
+#define NGX_HTTP_REFERER_NO_URI_PART  ((void *) 4)
+
 typedef struct {
     ngx_hash_t               hash;
     ngx_hash_wildcard_t     *dns_wildcards;
@@ -26,7 +28,7 @@ static char * ngx_http_referer_merge_con
 static char *ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 static char *ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys,
-    ngx_str_t *value);
+    ngx_str_t *value, ngx_str_t *uri);
 static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one,
     const void *two);
 
@@ -79,9 +81,12 @@ static ngx_int_t
 ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
      uintptr_t data)
 {
-    u_char                   *p, *ref;
+    u_char                   *p, *ref, *last;
     size_t                    len;
+    ngx_str_t                *uri;
+    ngx_uint_t                i, key;
     ngx_http_referer_conf_t  *rlcf;
+    u_char                    buf[256];
 
     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module);
 
@@ -89,19 +94,15 @@ ngx_http_referer_variable(ngx_http_reque
         && rlcf->dns_wildcards == NULL
         && rlcf->dns_wildcards->hash.buckets == NULL)
     {
-        *v = ngx_http_variable_null_value;
-        return NGX_OK;
+        goto valid;
     }
 
     if (r->headers_in.referer == NULL) {
         if (rlcf->no_referer) {
-            *v = ngx_http_variable_null_value;
-            return NGX_OK;
+            goto valid;
+        }
 
-        } else {
-            *v = ngx_http_variable_true_value;
-            return NGX_OK;
-        }
+        goto invalid;
     }
 
     len = r->headers_in.referer->value.len;
@@ -111,43 +112,79 @@ ngx_http_referer_variable(ngx_http_reque
         || (ngx_strncasecmp(ref, "http://", 7) != 0))
     {
         if (rlcf->blocked_referer) {
-            *v = ngx_http_variable_null_value;
-            return NGX_OK;
+            goto valid;
+        }
 
-        } else {
-            *v = ngx_http_variable_true_value;
-            return NGX_OK;
-        }
+        goto invalid;
     }
 
-    len -= 7;
+    last = ref + len;
     ref += 7;
+    i = 0;
+    key = 0;
 
-    for (p = ref; p < ref + len; p++) {
+    for (p = ref; p < last; p++) {
         if (*p == '/' || *p == ':') {
             break;
         }
+
+        buf[i] = ngx_tolower(*p);
+        key = ngx_hash(key, buf[i++]);
+
+        if (i == 256) {
+            goto invalid;
+        }
     }
 
     len = p - ref;
 
     if (rlcf->hash.buckets) {
-        if (ngx_hash_find(&rlcf->hash, ngx_hash_key_lc(ref, len), ref, len)) {
-            *v = ngx_http_variable_null_value;
-            return NGX_OK;
+        uri = ngx_hash_find(&rlcf->hash, key, buf, len);
+        if (uri) {
+            goto uri;
         }
     }
 
     if (rlcf->dns_wildcards && rlcf->dns_wildcards->hash.buckets) {
-        if (ngx_hash_find_wildcard(rlcf->dns_wildcards, ref, len)) {
-            *v = ngx_http_variable_null_value;
-            return NGX_OK;
+        uri = ngx_hash_find_wildcard(rlcf->dns_wildcards, buf, len);
+        if (uri) {
+            goto uri;
         }
     }
 
+invalid:
+
     *v = ngx_http_variable_true_value;
 
     return NGX_OK;
+
+uri:
+
+    for ( /* void */ ; p < last; p++) {
+        if (*p == '/') {
+            break;
+        }
+    }
+
+    len = last - p;
+
+    if (len == 0) {
+        goto invalid;
+    }
+
+    if (uri == NGX_HTTP_REFERER_NO_URI_PART) {
+        goto valid;
+    }
+
+    if (len < uri->len || ngx_strncmp(uri->data, p, uri->len) != 0) {
+        goto invalid;
+    }
+
+valid:
+
+    *v = ngx_http_variable_null_value;
+
+    return NGX_OK;
 }
 
 
@@ -241,7 +278,7 @@ ngx_http_valid_referers(ngx_conf_t *cf, 
     ngx_http_referer_conf_t  *rlcf = conf;
 
     u_char                    *p;
-    ngx_str_t                 *value, name;
+    ngx_str_t                 *value, uri, name;
     ngx_uint_t                 i, n;
     ngx_http_variable_t       *var;
     ngx_http_server_name_t    *sn;
@@ -291,13 +328,17 @@ ngx_http_valid_referers(ngx_conf_t *cf, 
             continue;
         }
 
+        uri.len = 0;
+
         if (ngx_strcmp(value[i].data, "server_names") == 0) {
 
             cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
 
             sn = cscf->server_names.elts;
             for (n = 0; n < cscf->server_names.nelts; n++) {
-                if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name) != NGX_OK)                {
+                if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name, &uri)
+                    != NGX_OK)
+                {
                     return NGX_CONF_ERROR;
                 }
             }
@@ -308,13 +349,12 @@ ngx_http_valid_referers(ngx_conf_t *cf, 
         p = (u_char *) ngx_strstr(value[i].data, "/");
 
         if (p) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "URI part \"%s\" is deprecated, ignored", p);
-
+            uri.len = (value[i].data + value[i].len) - p;
+            uri.data = p;
             value[i].len = p - value[i].data;
         }
 
-        if (ngx_http_add_referer(cf, rlcf->keys, &value[i]) != NGX_OK) {
+        if (ngx_http_add_referer(cf, rlcf->keys, &value[i], &uri) != NGX_OK) {
             return NGX_CONF_ERROR;
         }
     }
@@ -325,11 +365,12 @@ ngx_http_valid_referers(ngx_conf_t *cf, 
 
 static char *
 ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys,
-    ngx_str_t *value)
+    ngx_str_t *value, ngx_str_t *uri)
 {
-    u_char      ch;
-    ngx_int_t   rc;
-    ngx_uint_t  flags;
+    u_char       ch;
+    ngx_int_t    rc;
+    ngx_str_t   *u;
+    ngx_uint_t   flags;
 
     ch = value->data[0];
 
@@ -344,7 +385,19 @@ ngx_http_add_referer(ngx_conf_t *cf, ngx
 
     flags = (ch == '*' || ch == '.') ? NGX_HASH_WILDCARD_KEY : 0;
 
-    rc = ngx_hash_add_key(keys, value, (void *) 4, flags);
+    if (uri->len == 0) {
+        u = NGX_HTTP_REFERER_NO_URI_PART;
+
+    } else {
+        u = ngx_palloc(cf->pool, sizeof(ngx_str_t));
+        if (u == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *u = *uri;
+    }
+
+    rc = ngx_hash_add_key(keys, value, u, flags);
 
     if (rc == NGX_OK) {
         return NGX_CONF_OK;
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -11,8 +11,6 @@
 
 
 static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-static int ngx_libc_cdecl ngx_cmp_server_names(const void *one,
-    const void *two);
 static ngx_int_t ngx_http_add_address(ngx_conf_t *cf,
     ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *lscf,
     ngx_http_core_srv_conf_t *cscf);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -984,23 +984,66 @@ u_char *
 ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path,
     size_t reserved)
 {
-    u_char                    *last;
-    size_t                     alias;
-    ngx_http_core_loc_conf_t  *clcf;
+    u_char                       *last;
+    size_t                        alias, len;
+    ngx_http_script_code_pt       code;
+    ngx_http_script_engine_t      e;
+    ngx_http_core_loc_conf_t     *clcf;
+    ngx_http_script_len_code_pt   lcode;
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     alias = clcf->alias ? clcf->name.len : 0;
 
-    path->len = clcf->root.len + r->uri.len - alias + 1 + reserved;
-
-    path->data = ngx_palloc(r->pool, path->len);
+    if (clcf->root_lengths == NULL) {
+
+        r->root_length = clcf->root.len;
+
+        path->len = clcf->root.len + r->uri.len - alias + 1 + reserved;
+
+        path->data = ngx_palloc(r->pool, path->len);
+        if (path->data == NULL) {
+            return NULL;
+        }
+
+        last = ngx_copy(path->data, clcf->root.data, clcf->root.len);
+        last = ngx_cpystrn(last, r->uri.data + alias, r->uri.len - alias + 1);
+
+        return last;
+    }
+
+    ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+    e.ip = clcf->root_lengths->elts;
+    e.request = r;
+    e.flushed = 1;
+
+    len = 0;
+
+    while (*(uintptr_t *) e.ip) {
+        lcode = *(ngx_http_script_len_code_pt *) e.ip;
+        len += lcode(&e);
+    }
+
+    r->root_length = len;
+
+    len += r->uri.len - alias + 1 + reserved;
+
+    path->len = len;
+    path->data = ngx_palloc(r->pool, len);
     if (path->data == NULL) {
         return NULL;
     }
 
-    last = ngx_copy(path->data, clcf->root.data, clcf->root.len);
-    last = ngx_cpystrn(last, r->uri.data + alias, r->uri.len - alias + 1);
+    e.ip = clcf->root_values->elts;
+    e.pos = path->data;
+
+    while (*(uintptr_t *) e.ip) {
+        code = *(ngx_http_script_code_pt *) e.ip;
+        code((ngx_http_script_engine_t *) &e);
+    }
+
+    last = ngx_cpystrn(e.pos, r->uri.data + alias, r->uri.len - alias + 1);
 
     return last;
 }
@@ -1957,7 +2000,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     }
 
     ngx_conf_merge_unsigned_value(conf->types_hash_max_size,
-                                  prev->types_hash_max_size, 512);
+                                  prev->types_hash_max_size, 1024);
 
     ngx_conf_merge_unsigned_value(conf->types_hash_bucket_size,
                                   prev->types_hash_bucket_size,
@@ -1977,7 +2020,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
         types_hash.key = ngx_hash_key_lc;
         types_hash.max_size = conf->types_hash_max_size;
         types_hash.bucket_size = conf->types_hash_bucket_size;
-        types_hash.name = "mime_types";
+        types_hash.name = "types_hash";
         types_hash.pool = cf->pool;
         types_hash.temp_pool = NULL;
 
@@ -2019,7 +2062,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
         types_hash.key = ngx_hash_key_lc;
         types_hash.max_size = conf->types_hash_max_size;
         types_hash.bucket_size = conf->types_hash_bucket_size;
-        types_hash.name = "mime_types";
+        types_hash.name = "mime_types_hash";
         types_hash.pool = cf->pool;
         types_hash.temp_pool = NULL;
 
@@ -2340,8 +2383,9 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
 {
     ngx_http_core_loc_conf_t *lcf = conf;
 
-    ngx_uint_t   alias;
-    ngx_str_t   *value;
+    ngx_str_t                  *value;
+    ngx_uint_t                  alias, n;
+    ngx_http_script_compile_t   sc;
 
     alias = (cmd->name.len == sizeof("alias") - 1) ? 1 : 0;
 
@@ -2372,6 +2416,26 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
         lcf->root.len--;
     }
 
+    n = ngx_http_script_variables_count(&value[1]);
+
+    if (n == 0) {
+        return NGX_CONF_OK;
+    }
+
+    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+    sc.cf = cf;
+    sc.source = &value[1];
+    sc.lengths = &lcf->root_lengths;
+    sc.values = &lcf->root_values;
+    sc.variables = n;
+    sc.complete_lengths = 1;
+    sc.complete_values = 1;
+
+    if (ngx_http_script_compile(&sc) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -197,6 +197,9 @@ struct ngx_http_core_loc_conf_s {
     ngx_str_t     root;                    /* root, alias */
     ngx_str_t     post_action;
 
+    ngx_array_t  *root_lengths;
+    ngx_array_t  *root_values;
+
     ngx_array_t  *types;
     ngx_hash_t    types_hash;
     ngx_str_t     default_type;
--- a/src/http/ngx_http_postpone_filter_module.c
+++ b/src/http/ngx_http_postpone_filter_module.c
@@ -102,18 +102,22 @@ ngx_http_postpone_filter(ngx_http_reques
         out = in;
     }
 
-    if (out == NULL && r->main->out == NULL && !r->main->connection->buffered) {
-        return NGX_OK;
-    }
+    rc = NGX_OK;
+
+    if (out || r->main->out || r->main->connection->buffered) {
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http postpone filter out \"%V?%V\"", &r->uri, &r->args);
 
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http postpone filter out \"%V?%V\"", &r->uri, &r->args);
+        if (!(out && out->next == NULL && ngx_buf_sync_only(out->buf))) {
+
+            rc = ngx_http_next_filter(r->main, out);
 
-    rc = ngx_http_next_filter(r->main, out);
-
-    if (rc == NGX_ERROR) {
-        /* NGX_ERROR may be returned by any filter */
-        r->connection->error = 1;
+            if (rc == NGX_ERROR) {
+                /* NGX_ERROR may be returned by any filter */
+                r->connection->error = 1;
+            }
+        }
     }
 
     if (r->postponed == NULL) {
@@ -135,6 +139,7 @@ static ngx_int_t
 ngx_http_postpone_filter_output_postponed_request(ngx_http_request_t *r)
 {
     ngx_int_t                      rc;
+    ngx_chain_t                   *out;
     ngx_http_postponed_request_t  *pr;
 
     for ( ;; ) {
@@ -165,13 +170,17 @@ ngx_http_postpone_filter_output_postpone
             pr = r->postponed;
         }
 
-        if (pr->out) {
+        out = pr->out;
+
+        if (out) {
             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                            "http postpone filter out postponed \"%V?%V\"",
                            &r->uri, &r->args);
 
-            if (ngx_http_next_filter(r->main, pr->out) == NGX_ERROR) {
-                return NGX_ERROR;
+            if (!(out && out->next == NULL && ngx_buf_sync_only(out->buf))) {
+                if (ngx_http_next_filter(r->main, out) == NGX_ERROR) {
+                    return NGX_ERROR;
+                }
             }
         }
 
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -340,6 +340,8 @@ struct ngx_http_request_s {
 
     ngx_http_variable_value_t        *variables;
 
+    size_t                            root_length;
+
     size_t                            limit_rate;
 
     /* used to learn the Apache compatible response length without a header */