From c5433685e83d8e50c6284e80bef75eccbc53e86c Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Thu, 3 Feb 2005 19:34:28 +0000 Subject: 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 | 27 + CHANGES.ru | 28 + auto/cc/gcc | 1 + auto/modules | 6 + auto/options | 3 + auto/sources | 8 +- auto/unix | 8 +- src/core/nginx.h | 2 +- src/core/ngx_array.c | 99 +- src/core/ngx_array.h | 14 +- src/core/ngx_conf_file.c | 3 +- src/core/ngx_config.h | 2 +- src/core/ngx_core.h | 1 + src/core/ngx_palloc.c | 10 +- src/core/ngx_palloc.h | 4 +- src/core/ngx_radix_tree.c | 213 ++++ src/core/ngx_radix_tree.h | 44 + src/core/ngx_string.c | 55 +- src/core/ngx_string.h | 8 +- src/http/modules/ngx_http_access_handler.c | 2 +- src/http/modules/ngx_http_fastcgi_handler.c | 99 +- src/http/modules/ngx_http_geo_module.c | 252 ++++ src/http/modules/ngx_http_gzip_filter.c | 3 +- src/http/modules/ngx_http_rewrite_handler.c | 1347 +++++++++++++++++----- src/http/modules/ngx_http_ssl_module.c | 2 +- src/http/modules/proxy/ngx_http_proxy_handler.c | 59 +- src/http/modules/proxy/ngx_http_proxy_handler.h | 2 + src/http/modules/proxy/ngx_http_proxy_upstream.c | 122 +- src/http/ngx_http.c | 135 ++- src/http/ngx_http_config.h | 3 + src/http/ngx_http_core_module.c | 438 ++++--- src/http/ngx_http_core_module.h | 45 +- src/http/ngx_http_log_handler.c | 4 +- src/http/ngx_http_parse.c | 9 + src/http/ngx_http_request.h | 16 +- src/http/ngx_http_upstream.c | 7 +- 36 files changed, 2485 insertions(+), 596 deletions(-) create mode 100644 src/core/ngx_radix_tree.c create mode 100644 src/core/ngx_radix_tree.h create mode 100644 src/http/modules/ngx_http_geo_module.c diff --git a/CHANGES b/CHANGES index 679b62750..13a668b91 100644 --- a/CHANGES +++ b/CHANGES @@ -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 diff --git a/auto/unix b/auto/unix index 37bb5d2c6..406f2a23f 100755 --- a/auto/unix +++ b/auto/unix @@ -94,8 +94,8 @@ ngx_feature_name="NGX_HAVE_STRERROR_R" ngx_feature_run=yes ngx_feature_incs="#include " 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 " 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_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 #endif #include +#include #include #include #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 +#include + + +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 +#include + + +#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 +#include +#include + + +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 -#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 @@ -36,6 +36,27 @@ typedef enum { } ngx_http_phases; +typedef struct { + ngx_uint_t value; + ngx_str_t text; +} ngx_http_variable_value_t; + + +typedef struct ngx_http_variable_s ngx_http_variable_t; + +typedef ngx_http_variable_value_t + *(*ngx_http_get_variable_pt) (ngx_http_request_t *r, void *var); + + +struct ngx_http_variable_s { + ngx_str_t name; + ngx_uint_t index; + ngx_http_get_variable_pt handler; + void *data; + ngx_uint_t uses; +}; + + typedef struct { ngx_array_t handlers; ngx_int_t type; /* NGX_OK, NGX_DECLINED */ @@ -43,7 +64,7 @@ typedef struct { typedef struct { - ngx_array_t servers; /* array of ngx_http_core_srv_conf_t */ + ngx_array_t servers; /* ngx_http_core_srv_conf_t */ ngx_http_phase_t phases[NGX_HTTP_LAST_PHASE]; ngx_array_t index_handlers; @@ -52,20 +73,22 @@ typedef struct { ngx_uint_t server_names_hash_threshold; size_t max_server_name_len; + + ngx_array_t variables; /* ngx_http_variable_t */ } ngx_http_core_main_conf_t; typedef struct { /* - * array of ngx_http_core_loc_conf_t, used in the translation handler - * and in the merge phase + * array of the ngx_http_core_loc_conf_t, + * used in the translation handler and in the merge phase */ ngx_array_t locations; - /* "listen", array of ngx_http_listen_t */ + /* array of the ngx_http_listen_t, "listen" directive */ ngx_array_t listen; - /* "server_name", array of ngx_http_server_name_t */ + /* array of the ngx_http_server_name_t, "server_name" directive */ ngx_array_t server_names; /* server ctx */ @@ -158,6 +181,8 @@ struct ngx_http_core_loc_conf_s { ngx_regex_t *regex; #endif + unsigned noname:1; /* "if () {}" block */ + unsigned exact_match:1; unsigned noregex:1; @@ -205,19 +230,21 @@ struct ngx_http_core_loc_conf_s { ngx_log_t *err_log; +#if 0 ngx_http_core_loc_conf_t *prev_location; +#endif }; + extern ngx_http_module_t ngx_http_core_module_ctx; extern ngx_module_t ngx_http_core_module; -extern int ngx_http_max_module; +extern ngx_uint_t ngx_http_max_module; ngx_int_t ngx_http_find_location_config(ngx_http_request_t *r); -ngx_int_t ngx_http_core_translate_handler(ngx_http_request_t *r); ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r); ngx_int_t ngx_http_set_exten(ngx_http_request_t *r); @@ -225,6 +252,10 @@ ngx_int_t ngx_http_set_exten(ngx_http_request_t *r); ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args); +ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf); +ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r, + ngx_uint_t index); + typedef ngx_int_t (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r); typedef ngx_int_t (*ngx_http_output_body_filter_pt) 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; } -- cgit v1.2.1