diff options
36 files changed, 2485 insertions, 596 deletions
@@ -1,4 +1,31 @@ +Changes with nginx 0.1.17 03 Feb 2005 + + *) Feature: 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; bug appeared in 0.1.14. + + *) Bugfix: the system error message was not logged on Linux. + + Changes with nginx 0.1.16 25 Jan 2005 *) Bugfix: if the response were transferred by chunks, then on the HEAD diff --git a/CHANGES.ru b/CHANGES.ru index 05c7687fd..c9a42d9ba 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,32 @@ +Изменения в nginx 0.1.17 03.02.2005 + + *) Добавление: модуль ngx_http_rewrite_module полностью переписан. + Теперь можно делать редиректы, возвращать коды ошибок и проверять + переменные и рефереры. Эти директивы можно использовать внутри + location. Директива redirect упразднена. + + *) Добавление: модуль ngx_http_geo_module. + + *) Добавление: директивы proxy_set_x_var и fastcgi_set_var. + + *) Исправление: конфигурация location с модификатором "=" могла + использоваться в другом location. + + *) Исправление: правильный тип ответа выставлялся только для запросов, + у которых в расширении были только маленькие буквы. + + *) Исправление: если для location установлен proxy_pass или + fastcgi_pass, и доступ к нему запрещался, а ошибка перенаправлялась + на статическую страницу, то происходил segmentation fault. + + *) Исправление: если в проксированном ответе в заголовке "Location" + передавался относительный URL, то к нему добавлялось имя хоста и + слэш; ошибка появилась в 0.1.14. + + *) Исправление: на Linux в лог не записывался текст системной ошибки. + + Изменения в nginx 0.1.16 25.01.2005 *) Исправление: если ответ передавался chunk'ами, то при запросе HEAD diff --git a/auto/cc/gcc b/auto/cc/gcc index d5bf1dc3d..24b908d26 100644 --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -28,6 +28,7 @@ fi # optimizations #CFLAGS="$CFLAGS -O2 -fomit-frame-pointer" +#CFLAGS="$CFLAGS -Os -fomit-frame-pointer" case $CPU in pentium) diff --git a/auto/modules b/auto/modules index 3221e26f1..375b755f0 100644 --- a/auto/modules +++ b/auto/modules @@ -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 diff --git a/auto/options b/auto/options index 3d552df77..9aff6e228 100644 --- a/auto/options +++ b/auto/options @@ -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 diff --git a/auto/sources b/auto/sources index c61d83af3..ac177f1df 100644 --- a/auto/sources +++ b/auto/sources @@ -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 @@ -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 diff --git a/src/core/nginx.h b/src/core/nginx.h index 0b9d9905c..c6afc4599 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 6eae76ffd..82d5d1db8 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 */ + + 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; +} diff --git a/src/core/ngx_array.h b/src/core/ngx_array.h index 931c7fb50..d90cf76f0 100644 --- a/src/core/ngx_array.h +++ b/src/core/ngx_array.h @@ -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_ */ diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index 19a567f68..e9cc24de5 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -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; } diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h index fcef373c3..dc791d406 100644 --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -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__ */ diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index db43a4438..13053f200 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -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) diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c index c1b55e552..fc6f36e83 100644 --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -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; } diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h index 53448f4f3..71be7424e 100644 --- a/src/core/ngx_palloc.h +++ b/src/core/ngx_palloc.h @@ -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; diff --git a/src/core/ngx_radix_tree.c b/src/core/ngx_radix_tree.c new file mode 100644 index 000000000..9493bab8a --- /dev/null +++ b/src/core/ngx_radix_tree.c @@ -0,0 +1,213 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +static void *ngx_radix_alloc(ngx_radix_tree_t *tree); + + +ngx_radix_tree_t *ngx_radix_tree_create(ngx_pool_t *pool) +{ + ngx_radix_tree_t *tree; + + if (!(tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t)))) { + return NULL; + } + + tree->pool = pool; + tree->free = NULL; + tree->start = NULL; + tree->size = 0; + + if (!(tree->root = ngx_radix_alloc(tree))) { + return NULL; + } + + tree->root->right = NULL; + tree->root->left = NULL; + tree->root->parent = NULL; + tree->root->value = NGX_RADIX_NO_VALUE; + + return tree; +} + + +ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree, + uint32_t key, uint32_t mask, uintptr_t value) +{ + uint32_t bit; + ngx_radix_node_t *node, *next; + + bit = 0x80000000; + + node = tree->root; + next = tree->root; + + while (bit & mask) { + if (key & bit) { + next = node->right; + + } else { + next = node->left; + } + + if (next == NULL) { + break; + } + + bit >>= 1; + node = next; + } + + if (next) { + if (node->value != NGX_RADIX_NO_VALUE) { + return NGX_BUSY; + } + + node->value = value; + return NGX_OK; + } + + while (bit & mask) { + if (!(next = ngx_radix_alloc(tree))) { + return NGX_ERROR; + } + + next->right = NULL; + next->left = NULL; + next->parent = node; + next->value = NGX_RADIX_NO_VALUE; + + if (key & bit) { + node->right = next; + + } else { + node->left = next; + } + + bit >>= 1; + node = next; + } + + node->value = value; + + return NGX_OK; +} + + +ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree, + uint32_t key, uint32_t mask) +{ + uint32_t bit; + ngx_radix_node_t *node; + + bit = 0x80000000; + node = tree->root; + + while (node && (bit & mask)) { + if (key & bit) { + node = node->right; + + } else { + node = node->left; + } + + bit >>= 1; + } + + if (node == NULL) { + return NGX_ERROR; + } + + if (node->right || node->left) { + if (node->value != NGX_RADIX_NO_VALUE) { + node->value = NGX_RADIX_NO_VALUE; + return NGX_OK; + } + + return NGX_ERROR; + } + + for ( ;; ) { + if (node->parent->right == node) { + node->parent->right = NULL; + } else { + node->parent->left = NULL; + } + + node->right = tree->free; + tree->free = node; + + node = node->parent; + + if (node->right + || node->left + || node->value != NGX_RADIX_NO_VALUE + || node->parent == NULL) + { + break; + } + } + + return NGX_OK; +} + + +uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key) +{ + uint32_t bit; + uintptr_t value; + ngx_radix_node_t *node; + + bit = 0x80000000; + value = NGX_RADIX_NO_VALUE; + node = tree->root; + + while (node) { + if (node->value != NGX_RADIX_NO_VALUE) { + value = node->value; + } + + if (key & bit) { + node = node->right; + + } else { + node = node->left; + } + + bit >>= 1; + } + + return value; +} + + +static void *ngx_radix_alloc(ngx_radix_tree_t *tree) +{ + char *p; + + if (tree->free) { + p = (char *) tree->free; + tree->free = tree->free->right; + return p; + } + + if (tree->size < sizeof(ngx_radix_node_t)) { + if (!(tree->start = ngx_palloc(tree->pool, ngx_pagesize))) { + return NULL; + } + + tree->size = ngx_pagesize; + } + + p = tree->start; + 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 new file mode 100644 index 000000000..c2d8a36a2 --- /dev/null +++ b/src/core/ngx_radix_tree.h @@ -0,0 +1,44 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_RADIX_TREE_H_INCLUDED_ +#define _NGX_RADIX_TREE_H_INCLUDED_ + + +#include <ngx_config.h> +#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 { + ngx_radix_node_t *right; + ngx_radix_node_t *left; + ngx_radix_node_t *parent; + uintptr_t value; +}; + + +typedef struct { + ngx_radix_node_t *root; + ngx_pool_t *pool; + ngx_radix_node_t *free; + char *start; + size_t size; +} ngx_radix_tree_t; + + +ngx_radix_tree_t *ngx_radix_tree_create(ngx_pool_t *pool); +ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree, + uint32_t key, uint32_t mask, uintptr_t value); +ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree, + uint32_t key, uint32_t mask); +uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key); + + +#endif /* _NGX_RADIX_TREE_H_INCLUDED_ */ diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 37a75aab3..d63a23850 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -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; } diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h index abef82d45..766880738 100644 --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -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 diff --git a/src/http/modules/ngx_http_access_handler.c b/src/http/modules/ngx_http_access_handler.c index 01796897f..832f9c2ed 100644 --- a/src/http/modules/ngx_http_access_handler.c +++ b/src/http/modules/ngx_http_access_handler.c @@ -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; } diff --git a/src/http/modules/ngx_http_fastcgi_handler.c b/src/http/modules/ngx_http_fastcgi_handler.c index 9f5016a45..828f7accc 100644 --- a/src/http/modules/ngx_http_fastcgi_handler.c +++ b/src/http/modules/ngx_http_fastcgi_handler.c @@ -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 index 000000000..cd774894c --- /dev/null +++ b/src/http/modules/ngx_http_geo_module.c @@ -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; +} diff --git a/src/http/modules/ngx_http_gzip_filter.c b/src/http/modules/ngx_http_gzip_filter.c index cda9ca31e..ccf5dc4be 100644 --- a/src/http/modules/ngx_http_gzip_filter.c +++ b/src/http/modules/ngx_http_gzip_filter.c @@ -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), diff --git a/src/http/modules/ngx_http_rewrite_handler.c b/src/http/modules/ngx_http_rewrite_handler.c index 636331bc4..b1f591c97 100644 --- a/src/http/modules/ngx_http_rewrite_handler.c +++ b/src/http/modules/ngx_http_rewrite_handler.c @@ -9,79 +9,170 @@ #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 **) ®ex); + 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 **) ®ex); + 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 **) ®ex); + 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 **) ®ex); + 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 **) ®ex); + 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; } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 9cb6e171d..883e44fbc 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -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 */ }; diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c index ea3a0ca43..a195b45e4 100644 --- a/src/http/modules/proxy/ngx_http_proxy_handler.c +++ b/src/http/modules/proxy/ngx_http_proxy_handler.c @@ -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) diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.h b/src/http/modules/proxy/ngx_http_proxy_handler.h index 4dd97c22c..28d7971df 100644 --- a/src/http/modules/proxy/ngx_http_proxy_handler.h +++ b/src/http/modules/proxy/ngx_http_proxy_handler.h @@ -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; diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c index 4dfd4e6d1..cf5195368 100644 --- a/src/http/modules/proxy/ngx_http_proxy_upstream.c +++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c @@ -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 diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 21d2e5543..26f1cb416 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -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; diff --git a/src/http/ngx_http_config.h b/src/http/ngx_http_config.h index be0052e59..85be911a6 100644 --- a/src/http/ngx_http_config.h +++ b/src/http/ngx_http_config.h @@ -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) diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index bf455d867..10fcb8790 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -17,10 +17,10 @@ #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; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index eee43bcb0..1c60991af 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -37,13 +37,34 @@ typedef enum { 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 */ } ngx_http_phase_t; 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) diff --git a/src/http/ngx_http_log_handler.c b/src/http/ngx_http_log_handler.c index 142010739..d4f906f1a 100644 --- a/src/http/ngx_http_log_handler.c +++ b/src/http/ngx_http_log_handler.c @@ -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; } diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index b17c2008e..f5912ac60 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -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; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 14121d1ff..a4e3d0e5a 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -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; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index dae826926..11e0f3105 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -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; } |