# HG changeset patch # User Igor Sysoev # Date 1115909886 0 # Node ID 9b8c906f6e63ec2c71cecebfff35819a7d32227d # Parent ca1020ce99baa2592eee8501c76d46d3c7bef285 nginx-0.1.29-RELEASE import *) Feature: the ngx_http_ssi_module supports "include virtual" command. *) Feature: the ngx_http_ssi_module supports the condition command like 'if expr="$NAME"' and "else" and "endif" commands. Only one nested level is supported. *) Feature: the ngx_http_ssi_module supports the DATE_LOCAL and DATE_GMT variables and "config timefmt" command. *) Feature: the "ssi_ignore_recycled_buffers" directive. *) Bugfix: the "echo" command did not show the default value for the empty QUERY_STRING variable. *) Change: the ngx_http_proxy_module was rewritten. *) Feature: the "proxy_redirect", "proxy_pass_request_headers", "proxy_pass_request_body", and "proxy_method" directives. *) Feature: the "proxy_set_header" directive. The "proxy_x_var" was canceled and must be replaced with the proxy_set_header directive. *) Change: the "proxy_preserve_host" is canceled and must be replaced with the "proxy_set_header Host $host" and the "proxy_redirect off" directives, the "proxy_set_header Host $host:$proxy_port" directive and the appropriate proxy_redirect directives. *) Change: the "proxy_set_x_real_ip" is canceled and must be replaced with the "proxy_set_header X-Real-IP $remote_addr" directive. *) Change: the "proxy_add_x_forwarded_for" is canceled and must be replaced with the "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for" directive. *) Change: the "proxy_set_x_url" is canceled and must be replaced with the "proxy_set_header X-URL http://$host:$server_port$request_uri" directive. *) Feature: the "fastcgi_param" directive. *) Change: the "fastcgi_root", "fastcgi_set_var" and "fastcgi_params" directive are canceled and must be replaced with the fastcgi_param directives. *) Feature: the "index" directive can use the variables. *) Feature: the "index" directive can be used at http and server levels. *) Change: the last index only in the "index" directive can be absolute. *) Feature: the "rewrite" directive can use the variables. *) Feature: the "internal" directive. *) Feature: the CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR, SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME, REQUEST_METHOD, REQUEST_URI, and REMOTE_USER variables. *) Change: nginx now passes the invalid lines in a client request headers or a backend response header. *) Bugfix: if the backend did not transfer response for a long time and the "send_timeout" was less than "proxy_read_timeout", then nginx returned the 408 response. *) Bugfix: the segmentation fault was occurred if the backend sent an invalid line in response header; the bug had appeared in 0.1.26. *) Bugfix: the segmentation fault may occurred in FastCGI fault tolerance configuration. *) Bugfix: the "expires" directive did not remove the previous "Expires" and "Cache-Control" headers. *) Bugfix: nginx did not take into account trailing dot in "Host" header line. *) Bugfix: the ngx_http_auth_module did not work under Linux. *) Bugfix: the rewrite directive worked incorrectly, if the arguments were in a request. *) Bugfix: nginx could not be built on MacOS X. diff --git a/auto/cc/gcc b/auto/cc/gcc --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -57,6 +57,11 @@ case $CPU in CPU_OPT="-march=pentium4" ;; + opteron) + # optimize for Opteron, gcc 3.x + CPU_OPT="-march=opteron" + ;; + sparc64) # build 64-bit UltraSparc binary CPU_OPT="-m64" diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -6,18 +6,31 @@ # optimizations -# maximize speed +# maximize speed, equivalent to -Og -Oi -Ot -Oy -Ob2 -Gs -GF -Gy CFLAGS="$CFLAGS -O2" + # enable global optimization -CFLAGS="$CFLAGS -Og" +#CFLAGS="$CFLAGS -Og" # enable intrinsic functions -CFLAGS="$CFLAGS -Oi" -# inline expansion -CFLAGS="$CFLAGS -Ob1" +#CFLAGS="$CFLAGS -Oi" + +# disable inline expansion +#CFLAGS="$CFLAGS -Ob0" +# explicit inline expansion +#CFLAGS="$CFLAGS -Ob1" +# explicit and implicit inline expansion +#CFLAGS="$CFLAGS -Ob2" + # enable frame pointer omission -CFLAGS="$CFLAGS -Oy" +#CFLAGS="$CFLAGS -Oy" # disable stack checking calls -CFLAGS="$CFLAGS -Gs" +#CFLAGS="$CFLAGS -Gs" + +# pools strings as read/write +#CFLAGS="$CFLAGS -Gf" +# pools strings as read-only +#CFLAGS="$CFLAGS -GF" + case $CPU in pentium) diff --git a/auto/have_headers b/auto/have_headers new file mode 100644 --- /dev/null +++ b/auto/have_headers @@ -0,0 +1,11 @@ + +# Copyright (C) Igor Sysoev + + +cat << END >> $NGX_AUTO_HEADERS_H + +#ifndef $have +#define $have 1 +#endif + +END diff --git a/auto/include b/auto/include --- a/auto/include +++ b/auto/include @@ -39,14 +39,7 @@ if [ -x $NGX_AUTOTEST ]; then | tr '[a-z]' '[A-Z]'` - cat << END >> $NGX_AUTO_HEADERS_H - -#ifndef NGX_HAVE_$ngx_name -#define NGX_HAVE_$ngx_name 1 -#endif - -END - + have=NGX_HAVE_$ngx_name . auto/have_headers eval "NGX_INCLUDE_$ngx_name='#include <$ngx_include>'" diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -51,6 +51,10 @@ if [ $NGX_TEST_BUILD_SOLARIS_SENDFILEV = fi +if [ $HTTP_SSI = YES ]; then + HTTP_POSTPONE=YES +fi + # the filter order is important # ngx_http_write_filter # ngx_http_header_filter @@ -58,6 +62,7 @@ fi # ngx_http_range_header_filter # ngx_http_ssl_filter # ngx_http_gzip_filter +# ngx_http_postpone_filter # ngx_http_charset_filter # ngx_http_ssi_filter # ngx_http_headers_filter @@ -77,6 +82,11 @@ if [ $HTTP_GZIP = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_GZIP_SRCS" fi +if [ $HTTP_POSTPONE = YES ]; then + HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_POSTPONE_FILTER_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTPP_POSTPONE_FILTER_SRCS" +fi + if [ $HTTP_CHARSET = YES ]; then have=NGX_HTTP_CHARSET . auto/have HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_CHARSET_FILTER_MODULE" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -49,6 +49,7 @@ HTTP_CHARSET=YES HTTP_GZIP=YES HTTP_SSL=NO HTTP_SSI=YES +HTTP_POSTPONE=NO HTTP_ACCESS=YES HTTP_AUTH_BASIC=YES HTTP_USERID=YES diff --git a/auto/os/conf b/auto/os/conf --- a/auto/os/conf +++ b/auto/os/conf @@ -23,6 +23,15 @@ case "$NGX_PLATFORM" in . auto/os/freebsd ;; + Darwin:*) + have=NGX_DARWIN . auto/have_headers + have=NGX_HAVE_INHERITED_NONBLOCK . auto/have + CORE_INCS="$UNIX_INCS" + CORE_DEPS="$UNIX_DEPS $POSIX_DEPS" + CORE_SRCS="$UNIX_SRCS" + CRYPT_LIB= + ;; + Linux:*) . auto/os/linux ;; @@ -47,16 +56,16 @@ esac case "$NGX_MACHINE" in - i386|i686|i86pc|amd64) - have=NGX_HAVE_NONALIGNED . auto/have - ;; + i386|i686|i86pc|amd64) + have=NGX_HAVE_NONALIGNED . auto/have + ;; esac if [ "$NGX_PLATFORM" != win32 ]; then - NGX_USER=${NGX_USER:-nobody} + NGX_USER=${NGX_USER:-nobody} if [ -z "$NGX_GROUP" -a $NGX_USER = nobody ] ; then if grep nobody /etc/group 2>&1 >/dev/null; then diff --git a/auto/os/freebsd b/auto/os/freebsd --- a/auto/os/freebsd +++ b/auto/os/freebsd @@ -2,14 +2,7 @@ # Copyright (C) Igor Sysoev -cat << END >> $NGX_AUTO_HEADERS_H - -#ifndef NGX_FREEBSD -#define NGX_FREEBSD 1 -#endif - -END - +have=NGX_FREEBSD . auto/have_headers CORE_INCS="$UNIX_INCS" CORE_DEPS="$UNIX_DEPS $FREEBSD_DEPS" @@ -39,6 +32,7 @@ then echo " + setproctitle() in libutil" CORE_LIBS="$CORE_LIBS -lutil" + NGX_SETPROCTITLE_LIB="-lutil" fi # sendfile diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -2,13 +2,7 @@ # Copyright (C) Igor Sysoev -cat << END >> $NGX_AUTO_HEADERS_H - -#ifndef NGX_LINUX -#define NGX_LINUX 1 -#endif - -END +have=NGX_LINUX . auto/have_headers CORE_INCS="$UNIX_INCS" CORE_DEPS="$UNIX_DEPS $LINUX_DEPS" diff --git a/auto/os/solaris b/auto/os/solaris --- a/auto/os/solaris +++ b/auto/os/solaris @@ -2,13 +2,7 @@ # Copyright (C) Igor Sysoev -cat << END >> $NGX_AUTO_HEADERS_H - -#ifndef NGX_SOLARIS -#define NGX_SOLARIS 1 -#endif - -END +have=NGX_SOLARIS . auto/have_headers CORE_INCS="$UNIX_INCS" CORE_DEPS="$UNIX_DEPS $SOLARIS_DEPS" diff --git a/auto/os/win32 b/auto/os/win32 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -2,14 +2,7 @@ # Copyright (C) Igor Sysoev -cat << END >> $NGX_AUTO_HEADERS_H - -#ifndef NGX_WIN32 -#define NGX_WIN32 1 -#endif - -END - +have=NGX_WIN32 . auto/have_headers CORE_INCS="$WIN32_INCS" CORE_DEPS="$WIN32_DEPS" diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -120,6 +120,7 @@ UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/unix/ngx_channel.h \ src/os/unix/ngx_shared.h \ src/os/unix/ngx_process.h \ + src/os/unix/ngx_setproctitle.h \ src/os/unix/ngx_atomic.h \ src/os/unix/ngx_thread.h \ src/os/unix/ngx_socket.h \ @@ -224,9 +225,11 @@ HTTP_CACHE_MODULE=ngx_http_cache_module HTTP_WRITE_FILTER_MODULE="ngx_http_write_filter_module" HTTP_HEADER_FILTER_MODULE="ngx_http_header_filter_module" +HTTP_POSTPONE_FILTER_MODULE=ngx_http_postpone_filter_module +HTTP_COPY_FILTER_MODULE=ngx_http_copy_filter_module + HTTP_CHUNKED_FILTER_MODULE=ngx_http_chunked_filter_module HTTP_HEADERS_FILTER_MODULE=ngx_http_headers_filter_module -HTTP_COPY_FILTER_MODULE=ngx_http_copy_filter_module HTTP_RANGE_HEADER_FILTER_MODULE=ngx_http_range_header_filter_module HTTP_RANGE_BODY_FILTER_MODULE=ngx_http_range_body_filter_module @@ -273,6 +276,8 @@ HTTP_SRCS="src/http/ngx_http.c \ # STUB HTTP_SRCS="$HTTP_SRCS src/http/ngx_http_busy_lock.c" +HTPP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c + HTPP_CACHE_SRCS=src/http/ngx_http_cache.c HTPP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c @@ -323,17 +328,7 @@ HTTP_SSL_SRCS=src/http/modules/ngx_http_ HTTP_PROXY_MODULE=ngx_http_proxy_module -#HTTP_PROXY_SRCS=src/http/modules/ngx_http_proxy_module.c - -HTTP_PROXY_INCS="src/http/modules/proxy" -HTTP_PROXY_DEPS=src/http/modules/proxy/ngx_http_proxy_handler.h -HTTP_PROXY_SRCS="src/http/modules/proxy/ngx_http_proxy_handler.c \ - src/http/modules/proxy/ngx_http_proxy_upstream.c \ - src/http/modules/proxy/ngx_http_proxy_parse.c \ - src/http/modules/proxy/ngx_http_proxy_header.c" - -# STUB -# src/http/modules/proxy/ngx_http_proxy_cache.c \ +HTTP_PROXY_SRCS=src/http/modules/ngx_http_proxy_module.c HTTP_FASTCGI_MODULE=ngx_http_fastcgi_module diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -64,7 +64,7 @@ ngx_feature="setproctitle()" ngx_feature_name="NGX_HAVE_SETPROCTITLE" ngx_feature_run=no ngx_feature_incs= -ngx_feature_libs= +ngx_feature_libs=$NGX_SETPROCTITLE_LIB ngx_feature_test="setproctitle(\"test\");" . auto/feature diff --git a/conf/mime.types b/conf/mime.types --- a/conf/mime.types +++ b/conf/mime.types @@ -17,6 +17,7 @@ types { application/x-javascript js; application/x-rar-compressed rar; application/x-xpinstall xpi; + application/x-x509-ca-cert der pem crt; audio/mpeg mp3; audio/x-realaudio ra; diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -9,6 +9,319 @@ nginx changelog + + + + +модуль ngx_http_ssi_module поддерживает команду include virtual. + + +the ngx_http_ssi_module supports "include virtual" command. + + + + + +модуль ngx_http_ssi_module поддерживает условную команду вида +'if expr="$NAME"' и команды else и endif. +Допускается только один уровень вложенности. + + +the ngx_http_ssi_module supports the condition command like +'if expr="$NAME"' and "else" and "endif" commands. +Only one nested level is supported. + + + + + +модуль ngx_http_ssi_module поддерживает две переменные DATE_LOCAL и DATE_GMT +и команду config timefmt. + + +the ngx_http_ssi_module supports the DATE_LOCAL and DATE_GMT variables +and "config timefmt" command. + + + + + +директива ssi_ignore_recycled_buffers. + + +the "ssi_ignore_recycled_buffers" directive. + + + + + +если переменная QUERY_STRING не была определена, то в команде echo +не ставилось значение по умолчанию. + + +the "echo" command did not show the default value for the empty QUERY_STRING +variable. + + + + + +модуль ngx_http_proxy_module полностью переписан. + + +the ngx_http_proxy_module was rewritten. + + + + + +директивы proxy_redirect, proxy_pass_request_headers, +proxy_pass_request_body и proxy_method. + + +the "proxy_redirect", "proxy_pass_request_headers", +"proxy_pass_request_body", and "proxy_method" directives. + + + + + +директива proxy_set_header. +Директива proxy_x_var упразднена и должна быть заменена директивой +proxy_set_header. + + +the "proxy_set_header" directive. +The "proxy_x_var" is canceled and must be replaced with the proxy_set_header +directive. + + + + + +директива proxy_preserve_host упразднена и должна быть заменена директивами +"proxy_set_header Host $host" и "proxy_redirect off" +или директивой "proxy_set_header Host $host:$proxy_port" +и соответствующими ей директивами proxy_redirect. + + +the "proxy_preserve_host" is canceled and must be replaced with +the "proxy_set_header Host $host" and the "proxy_redirect off" directives, +the "proxy_set_header Host $host:$proxy_port" directive +and the appropriate proxy_redirect directives. + + + + + +директива proxy_set_x_real_ip упразднена и должна быть заменена директивой +"proxy_set_header X-Real-IP $remote_addr". + + +the "proxy_set_x_real_ip" is canceled and must be replaced with +the "proxy_set_header X-Real-IP $remote_addr" directive. + + + + + +директива proxy_add_x_forwarded_for упразднена и должна быть заменена +директивой +"proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for". + + +the "proxy_add_x_forwarded_for" is canceled and must be replaced with +the "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for" +directive. + + + + + +директива proxy_set_x_url упразднена и должна быть заменена директивой +"proxy_set_header X-URL http://$host:$server_port$request_uri". + + +the "proxy_set_x_url" is canceled and must be replaced with +the "proxy_set_header X-URL http://$host:$server_port$request_uri" +directive. + + + + + +директива fastcgi_param. + + +the "fastcgi_param" directive. + + + + + +директивы fastcgi_set_var и fastcgi_params упразднены и должны быть +замены директивами fastcgi_param. + + +the "fastcgi_set_var" and "fastcgi_params" directive are canceled and +must be replaced with the fastcgi_param directives. + + + + + +директива index может использовать переменные. + + +the "index" directive can use the variables. + + + + + +директива index может быть указана на уровне http и server. + + +the "index" directive can be used at http and server levels. + + + + + +только последний параметр в директиве index может быть абсолютным. + + +the last index only in the "index" directive can be absolute. + + + + + +в директиве rewrite могут использоваться переменные. + + +the "rewrite" directive can use the variables. + + + + + +директива internal. + + +the "internal" directive. + + + + + +переменные CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR, +SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME, +REQUEST_METHOD, REQUEST_URI и REMOTE_USER. + + +the CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR, +SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME, +REQUEST_METHOD, REQUEST_URI, and REMOTE_USER variables. + + + + + +nginx теперь передаёт неверные строки в заголовках запроса клиента и +ответа бэкенда. + + +nginx now passes the invalid lines in a client request headers +or a backend response header. + + + + + +если бэкенд долго не передавал ответ и send_timeout был меньше, чем +proxy_read_timeout, то клиенту возвращался ответ 408. + + +if the backend did not transfer response for a long time and +the "send_timeout" was less than "proxy_read_timeout", then nginx +returned the 408 response. + + + + + +если бэкенд передавал неверную строку в заголовке ответа, то происходил +segmentation fault; +ошибка появилась в 0.1.26. + + +the segmentation fault was occurred if the backend sent an invalid line +in response header; +bug appeared in 0.1.26. + + + + + +при использовании отказоустойчивой конфигурации в FastCGI мог +происходить segmentation fault. + + +the segmentation fault may occurred in FastCGI fault tolerance configuration. + + + + + +директива expires не удаляла уже установленные строки заголовка +"Expires" и "Cache-Control". + + +the "expires" directive did not remove the previous "Expires" and +"Cache-Control" headers. + + + + + +nginx не учитывал завершающую точку в строке заголовка запроса "Host". + + +nginx did not take into account trailing dot in "Host" header line. + + + + + +модуль ngx_http_auth_module не работал на Linux. + + +the ngx_http_auth_module did not work under Linux. + + + + + +директива rewrite неверно работала, если в запросе присутствовали аргументы. + + +the rewrite directive worked incorrectly, if the arguments were in a request. + + + + + +nginx не собирался на MacOS X. + + +nginx could not be built on MacOS X. + + + + + + @@ -586,7 +899,7 @@ the rewrite/location cycle and sets the - + модуль ngx_http_rewrite_module полностью переписан. Теперь можно делать редиректы, возвращать коды ошибок diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -107,7 +107,7 @@ static ngx_core_module_t ngx_core_modul ngx_module_t ngx_core_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_core_module_ctx, /* module context */ ngx_core_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.1.28" +#define NGINX_VER "nginx/0.1.29" #define NGINX_VAR "NGINX" #define NGX_NEWPID_EXT ".newbin" diff --git a/src/core/ngx_array.h b/src/core/ngx_array.h --- a/src/core/ngx_array.h +++ b/src/core/ngx_array.h @@ -30,16 +30,21 @@ void *ngx_array_push_n(ngx_array_t *a, n static ngx_inline ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size) { - array->elts = ngx_palloc(pool, n * size); - if (array->elts == NULL) { - return NGX_ERROR; - } + /* + * set "array->nelts" before "array->elts", otherwise MSVC thinks + * that "array->nelts" may be used without having been initialized + */ array->nelts = 0; array->size = size; array->nalloc = n; array->pool = pool; + array->elts = ngx_palloc(pool, n * size); + if (array->elts == NULL) { + return NGX_ERROR; + } + return NGX_OK; } diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c --- a/src/core/ngx_buf.c +++ b/src/core/ngx_buf.c @@ -31,7 +31,7 @@ ngx_create_temp_buf(ngx_pool_t *pool, si * b->file = NULL; * b->shadow = NULL; * b->tag = 0; - * + * and flags */ b->pos = b->start; @@ -94,6 +94,7 @@ ngx_create_chain_of_bufs(ngx_pool_t *poo * b->file = NULL; * b->shadow = NULL; * b->tag = 0; + * and flags * */ diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -44,7 +44,9 @@ struct ngx_buf_s { unsigned recycled:1; unsigned in_file:1; unsigned flush:1; + unsigned sync:1; unsigned last_buf:1; + unsigned last_in_chain:1; unsigned last_shadow:1; unsigned temp_file:1; @@ -104,7 +106,8 @@ typedef struct { #define ngx_buf_in_memory(b) (b->temporary || b->memory || b->mmap) #define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !b->in_file) #define ngx_buf_special(b) \ - ((b->flush || b->last_buf) && !ngx_buf_in_memory(b) && !b->in_file) + ((b->flush || b->last_buf || b->sync) \ + && !ngx_buf_in_memory(b) && !b->in_file) #define ngx_buf_size(b) \ (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos): \ diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -27,7 +27,7 @@ static ngx_command_t ngx_conf_commands[ ngx_module_t ngx_conf_module = { - NGX_MODULE, + NGX_MODULE_V1, NULL, /* module context */ ngx_conf_commands, /* module directives */ NGX_CONF_MODULE, /* module type */ @@ -336,7 +336,7 @@ ngx_conf_read_token(ngx_conf_t *cf) { u_char *start, ch, *src, *dst; int len; - int found, need_space, last_space, sharp_comment; + int found, need_space, last_space, sharp_comment, variable; int quoted, s_quoted, d_quoted; ssize_t n; ngx_str_t *word; @@ -346,6 +346,7 @@ ngx_conf_read_token(ngx_conf_t *cf) need_space = 0; last_space = 1; sharp_comment = 0; + variable = 0; quoted = s_quoted = d_quoted = 0; cf->args->nelts = 0; @@ -492,11 +493,22 @@ ngx_conf_read_token(ngx_conf_t *cf) } } else { + if (ch == '{' && variable) { + continue; + } + + variable = 0; + if (ch == '\\') { quoted = 1; continue; } + if (ch == '$') { + variable = 1; + continue; + } + if (d_quoted) { if (ch == '"') { d_quoted = 0; @@ -802,6 +814,45 @@ ngx_conf_set_str_slot(ngx_conf_t *cf, ng char * +ngx_conf_set_table_elt_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_array_t **a; + ngx_table_elt_t *elt; + ngx_conf_post_t *post; + + a = (ngx_array_t **) (p + cmd->offset); + + if (*a == NULL) { + *a = ngx_array_create(cf->pool, 4, sizeof(ngx_table_elt_t)); + if (*a == NULL) { + return NGX_CONF_ERROR; + } + } + + elt = ngx_array_push(*a); + if (elt == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + elt->hash = 0; + elt->key = value[1]; + elt->value = value[2]; + + if (cmd->post) { + post = cmd->post; + return post->post_handler(cf, post, elt); + } + + return NGX_CONF_OK; +} + + +char * ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -63,7 +63,7 @@ #define NGX_CONF_BLOCK_DONE 2 #define NGX_CONF_FILE_DONE 3 -#define NGX_MODULE 0, 0 +#define NGX_MODULE_V1 0, 0, 1, 0, 0 #define NGX_CORE_MODULE 0x45524F43 /* "CORE" */ #define NGX_CONF_MODULE 0x464E4F43 /* "CONF" */ @@ -100,6 +100,10 @@ struct ngx_open_file_s { struct ngx_module_s { ngx_uint_t ctx_index; ngx_uint_t index; + ngx_uint_t version; + ngx_uint_t spare0; + ngx_uint_t spare1; + void *ctx; ngx_command_t *commands; ngx_uint_t type; @@ -280,6 +284,8 @@ void ngx_cdecl ngx_conf_log_error(ngx_ui char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_conf_set_table_elt_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -517,7 +517,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t ngx_old_cycles.nalloc = n; ngx_old_cycles.pool = ngx_temp_pool; - ngx_cleaner_event.event_handler = ngx_clean_old_cycles; + ngx_cleaner_event.handler = ngx_clean_old_cycles; ngx_cleaner_event.log = cycle->log; ngx_cleaner_event.data = &dumb; dumb.fd = (ngx_socket_t) -1; diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -38,8 +38,10 @@ ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool, int persistent) { - ngx_err_t err; - ngx_atomic_uint_t n; + ngx_err_t err; + ngx_atomic_uint_t n; + ngx_pool_cleanup_file_t *cln; + file->name.len = path->name.len + 1 + path->len + NGX_ATOMIC_T_LEN; @@ -74,6 +76,20 @@ ngx_create_temp_file(ngx_file_t *file, n "temp fd:%d", file->fd); if (file->fd != NGX_INVALID_FILE) { + cln = ngx_palloc(pool, sizeof(ngx_pool_cleanup_file_t)); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->fd = file->fd; + cln->name = file->name.data; + cln->log = pool->log; + + if (ngx_pool_cleanup_add(pool, ngx_pool_cleanup_file, cln) == NULL) + { + return NGX_ERROR; + } + return NGX_OK; } diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -9,11 +9,20 @@ ngx_int_t -ngx_hash_init(ngx_hash_t *hash, ngx_pool_t *pool, void *names) +ngx_hash_init(ngx_hash_t *hash, ngx_pool_t *pool, void *names, ngx_uint_t nelts) { u_char *p; - ngx_str_t *n, *bucket; - ngx_uint_t i, key, size, best, *test, buckets, min_buckets; + ngx_str_t *name, *bucket; + ngx_uint_t i, n, key, size, best, *test, buckets, min_buckets; + + if (nelts == 0) { + for (name = (ngx_str_t *) names; + name->len; + name = (ngx_str_t *) ((char *) name + hash->bucket_size)) + { + nelts++; + } + } test = ngx_alloc(hash->max_size * sizeof(ngx_uint_t), pool->log); if (test == NULL) { @@ -34,14 +43,14 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool test[i] = 0; } - for (n = (ngx_str_t *) names; - n->len; - n = (ngx_str_t *) ((char *) n + hash->bucket_size)) + for (n = 0, name = (ngx_str_t *) names; + n < nelts; + n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size)) { key = 0; - for (i = 0; i < n->len; i++) { - key += ngx_tolower(n->data[i]); + for (i = 0; i < name->len; i++) { + key += ngx_tolower(name->data[i]); } key %= size; @@ -57,7 +66,7 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool } } - if (n->len == 0) { + if (n == nelts) { if (min_buckets > buckets) { min_buckets = buckets; best = size; @@ -91,14 +100,14 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool test[i] = 0; } - for (n = (ngx_str_t *) names; - n->len; - n = (ngx_str_t *) ((char *) n + hash->bucket_size)) + for (n = 0, name = (ngx_str_t *) names; + n < nelts; + n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size)) { key = 0; - for (i = 0; i < n->len; i++) { - key += ngx_tolower(n->data[i]); + for (i = 0; i < name->len; i++) { + key += ngx_tolower(name->data[i]); } key %= best; @@ -122,21 +131,21 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool } } - for (n = (ngx_str_t *) names; - n->len; - n = (ngx_str_t *) ((char *) n + hash->bucket_size)) + for (n = 0, name = (ngx_str_t *) names; + n < nelts; + n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size)) { key = 0; - for (i = 0; i < n->len; i++) { - key += ngx_tolower(n->data[i]); + for (i = 0; i < name->len; i++) { + key += ngx_tolower(name->data[i]); } key %= best; if (hash->bucket_limit == 1) { p = (u_char *) hash->buckets + key * hash->bucket_size; - ngx_memcpy(p, n, hash->bucket_size); + ngx_memcpy(p, name, hash->bucket_size); continue; } @@ -147,7 +156,7 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool bucket->len &= 0x7fffffff; } - ngx_memcpy(bucket, n, hash->bucket_size); + ngx_memcpy(bucket, name, hash->bucket_size); bucket->len |= 0x80000000; } diff --git a/src/core/ngx_hash.h b/src/core/ngx_hash.h --- a/src/core/ngx_hash.h +++ b/src/core/ngx_hash.h @@ -31,7 +31,8 @@ typedef struct { } ngx_table_elt_t; -ngx_int_t ngx_hash_init(ngx_hash_t *hash, ngx_pool_t *pool, void *names); +ngx_int_t ngx_hash_init(ngx_hash_t *hash, ngx_pool_t *pool, void *names, + ngx_uint_t nelts); #endif /* _NGX_HASH_H_INCLUDED_ */ diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -21,7 +21,8 @@ */ -static ngx_inline size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len) +static +ngx_inline size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len) { size_t n; ngx_uint_t c1, c2; @@ -65,8 +66,8 @@ static ngx_inline size_t ngx_sprint_ucha /* AF_INET only */ -size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, - size_t len) +size_t +ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len) { u_char *p; size_t n; @@ -119,7 +120,8 @@ size_t ngx_sock_ntop(int family, struct return n; } -size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len) +size_t +ngx_inet_ntop(int family, void *addr, u_char *text, size_t len) { u_char *p; size_t n; @@ -173,7 +175,8 @@ size_t ngx_inet_ntop(int family, void *a /* AF_INET only */ -ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr) +ngx_int_t +ngx_ptocidr(ngx_str_t *text, void *cidr) { ngx_int_t m; ngx_uint_t i; @@ -217,7 +220,8 @@ ngx_int_t ngx_ptocidr(ngx_str_t *text, v } -ngx_peers_t *ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u) +ngx_peers_t * +ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u) { char *err; u_char *host; @@ -392,7 +396,8 @@ ngx_peers_t *ngx_inet_upstream_parse(ngx } -char *ngx_inet_parse_host_port(ngx_inet_upstream_t *u) +char * +ngx_inet_parse_host_port(ngx_inet_upstream_t *u) { size_t i; ngx_int_t port; diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -33,7 +33,7 @@ static ngx_core_module_t ngx_errlog_mod ngx_module_t ngx_errlog_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_errlog_module_ctx, /* module context */ ngx_errlog_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -49,7 +49,7 @@ ngx_output_chain(ngx_output_chain_ctx_t #if (NGX_SENDFILE_LIMIT) && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT) #endif - && (!ngx_output_chain_need_to_copy(ctx, in->buf))) + && !ngx_output_chain_need_to_copy(ctx, in->buf)) { return ctx->output_filter(ctx->filter_ctx, in); } @@ -132,7 +132,7 @@ ngx_output_chain(ngx_output_chain_ctx_t size = ctx->bufs.size; - if (ctx->in->buf->last_buf) { + if (ctx->in->buf->last_in_chain) { if (bsize < (off_t) ctx->bufs.size) { @@ -202,6 +202,11 @@ ngx_output_chain(ngx_output_chain_ctx_t } if (out == NULL && last != NGX_NONE) { + + if (ctx->in) { + return NGX_AGAIN; + } + return last; } diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -23,6 +23,7 @@ ngx_create_pool(size_t size, ngx_log_t * p->next = NULL; p->large = NULL; p->chain = NULL; + p->cleanup = NULL; p->log = log; return p; @@ -32,8 +33,15 @@ ngx_create_pool(size_t size, ngx_log_t * void ngx_destroy_pool(ngx_pool_t *pool) { - ngx_pool_t *p, *n; - ngx_pool_large_t *l; + ngx_pool_t *p, *n; + ngx_pool_large_t *l; + ngx_pool_cleanup_t *c; + + for (c = pool->cleanup; c; c = c->next) { + if (c->handler) { + c->handler(c->data); + } + } for (l = pool->large; l; l = l->next) { @@ -197,6 +205,39 @@ ngx_pcalloc(ngx_pool_t *pool, size_t siz return p; } + +ngx_pool_cleanup_t * +ngx_pool_cleanup_add(ngx_pool_t *p, ngx_pool_cleanup_pt handler, void *data) +{ + ngx_pool_cleanup_t *c; + + c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t)); + if (c == NULL) { + return NULL; + } + + c->handler = handler; + c->data = data; + c->next = p->cleanup; + + p->cleanup = c; + + return c; +} + + +void +ngx_pool_cleanup_file(void *data) +{ + ngx_pool_cleanup_file_t *c = data; + + if (ngx_close_file(c->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", c->name); + } +} + + #if 0 static void * diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h --- a/src/core/ngx_palloc.h +++ b/src/core/ngx_palloc.h @@ -22,24 +22,44 @@ #define NGX_DEFAULT_POOL_SIZE (16 * 1024) +typedef void (*ngx_pool_cleanup_pt)(void *data); + +typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t; + +struct ngx_pool_cleanup_s { + ngx_pool_cleanup_pt handler; + void *data; + ngx_pool_cleanup_t *next; +}; + + typedef struct ngx_pool_large_s ngx_pool_large_t; struct ngx_pool_large_s { - ngx_pool_large_t *next; - void *alloc; + ngx_pool_large_t *next; + void *alloc; }; struct ngx_pool_s { - u_char *last; - u_char *end; - ngx_chain_t *chain; - ngx_pool_t *next; - ngx_pool_large_t *large; - ngx_log_t *log; + u_char *last; + u_char *end; + ngx_chain_t *chain; + ngx_pool_t *next; + ngx_pool_large_t *large; + ngx_pool_cleanup_t *cleanup; + ngx_log_t *log; }; +typedef struct { + ngx_fd_t fd; + u_char *name; + ngx_log_t *log; +} ngx_pool_cleanup_file_t; + + + void *ngx_alloc(size_t size, ngx_log_t *log); void *ngx_calloc(size_t size, ngx_log_t *log); @@ -51,4 +71,9 @@ void *ngx_pcalloc(ngx_pool_t *pool, size ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p); +ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, + ngx_pool_cleanup_pt handler, void *data); +void ngx_pool_cleanup_file(void *data); + + #endif /* _NGX_PALLOC_H_INCLUDED_ */ diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -12,8 +12,9 @@ ngx_epoch_msec_t ngx_elapsed_msec; ngx_epoch_msec_t ngx_old_elapsed_msec; ngx_epoch_msec_t ngx_start_msec; +ngx_int_t ngx_gmtoff; + static ngx_tm_t ngx_cached_gmtime; -static ngx_int_t ngx_gmtoff; /* diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h --- a/src/core/ngx_times.h +++ b/src/core/ngx_times.h @@ -53,6 +53,7 @@ extern ngx_epoch_msec_t ngx_elapsed_mse */ extern ngx_epoch_msec_t ngx_old_elapsed_msec; +extern ngx_int_t ngx_gmtoff; #endif /* _NGX_TIMES_H_INCLUDED_ */ diff --git a/src/core/ngx_unix_domain.c b/src/core/ngx_unix_domain.c --- a/src/core/ngx_unix_domain.c +++ b/src/core/ngx_unix_domain.c @@ -14,8 +14,8 @@ #undef sun -ngx_peers_t *ngx_unix_upstream_parse(ngx_conf_t *cf, - ngx_unix_domain_upstream_t *u) +ngx_peers_t * +ngx_unix_upstream_parse(ngx_conf_t *cf, ngx_unix_domain_upstream_t *u) { size_t len; ngx_uint_t i; diff --git a/src/event/modules/ngx_aio_module.c b/src/event/modules/ngx_aio_module.c --- a/src/event/modules/ngx_aio_module.c +++ b/src/event/modules/ngx_aio_module.c @@ -54,7 +54,7 @@ ngx_event_module_t ngx_aio_module_ctx = }; ngx_module_t ngx_aio_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_aio_module_ctx, /* module context */ NULL, /* module directives */ NGX_EVENT_MODULE, /* module type */ diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -91,7 +91,7 @@ ngx_event_module_t ngx_devpoll_module_c }; ngx_module_t ngx_devpoll_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_devpoll_module_ctx, /* module context */ ngx_devpoll_commands, /* module directives */ NGX_EVENT_MODULE, /* module type */ @@ -511,7 +511,7 @@ ngx_devpoll_process_events(ngx_cycle_t * wev->ready = 1; if (!ngx_threaded && !ngx_accept_mutex_held) { - wev->event_handler(wev); + wev->handler(wev); } else { ngx_post_event(wev); @@ -530,7 +530,7 @@ ngx_devpoll_process_events(ngx_cycle_t * rev->ready = 1; if (!ngx_threaded && !ngx_accept_mutex_held) { - rev->event_handler(rev); + rev->handler(rev); } else if (!rev->accept) { ngx_post_event(rev); @@ -538,7 +538,7 @@ ngx_devpoll_process_events(ngx_cycle_t * } else if (ngx_accept_disabled <= 0) { ngx_mutex_unlock(ngx_posted_events_mutex); - c->read->event_handler(rev); + c->read->handler(rev); if (ngx_accept_disabled > 0) { ngx_accept_mutex_unlock(); diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -121,7 +121,7 @@ ngx_event_module_t ngx_epoll_module_ctx }; ngx_module_t ngx_epoll_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_epoll_module_ctx, /* module context */ ngx_epoll_commands, /* module directives */ NGX_EVENT_MODULE, /* module type */ @@ -573,7 +573,7 @@ ngx_epoll_process_events(ngx_cycle_t *cy wev->ready = 1; if (!ngx_accept_mutex_held) { - wev->event_handler(wev); + wev->handler(wev); } else { ngx_post_event(wev); @@ -600,7 +600,7 @@ ngx_epoll_process_events(ngx_cycle_t *cy rev->ready = 1; if (!ngx_threaded && !ngx_accept_mutex_held) { - rev->event_handler(rev); + rev->handler(rev); } else if (!rev->accept) { ngx_post_event(rev); @@ -609,7 +609,7 @@ ngx_epoll_process_events(ngx_cycle_t *cy ngx_mutex_unlock(ngx_posted_events_mutex); - rev->event_handler(rev); + rev->handler(rev); if (ngx_accept_disabled > 0) { ngx_accept_mutex_unlock(); diff --git a/src/event/modules/ngx_iocp_module.c b/src/event/modules/ngx_iocp_module.c --- a/src/event/modules/ngx_iocp_module.c +++ b/src/event/modules/ngx_iocp_module.c @@ -69,7 +69,7 @@ ngx_event_module_t ngx_iocp_module_ctx }; ngx_module_t ngx_iocp_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_iocp_module_ctx, /* module context */ ngx_iocp_commands, /* module directives */ NGX_EVENT_MODULE, /* module type */ @@ -294,9 +294,9 @@ ngx_int_t ngx_iocp_process_events(ngx_cy ev->available = bytes; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - "iocp event handler: %p", ev->event_handler); + "iocp event handler: %p", ev->handler); - ev->event_handler(ev); + ev->handler(ev); if (timer != INFINITE && delta) { ngx_event_expire_timers((ngx_msec_t) delta); diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -94,7 +94,7 @@ ngx_event_module_t ngx_kqueue_module_ct }; ngx_module_t ngx_kqueue_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_kqueue_module_ctx, /* module context */ ngx_kqueue_commands, /* module directives */ NGX_EVENT_MODULE, /* module type */ @@ -192,11 +192,13 @@ ngx_kqueue_init(ngx_cycle_t *cycle) ngx_event_actions = ngx_kqueue_module_ctx.actions; ngx_event_flags = NGX_USE_ONESHOT_EVENT +#if 1 #if (NGX_HAVE_CLEAR_EVENT) |NGX_USE_CLEAR_EVENT #else |NGX_USE_LEVEL_EVENT #endif +#endif #if (NGX_HAVE_LOWAT_EVENT) |NGX_USE_LOWAT_EVENT #endif @@ -615,6 +617,10 @@ ngx_kqueue_process_events(ngx_cycle_t *c ngx_kqueue_dump_event(ev->log, &event_list[i]); } + if (ev->oneshot) { + ev->active = 0; + } + #if (NGX_THREADS) if (ngx_threaded && !ev->accept) { @@ -663,7 +669,7 @@ ngx_kqueue_process_events(ngx_cycle_t *c } if (!ngx_threaded && !ngx_accept_mutex_held) { - ev->event_handler(ev); + ev->handler(ev); continue; } @@ -678,7 +684,7 @@ ngx_kqueue_process_events(ngx_cycle_t *c ngx_mutex_unlock(ngx_posted_events_mutex); - ev->event_handler(ev); + ev->handler(ev); if (ngx_accept_disabled > 0) { ngx_accept_mutex_unlock(); diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -50,7 +50,7 @@ ngx_event_module_t ngx_poll_module_ctx }; ngx_module_t ngx_poll_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_poll_module_ctx, /* module context */ NULL, /* module directives */ NGX_EVENT_MODULE, /* module type */ @@ -536,7 +536,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc } } - ev->event_handler(ev); + ev->handler(ev); } #endif @@ -553,7 +553,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc ngx_mutex_unlock(ngx_posted_events_mutex); - ev->event_handler(ev); + ev->handler(ev); if (ngx_accept_disabled > 0) { lock = 0; diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c --- a/src/event/modules/ngx_rtsig_module.c +++ b/src/event/modules/ngx_rtsig_module.c @@ -118,7 +118,7 @@ ngx_event_module_t ngx_rtsig_module_ctx }; ngx_module_t ngx_rtsig_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_rtsig_module_ctx, /* module context */ ngx_rtsig_commands, /* module directives */ NGX_EVENT_MODULE, /* module type */ @@ -461,11 +461,11 @@ ngx_rtsig_process_events(ngx_cycle_t *cy rev->ready = 1; if (!ngx_threaded && !ngx_accept_mutex_held) { - rev->event_handler(rev); + rev->handler(rev); } else if (rev->accept) { if (ngx_accept_disabled <= 0) { - rev->event_handler(rev); + rev->handler(rev); } } else { @@ -495,7 +495,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy wev->ready = 1; if (!ngx_threaded && !ngx_accept_mutex_held) { - wev->event_handler(wev); + wev->handler(wev); } else { ngx_post_event(wev); @@ -598,11 +598,11 @@ ngx_rtsig_process_overflow(ngx_cycle_t * events = 0; - if (c->read->active && c->read->event_handler) { + if (c->read->active && c->read->handler) { events |= POLLIN; } - if (c->write->active && c->write->event_handler) { + if (c->write->active && c->write->handler) { events |= POLLOUT; } @@ -652,7 +652,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t * if (rev->active && !rev->closed - && rev->event_handler + && rev->handler && (overflow_list[i].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL))) { @@ -664,7 +664,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t * } else { rev->ready = 1; - rev->event_handler(rev); + rev->handler(rev); } } @@ -672,7 +672,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t * if (wev->active && !wev->closed - && wev->event_handler + && wev->handler && (overflow_list[i].revents & (POLLOUT|POLLERR|POLLHUP|POLLNVAL))) { @@ -684,7 +684,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t * } else { wev->ready = 1; - wev->event_handler(wev); + wev->handler(wev); } } } diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c --- a/src/event/modules/ngx_select_module.c +++ b/src/event/modules/ngx_select_module.c @@ -63,7 +63,7 @@ ngx_event_module_t ngx_select_module_ct }; ngx_module_t ngx_select_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_select_module_ctx, /* module context */ NULL, /* module directives */ NGX_EVENT_MODULE, /* module type */ @@ -540,7 +540,7 @@ ngx_select_process_events(ngx_cycle_t *c } } - ev->event_handler(ev); + ev->handler(ev); } #endif @@ -557,7 +557,7 @@ ngx_select_process_events(ngx_cycle_t *c ngx_mutex_unlock(ngx_posted_events_mutex); - ev->event_handler(ev); + ev->handler(ev); if (ngx_accept_disabled > 0) { lock = 0; diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -24,10 +24,10 @@ static ngx_int_t ngx_event_process_init( static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_event_connections(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); + void *conf); static char *ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); + void *conf); static void *ngx_event_create_conf(ngx_cycle_t *cycle); static char *ngx_event_init_conf(ngx_cycle_t *cycle, void *conf); @@ -91,7 +91,7 @@ static ngx_core_module_t ngx_events_mod ngx_module_t ngx_events_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_events_module_ctx, /* module context */ ngx_events_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ @@ -163,7 +163,7 @@ ngx_event_module_t ngx_event_core_modul ngx_module_t ngx_event_core_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_event_core_module_ctx, /* module context */ ngx_event_core_commands, /* module directives */ NGX_EVENT_MODULE, /* module type */ @@ -172,7 +172,143 @@ ngx_module_t ngx_event_core_module = { }; -static ngx_int_t ngx_event_module_init(ngx_cycle_t *cycle) +ngx_int_t +ngx_handle_read_event(ngx_event_t *rev, u_int flags) +{ + if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { + + /* kqueue, epoll */ + + if (!rev->active && !rev->ready) { + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) + == NGX_ERROR) + { + return NGX_ERROR; + } + } + + return NGX_OK; + + } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { + + /* select, poll, /dev/poll */ + + if (!rev->active && !rev->ready) { + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) + == NGX_ERROR) + { + return NGX_ERROR; + } + + return NGX_OK; + } + + if (rev->active && (rev->ready || (flags & NGX_CLOSE_EVENT))) { + if (ngx_del_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT | flags) + == NGX_ERROR) + { + return NGX_ERROR; + } + + return NGX_OK; + } + + } else if (ngx_event_flags & NGX_USE_ONESHOT_EVENT) { + + /* event ports */ + + if (!rev->active) { + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_ONESHOT_EVENT) + == NGX_ERROR) + { + return NGX_ERROR; + } + } + + return NGX_OK; + } + + /* aio, iocp, rtsig */ + + return NGX_OK; +} + + +ngx_int_t +ngx_handle_write_event(ngx_event_t *wev, size_t lowat) +{ + ngx_connection_t *c; + + if (lowat) { + c = (ngx_connection_t *) wev->data; + + if (ngx_send_lowat(c, lowat) == NGX_ERROR) { + return NGX_ERROR; + } + } + + if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { + + /* kqueue, epoll */ + + if (!wev->active && !wev->ready) { + if (ngx_add_event(wev, NGX_WRITE_EVENT, + NGX_CLEAR_EVENT | (lowat ? NGX_LOWAT_EVENT : 0)) + == NGX_ERROR) + { + return NGX_ERROR; + } + } + + return NGX_OK; + + } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { + + /* select, poll, /dev/poll */ + + if (!wev->active && !wev->ready) { + if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT) + == NGX_ERROR) + { + return NGX_ERROR; + } + + return NGX_OK; + } + + if (wev->active && wev->ready) { + if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT) + == NGX_ERROR) + { + return NGX_ERROR; + } + + return NGX_OK; + } + + } else if (ngx_event_flags & NGX_USE_ONESHOT_EVENT) { + + /* event ports */ + + if (!wev->active) { + if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_ONESHOT_EVENT) + == NGX_ERROR) + { + return NGX_ERROR; + } + } + + return NGX_OK; + } + + /* aio, iocp, rtsig */ + + return NGX_OK; +} + + +static ngx_int_t +ngx_event_module_init(ngx_cycle_t *cycle) { #if !(NGX_WIN32) @@ -248,7 +384,8 @@ static ngx_int_t ngx_event_module_init(n } -static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) +static ngx_int_t +ngx_event_process_init(ngx_cycle_t *cycle) { ngx_uint_t m, i; ngx_socket_t fd; @@ -417,7 +554,7 @@ static ngx_int_t ngx_event_process_init( #if (NGX_WIN32) if (ngx_event_flags & NGX_USE_IOCP_EVENT) { - rev->event_handler = ngx_event_acceptex; + rev->handler = ngx_event_acceptex; if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; @@ -431,7 +568,7 @@ static ngx_int_t ngx_event_process_init( } } else { - rev->event_handler = ngx_event_accept; + rev->handler = ngx_event_accept; if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; @@ -440,7 +577,7 @@ static ngx_int_t ngx_event_process_init( #else - rev->event_handler = ngx_event_accept; + rev->handler = ngx_event_accept; if (ngx_accept_mutex) { continue; @@ -464,7 +601,8 @@ static ngx_int_t ngx_event_process_init( } -ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat) +ngx_int_t +ngx_send_lowat(ngx_connection_t *c, size_t lowat) { int sndlowat; @@ -497,7 +635,8 @@ ngx_int_t ngx_send_lowat(ngx_connection_ } -static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +static char * +ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; void ***ctx; @@ -574,8 +713,8 @@ static char *ngx_events_block(ngx_conf_t } -static char *ngx_event_connections(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) +static char * +ngx_event_connections(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_event_conf_t *ecf = conf; @@ -600,7 +739,8 @@ static char *ngx_event_connections(ngx_c } -static char *ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +static char * +ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_event_conf_t *ecf = conf; @@ -662,8 +802,8 @@ static char *ngx_event_use(ngx_conf_t *c } -static char *ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) +static char * +ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { #if (NGX_DEBUG) ngx_event_conf_t *ecf = conf; @@ -709,7 +849,8 @@ static char *ngx_event_debug_connection( } -static void *ngx_event_create_conf(ngx_cycle_t *cycle) +static void * +ngx_event_create_conf(ngx_cycle_t *cycle) { ngx_event_conf_t *ecf; @@ -739,7 +880,8 @@ static void *ngx_event_create_conf(ngx_c } -static char *ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) +static char * +ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) { ngx_event_conf_t *ecf = conf; @@ -874,7 +1016,8 @@ static char *ngx_event_init_conf(ngx_cyc } -static char *ngx_accept_mutex_check(ngx_conf_t *cf, void *post, void *data) +static char * +ngx_accept_mutex_check(ngx_conf_t *cf, void *post, void *data) { #if !(NGX_HAVE_ATOMIC_OPS) diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -113,8 +113,7 @@ struct ngx_event_s { unsigned available:1; #endif - /* TODO rename to handler */ - ngx_event_handler_pt event_handler; + ngx_event_handler_pt handler; #if (NGX_HAVE_AIO) @@ -474,6 +473,10 @@ ngx_int_t ngx_disable_accept_events(ngx_ ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); +ngx_int_t ngx_handle_read_event(ngx_event_t *rev, u_int flags); +ngx_int_t ngx_handle_write_event(ngx_event_t *wev, size_t lowat); + + #if (NGX_WIN32) void ngx_event_acceptex(ngx_event_t *ev); int ngx_event_post_acceptex(ngx_listening_t *ls, int n); @@ -496,158 +499,4 @@ ngx_int_t ngx_send_lowat(ngx_connection_ #endif - -static ngx_inline ngx_int_t ngx_handle_read_event(ngx_event_t *rev, u_int flags) -{ - if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { - - /* kqueue, epoll */ - - if (!rev->active && !rev->ready) { - if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) - == NGX_ERROR) { - return NGX_ERROR; - } - } - - return NGX_OK; - - } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { - - /* select, poll, /dev/poll */ - - if (!rev->active && !rev->ready) { - if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) - == NGX_ERROR) - { - return NGX_ERROR; - } - - return NGX_OK; - } - - if (rev->active && (rev->ready || (flags & NGX_CLOSE_EVENT))) { - if (ngx_del_event(rev, NGX_READ_EVENT, flags) == NGX_ERROR) { - return NGX_ERROR; - } - - return NGX_OK; - } - } - - /* aio, iocp, rtsig */ - - return NGX_OK; -} - - -static ngx_inline ngx_int_t ngx_handle_level_read_event(ngx_event_t *rev) -{ - if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { - if (!rev->active && !rev->ready) { - if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) - == NGX_ERROR) - { - return NGX_ERROR; - } - - return NGX_OK; - } - - if (rev->active && rev->ready) { - if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { - return NGX_ERROR; - } - - return NGX_OK; - } - } - - return NGX_OK; -} - - -static ngx_inline ngx_int_t ngx_handle_write_event(ngx_event_t *wev, - size_t lowat) -{ - ngx_connection_t *c; - - if (lowat) { - c = (ngx_connection_t *) wev->data; - - if (ngx_send_lowat(c, lowat) == NGX_ERROR) { - return NGX_ERROR; - } - } - - if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { - - /* kqueue, epoll */ - - if (!wev->active && !wev->ready) { - if (ngx_add_event(wev, NGX_WRITE_EVENT, - NGX_CLEAR_EVENT | (lowat ? NGX_LOWAT_EVENT : 0)) - == NGX_ERROR) - { - return NGX_ERROR; - } - } - - return NGX_OK; - - } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { - - /* select, poll, /dev/poll */ - - if (!wev->active && !wev->ready) { - if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT) - == NGX_ERROR) - { - return NGX_ERROR; - } - - return NGX_OK; - } - - if (wev->active && wev->ready) { - if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { - return NGX_ERROR; - } - - return NGX_OK; - } - } - - /* aio, iocp, rtsig */ - - return NGX_OK; -} - - -static ngx_inline ngx_int_t ngx_handle_level_write_event(ngx_event_t *wev) -{ - if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { - if (!wev->active && !wev->ready) { - if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT) - == NGX_ERROR) - { - return NGX_ERROR; - } - - return NGX_OK; - } - - if (wev->active && wev->ready) { - if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { - return NGX_ERROR; - } - - return NGX_OK; - } - } - - return NGX_OK; -} - - #endif /* _NGX_EVENT_H_INCLUDED_ */ diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -106,7 +106,9 @@ ngx_event_accept(ngx_event_t *ev) return; } - ngx_log_error(NGX_LOG_ALERT, ev->log, err, + ngx_log_error((err == NGX_ECONNABORTED) ? NGX_LOG_CRIT: + NGX_LOG_ALERT, + ev->log, err, "accept() on %V failed", &ls->listening->addr_text); if (err == NGX_ECONNABORTED) { diff --git a/src/event/ngx_event_acceptex.c b/src/event/ngx_event_acceptex.c --- a/src/event/ngx_event_acceptex.c +++ b/src/event/ngx_event_acceptex.c @@ -132,7 +132,7 @@ int ngx_event_post_acceptex(ngx_listenin rev->ovlp.event = rev; wev->ovlp.event = wev; - rev->event_handler = ngx_event_acceptex; + rev->handler = ngx_event_acceptex; rev->data = c; wev->data = c; diff --git a/src/event/ngx_event_busy_lock.c b/src/event/ngx_event_busy_lock.c --- a/src/event/ngx_event_busy_lock.c +++ b/src/event/ngx_event_busy_lock.c @@ -43,7 +43,7 @@ ngx_int_t ngx_event_busy_lock(ngx_event_ } else if (ctx->timer && bl->waiting < bl->max_waiting) { bl->waiting++; ngx_add_timer(ctx->event, ctx->timer); - ctx->event->event_handler = ngx_event_busy_lock_handler; + ctx->event->handler = ngx_event_busy_lock_handler; if (bl->events) { bl->last->next = ctx; @@ -92,7 +92,7 @@ ngx_int_t ngx_event_busy_lock_cachable(n if (ctx->timer && bl->waiting < bl->max_waiting) { bl->waiting++; ngx_add_timer(ctx->event, ctx->timer); - ctx->event->event_handler = ngx_event_busy_lock_handler; + ctx->event->handler = ngx_event_busy_lock_handler; if (bl->events == NULL) { bl->events = ctx; @@ -296,7 +296,7 @@ static void ngx_event_busy_lock_handler( ngx_mutex_unlock(ngx_posted_events_mutex); - ev->event_handler = ngx_event_busy_lock_posted_handler; + ev->handler = ngx_event_busy_lock_posted_handler; } diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -114,6 +114,9 @@ ngx_event_connect_peer(ngx_peer_connecti s = ngx_socket(peer->sockaddr->sa_family, SOCK_STREAM, 0); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "socket %d", s); + if (s == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_socket_n " failed"); diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -170,7 +170,7 @@ ngx_ssl_handle_recv(ngx_connection_t *c, if (c->ssl->saved_write_handler) { - c->write->event_handler = c->ssl->saved_write_handler; + c->write->handler = c->ssl->saved_write_handler; c->ssl->saved_write_handler = NULL; c->write->ready = 1; @@ -223,8 +223,8 @@ ngx_ssl_handle_recv(ngx_connection_t *c, */ if (c->ssl->saved_write_handler == NULL) { - c->ssl->saved_write_handler = c->write->event_handler; - c->write->event_handler = ngx_ssl_write_handler; + c->ssl->saved_write_handler = c->write->handler; + c->write->handler = ngx_ssl_write_handler; } return NGX_AGAIN; @@ -253,7 +253,7 @@ ngx_ssl_write_handler(ngx_event_t *wev) ngx_connection_t *c; c = wev->data; - c->read->event_handler(c->read); + c->read->handler(c->read); } @@ -405,7 +405,7 @@ ngx_ssl_write(ngx_connection_t *c, u_cha if (n > 0) { if (c->ssl->saved_read_handler) { - c->read->event_handler = c->ssl->saved_read_handler; + c->read->handler = c->ssl->saved_read_handler; c->ssl->saved_read_handler = NULL; c->read->ready = 1; @@ -460,8 +460,8 @@ ngx_ssl_write(ngx_connection_t *c, u_cha */ if (c->ssl->saved_read_handler == NULL) { - c->ssl->saved_read_handler = c->read->event_handler; - c->read->event_handler = ngx_ssl_read_handler; + c->ssl->saved_read_handler = c->read->handler; + c->read->handler = ngx_ssl_read_handler; } return NGX_AGAIN; @@ -482,7 +482,7 @@ ngx_ssl_read_handler(ngx_event_t *rev) ngx_connection_t *c; c = rev->data; - c->write->event_handler(c->write); + c->write->handler(c->write); } @@ -592,3 +592,12 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_ ngx_log_error(level, log, err, "%s)", errstr); } + + +void +ngx_ssl_cleanup_ctx(void *data) +{ + SSL_CTX *ctx = data; + + SSL_CTX_free(ctx); +} diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -54,6 +54,7 @@ ngx_chain_t *ngx_ssl_send_chain(ngx_conn ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c); void ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...); +void ngx_ssl_cleanup_ctx(void *data); #endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */ diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -64,13 +64,13 @@ ngx_int_t ngx_event_pipe(ngx_event_pipe_ } } - if (p->downstream->fd != -1) { + if (p->downstream->fd != -1 && p->downstream->data == p->output_ctx) { wev = p->downstream->write; if (ngx_handle_write_event(wev, p->send_lowat) == NGX_ERROR) { return NGX_ABORT; } - if (wev->active) { + if (wev->active && !wev->ready && !wev->delayed) { ngx_add_timer(wev, p->send_timeout); } } @@ -180,8 +180,10 @@ static ngx_int_t ngx_event_pipe_read_ups chain->buf = b; chain->next = NULL; - } else if (!p->cachable && p->downstream->write->ready) { - + } else if (!p->cachable + && p->downstream->data == p->output_ctx + && p->downstream->write->ready) + { /* * if the bufs are not needed to be saved in a cache and * a downstream is ready then write the bufs to a downstream @@ -409,10 +411,18 @@ static ngx_int_t ngx_event_pipe_write_to /* pass the p->out and p->in chains to the output filter */ + for (cl = p->busy; cl; cl = cl->next) { + cl->buf->recycled = 0; + } + if (p->out) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream flush out"); + for (cl = p->out; cl; cl = cl->next) { + cl->buf->recycled = 0; + } + if (p->output_filter(p->output_ctx, p->out) == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); @@ -425,6 +435,10 @@ static ngx_int_t ngx_event_pipe_write_to ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream flush in"); + for (cl = p->in; cl; cl = cl->next) { + cl->buf->recycled = 0; + } + if (p->output_filter(p->output_ctx, p->in) == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); @@ -442,7 +456,9 @@ static ngx_int_t ngx_event_pipe_write_to break; } - if (!p->downstream->write->ready) { + if (p->downstream->data != p->output_ctx + || !p->downstream->write->ready) + { break; } diff --git a/src/event/ngx_event_posted.c b/src/event/ngx_event_posted.c --- a/src/event/ngx_event_posted.c +++ b/src/event/ngx_event_posted.c @@ -33,7 +33,7 @@ void ngx_event_process_posted(ngx_cycle_ ngx_delete_posted_event(ev); - ev->event_handler(ev); + ev->handler(ev); } } @@ -137,7 +137,7 @@ ngx_int_t ngx_event_thread_process_poste ngx_mutex_unlock(ngx_posted_events_mutex); - ev->event_handler(ev); + ev->handler(ev); if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { return NGX_ERROR; diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -156,7 +156,7 @@ ngx_event_expire_timers(ngx_msec_t timer ev->timedout = 1; - ev->event_handler(ev); + ev->handler(ev); continue; } diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -54,7 +54,8 @@ static ngx_command_t ngx_http_access_co ngx_http_module_t ngx_http_access_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -68,7 +69,7 @@ ngx_http_module_t ngx_http_access_modul ngx_module_t ngx_http_access_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_access_module_ctx, /* module context */ ngx_http_access_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -60,7 +60,8 @@ static ngx_command_t ngx_http_auth_basi ngx_http_module_t ngx_http_auth_basic_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -74,7 +75,7 @@ ngx_http_module_t ngx_http_auth_basic_m ngx_module_t ngx_http_auth_basic_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_auth_basic_module_ctx, /* module context */ ngx_http_auth_basic_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -327,6 +328,7 @@ ngx_http_auth_basic_set_realm(ngx_http_r return NGX_HTTP_INTERNAL_SERVER_ERROR; } + r->headers_out.www_authenticate->hash = 1; r->headers_out.www_authenticate->key.len = sizeof("WWW-Authenticate") - 1; r->headers_out.www_authenticate->key.data = (u_char *) "WWW-Authenticate"; r->headers_out.www_authenticate->value = *realm; diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -63,7 +63,8 @@ static ngx_command_t ngx_http_autoindex ngx_http_module_t ngx_http_autoindex_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -77,7 +78,7 @@ ngx_http_module_t ngx_http_autoindex_mo ngx_module_t ngx_http_autoindex_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_autoindex_module_ctx, /* module context */ ngx_http_autoindex_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -419,16 +420,8 @@ ngx_http_autoindex_handler(ngx_http_requ r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = b->last - b->pos; - - r->headers_out.content_type = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.content_type == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->headers_out.content_type->key.len = 0; - r->headers_out.content_type->key.data = NULL; - r->headers_out.content_type->value.len = sizeof("text/html") - 1; - r->headers_out.content_type->value.data = (u_char *) "text/html"; + r->headers_out.content_type.len = sizeof("text/html") - 1; + r->headers_out.content_type.data = (u_char *) "text/html"; rc = ngx_http_send_header(r); @@ -436,10 +429,12 @@ ngx_http_autoindex_handler(ngx_http_requ return rc; } - if (!r->main) { + if (r->main == NULL) { b->last_buf = 1; } + b->last_in_chain = 1; + out.buf = b; out.next = NULL; diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c --- a/src/http/modules/ngx_http_charset_filter_module.c +++ b/src/http/modules/ngx_http_charset_filter_module.c @@ -106,7 +106,8 @@ static ngx_command_t ngx_http_charset_f static ngx_http_module_t ngx_http_charset_filter_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ ngx_http_charset_create_main_conf, /* create main configuration */ ngx_http_charset_init_main_conf, /* init main configuration */ @@ -120,7 +121,7 @@ static ngx_http_module_t ngx_http_chars ngx_module_t ngx_http_charset_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_charset_filter_module_ctx, /* module context */ ngx_http_charset_filter_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -148,19 +149,18 @@ ngx_http_charset_header_filter(ngx_http_ return ngx_http_next_header_filter(r); } - if (r->headers_out.content_type == NULL) { + if (r->headers_out.content_type.len == 0) { return ngx_http_next_header_filter(r); } - if (ngx_strncasecmp(r->headers_out.content_type->value.data, - "text/", 5) != 0 - && ngx_strncasecmp(r->headers_out.content_type->value.data, - "application/x-javascript", 24) != 0) + if (ngx_strncasecmp(r->headers_out.content_type.data, "text/", 5) != 0 + && ngx_strncasecmp(r->headers_out.content_type.data, + "application/x-javascript", 24) != 0) { return ngx_http_next_header_filter(r); } - if (ngx_strstr(r->headers_out.content_type->value.data, "charset") != NULL) + if (ngx_strstr(r->headers_out.content_type.data, "charset") != NULL) { return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c --- a/src/http/modules/ngx_http_chunked_filter_module.c +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -13,7 +13,8 @@ static ngx_int_t ngx_http_chunked_filter static ngx_http_module_t ngx_http_chunked_filter_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -27,7 +28,7 @@ static ngx_http_module_t ngx_http_chunk ngx_module_t ngx_http_chunked_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_chunked_filter_module_ctx, /* module context */ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -43,7 +44,7 @@ static ngx_http_output_body_filter_pt static ngx_int_t ngx_http_chunked_header_filter(ngx_http_request_t *r) { - if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { + if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED || r->main) { return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -15,37 +15,14 @@ typedef struct { ngx_peers_t *peers; - ngx_uint_t params; - - ngx_str_t root; ngx_str_t index; - ngx_array_t *vars; - - ngx_str_t *location; + ngx_array_t *params_len; + ngx_array_t *params; + ngx_array_t *params_source; } ngx_http_fastcgi_loc_conf_t; -typedef struct { - ngx_list_t headers; - - ngx_table_elt_t *status; - - ngx_table_elt_t *content_type; - ngx_table_elt_t *content_length; - ngx_table_elt_t *x_powered_by; - -#if (NGX_HTTP_GZIP) - ngx_table_elt_t *content_encoding; -#endif -} ngx_http_fastcgi_headers_in_t; - - -typedef struct { - ngx_http_fastcgi_headers_in_t headers_in; -} ngx_http_fastcgi_upstream_t; - - typedef enum { ngx_http_fastcgi_st_version = 0, ngx_http_fastcgi_st_type, @@ -69,28 +46,9 @@ typedef struct { size_t padding; ngx_uint_t header; - - ngx_http_fastcgi_upstream_t *upstream; } ngx_http_fastcgi_ctx_t; -#define NGX_HTTP_FASTCGI_REMOTE_ADDR 0x00000002 -#define NGX_HTTP_FASTCGI_REMOTE_USER 0x00000004 -#define NGX_HTTP_FASTCGI_SERVER_NAME 0x00000008 -#define NGX_HTTP_FASTCGI_SERVER_ADDR 0x00000010 -#define NGX_HTTP_FASTCGI_SERVER_PORT 0x00000020 -#define NGX_HTTP_FASTCGI_SCRIPT_NAME 0x00000040 -#define NGX_HTTP_FASTCGI_AUTH_TYPE 0x00000080 -#define NGX_HTTP_FASTCGI_SERVER_PROTOCOL 0x00000100 -#define NGX_HTTP_FASTCGI_SERVER_SOFTWARE 0x00000200 -#define NGX_HTTP_FASTCGI_GATEWAY_INTERFACE 0x00000400 -#define NGX_HTTP_FASTCGI_REQUEST_URI 0x00000800 -#define NGX_HTTP_FASTCGI_REDIRECT_STATUS 0x00001000 -#define NGX_HTTP_FASTCGI_DOCUMENT_ROOT 0x00002000 -#define NGX_HTTP_FASTCGI_SCRIPT_FILENAME 0x00004000 -#define NGX_HTTP_FASTCGI_REMOTE_PORT 0x00008000 - - #define NGX_HTTP_FASTCGI_RESPONDER 1 #define NGX_HTTP_FASTCGI_BEGIN_REQUEST 1 @@ -123,10 +81,24 @@ typedef struct { } ngx_http_fastcgi_begin_request_t; +typedef struct { + u_char version; + u_char type; + u_char request_id_hi; + u_char request_id_lo; +} ngx_http_fastcgi_header_small_t; + + +typedef struct { + ngx_http_fastcgi_header_t h0; + ngx_http_fastcgi_begin_request_t br; + ngx_http_fastcgi_header_small_t h1; +} ngx_http_fastcgi_request_start_t; + + static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r); static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r); -static ngx_int_t ngx_http_fastcgi_send_header(ngx_http_request_t *r); static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf); static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r, @@ -135,22 +107,54 @@ static void ngx_http_fastcgi_abort_reque static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc); +static ngx_int_t ngx_http_fastcgi_add_variables(ngx_conf_t *cf); +static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_http_variable_value_t * + ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, + uintptr_t data); + 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); -static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); +static ngx_http_fastcgi_request_start_t ngx_http_fastcgi_request_start = { + { 1, /* version */ + NGX_HTTP_FASTCGI_BEGIN_REQUEST, /* type */ + 0, /* request_id_hi */ + 1, /* request_id_lo */ + 0, /* content_length_hi */ + sizeof(ngx_http_fastcgi_begin_request_t), /* content_length_lo */ + 0, /* padding_length */ + 0 }, /* reserved */ + + { 0, /* role_hi */ + NGX_HTTP_FASTCGI_RESPONDER, /* role_lo */ + 0, /* NGX_HTTP_FASTCGI_KEEP_CONN */ /* flags */ + { 0, 0, 0, 0, 0 } }, /* reserved[5] */ + + { 1, /* version */ + NGX_HTTP_FASTCGI_PARAMS, /* type */ + 0, /* request_id_hi */ + 1 }, /* request_id_lo */ + +}; + + +#if 0 static ngx_str_t ngx_http_fastcgi_methods[] = { ngx_string("GET"), ngx_string("HEAD"), ngx_string("POST") }; +#endif + + +static ngx_str_t ngx_http_fastcgi_script_name = + ngx_string("fastcgi_script_name"); #if (NGX_PCRE) @@ -158,30 +162,14 @@ static ngx_str_t ngx_http_fastcgi_uri = #endif -static ngx_http_header_t ngx_http_fastcgi_headers_in[] = { - { ngx_string("Status"), offsetof(ngx_http_fastcgi_headers_in_t, status) }, - - { ngx_string("Content-Type"), - offsetof(ngx_http_fastcgi_headers_in_t, content_type) }, - - { ngx_string("Content-Length"), - offsetof(ngx_http_fastcgi_headers_in_t, content_length) }, +static ngx_conf_post_t ngx_http_fastcgi_lowat_post = + { ngx_http_fastcgi_lowat_check }; - { ngx_string("X-Powered-By"), - offsetof(ngx_http_fastcgi_headers_in_t, x_powered_by) }, - -#if (NGX_HTTP_GZIP) - { ngx_string("Content-Encoding"), - offsetof(ngx_http_fastcgi_headers_in_t, content_encoding) }, -#endif - +static ngx_conf_enum_t ngx_http_fastcgi_set_methods[] = { + { ngx_string("get"), NGX_HTTP_GET }, { ngx_null_string, 0 } }; - -static ngx_conf_post_t ngx_http_fastcgi_lowat_post = - { ngx_http_fastcgi_lowat_check }; - static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, @@ -192,28 +180,6 @@ static ngx_conf_bitmask_t ngx_http_fast }; -static ngx_conf_bitmask_t ngx_http_fastcgi_params_masks[] = { - { ngx_string("remote_addr"), NGX_HTTP_FASTCGI_REMOTE_ADDR }, - { ngx_string("server_port"), NGX_HTTP_FASTCGI_SERVER_PORT }, - { ngx_string("server_addr"), NGX_HTTP_FASTCGI_SERVER_ADDR }, - { ngx_string("server_name"), NGX_HTTP_FASTCGI_SERVER_NAME }, - { ngx_string("script_name"), NGX_HTTP_FASTCGI_SCRIPT_NAME }, - - { ngx_string("server_protocol"), NGX_HTTP_FASTCGI_SERVER_PROTOCOL }, - { ngx_string("server_software"), NGX_HTTP_FASTCGI_SERVER_SOFTWARE }, - { ngx_string("gateway_interface"), NGX_HTTP_FASTCGI_GATEWAY_INTERFACE }, - - { ngx_string("redirect_status"), NGX_HTTP_FASTCGI_REDIRECT_STATUS }, - { ngx_string("request_uri"), NGX_HTTP_FASTCGI_REQUEST_URI }, - - { ngx_string("document_root"), NGX_HTTP_FASTCGI_DOCUMENT_ROOT }, - { ngx_string("script_filename"), NGX_HTTP_FASTCGI_SCRIPT_FILENAME }, - { ngx_string("remote_port"), NGX_HTTP_FASTCGI_REMOTE_PORT }, - - { ngx_null_string, 0 } -}; - - static ngx_command_t ngx_http_fastcgi_commands[] = { { ngx_string("fastcgi_pass"), @@ -223,13 +189,6 @@ static ngx_command_t ngx_http_fastcgi_c 0, NULL }, - { ngx_string("fastcgi_root"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, root), - NULL }, - { ngx_string("fastcgi_index"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -265,6 +224,27 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.header_buffer_size), NULL }, + { ngx_string("fastcgi_method"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.method), + ngx_http_fastcgi_set_methods }, + + { ngx_string("fastcgi_pass_request_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_headers), + NULL }, + + { ngx_string("fastcgi_pass_request_body"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_body), + NULL }, + { ngx_string("fastcgi_redirect_errors"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -276,7 +256,7 @@ static ngx_command_t ngx_http_fastcgi_c NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.x_powered_by), + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_x_powered_by), NULL }, { ngx_string("fastcgi_read_timeout"), @@ -328,26 +308,20 @@ static ngx_command_t ngx_http_fastcgi_c 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_string("fastcgi_param"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_table_elt_slot, NGX_HTTP_LOC_CONF_OFFSET, - 0, + offsetof(ngx_http_fastcgi_loc_conf_t, params_source), 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, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, params), - &ngx_http_fastcgi_params_masks }, - ngx_null_command }; ngx_http_module_t ngx_http_fastcgi_module_ctx = { - NULL, /* pre conf */ + ngx_http_fastcgi_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -361,7 +335,7 @@ ngx_http_module_t ngx_http_fastcgi_modu ngx_module_t ngx_http_fastcgi_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_fastcgi_module_ctx, /* module context */ ngx_http_fastcgi_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -396,26 +370,15 @@ ngx_http_fastcgi_handler(ngx_http_reques u->conf = &flcf->upstream; - u->location0 = flcf->location; - u->create_request = ngx_http_fastcgi_create_request; u->reinit_request = ngx_http_fastcgi_reinit_request; u->process_header = ngx_http_fastcgi_process_header; - u->send_header = ngx_http_fastcgi_send_header; u->abort_request = ngx_http_fastcgi_abort_request; u->finalize_request = ngx_http_fastcgi_finalize_request; u->pipe.input_filter = ngx_http_fastcgi_input_filter; u->pipe.input_ctx = r; - u->log_ctx = r->connection->log->data; - u->log_handler = ngx_http_upstream_log_error; - - u->schema0.len = sizeof("fastcgi://") - 1; - u->schema0.data = (u_char *) "fastcgi://"; - u->uri0.len = sizeof("/") - 1; - u->uri0.data = (u_char *) "/"; - r->upstream = u; rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); @@ -431,206 +394,67 @@ ngx_http_fastcgi_handler(ngx_http_reques static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r) { - u_char ch, *pos, addr_text[INET_ADDRSTRLEN], - port_text[sizeof("65535") - 1]; - size_t size, len, index, padding, - addr_len, port_len; - off_t file_pos; - ngx_buf_t *b; - socklen_t slen; - ngx_chain_t *cl, *body; - ngx_uint_t i, n, next, *vindex, port; - ngx_list_part_t *part; - ngx_table_elt_t *header; - struct sockaddr_in sin, *sinp; - ngx_http_variable_t *var; - ngx_http_variable_value_t *value; - ngx_http_core_loc_conf_t *clcf; - 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; + off_t file_pos; + u_char ch, *pos; + size_t size, len, key_len, val_len, padding; + ngx_uint_t i, n, next; + ngx_buf_t *b; + ngx_chain_t *cl, *body; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_http_script_code_pt code; + ngx_http_script_engine_t e, le; + ngx_http_fastcgi_header_t *h; + ngx_http_fastcgi_loc_conf_t *flcf; + ngx_http_script_len_code_pt lcode; + len = 0; flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); - if ((flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) && r->in_addr == 0) { - - slen = sizeof(struct sockaddr_in); - if (getsockname(r->connection->fd, - (struct sockaddr *) &sin, &slen) == -1) - { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, - ngx_socket_errno, "getsockname() failed"); - return NGX_ERROR; - } - - r->in_addr = sin.sin_addr.s_addr; - } - - addr_len = ngx_inet_ntop(r->connection->listening->family, &r->in_addr, - addr_text, INET_ADDRSTRLEN); - if (addr_len == 0) { - return NGX_ERROR; - } - -#if (NGX_SUPPRESS_WARN) - clcf = NULL; - var = NULL; - vindex = NULL; -#endif - - - if (r->upstream->method) { - len = 1 + 1 + sizeof("REQUEST_METHOD") - 1 - + ngx_http_fastcgi_methods[r->upstream->method - 1].len; - - } else { - len = 1 + ((r->method_name.len - 1 > 127) ? 4 : 1) - + sizeof("REQUEST_METHOD") - 1 - + r->method_name.len - 1; - } - + if (flcf->params_len) { + ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); - index = (r->uri.data[r->uri.len - 1] == '/') ? flcf->index.len : 0; - - len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1) - + sizeof("PATH_TRANSLATED") - 1 + flcf->root.len + r->uri.len + index; - - if (r->args.len) { - len += 1 + ((r->args.len > 127) ? 4 : 1) + sizeof("QUERY_STRING") - 1 - + r->args.len; - } - - if (r->headers_in.content_length_n > 0) { - len += 1 + ((r->headers_in.content_length->value.len > 127) ? 4 : 1) - + sizeof("CONTENT_LENGTH") - 1 - + r->headers_in.content_length->value.len; - } - + le.ip = flcf->params_len->elts; + le.request = r; - if (r->headers_in.content_type) { - len += 1 + ((r->headers_in.content_type->value.len > 127) ? 4 : 1) - + sizeof("CONTENT_TYPE") - 1 - + r->headers_in.content_type->value.len; - } - - - if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) { - len += 1 + 1 + sizeof("REDIRECT_STATUS200") - 1; - } - - if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) { - len += 1 + ((r->unparsed_uri.len > 127) ? 4 : 1) - + sizeof("REQUEST_URI") - 1 + r->unparsed_uri.len; - } - - if (flcf->params & NGX_HTTP_FASTCGI_DOCUMENT_ROOT) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - len += 1 + ((clcf->root.len > 127) ? 4 : 1) - + sizeof("DOCUMENT_ROOT") - 1 + clcf->root.len; - } + while (*(uintptr_t *) le.ip) { - if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_FILENAME) { - len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1) - + sizeof("SCRIPT_FILENAME") - 1 - + flcf->root.len + r->uri.len + index; - } - - if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) { - len += 1 + ((r->uri.len + index > 127) ? 4 : 1) - + sizeof("SCRIPT_NAME") - 1 + r->uri.len + index ; - } - - if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) { - len += 1 + 1 + sizeof("REMOTE_ADDR") - 1 + r->connection->addr_text.len; - } - - port_len = 0; - - if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_PORT) { - - /* AF_INET only */ - - if (r->connection->sockaddr->sa_family == AF_INET) { - sinp = (struct sockaddr_in *) r->connection->sockaddr; - - port = ntohs(sinp->sin_port); - - if (port > 0 && port < 65536) { - port_len = ngx_sprintf(port_text, "%ui", port) - port_text; - } - - len += 1 + 1 + sizeof("REMOTE_PORT") - 1 + port_len; - } - } - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) { - len += 1 + 1 + sizeof("SERVER_NAME") - 1 + r->server_name.len; - } + lcode = *(ngx_http_script_len_code_pt *) le.ip; + key_len = lcode(&le); - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) { - len += 1 + 1 + sizeof("SERVER_PORT") - 1 + r->port_text->len - 1; - } - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) { - len += 1 + 1 + sizeof("SERVER_ADDR") - 1 + addr_len; - } - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL - && r->http_protocol.len) - { - len += 1 + ((r->http_protocol.len > 127) ? 4 : 1) - + sizeof("SERVER_PROTOCOL") - 1 + r->http_protocol.len; - } - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) { - len += 1 + 1 + sizeof("SERVER_SOFTWARE") - 1 + sizeof(NGINX_VER) - 1; - } + for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { + lcode = *(ngx_http_script_len_code_pt *) le.ip; + } + le.ip += sizeof(uintptr_t); - if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) { - len += 1 + 1 + sizeof("GATEWAY_INTERFACE") - 1 + sizeof("CGI/1.1") - 1; - } - - - if (flcf->vars) { - 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++) { - - value = ngx_http_get_indexed_variable(r, vindex[i]); - if (value == NULL) { - continue; - } - - if (value->text.len) { - len += 1 + 1 + var[vindex[i]].name.len + value->text.len; + if (val_len) { + len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len; } } } + if (flcf->upstream.pass_request_headers) { - part = &r->headers_in.headers.part; - header = part->elts; + part = &r->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { - for (i = 0; /* void */; i++) { + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } - if (i >= part->nelts) { - if (part->next == NULL) { - break; + part = part->next; + header = part->elts; + i = 0; } - part = part->next; - header = part->elts; - i = 0; + len += ((sizeof("HTTP_") - 1 + header[i].key.len > 127) ? 4 : 1) + + ((header[i].value.len > 127) ? 4 : 1) + + sizeof("HTTP_") - 1 + header[i].key.len + header[i].value.len; } - - len += ((header[i].key.len > 127) ? 4 : 1) - + ((header[i].value.len > 127) ? 4 : 1) - + 5 + header[i].key.len + header[i].value.len; } @@ -667,36 +491,13 @@ ngx_http_fastcgi_create_request(ngx_http cl->buf = b; - h = (ngx_http_fastcgi_header_t *) b->pos; - - h->version = 1; - h->type = NGX_HTTP_FASTCGI_BEGIN_REQUEST; - h->request_id_hi = 0; - h->request_id_lo = 1; - h->content_length_hi = 0; - h->content_length_lo = sizeof(ngx_http_fastcgi_begin_request_t); - h->padding_length = 0; - h->reserved = 0; - - br = (ngx_http_fastcgi_begin_request_t *) - (b->pos + sizeof(ngx_http_fastcgi_header_t)); - br->role_hi = 0; - br->role_lo = NGX_HTTP_FASTCGI_RESPONDER; - br->flags = 0; /* NGX_HTTP_FASTCGI_KEEP_CONN */ - br->reserved[0] = 0; - br->reserved[1] = 0; - br->reserved[2] = 0; - br->reserved[3] = 0; - br->reserved[4] = 0; + ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start, + sizeof(ngx_http_fastcgi_request_start_t)); h = (ngx_http_fastcgi_header_t *) (b->pos + sizeof(ngx_http_fastcgi_header_t) + sizeof(ngx_http_fastcgi_begin_request_t)); - h->version = 1; - h->type = NGX_HTTP_FASTCGI_PARAMS; - h->request_id_hi = 0; - h->request_id_lo = 1; h->content_length_hi = (u_char) ((len >> 8) & 0xff); h->content_length_lo = (u_char) (len & 0xff); h->padding_length = (u_char) padding; @@ -707,376 +508,109 @@ ngx_http_fastcgi_create_request(ngx_http + sizeof(ngx_http_fastcgi_header_t); - *b->last++ = sizeof("PATH_TRANSLATED") - 1; + if (flcf->params_len) { + ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); - len = flcf->root.len + r->uri.len + index; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); + e.ip = flcf->params->elts; + e.pos = b->last; + e.request = r; - } else { - *b->last++ = (u_char) len; - } + le.ip = flcf->params_len->elts; - b->last = ngx_cpymem(b->last, "PATH_TRANSLATED", - sizeof("PATH_TRANSLATED") - 1); - b->last = ngx_cpymem(b->last, flcf->root.data, flcf->root.len); - b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); + while (*(uintptr_t *) le.ip) { - if (index) { - b->last = ngx_cpymem(b->last, flcf->index.data, index); - } + lcode = *(ngx_http_script_len_code_pt *) le.ip; + key_len = (u_char) lcode(&le); - - *b->last++ = sizeof("REQUEST_METHOD") - 1; - - if (r->upstream->method) { - *b->last++ = (u_char) - ngx_http_fastcgi_methods[r->upstream->method - 1].len; - - b->last = ngx_cpymem(b->last, "REQUEST_METHOD", - sizeof("REQUEST_METHOD") - 1); + for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { + lcode = *(ngx_http_script_len_code_pt *) le.ip; + } + le.ip += sizeof(uintptr_t); - b->last = ngx_cpymem(b->last, - ngx_http_fastcgi_methods[r->upstream->method - 1].data, - ngx_http_fastcgi_methods[r->upstream->method - 1].len); + if (val_len) { + *e.pos++ = (u_char) key_len; - } else { - len = r->method_name.len - 1; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } + if (val_len > 127) { + *e.pos++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80); + *e.pos++ = (u_char) ((val_len >> 16) & 0xff); + *e.pos++ = (u_char) ((val_len >> 8) & 0xff); + *e.pos++ = (u_char) (val_len & 0xff); - b->last = ngx_cpymem(b->last, "REQUEST_METHOD", - sizeof("REQUEST_METHOD") - 1); - b->last = ngx_cpymem(b->last, r->method_name.data, len); - } - - - if (r->args.len) { - *b->last++ = sizeof("QUERY_STRING") - 1; + } else { + *e.pos++ = (u_char) val_len; + } + } - len = r->args.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); + e.skip = val_len ? 0 : 1; - } else { - *b->last++ = (u_char) len; + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } + e.ip += sizeof(uintptr_t); } - b->last = ngx_cpymem(b->last, "QUERY_STRING", - sizeof("QUERY_STRING") - 1); - b->last = ngx_cpymem(b->last, r->args.data, len); - } - - - if (r->headers_in.content_length_n > 0) { - *b->last++ = sizeof("CONTENT_LENGTH") - 1; - - len = r->headers_in.content_length->value.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "CONTENT_LENGTH", - sizeof("CONTENT_LENGTH") - 1); - b->last = ngx_cpymem(b->last, r->headers_in.content_length->value.data, - len); - } - - - if (r->headers_in.content_type) { - *b->last++ = sizeof("CONTENT_TYPE") - 1; - - len = r->headers_in.content_type->value.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "CONTENT_TYPE", - sizeof("CONTENT_TYPE") - 1); - b->last = ngx_cpymem(b->last, r->headers_in.content_type->value.data, - len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) { - *b->last++ = sizeof("REDIRECT_STATUS") - 1; - *b->last++ = sizeof("200") - 1; - b->last = ngx_cpymem(b->last, "REDIRECT_STATUS200", - sizeof("REDIRECT_STATUS200") - 1); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) { - *b->last++ = sizeof("REQUEST_URI") - 1; - - len = r->unparsed_uri.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "REQUEST_URI", sizeof("REQUEST_URI") - 1); - b->last = ngx_cpymem(b->last, r->unparsed_uri.data, len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_DOCUMENT_ROOT) { - *b->last++ = sizeof("DOCUMENT_ROOT") - 1; - - len = clcf->root.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "DOCUMENT_ROOT", - sizeof("DOCUMENT_ROOT") - 1); - b->last = ngx_cpymem(b->last, clcf->root.data, len); + b->last = e.pos; } - if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_FILENAME) { - *b->last++ = sizeof("SCRIPT_FILENAME") - 1; - - len = flcf->root.len + r->uri.len + index; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "SCRIPT_FILENAME", - sizeof("SCRIPT_FILENAME") - 1); - b->last = ngx_cpymem(b->last, flcf->root.data, flcf->root.len); - b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); - - if (index) { - b->last = ngx_cpymem(b->last, flcf->index.data, index); - } - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) { - *b->last++ = sizeof("SCRIPT_NAME") - 1; + if (flcf->upstream.pass_request_headers) { - len = r->uri.len + index; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME") - 1); - b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); + part = &r->headers_in.headers.part; + header = part->elts; - if (index) { - b->last = ngx_cpymem(b->last, flcf->index.data, index); - } - } - - - if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) { - *b->last++ = sizeof("REMOTE_ADDR") - 1; - *b->last++ = (u_char) (r->connection->addr_text.len); - b->last = ngx_cpymem(b->last, "REMOTE_ADDR", sizeof("REMOTE_ADDR") - 1); - b->last = ngx_cpymem(b->last, r->connection->addr_text.data, - r->connection->addr_text.len); - } - - - if (port_len) { - *b->last++ = sizeof("REMOTE_PORT") - 1; - *b->last++ = (u_char) port_len; - b->last = ngx_cpymem(b->last, "REMOTE_PORT", sizeof("REMOTE_PORT") - 1); - b->last = ngx_cpymem(b->last, port_text, port_len); - } - + for (i = 0; /* void */; i++) { - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) { - *b->last++ = sizeof("SERVER_NAME") - 1; - *b->last++ = (u_char) r->server_name.len; - b->last = ngx_cpymem(b->last, "SERVER_NAME", sizeof("SERVER_NAME") - 1); - b->last = ngx_cpymem(b->last, r->server_name.data, r->server_name.len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) { - *b->last++ = sizeof("SERVER_PORT") - 1; - *b->last++ = (u_char) (r->port_text->len - 1); - b->last = ngx_cpymem(b->last, "SERVER_PORT", sizeof("SERVER_PORT") - 1); - b->last = ngx_cpymem(b->last, r->port_text->data + 1, - r->port_text->len - 1); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) { - *b->last++ = sizeof("SERVER_ADDR") - 1; - *b->last++ = (u_char) addr_len; - b->last = ngx_cpymem(b->last, "SERVER_ADDR", sizeof("SERVER_ADDR") - 1); - b->last = ngx_cpymem(b->last, addr_text, addr_len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL - && r->http_protocol.len) - { - *b->last++ = sizeof("SERVER_PROTOCOL") - 1; + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } - len = r->http_protocol.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "SERVER_PROTOCOL", - sizeof("SERVER_PROTOCOL") - 1); - b->last = ngx_cpymem(b->last, r->http_protocol.data, len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) { - *b->last++ = sizeof("SERVER_SOFTWARE") - 1; - *b->last++ = (u_char) (sizeof(NGINX_VER) - 1); - b->last = ngx_cpymem(b->last, "SERVER_SOFTWARE", - sizeof("SERVER_SOFTWARE") - 1); - b->last = ngx_cpymem(b->last, NGINX_VER, sizeof(NGINX_VER) - 1); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) { - *b->last++ = sizeof("GATEWAY_INTERFACE") - 1; - *b->last++ = (u_char) (sizeof("CGI/1.1") - 1); - b->last = ngx_cpymem(b->last, "GATEWAY_INTERFACE", - sizeof("GATEWAY_INTERFACE") - 1); - b->last = ngx_cpymem(b->last, "CGI/1.1", sizeof("CGI/1.1") - 1); - } - - - if (flcf->vars) { - for (i = 0; i < flcf->vars->nelts; i++) { - - value = ngx_http_get_indexed_variable(r, vindex[i]); - if (value == NULL) { - continue; + len = sizeof("HTTP_") - 1 + header[i].key.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; } - 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); + len = header[i].value.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); - b->last = ngx_cpymem(b->last, value->text.data, value->text.len); - } - } - - - part = &r->headers_in.headers.part; - header = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; + } else { + *b->last++ = (u_char) len; } - part = part->next; - header = part->elts; - i = 0; - } + b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1); - len = 5 + header[i].key.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } + for (n = 0; n < header[i].key.len; n++) { + ch = header[i].key.data[n]; - len = header[i].value.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } + if (ch >= 'a' && ch <= 'z') { + ch &= ~0x20; - b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1); - - for (n = 0; n < header[i].key.len; n++) { - ch = header[i].key.data[n]; + } else if (ch == '-') { + ch = '_'; + } - if (ch >= 'a' && ch <= 'z') { - ch &= ~0x20; - - } else if (ch == '-') { - ch = '_'; + *b->last++ = ch; } - *b->last++ = ch; + b->last = ngx_cpymem(b->last, header[i].value.data, + header[i].value.len); } - - b->last = ngx_cpymem(b->last, header[i].value.data, - header[i].value.len); } @@ -1101,103 +635,109 @@ ngx_http_fastcgi_create_request(ngx_http h = (ngx_http_fastcgi_header_t *) b->last; b->last += sizeof(ngx_http_fastcgi_header_t); - body = r->request_body->bufs; - r->request_body->bufs = cl; + if (flcf->upstream.pass_request_body) { + body = r->upstream->request_bufs; + r->upstream->request_bufs = cl; #if (NGX_SUPPRESS_WARN) - file_pos = 0; - pos = NULL; + file_pos = 0; + pos = NULL; #endif - while (body) { - - if (body->buf->in_file) { - file_pos = body->buf->file_pos; + while (body) { - } else { - pos = body->buf->pos; - } + if (body->buf->in_file) { + file_pos = body->buf->file_pos; - next = 0; - - do { - b = ngx_alloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; + } else { + pos = body->buf->pos; } - ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); - - if (body->buf->in_file) { - b->file_pos = file_pos; - file_pos += 32 * 1024; - - if (file_pos > body->buf->file_last) { - file_pos = body->buf->file_last; - next = 1; - } + next = 0; - b->file_last = file_pos; - len = (ngx_uint_t) (file_pos - b->file_pos); - - } else { - b->pos = pos; - pos += 32 * 1024; - - if (pos > body->buf->last) { - pos = body->buf->last; - next = 1; + do { + b = ngx_alloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; } - b->last = pos; - len = (ngx_uint_t) (pos - b->pos); - } + ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); + + if (body->buf->in_file) { + b->file_pos = file_pos; + file_pos += 32 * 1024; - padding = 8 - len % 8; - padding = (padding == 8) ? 0 : padding; + if (file_pos > body->buf->file_last) { + file_pos = body->buf->file_last; + next = 1; + } + + b->file_last = file_pos; + len = (ngx_uint_t) (file_pos - b->file_pos); + + } else { + b->pos = pos; + pos += 32 * 1024; - h->version = 1; - h->type = NGX_HTTP_FASTCGI_STDIN; - h->request_id_hi = 0; - h->request_id_lo = 1; - h->content_length_hi = (u_char) ((len >> 8) & 0xff); - h->content_length_lo = (u_char) (len & 0xff); - h->padding_length = (u_char) padding; - h->reserved = 0; + if (pos > body->buf->last) { + pos = body->buf->last; + next = 1; + } + + b->last = pos; + len = (ngx_uint_t) (pos - b->pos); + } - cl->next = ngx_alloc_chain_link(r->pool); - if (cl->next == NULL) { - return NGX_ERROR; - } + padding = 8 - len % 8; + padding = (padding == 8) ? 0 : padding; - cl = cl->next; - cl->buf = b; + h->version = 1; + h->type = NGX_HTTP_FASTCGI_STDIN; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = (u_char) ((len >> 8) & 0xff); + h->content_length_lo = (u_char) (len & 0xff); + h->padding_length = (u_char) padding; + h->reserved = 0; - b = ngx_create_temp_buf(r->pool, sizeof(ngx_http_fastcgi_header_t) - + padding); - if (b == NULL) { - return NGX_ERROR; - } + cl->next = ngx_alloc_chain_link(r->pool); + if (cl->next == NULL) { + return NGX_ERROR; + } - if (padding) { - ngx_memzero(b->last, padding); - b->last += padding; - } + cl = cl->next; + cl->buf = b; + + b = ngx_create_temp_buf(r->pool, + sizeof(ngx_http_fastcgi_header_t) + + padding); + if (b == NULL) { + return NGX_ERROR; + } - h = (ngx_http_fastcgi_header_t *) b->last; - b->last += sizeof(ngx_http_fastcgi_header_t); + if (padding) { + ngx_memzero(b->last, padding); + b->last += padding; + } + + h = (ngx_http_fastcgi_header_t *) b->last; + b->last += sizeof(ngx_http_fastcgi_header_t); - cl->next = ngx_alloc_chain_link(r->pool); - if (cl->next == NULL) { - return NGX_ERROR; - } + cl->next = ngx_alloc_chain_link(r->pool); + if (cl->next == NULL) { + return NGX_ERROR; + } + + cl = cl->next; + cl->buf = b; - cl = cl->next; - cl->buf = b; + } while (!next); - } while (!next); + body = body->next; + } - body = body->next; + } else { + r->upstream->request_bufs = cl; } h->version = 1; @@ -1229,17 +769,6 @@ ngx_http_fastcgi_reinit_request(ngx_http f->state = ngx_http_fastcgi_st_version; f->header = 0; - ngx_memzero(&f->upstream->headers_in, - sizeof(ngx_http_fastcgi_headers_in_t)); - - if (f->upstream->headers_in.headers.part.elts) { - if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 8, - sizeof(ngx_table_elt_t)) == NGX_ERROR) - { - return NGX_ERROR; - } - } - return NGX_OK; } @@ -1247,16 +776,21 @@ ngx_http_fastcgi_reinit_request(ngx_http static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r) { - u_char *start, *last; - ngx_str_t *status_line, line; - ngx_int_t rc, status; - ngx_uint_t i; - ngx_table_elt_t *h; - ngx_http_upstream_t *u; - ngx_http_fastcgi_ctx_t *f; + u_char *start, *last; + ngx_str_t *status_line, line; + ngx_int_t rc, status; + ngx_uint_t key; + ngx_table_elt_t *h; + ngx_http_upstream_t *u; + ngx_http_fastcgi_ctx_t *f; + ngx_http_upstream_header_t *hh; + ngx_http_upstream_main_conf_t *umcf; f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + hh = (ngx_http_upstream_header_t *) umcf->headers_in_hash.buckets; + if (f == NULL) { f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)); if (f == NULL) { @@ -1264,17 +798,6 @@ ngx_http_fastcgi_process_header(ngx_http } ngx_http_set_ctx(r, f, ngx_http_fastcgi_module); - - f->upstream = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_upstream_t)); - if (f->upstream == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 8, - sizeof(ngx_table_elt_t)) == NGX_ERROR) - { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } } u = r->upstream; @@ -1424,11 +947,13 @@ ngx_http_fastcgi_process_header(ngx_http /* a header line has been parsed successfully */ - h = ngx_list_push(&f->upstream->headers_in.headers); + h = ngx_list_push(&u->headers_in.headers); if (h == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } + h->hash = r->header_hash; + h->key.len = r->header_name_end - r->header_name_start; h->value.len = r->header_end - r->header_start; @@ -1443,18 +968,13 @@ ngx_http_fastcgi_process_header(ngx_http ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); - for (i = 0; ngx_http_fastcgi_headers_in[i].name.len != 0; i++) { - if (ngx_http_fastcgi_headers_in[i].name.len != h->key.len) { - continue; - } + key = h->hash % umcf->headers_in_hash.hash_size; - if (ngx_strcasecmp(ngx_http_fastcgi_headers_in[i].name.data, - h->key.data) == 0) - { - *((ngx_table_elt_t **) - ((char *) &f->upstream->headers_in - + ngx_http_fastcgi_headers_in[i].offset)) = h; - break; + if (hh[key].name.len == h->key.len + && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0) + { + if (hh[key].handler(r, h, hh[key].offset) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; } } @@ -1472,8 +992,8 @@ ngx_http_fastcgi_process_header(ngx_http ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fastcgi header done"); - if (f->upstream->headers_in.status) { - status_line = &f->upstream->headers_in.status->value; + if (u->headers_in.status) { + status_line = &u->headers_in.status->value; status = ngx_atoi(status_line->data, 3); @@ -1541,84 +1061,6 @@ ngx_http_fastcgi_process_header(ngx_http static ngx_int_t -ngx_http_fastcgi_send_header(ngx_http_request_t *r) -{ - ngx_uint_t i; - ngx_list_part_t *part; - ngx_table_elt_t *ho, *h; - ngx_http_fastcgi_ctx_t *f; - ngx_http_fastcgi_headers_in_t *headers_in; - - f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); - - headers_in = &f->upstream->headers_in; - part = &headers_in->headers.part; - h = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - h = part->elts; - i = 0; - } - - /* ignore some headers */ - - if (&h[i] == headers_in->status) { - continue; - } - - - if (&h[i] == headers_in->x_powered_by - && !r->upstream->conf->x_powered_by) - { - continue; - } - - - /* "Content-Type" is handled specially */ - - if (&h[i] == headers_in->content_type) { - r->headers_out.content_type = &h[i]; - r->headers_out.content_type->key.len = 0; - continue; - } - - - /* copy some header pointers and set up r->headers_out */ - - ho = ngx_list_push(&r->headers_out.headers); - if (ho == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - *ho = h[i]; - -#if (NGX_HTTP_GZIP) - if (&h[i] == headers_in->content_encoding) { - r->headers_out.content_encoding = ho; - continue; - } -#endif - - if (&h[i] == headers_in->content_length) { - r->headers_out.content_length = ho; - r->headers_out.content_length_n = ngx_atoi(ho->value.data, - ho->value.len); - continue; - } - } - - return ngx_http_send_header(r); -} - - -static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) { ngx_int_t rc; @@ -1937,7 +1379,6 @@ ngx_http_fastcgi_process_record(ngx_http } } - f->pos = p + 1; f->state = state; return NGX_AGAIN; @@ -1964,140 +1405,19 @@ ngx_http_fastcgi_finalize_request(ngx_ht } -static char * -ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +static ngx_int_t +ngx_http_fastcgi_add_variables(ngx_conf_t *cf) { - ngx_http_fastcgi_loc_conf_t *lcf = conf; - - ngx_str_t *value; - ngx_inet_upstream_t inet_upstream; - ngx_http_core_loc_conf_t *clcf; -#if (NGX_HAVE_UNIX_DOMAIN) - ngx_unix_domain_upstream_t unix_upstream; -#endif - - value = cf->args->elts; - - if (ngx_strncasecmp(value[1].data, "unix:", 5) == 0) { - -#if (NGX_HAVE_UNIX_DOMAIN) - - ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); - - unix_upstream.name = value[1]; - unix_upstream.url = value[1]; - - lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); - if (lcf->peers == NULL) { - return NGX_CONF_ERROR; - } + ngx_http_variable_t *var; -#else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the unix domain sockets are not supported " - "on this platform"); - return NGX_CONF_ERROR; - -#endif - - } else { - ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); - - inet_upstream.name = value[1]; - inet_upstream.url = value[1]; - - lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); - if (lcf->peers == NULL) { - return NGX_CONF_ERROR; - } - } - - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - - 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; + var = ngx_http_add_variable(cf, &ngx_http_fastcgi_script_name, 0); + if (var == NULL) { + return NGX_ERROR; } - return NGX_CONF_OK; -} - - -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 == NULL) { - lcf->vars = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_variable_t *)); - if (lcf->vars == NULL) { - 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) { - - index = ngx_array_push(lcf->vars); - if (index == NULL) { - return NGX_CONF_ERROR; - } + var->handler = ngx_http_fastcgi_script_name_variable; - *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) -{ -#if (NGX_FREEBSD) - ssize_t *np = data; - - if (*np >= ngx_freebsd_net_inet_tcp_sendspace) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"fastcgi_send_lowat\" must be less than %d " - "(sysctl net.inet.tcp.sendspace)", - ngx_freebsd_net_inet_tcp_sendspace); - - return NGX_CONF_ERROR; - } - -#elif !(NGX_HAVE_SO_SNDLOWAT) - ssize_t *np = data; - - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "\"fastcgi_send_lowat\" is not supported, ignored"); - - *np = 0; - -#endif - - return NGX_CONF_OK; + return NGX_OK; } @@ -2118,12 +1438,12 @@ ngx_http_fastcgi_create_loc_conf(ngx_con * conf->upstream.path = NULL; * conf->upstream.next_upstream = 0; * conf->upstream.temp_path = NULL; - * conf->params = 0; - * conf->root.len = 0; - * conf->root.data = NULL; + * conf->upstream.schema = { 0, NULL }; + * conf->upstream.uri = { 0, NULL }; + * conf->upstream.location = NULL; + * * conf->index.len = 0; * conf->index.data = NULL; - * conf->location = NULL; */ conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; @@ -2135,14 +1455,23 @@ ngx_http_fastcgi_create_loc_conf(ngx_con conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE; conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE; - + + conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET; + conf->upstream.method = NGX_CONF_UNSET_UINT; + conf->upstream.pass_request_headers = NGX_CONF_UNSET; + conf->upstream.pass_request_body = NGX_CONF_UNSET; + conf->upstream.redirect_errors = NGX_CONF_UNSET; - conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET; - conf->upstream.x_powered_by = NGX_CONF_UNSET; /* "fastcgi_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; + conf->upstream.pass_x_powered_by = NGX_CONF_UNSET; + + /* the hardcoded values */ + conf->upstream.pass_server = 1; + conf->upstream.pass_date = 1; + return conf; } @@ -2153,7 +1482,13 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf ngx_http_fastcgi_loc_conf_t *prev = parent; ngx_http_fastcgi_loc_conf_t *conf = child; - size_t size; + u_char *p; + size_t size; + uintptr_t *code; + ngx_uint_t i; + ngx_table_elt_t *src; + ngx_http_script_compile_t sc; + ngx_http_script_copy_code_t *copy; ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -2263,51 +1598,300 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0, ngx_garbage_collector_temp_handler, cf); - - ngx_conf_merge_msec_value(conf->upstream.redirect_errors, - prev->upstream.redirect_errors, 0); - ngx_conf_merge_msec_value(conf->upstream.pass_unparsed_uri, prev->upstream.pass_unparsed_uri, 0); - if (conf->upstream.pass_unparsed_uri && conf->location->len > 1) { + if (conf->upstream.pass_unparsed_uri && conf->upstream.location->len > 1) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "\"fastcgi_pass_unparsed_uri\" can be set for " "location \"/\" or given by regular expression."); return NGX_CONF_ERROR; } - ngx_conf_merge_msec_value(conf->upstream.x_powered_by, - prev->upstream.x_powered_by, 1); + if (conf->upstream.method == NGX_CONF_UNSET_UINT) { + conf->upstream.method = prev->upstream.method; + } + + ngx_conf_merge_value(conf->upstream.pass_request_headers, + prev->upstream.pass_request_headers, 1); + ngx_conf_merge_value(conf->upstream.pass_request_body, + prev->upstream.pass_request_body, 1); + + ngx_conf_merge_msec_value(conf->upstream.redirect_errors, + prev->upstream.redirect_errors, 0); + + ngx_conf_merge_msec_value(conf->upstream.pass_x_powered_by, + prev->upstream.pass_x_powered_by, 1); - ngx_conf_merge_bitmask_value(conf->params, prev->params, - (NGX_CONF_BITMASK_SET - |NGX_HTTP_FASTCGI_REMOTE_ADDR - |NGX_HTTP_FASTCGI_REMOTE_USER - |NGX_HTTP_FASTCGI_SERVER_NAME - |NGX_HTTP_FASTCGI_SERVER_PORT - |NGX_HTTP_FASTCGI_SCRIPT_NAME - |NGX_HTTP_FASTCGI_AUTH_TYPE - |NGX_HTTP_FASTCGI_REQUEST_URI - |NGX_HTTP_FASTCGI_REDIRECT_STATUS)); - - ngx_conf_merge_str_value(conf->root, prev->root, ""); - - if (conf->root.len && conf->root.data[conf->root.len - 1] == '/') { - conf->root.len--; - } - ngx_conf_merge_str_value(conf->index, prev->index, ""); - if (conf->vars == NULL) { - conf->vars = prev->vars; - } - if (conf->peers == NULL) { conf->peers = prev->peers; conf->upstream = prev->upstream; } + if (conf->params_source == NULL) { + conf->params_source = prev->params_source; + conf->params_len = prev->params_len; + conf->params = prev->params; + + if (conf->params_source == NULL) { + return NGX_CONF_OK; + } + } + + conf->params_len = ngx_array_create(cf->pool, 64, 1); + if (conf->params_len == NULL) { + return NGX_CONF_ERROR; + } + + conf->params = ngx_array_create(cf->pool, 512, 1); + if (conf->params == NULL) { + return NGX_CONF_ERROR; + } + + src = conf->params_source->elts; + for (i = 0; i < conf->params_source->nelts; i++) { + + if (ngx_http_script_variables_count(&src[i].value) == 0) { + copy = ngx_array_push_n(conf->params_len, + sizeof(ngx_http_script_copy_code_t)); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = (ngx_http_script_code_pt) + ngx_http_script_copy_len_code; + copy->len = src[i].key.len; + + + copy = ngx_array_push_n(conf->params_len, + sizeof(ngx_http_script_copy_code_t)); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = (ngx_http_script_code_pt) + ngx_http_script_copy_len_code; + copy->len = src[i].value.len; + + + size = (sizeof(ngx_http_script_copy_code_t) + + src[i].key.len + src[i].value.len + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + copy = ngx_array_push_n(conf->params, size); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = ngx_http_script_copy_code; + copy->len = src[i].key.len + src[i].value.len; + + p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + + p = ngx_cpymem(p, src[i].key.data, src[i].key.len); + ngx_memcpy(p, src[i].value.data, src[i].value.len); + + } else { + copy = ngx_array_push_n(conf->params_len, + sizeof(ngx_http_script_copy_code_t)); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = (ngx_http_script_code_pt) + ngx_http_script_copy_len_code; + copy->len = src[i].key.len; + + + size = (sizeof(ngx_http_script_copy_code_t) + + src[i].key.len + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + copy = ngx_array_push_n(conf->params, size); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = ngx_http_script_copy_code; + copy->len = src[i].key.len; + + p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + ngx_memcpy(p, src[i].key.data, src[i].key.len); + + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &src[i].value; + sc.lengths = &conf->params_len; + sc.values = &conf->params; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_CONF_ERROR; + } + + *code = (uintptr_t) NULL; + + + code = ngx_array_push_n(conf->params, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_CONF_ERROR; + } + + *code = (uintptr_t) NULL; + } + + code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_CONF_ERROR; + } + + *code = (uintptr_t) NULL; + return NGX_CONF_OK; } + + +static ngx_http_variable_value_t * +ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, uintptr_t data) +{ + u_char *p; + ngx_http_variable_value_t *vv; + ngx_http_fastcgi_loc_conf_t *flcf; + + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { + return NULL; + } + + vv->value = 0; + + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + if (r->uri.data[r->uri.len - 1] != '/') { + vv->text = r->uri; + return vv; + } + + vv->text.len = r->uri.len + flcf->index.len; + + vv->text.data = ngx_palloc(r->pool, vv->text.len); + if (vv->text.data == NULL) { + return NULL; + } + + p = ngx_cpymem(vv->text.data, r->uri.data, r->uri.len); + ngx_memcpy(p, flcf->index.data, flcf->index.len); + + return vv; +} + + +static char * +ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_fastcgi_loc_conf_t *lcf = conf; + + ngx_str_t *value; + ngx_inet_upstream_t inet_upstream; + ngx_http_core_loc_conf_t *clcf; +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_unix_domain_upstream_t unix_upstream; +#endif + + value = cf->args->elts; + + if (ngx_strncasecmp(value[1].data, "unix:", 5) == 0) { + +#if (NGX_HAVE_UNIX_DOMAIN) + + ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); + + unix_upstream.name = value[1]; + unix_upstream.url = value[1]; + + lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); + if (lcf->peers == NULL) { + return NGX_CONF_ERROR; + } + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the unix domain sockets are not supported " + "on this platform"); + return NGX_CONF_ERROR; + +#endif + + } else { + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + + inet_upstream.name = value[1]; + inet_upstream.url = value[1]; + + lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); + if (lcf->peers == NULL) { + return NGX_CONF_ERROR; + } + } + + lcf->upstream.schema.len = sizeof("fastcgi://") - 1; + lcf->upstream.schema.data = (u_char *) "fastcgi://"; + lcf->upstream.uri.len = sizeof("/") - 1; + lcf->upstream.uri.data = (u_char *) "/"; + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + clcf->handler = ngx_http_fastcgi_handler; + +#if (NGX_PCRE) + lcf->upstream.location = clcf->regex ? &ngx_http_fastcgi_uri : &clcf->name; +#else + lcf->upstream.location = &clcf->name; +#endif + + if (clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data) +{ +#if (NGX_FREEBSD) + ssize_t *np = data; + + if (*np >= ngx_freebsd_net_inet_tcp_sendspace) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_send_lowat\" must be less than %d " + "(sysctl net.inet.tcp.sendspace)", + ngx_freebsd_net_inet_tcp_sendspace); + + return NGX_CONF_ERROR; + } + +#elif !(NGX_HAVE_SO_SNDLOWAT) + ssize_t *np = data; + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"fastcgi_send_lowat\" is not supported, ignored"); + + *np = 0; + +#endif + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -34,7 +34,8 @@ static ngx_command_t ngx_http_geo_comma static ngx_http_module_t ngx_http_geo_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -48,7 +49,7 @@ static ngx_http_module_t ngx_http_geo_m ngx_module_t ngx_http_geo_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_geo_module_ctx, /* module context */ ngx_http_geo_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -110,7 +111,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c name.data++; } - var = ngx_http_add_variable(cf, &name, 1); + var = ngx_http_add_variable(cf, &name, 0); if (var == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -207,7 +207,8 @@ static ngx_command_t ngx_http_gzip_filt static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { - ngx_http_gzip_add_log_formats, /* pre conf */ + ngx_http_gzip_add_log_formats, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -221,7 +222,7 @@ static ngx_http_module_t ngx_http_gzip_ ngx_module_t ngx_http_gzip_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_gzip_filter_module_ctx, /* module context */ ngx_http_gzip_filter_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -257,6 +258,11 @@ struct gztrailer { #endif +static ngx_str_t ngx_http_gzip_no_cache = ngx_string("no-cache"); +static ngx_str_t ngx_http_gzip_no_store = ngx_string("no-store"); +static ngx_str_t ngx_http_gzip_private = ngx_string("private"); + + static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter; @@ -276,8 +282,9 @@ ngx_http_gzip_header_filter(ngx_http_req && r->headers_out.status != NGX_HTTP_FORBIDDEN && r->headers_out.status != NGX_HTTP_NOT_FOUND) || r->header_only + || r->main || r->http_version < conf->http_version - || r->headers_out.content_type == NULL + || r->headers_out.content_type.len == 0 || (r->headers_out.content_encoding && r->headers_out.content_encoding->value.len) || r->headers_in.accept_encoding == NULL @@ -294,8 +301,8 @@ ngx_http_gzip_header_filter(ngx_http_req type = conf->types->elts; for (i = 0; i < conf->types->nelts; i++) { - if (r->headers_out.content_type->value.len >= type[i].name.len - && ngx_strncasecmp(r->headers_out.content_type->value.data, + if (r->headers_out.content_type.len >= type[i].name.len + && ngx_strncasecmp(r->headers_out.content_type.data, type[i].name.data, type[i].name.len) == 0) { found = 1; @@ -346,6 +353,7 @@ ngx_http_gzip_header_filter(ngx_http_req return NGX_ERROR; } + r->headers_out.content_encoding->hash = 1; r->headers_out.content_encoding->key.len = sizeof("Content-Encoding") - 1; r->headers_out.content_encoding->key.data = (u_char *) "Content-Encoding"; r->headers_out.content_encoding->value.len = sizeof("gzip") - 1; @@ -353,10 +361,12 @@ ngx_http_gzip_header_filter(ngx_http_req ctx->length = r->headers_out.content_length_n; r->headers_out.content_length_n = -1; + if (r->headers_out.content_length) { - r->headers_out.content_length->key.len = 0; + r->headers_out.content_length->hash = 0; r->headers_out.content_length = NULL; } + r->filter_need_in_memory = 1; return ngx_http_next_header_filter(r); @@ -404,22 +414,25 @@ ngx_http_gzip_proxied(ngx_http_request_t return NGX_DECLINED; } - if (r->headers_out.cache_control) { + if (r->headers_out.cache_control.elts) { if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_CACHE) - && ngx_strstr(r->headers_out.cache_control->value.data, "no-cache")) + && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control, + &ngx_http_gzip_no_cache, NULL) >= 0) { return NGX_OK; } if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_STORE) - && ngx_strstr(r->headers_out.cache_control->value.data, "no-store")) + && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control, + &ngx_http_gzip_no_store, NULL) >= 0) { return NGX_OK; } if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_PRIVATE) - && ngx_strstr(r->headers_out.cache_control->value.data, "private")) + && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control, + &ngx_http_gzip_private, NULL) >= 0) { return NGX_OK; } @@ -484,8 +497,8 @@ ngx_http_gzip_body_filter(ngx_http_reque * and do not wait while a whole response will be sent to a client. * * 8K is for zlib deflate_state, it takes - * * 5816 bytes on x86 and sparc64 (32-bit mode) - * * 5920 bytes on amd64 and sparc64 + * *) 5816 bytes on i386 and sparc64 (32-bit mode) + * *) 5920 bytes on amd64 and sparc64 */ ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); @@ -696,7 +709,8 @@ ngx_http_gzip_body_filter(ngx_http_reque if (ctx->flush == Z_SYNC_FLUSH) { - ctx->out_buf->flush = 0; + ctx->zstream.avail_out = 0; + ctx->out_buf->flush = 1; ctx->flush = Z_NO_FLUSH; cl = ngx_alloc_chain_link(r->pool); diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -41,7 +41,8 @@ static ngx_command_t ngx_http_headers_f static ngx_http_module_t ngx_http_headers_filter_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -55,7 +56,7 @@ static ngx_http_module_t ngx_http_heade ngx_module_t ngx_http_headers_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_headers_filter_module_ctx, /* module context */ ngx_http_headers_filter_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -71,10 +72,11 @@ static ngx_int_t ngx_http_headers_filter(ngx_http_request_t *r) { size_t len; + ngx_uint_t i; ngx_table_elt_t *expires, *cc; ngx_http_headers_conf_t *conf; - if (r->headers_out.status != NGX_HTTP_OK) { + if (r->headers_out.status != NGX_HTTP_OK || r->main) { return ngx_http_next_header_filter(r); } @@ -82,28 +84,43 @@ ngx_http_headers_filter(ngx_http_request if (conf->expires != NGX_HTTP_EXPIRES_OFF) { - expires = ngx_list_push(&r->headers_out.headers); + expires = r->headers_out.expires; + if (expires == NULL) { - return NGX_ERROR; + + expires = ngx_list_push(&r->headers_out.headers); + if (expires == NULL) { + return NGX_ERROR; + } + + r->headers_out.expires = expires; + + expires->hash = 1; + expires->key.len = sizeof("Expires") - 1; + expires->key.data = (u_char *) "Expires"; } - r->headers_out.expires = expires; - - cc = ngx_list_push(&r->headers_out.headers); - if (cc == NULL) { - return NGX_ERROR; - } - - r->headers_out.cache_control = cc; - len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT"); - - expires->key.len = sizeof("Expires") - 1; - expires->key.data = (u_char *) "Expires"; expires->value.len = len - 1; - cc->key.len = sizeof("Cache-Control") - 1; - cc->key.data = (u_char *) "Cache-Control"; + cc = r->headers_out.cache_control.elts; + + if (cc == NULL) { + + cc = ngx_list_push(&r->headers_out.headers); + if (cc == NULL) { + return NGX_ERROR; + } + + cc->hash = 1; + cc->key.len = sizeof("Cache-Control") - 1; + cc->key.data = (u_char *) "Cache-Control"; + + } else { + for (i = 1; i < r->headers_out.cache_control.nelts; i++) { + cc[i].hash = 0; + } + } if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) { expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT"; diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c @@ -10,42 +10,52 @@ typedef struct { - ngx_array_t indices; + ngx_str_t name; + ngx_array_t *lengths; + ngx_array_t *values; +} ngx_http_index_t; + + +typedef struct { + ngx_array_t *indices; /* array of ngx_http_index_t */ size_t max_index_len; - ngx_http_cache_hash_t *index_cache; } ngx_http_index_loc_conf_t; typedef struct { - ngx_uint_t index; - u_char *last; - ngx_str_t path; - ngx_str_t redirect; - ngx_http_cache_entry_t *cache; - ngx_uint_t tested; /* unsigned tested:1 */ + ngx_uint_t current; + size_t allocated; + + u_char *path; + ngx_str_t uri; + ngx_str_t index; + + ngx_uint_t tested; /* unsigned tested:1 */ } ngx_http_index_ctx_t; #define NGX_HTTP_DEFAULT_INDEX "index.html" +static ngx_int_t ngx_http_index_alloc(ngx_http_request_t *r, size_t size, + ngx_http_index_ctx_t *ctx, ngx_http_core_loc_conf_t *clcf); static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, - ngx_http_index_ctx_t *ctx); + ngx_http_index_ctx_t *ctx); static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, - ngx_http_index_ctx_t *ctx, ngx_err_t err); + ngx_http_index_ctx_t *ctx, ngx_err_t err); static ngx_int_t ngx_http_index_init(ngx_cycle_t *cycle); static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); + void *parent, void *child); static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); + void *conf); static ngx_command_t ngx_http_index_commands[] = { { ngx_string("index"), - NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_http_index_set_index, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -67,7 +77,8 @@ static ngx_command_t ngx_http_index_com ngx_http_module_t ngx_http_index_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -81,7 +92,7 @@ ngx_http_module_t ngx_http_index_module ngx_module_t ngx_http_index_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_index_module_ctx, /* module context */ ngx_http_index_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -100,21 +111,24 @@ ngx_module_t ngx_http_index_module = { * that path contains the usual file in place of the directory. */ -static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r) +static ngx_int_t +ngx_http_index_handler(ngx_http_request_t *r) { - u_char *name; - ngx_fd_t fd; - ngx_int_t rc; - ngx_str_t *index; - ngx_err_t err; - ngx_log_t *log; - ngx_http_index_ctx_t *ctx; - ngx_http_core_loc_conf_t *clcf; - ngx_http_index_loc_conf_t *ilcf; -#if (NGX_HTTP_CACHE0) - /* crc must be in ctx !! */ - uint32_t crc; -#endif + u_char *name; + size_t len; + ngx_fd_t fd; + ngx_int_t rc; + ngx_err_t err; + ngx_log_t *log; + ngx_uint_t i; + ngx_http_index_t *index; + ngx_http_index_ctx_t *ctx; + ngx_pool_cleanup_file_t *cln; + ngx_http_script_code_pt code; + ngx_http_script_engine_t e; + ngx_http_core_loc_conf_t *clcf; + ngx_http_index_loc_conf_t *ilcf; + ngx_http_script_len_code_pt lcode; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; @@ -128,8 +142,8 @@ static ngx_int_t ngx_http_index_handler( log = r->connection->log; /* - * we use context because the handler supports an async file opening - * and thus can be called several times + * we use context because the handler supports an async file opening, + * and may be called several times */ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -144,108 +158,63 @@ static ngx_int_t ngx_http_index_handler( } ngx_http_set_ctx(r, ctx, ngx_http_index_module); + } -#if (NGX_HTTP_CACHE) + index = ilcf->indices->elts; + for (i = ctx->current; i < ilcf->indices->nelts; i++) { + + if (index[i].lengths == NULL) { - if (ilcf->index_cache) { - ctx->cache = ngx_http_cache_get(ilcf->index_cache, NULL, - &r->uri, &crc); + if (index[i].name.data[0] == '/') { + return ngx_http_internal_redirect(r, &index[i].name, &r->args); + } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http index cache get: %p", ctx->cache); + len = ilcf->max_index_len; + ctx->index.len = index[i].name.len; - if (ctx->cache && !ctx->cache->expired) { + } else { + ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); - ctx->cache->accessed = ngx_cached_time; + e.ip = index[i].lengths->elts; + e.request = r; + + len = 1; - ctx->redirect.len = ctx->cache->data.value.len; - ctx->redirect.data = ngx_palloc(r->pool, ctx->redirect.len + 1); - if (ctx->redirect.data == NULL) { - ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_http_script_len_code_pt *) e.ip; + len += lcode(&e); + } - ngx_memcpy(ctx->redirect.data, ctx->cache->data.value.data, - ctx->redirect.len + 1); - ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); + ctx->index.len = len; + } - return ngx_http_internal_redirect(r, &ctx->redirect, NULL); + if (len > ctx->allocated) { + if (ngx_http_index_alloc(r, len, ctx, clcf) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; } } -#endif - -#if 0 - ctx->path.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len - + ilcf->max_index_len - - clcf->alias * clcf->name.len); - if (ctx->path.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + if (index[i].values == NULL) { + ngx_memcpy(ctx->index.data, index[i].name.data, ctx->index.len); - ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->root.data, - clcf->root.len); -#endif + } else { + e.ip = index[i].values->elts; + e.pos = ctx->index.data; - if (clcf->alias) { - ctx->path.data = ngx_palloc(r->pool, clcf->root.len - + r->uri.len + 1 - clcf->name.len - + ilcf->max_index_len); - if (ctx->path.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ctx->redirect.data = ngx_palloc(r->pool, r->uri.len - + ilcf->max_index_len); - if (ctx->redirect.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); } - ngx_memcpy(ctx->path.data, clcf->root.data, clcf->root.len); - - ctx->last = ngx_cpystrn(ctx->path.data + clcf->root.len, - r->uri.data + clcf->name.len, - r->uri.len + 1 - clcf->name.len); - -#if 0 - /* - * aliases usually have trailling "/", - * set it in the start of the possible redirect - */ - - if (*ctx->redirect.data != '/') { - ctx->redirect.data--; - } -#endif - - } else { - ctx->path.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len - + ilcf->max_index_len); - if (ctx->path.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (*ctx->index.data == '/') { + ctx->index.len--; + return ngx_http_internal_redirect(r, &ctx->index, &r->args); } - ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->root.data, - clcf->root.len); - - ctx->last = ngx_cpystrn(ctx->redirect.data, r->uri.data, - r->uri.len + 1); + *e.pos++ = '\0'; } - } - - ctx->path.len = ctx->last - ctx->path.data; - index = ilcf->indices.elts; - for (/* void */; ctx->index < ilcf->indices.nelts; ctx->index++) { - - if (index[ctx->index].data[0] == '/') { - name = index[ctx->index].data; - - } else { - ngx_memcpy(ctx->last, index[ctx->index].data, - index[ctx->index].len + 1); - name = ctx->path.data; - } + name = ctx->path; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "open index \"%s\"", name); @@ -253,6 +222,7 @@ static ngx_int_t ngx_http_index_handler( fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN); if (fd == (ngx_fd_t) NGX_AGAIN) { + ctx->current = i; return NGX_AGAIN; } @@ -290,131 +260,268 @@ static ngx_int_t ngx_http_index_handler( } - /* STUB: open file cache */ - - r->file.name.data = name; - r->file.fd = fd; - - if (index[ctx->index].data[0] == '/') { - r->file.name.len = index[ctx->index].len; - ctx->redirect.len = index[ctx->index].len; - ctx->redirect.data = index[ctx->index].data; - - } else { - if (clcf->alias) { - name = ngx_cpymem(ctx->redirect.data, r->uri.data, r->uri.len); - ngx_memcpy(name, index[ctx->index].data, - index[ctx->index].len + 1); - } - - ctx->redirect.len = r->uri.len + index[ctx->index].len; - r->file.name.len = clcf->root.len + r->uri.len - - clcf->alias * clcf->name.len - + index[ctx->index].len; + cln = ngx_palloc(r->pool, sizeof(ngx_pool_cleanup_file_t)); + if (cln == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; } - /**/ + cln->fd = fd; + cln->name = name; + cln->log = r->pool->log; + + if (ngx_pool_cleanup_add(r->pool, ngx_pool_cleanup_file, cln) == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } -#if (NGX_HTTP_CACHE) - - if (ilcf->index_cache) { - - if (ctx->cache) { - if (ctx->redirect.len == ctx->cache->data.value.len - && ngx_memcmp(ctx->cache->data.value.data, - ctx->redirect.data, ctx->redirect.len) == 0) - { - ctx->cache->accessed = ngx_cached_time; - ctx->cache->updated = ngx_cached_time; - ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); - - return ngx_http_internal_redirect(r, &ctx->redirect, NULL); - } - } - - ctx->redirect.len++; - ctx->cache = ngx_http_cache_alloc(ilcf->index_cache, ctx->cache, - NULL, &r->uri, crc, - &ctx->redirect, log); - ctx->redirect.len--; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http index cache alloc: %p", ctx->cache); - - if (ctx->cache) { - ctx->cache->fd = NGX_INVALID_FILE; - ctx->cache->accessed = ngx_cached_time; - ctx->cache->last_modified = 0; - ctx->cache->updated = ngx_cached_time; - ctx->cache->memory = 1; - ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); - } + if (clcf->alias) { + name = ngx_cpymem(ctx->uri.data, r->uri.data, r->uri.len); + ngx_memcpy(name, ctx->index.data, ctx->index.len - 1); } -#endif + ctx->uri.len = r->uri.len + ctx->index.len - 1; - return ngx_http_internal_redirect(r, &ctx->redirect, NULL); + return ngx_http_internal_redirect(r, &ctx->uri, &r->args); } return NGX_DECLINED; } -static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, - ngx_http_index_ctx_t *ctx) +static ngx_int_t +ngx_http_index_alloc(ngx_http_request_t *r, size_t size, + ngx_http_index_ctx_t *ctx, ngx_http_core_loc_conf_t *clcf) { - ngx_err_t err; + ctx->allocated = size; + + if (!clcf->alias) { + ctx->path = ngx_palloc(r->pool, clcf->root.len + r->uri.len + size); + if (ctx->path == NULL) { + return NGX_ERROR; + } + + ctx->uri.data = ngx_cpymem(ctx->path, clcf->root.data, clcf->root.len); + + ctx->index.data = ngx_cpymem(ctx->uri.data, r->uri.data, r->uri.len); + + } else { + ctx->path = ngx_palloc(r->pool, + clcf->root.len + r->uri.len - clcf->name.len + size); + if (ctx->path == NULL) { + return NGX_ERROR; + } - ctx->path.data[ctx->path.len - 1] = '\0'; - ctx->path.data[ctx->path.len] = '\0'; + ctx->uri.data = ngx_palloc(r->pool, r->uri.len + size); + if (ctx->uri.data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(ctx->path, clcf->root.data, clcf->root.len); + + ctx->index.data = ngx_cpymem(ctx->path + clcf->root.len, + r->uri.data + clcf->name.len, + r->uri.len - clcf->name.len); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx) +{ + ngx_err_t err; + ngx_file_info_t fi; + + *(ctx->index.data - 1) = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http check dir: \"%s\"", ctx->path.data); + "http index check dir: \"%s\"", ctx->path); - if (ngx_file_info(ctx->path.data, &r->file.info) == -1) { + if (ngx_file_info(ctx->path, &fi) == -1) { err = ngx_errno; if (err == NGX_ENOENT) { - ctx->path.data[ctx->path.len - 1] = '/'; + *(ctx->index.data - 1) = '/'; return ngx_http_index_error(r, ctx, err); } ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, - ngx_file_info_n " \"%s\" failed", ctx->path.data); + ngx_file_info_n " \"%s\" failed", ctx->path); return NGX_HTTP_INTERNAL_SERVER_ERROR; } - ctx->path.data[ctx->path.len - 1] = '/'; + *(ctx->index.data - 1) = '/'; - if (ngx_is_dir(&r->file.info)) { + if (ngx_is_dir(&fi)) { return NGX_OK; } - /* THINK: not reached ??? */ - return ngx_http_index_error(r, ctx, 0); + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "\"%s\" is not a directory", ctx->path); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; } -static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, - ngx_http_index_ctx_t *ctx, ngx_err_t err) +static ngx_int_t +ngx_http_index_error(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx, + ngx_err_t err) { if (err == NGX_EACCES) { ngx_log_error(NGX_LOG_ERR, r->connection->log, err, - "\"%s\" is forbidden", ctx->path.data); + "\"%s\" is forbidden", ctx->path); return NGX_HTTP_FORBIDDEN; } ngx_log_error(NGX_LOG_ERR, r->connection->log, err, - "\"%s\" is not found", ctx->path.data); + "\"%s\" is not found", ctx->path); + return NGX_HTTP_NOT_FOUND; } -static ngx_int_t ngx_http_index_init(ngx_cycle_t *cycle) +static void * +ngx_http_index_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_index_loc_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->indices = NULL; + conf->max_index_len = 1; + + return conf; +} + + +static char * +ngx_http_index_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_index_loc_conf_t *prev = parent; + ngx_http_index_loc_conf_t *conf = child; + + ngx_http_index_t *index; + + if (conf->indices == NULL) { + conf->indices = prev->indices; + conf->max_index_len = prev->max_index_len; + } + + if (conf->indices == NULL) { + conf->indices = ngx_array_create(cf->pool, 1, sizeof(ngx_http_index_t)); + if (conf->indices == NULL) { + return NGX_CONF_ERROR; + } + + index = ngx_array_push(conf->indices); + if (index == NULL) { + return NGX_CONF_ERROR; + } + + index->name.len = sizeof(NGX_HTTP_DEFAULT_INDEX); + index->name.data = (u_char *) NGX_HTTP_DEFAULT_INDEX; + index->lengths = NULL; + index->values = NULL; + + conf->max_index_len = sizeof(NGX_HTTP_DEFAULT_INDEX); + + return NGX_CONF_OK; + } + + return NGX_CONF_OK; +} + + +/* TODO: warn about duplicate indices */ + +static char * +ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_index_loc_conf_t *ilcf = conf; + + ngx_uint_t i, n; + ngx_str_t *value; + ngx_http_index_t *index; + ngx_http_script_compile_t sc; + + if (ilcf->indices == NULL) { + ilcf->indices = ngx_array_create(cf->pool, 2, sizeof(ngx_http_index_t)); + if (ilcf->indices == NULL) { + return NGX_CONF_ERROR; + } + } + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + if (value[i].data[0] == '/' && i != cf->args->nelts - 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "only the last index in \"index\" directive " + "may be absolute"); + return NGX_CONF_ERROR; + } + + if (value[i].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "index \"%V\" in \"index\" directive is invalid", + &value[1]); + return NGX_CONF_ERROR; + } + + index = ngx_array_push(ilcf->indices); + if (index == NULL) { + return NGX_CONF_ERROR; + } + + index->name.len = value[i].len; + index->name.data = value[i].data; + index->lengths = NULL; + index->values = NULL; + + n = ngx_http_script_variables_count(&value[i]); + + if (n == 0) { + index->name.len++; + + if (ilcf->max_index_len != 0 + && ilcf->max_index_len < index->name.len) + { + ilcf->max_index_len = index->name.len; + } + + continue; + } + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &value[i]; + sc.lengths = &index->lengths; + sc.values = &index->values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + ilcf->max_index_len = 0; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_index_init(ngx_cycle_t *cycle) { ngx_http_handler_pt *h; ngx_http_core_main_conf_t *cmcf; @@ -430,129 +537,3 @@ static ngx_int_t ngx_http_index_init(ngx return NGX_OK; } - - -static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_index_loc_conf_t *conf; - - conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t)); - if (conf == NULL) { - return NGX_CONF_ERROR; - } - - if (ngx_array_init(&conf->indices, cf->pool, 2, sizeof(ngx_str_t)) - == NGX_ERROR) - { - return NGX_CONF_ERROR; - } - - conf->max_index_len = 0; - - conf->index_cache = NULL; - - return conf; -} - - -/* TODO: remove duplicate indices */ - -static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child) -{ - ngx_http_index_loc_conf_t *prev = parent; - ngx_http_index_loc_conf_t *conf = child; - - ngx_str_t *index; - - if (conf->max_index_len == 0) { - if (prev->max_index_len != 0) { - ngx_memcpy(conf, prev, sizeof(ngx_http_index_loc_conf_t)); - return NGX_CONF_OK; - } - - index = ngx_array_push(&conf->indices); - if (index == NULL) { - return NGX_CONF_ERROR; - } - - index->len = sizeof(NGX_HTTP_DEFAULT_INDEX) - 1; - index->data = (u_char *) NGX_HTTP_DEFAULT_INDEX; - conf->max_index_len = sizeof(NGX_HTTP_DEFAULT_INDEX); - - return NGX_CONF_OK; - } - -#if 0 - - if (prev->max_index_len != 0) { - - prev_index = prev->indices.elts; - for (i = 0; i < prev->indices.nelts; i++) { - index = ngx_array_push(&conf->indices); - if (index == NULL) { - return NGX_CONF_ERROR; - } - - index->len = prev_index[i].len; - index->data = prev_index[i].data; - } - } - - if (conf->max_index_len < prev->max_index_len) { - conf->max_index_len = prev->max_index_len; - } - -#endif - - if (conf->index_cache == NULL) { - conf->index_cache = prev->index_cache; - } - - return NGX_CONF_OK; -} - - -/* TODO: warn about duplicate indices */ - -static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_http_index_loc_conf_t *ilcf = conf; - - ngx_uint_t i; - ngx_str_t *index, *value; - - value = cf->args->elts; - - if (value[1].data[0] == '/' && ilcf->indices.nelts == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "first index \"%V\" in \"%V\" directive " - "must not be absolute", - &value[1], &cmd->name); - return NGX_CONF_ERROR; - } - - for (i = 1; i < cf->args->nelts; i++) { - if (value[i].len == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "index \"%V\" in \"%V\" directive is invalid", - &value[1], &cmd->name); - return NGX_CONF_ERROR; - } - - index = ngx_array_push(&ilcf->indices); - if (index == NULL) { - return NGX_CONF_ERROR; - } - - index->len = value[i].len; - index->data = value[i].data; - - if (ilcf->max_index_len < index->len + 1) { - ilcf->max_index_len = index->len + 1; - } - } - - return NGX_CONF_OK; -} diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c --- a/src/http/modules/ngx_http_not_modified_filter_module.c +++ b/src/http/modules/ngx_http_not_modified_filter_module.c @@ -14,7 +14,8 @@ static ngx_int_t ngx_http_not_modified_f static ngx_http_module_t ngx_http_not_modified_filter_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -28,7 +29,7 @@ static ngx_http_module_t ngx_http_not_m ngx_module_t ngx_http_not_modified_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_not_modified_filter_module_ctx, /* module context */ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -45,6 +46,7 @@ static ngx_int_t ngx_http_not_modified_h time_t ims; if (r->headers_out.status != NGX_HTTP_OK + || r->main || r->headers_in.if_modified_since == NULL || r->headers_out.last_modified_time == -1) { @@ -63,12 +65,11 @@ static ngx_int_t ngx_http_not_modified_h if (ims != NGX_ERROR && ims == r->headers_out.last_modified_time) { r->headers_out.status = NGX_HTTP_NOT_MODIFIED; - r->headers_out.content_type->key.len = 0; - r->headers_out.content_type = NULL; + r->headers_out.content_type.len = 0; r->headers_out.content_length_n = -1; r->headers_out.content_length = NULL; #if 0 - r->headers_out.accept_ranges->key.len = 0; + r->headers_out.accept_ranges->hash = 0; #endif } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -10,89 +10,100 @@ #include -typedef struct { - ngx_http_upstream_conf_t upstream; +typedef struct ngx_http_proxy_redirect_s ngx_http_proxy_redirect_t; + +typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr); - ngx_peers_t *peers; +struct ngx_http_proxy_redirect_s { + ngx_http_proxy_redirect_pt handler; + ngx_str_t redirect; - ngx_array_t *headers_set_len; - ngx_array_t *headers_set; - ngx_hash_t *headers_set_hash; + union { + ngx_str_t text; + + struct { + void *lengths; + void *values; + } vars; - ngx_flag_t preserve_host; - ngx_flag_t set_x_url; - ngx_flag_t set_x_real_ip; - ngx_flag_t add_x_forwarded_for; - ngx_flag_t pass_server; - ngx_flag_t pass_x_accel_expires; + void *regex; + } replacement; +}; + + +typedef struct { + ngx_http_upstream_conf_t upstream; + + ngx_peers_t *peers; - ngx_str_t *location0; + ngx_array_t *headers_set_len; + ngx_array_t *headers_set; + ngx_hash_t *headers_set_hash; + + ngx_array_t *headers_source; + ngx_array_t *headers_names; - ngx_str_t host_header; - ngx_str_t uri0; + ngx_array_t *redirects; - ngx_array_t *headers_sources; - ngx_array_t *headers_names; + ngx_str_t host_header; + ngx_str_t port_text; + + ngx_flag_t redirect; } ngx_http_proxy_loc_conf_t; typedef struct { - ngx_list_t headers; - - ngx_table_elt_t *date; - ngx_table_elt_t *server; - - ngx_table_elt_t *expires; - ngx_table_elt_t *cache_control; - ngx_table_elt_t *etag; - ngx_table_elt_t *x_accel_expires; + ngx_uint_t status; + ngx_uint_t status_count; + u_char *status_start; + u_char *status_end; +} ngx_http_proxy_ctx_t; - ngx_table_elt_t *connection; - ngx_table_elt_t *content_type; - ngx_table_elt_t *content_length; - -#if (NGX_HTTP_GZIP) - ngx_table_elt_t *content_encoding; -#endif - - ngx_table_elt_t *last_modified; - ngx_table_elt_t *location; - ngx_table_elt_t *accept_ranges; - ngx_table_elt_t *x_pad; - off_t content_length_n; -} ngx_http_proxy_headers_in_t; +#define NGX_HTTP_PROXY_PARSE_NO_HEADER 20 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r); static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r); +static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r); +static ngx_int_t ngx_http_proxy_parse_status_line(ngx_http_request_t *r, + ngx_http_proxy_ctx_t *p); static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r); -static ngx_int_t ngx_http_proxy_send_header(ngx_http_request_t *r); static void ngx_http_proxy_abort_request(ngx_http_request_t *r); static void ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc); -static ngx_int_t ngx_http_proxy_compile_header_start(ngx_table_elt_t *h, - ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value); -static ngx_int_t ngx_http_proxy_compile_header_end(ngx_array_t *lengths, - ngx_array_t *values); +static ngx_http_variable_value_t * + ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data); +static ngx_http_variable_value_t * + ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data); +static ngx_http_variable_value_t * + ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, + uintptr_t data); +static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix); -static ngx_int_t ngx_http_proxy_init(ngx_cycle_t *cycle); -static ngx_http_variable_value_t *ngx_http_proxy_host_variable - (ngx_http_request_t *r, uintptr_t data); +static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf); static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); -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 = - { ngx_http_proxy_lowat_check }; + { ngx_http_proxy_lowat_check }; + +static ngx_conf_enum_t ngx_http_proxy_set_methods[] = { + { ngx_string("get"), NGX_HTTP_GET }, + { ngx_null_string, 0 } +}; static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, @@ -113,6 +124,13 @@ static ngx_command_t ngx_http_proxy_com 0, NULL }, + { ngx_string("proxy_redirect"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_proxy_redirect, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("proxy_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -134,6 +152,13 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat), &ngx_http_proxy_lowat_post }, + { ngx_string("proxy_redirect_errors"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.redirect_errors), + NULL }, + { ngx_string("proxy_pass_unparsed_uri"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -141,39 +166,32 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_unparsed_uri), NULL }, - { ngx_string("proxy_preserve_host"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, + { ngx_string("proxy_set_header"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_table_elt_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, preserve_host), + offsetof(ngx_http_proxy_loc_conf_t, headers_source), NULL }, - { ngx_string("proxy_set_x_url"), + { ngx_string("proxy_method"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.method), + ngx_http_proxy_set_methods }, + + { ngx_string("proxy_pass_request_headers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, set_x_url), + offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers), NULL }, - { ngx_string("proxy_set_x_real_ip"), + { ngx_string("proxy_pass_request_body"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - 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, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, add_x_forwarded_for), + offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body), NULL }, { ngx_string("proxy_header_buffer_size"), @@ -232,18 +250,25 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream), &ngx_http_proxy_next_upstream_masks }, + { ngx_string("proxy_pass_x_powered_by"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_x_powered_by), + NULL }, + { ngx_string("proxy_pass_server"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, pass_server), + offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_server), NULL }, { ngx_string("proxy_pass_x_accel_expires"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, pass_x_accel_expires), + offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_x_accel_expires), NULL }, ngx_null_command @@ -251,7 +276,8 @@ static ngx_command_t ngx_http_proxy_com ngx_http_module_t ngx_http_proxy_module_ctx = { - NULL, /* pre conf */ + ngx_http_proxy_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -265,25 +291,49 @@ ngx_http_module_t ngx_http_proxy_module ngx_module_t ngx_http_proxy_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_proxy_module_ctx, /* module context */ ngx_http_proxy_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ - ngx_http_proxy_init, /* init module */ + NULL, /* init module */ NULL /* init process */ }; static ngx_str_t ngx_http_proxy_methods[] = { - ngx_string("GET"), - ngx_string("HEAD"), - ngx_string("POST") + ngx_string("GET "), + ngx_string("HEAD "), + ngx_string("POST ") }; static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF; -static ngx_str_t ngx_http_proxy_host = ngx_string("PROXY_HOST"); + +static ngx_table_elt_t ngx_http_proxy_headers[] = { + { 0, ngx_string("Host"), ngx_string("$proxy_host"), }, + { 0, ngx_string("Connection"), ngx_string("close"), }, + { 0, ngx_null_string, ngx_null_string } +}; + + +static ngx_http_variable_t ngx_http_proxy_vars[] = { + + { ngx_string("proxy_host"), ngx_http_proxy_host_variable, 0, + NGX_HTTP_VAR_CHANGABLE }, + + { ngx_string("proxy_port"), ngx_http_proxy_port_variable, 0, + NGX_HTTP_VAR_CHANGABLE }, + + { ngx_string("proxy_add_x_forwarded_for"), + ngx_http_proxy_add_x_forwarded_for_variable, 0, 0 }, + +#if 0 + { ngx_string("proxy_add_via"), NULL, 0, 0 }, +#endif + + { ngx_null_string, NULL, 0, 0 } +}; #if (NGX_PCRE) @@ -291,45 +341,6 @@ static ngx_str_t ngx_http_proxy_uri = ng #endif -#if 0 - -ngx_http_header_t ngx_http_proxy_headers_in[] = { - { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) }, - { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) }, - - { ngx_string("Expires"), offsetof(ngx_http_proxy_headers_in_t, expires) }, - { ngx_string("Cache-Control"), - offsetof(ngx_http_proxy_headers_in_t, cache_control) }, - { ngx_string("ETag"), offsetof(ngx_http_proxy_headers_in_t, etag) }, - { ngx_string("X-Accel-Expires"), - offsetof(ngx_http_proxy_headers_in_t, x_accel_expires) }, - - { ngx_string("Connection"), - offsetof(ngx_http_proxy_headers_in_t, connection) }, - { ngx_string("Content-Type"), - offsetof(ngx_http_proxy_headers_in_t, content_type) }, - { ngx_string("Content-Length"), - offsetof(ngx_http_proxy_headers_in_t, content_length) }, - -#if (NGX_HTTP_GZIP) - { ngx_string("Content-Encoding"), - offsetof(ngx_http_proxy_headers_in_t, content_encoding) }, -#endif - - { ngx_string("Last-Modified"), - offsetof(ngx_http_proxy_headers_in_t, last_modified) }, - { ngx_string("Location"), - offsetof(ngx_http_proxy_headers_in_t, location) }, - { ngx_string("Accept-Ranges"), - offsetof(ngx_http_proxy_headers_in_t, accept_ranges) }, - { ngx_string("X-Pad"), offsetof(ngx_http_proxy_headers_in_t, x_pad) }, - - { ngx_null_string, 0 } -}; - -#endif - - static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r) { @@ -358,20 +369,17 @@ ngx_http_proxy_handler(ngx_http_request_ u->create_request = ngx_http_proxy_create_request; u->reinit_request = ngx_http_proxy_reinit_request; - u->process_header = ngx_http_proxy_process_header; - u->send_header = ngx_http_proxy_send_header; + u->process_header = ngx_http_proxy_process_status_line; u->abort_request = ngx_http_proxy_abort_request; u->finalize_request = ngx_http_proxy_finalize_request; + if (plcf->redirects) { + u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; + } + u->pipe.input_filter = ngx_event_pipe_copy_input_filter; - u->log_ctx = r->connection->log->data; - u->log_handler = ngx_http_upstream_log_error; - - u->schema0.len = sizeof("http://") - 1; - u->schema0.data = (u_char *) "http://"; - u->uri0 = plcf->uri0; - u->location0 = plcf->location0; + u->accel = 1; r->upstream = u; @@ -388,19 +396,19 @@ ngx_http_proxy_handler(ngx_http_request_ static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r) { - size_t len; - ngx_uint_t i, key; - uintptr_t escape; - ngx_buf_t *b; - ngx_str_t *hh; - ngx_chain_t *cl; - ngx_list_part_t *part; - ngx_table_elt_t *header; - ngx_http_upstream_t *u; - ngx_http_proxy_loc_conf_t *plcf; - ngx_http_script_code_pt code; - ngx_http_script_len_code_pt lcode; - ngx_http_script_lite_engine_t e; + size_t len, loc_len; + ngx_uint_t i, key; + uintptr_t escape; + ngx_buf_t *b; + ngx_str_t *hh; + ngx_chain_t *cl, *body; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_http_upstream_t *u; + ngx_http_script_code_pt code; + ngx_http_script_engine_t e, le; + ngx_http_proxy_loc_conf_t *plcf; + ngx_http_script_len_code_pt lcode; u = r->upstream; @@ -409,64 +417,72 @@ ngx_http_proxy_create_request(ngx_http_r len = sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1; if (u->method) { - len += ngx_http_proxy_methods[u->method - 1].len + u->uri0.len; + len += ngx_http_proxy_methods[u->method - 1].len + u->conf->uri.len; } else { - len += r->method_name.len + u->uri0.len; + len += r->method_name.len + 1 + u->conf->uri.len; } escape = 0; - + + loc_len = r->valid_location ? u->conf->location->len : 1; + if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) { len += r->unparsed_uri.len - 1; } else { if (r->quoted_uri) { - escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location0->len, - r->uri.len - u->location0->len, - NGX_ESCAPE_URI); + escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, + r->uri.len - loc_len, NGX_ESCAPE_URI); } - len += r->uri.len - u->location0->len + escape - + sizeof("?") - 1 + r->args.len; + len += r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len; } + ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); - e.ip = plcf->headers_set_len->elts; - e.request = r; + le.ip = plcf->headers_set_len->elts; + le.request = r; - while (*(uintptr_t *) e.ip) { - lcode = *(ngx_http_script_len_code_pt *) e.ip; - len += lcode(&e); + while (*(uintptr_t *) le.ip) { + while (*(uintptr_t *) le.ip) { + lcode = *(ngx_http_script_len_code_pt *) le.ip; + len += lcode(&le); + } + le.ip += sizeof(uintptr_t); } - part = &r->headers_in.headers.part; - header = part->elts; hh = (ngx_str_t *) plcf->headers_set_hash->buckets; - for (i = 0; /* void */; i++) { + if (plcf->upstream.pass_request_headers) { + part = &r->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { - if (i >= part->nelts) { - if (part->next == NULL) { - break; + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; } - part = part->next; - header = part->elts; - i = 0; - } - - key = header[i].hash % plcf->headers_set_hash->hash_size; + key = header[i].hash % plcf->headers_set_hash->hash_size; - if (hh[key].len == header[i].key.len - && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0) - { - continue; + if (hh[key].len == header[i].key.len + && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0) + { + continue; + } + + len += header[i].key.len + sizeof(": ") - 1 + + header[i].value.len + sizeof(CRLF) - 1; } + } - len += header[i].key.len + sizeof(": ") - 1 - + header[i].value.len + sizeof(CRLF) - 1; - } b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { @@ -479,9 +495,6 @@ ngx_http_proxy_create_request(ngx_http_r } cl->buf = b; - cl->next = NULL; - - r->request_body->bufs = cl; /* the request line */ @@ -491,23 +504,24 @@ ngx_http_proxy_create_request(ngx_http_r ngx_http_proxy_methods[u->method - 1].data, ngx_http_proxy_methods[u->method - 1].len); } else { - b->last = ngx_cpymem(b->last, r->method_name.data, r->method_name.len); + b->last = ngx_cpymem(b->last, r->method_name.data, + r->method_name.len + 1); } - b->last = ngx_cpymem(b->last, u->uri0.data, u->uri0.len); + b->last = ngx_cpymem(b->last, u->conf->uri.data, u->conf->uri.len); if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) { b->last = ngx_cpymem(b->last, r->unparsed_uri.data + 1, r->unparsed_uri.len - 1); } else { if (escape) { - ngx_escape_uri(b->last, r->uri.data + u->location0->len, - r->uri.len - u->location0->len, NGX_ESCAPE_URI); - b->last += r->uri.len - u->location0->len + escape; + ngx_escape_uri(b->last, r->uri.data + loc_len, + r->uri.len - loc_len, NGX_ESCAPE_URI); + b->last += r->uri.len - loc_len + escape; } else { - b->last = ngx_cpymem(b->last, r->uri.data + u->location0->len, - r->uri.len - u->location0->len); + b->last = ngx_cpymem(b->last, r->uri.data + loc_len, + r->uri.len - loc_len); } if (r->args.len > 0) { @@ -522,50 +536,76 @@ ngx_http_proxy_create_request(ngx_http_r e.ip = plcf->headers_set->elts; e.pos = b->last; + e.request = r; - while (*(uintptr_t *) e.ip) { - code = *(ngx_http_script_code_pt *) e.ip; - code((ngx_http_script_engine_t *) &e); + le.ip = plcf->headers_set_len->elts; + + while (*(uintptr_t *) le.ip) { + lcode = *(ngx_http_script_len_code_pt *) le.ip; + lcode(&le); + + if (*(ngx_http_script_len_code_pt *) le.ip) { + + for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { + lcode = *(ngx_http_script_len_code_pt *) le.ip; + } + + e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0; + + } else { + e.skip = 0; + } + + le.ip += sizeof(uintptr_t); + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } + e.ip += sizeof(uintptr_t); } b->last = e.pos; - part = &r->headers_in.headers.part; - header = part->elts; + if (plcf->upstream.pass_request_headers) { + part = &r->headers_in.headers.part; + header = part->elts; - for (i = 0; /* void */; i++) { + for (i = 0; /* void */; i++) { - if (i >= part->nelts) { - if (part->next == NULL) { - break; + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; } - part = part->next; - header = part->elts; - i = 0; - } + key = header[i].hash % plcf->headers_set_hash->hash_size; - key = header[i].hash % plcf->headers_set_hash->hash_size; + if (hh[key].len == header[i].key.len + && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0) + { + continue; + } - if (hh[key].len == header[i].key.len - && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0) - { - continue; - } + b->last = ngx_cpymem(b->last, header[i].key.data, + header[i].key.len); - 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 = 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\"", - &header[i].key, &header[i].value); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy header: \"%V: %V\"", + &header[i].key, &header[i].value); + } } /* add "\r\n" at the header end */ @@ -582,6 +622,36 @@ ngx_http_proxy_create_request(ngx_http_r } #endif + if (plcf->upstream.pass_request_body) { + + body = u->request_bufs; + u->request_bufs = cl; + + while (body) { + b = ngx_alloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); + + cl->next = ngx_alloc_chain_link(r->pool); + if (cl->next == NULL) { + return NGX_ERROR; + } + + cl = cl->next; + cl->buf = b; + + body = body->next; + } + + } else { + u->request_bufs = cl; + } + + cl->next = NULL; + return NGX_OK; } @@ -589,6 +659,286 @@ ngx_http_proxy_create_request(ngx_http_r static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r) { + ngx_http_proxy_ctx_t *p; + + p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (p == NULL) { + return NGX_OK; + } + + p->status = 0; + p->status_count = 0; + p->status_start = NULL; + p->status_end = NULL; + + r->upstream->process_header = ngx_http_proxy_process_status_line; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_proxy_process_status_line(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_upstream_t *u; + ngx_http_proxy_ctx_t *p; + + p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + if (p == NULL) { + p = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); + if (p == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_http_set_ctx(r, p, ngx_http_proxy_module); + } + + rc = ngx_http_proxy_parse_status_line(r, p); + + if (rc == NGX_AGAIN) { + return rc; + } + + u = r->upstream; + + if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent no valid HTTP/1.0 header"); + + if (u->accel) { + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + r->http_version = NGX_HTTP_VERSION_9; + p->status = NGX_HTTP_OK; + + return NGX_OK; + } + + r->headers_out.status = p->status; + u->state->status = p->status; + + r->headers_out.status_line.len = p->status_end - p->status_start; + r->headers_out.status_line.data = ngx_palloc(r->pool, + r->headers_out.status_line.len); + if (r->headers_out.status_line.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + ngx_memcpy(r->headers_out.status_line.data, p->status_start, + r->headers_out.status_line.len); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy status %ui \"%V\"", + r->headers_out.status, &r->headers_out.status_line); + + u->process_header = ngx_http_proxy_process_header; + + return ngx_http_proxy_process_header(r); +} + + +static ngx_int_t +ngx_http_proxy_parse_status_line(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p) +{ + u_char ch; + u_char *pos; + ngx_http_upstream_t *u; + enum { + sw_start = 0, + sw_H, + sw_HT, + sw_HTT, + sw_HTTP, + sw_first_major_digit, + sw_major_digit, + sw_first_minor_digit, + sw_minor_digit, + sw_status, + sw_space_after_status, + sw_status_text, + sw_almost_done + } state; + + u = r->upstream; + + state = r->state; + + for (pos = u->header_in.pos; pos < u->header_in.last; pos++) { + ch = *pos; + + switch (state) { + + /* "HTTP/" */ + case sw_start: + switch (ch) { + case 'H': + state = sw_H; + break; + default: + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + break; + + case sw_H: + switch (ch) { + case 'T': + state = sw_HT; + break; + default: + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + break; + + case sw_HT: + switch (ch) { + case 'T': + state = sw_HTT; + break; + default: + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + break; + + case sw_HTT: + switch (ch) { + case 'P': + state = sw_HTTP; + break; + default: + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + break; + + case sw_HTTP: + switch (ch) { + case '/': + state = sw_first_major_digit; + break; + default: + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + break; + + /* the first digit of major HTTP version */ + case sw_first_major_digit: + if (ch < '1' || ch > '9') { + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + + state = sw_major_digit; + break; + + /* the major HTTP version or dot */ + case sw_major_digit: + if (ch == '.') { + state = sw_first_minor_digit; + break; + } + + if (ch < '0' || ch > '9') { + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + + break; + + /* the first digit of minor HTTP version */ + case sw_first_minor_digit: + if (ch < '0' || ch > '9') { + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + + state = sw_minor_digit; + break; + + /* the minor HTTP version or the end of the request line */ + case sw_minor_digit: + if (ch == ' ') { + state = sw_status; + break; + } + + if (ch < '0' || ch > '9') { + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + + break; + + /* HTTP status code */ + case sw_status: + if (ch < '0' || ch > '9') { + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + + p->status = p->status * 10 + ch - '0'; + + if (++p->status_count == 3) { + state = sw_space_after_status; + p->status_start = pos - 2; + } + + break; + + /* space or end of line */ + case sw_space_after_status: + switch (ch) { + case ' ': + state = sw_status_text; + break; + case '.': /* IIS may send 403.1, 403.2, etc */ + state = sw_status_text; + break; + case CR: + state = sw_almost_done; + break; + case LF: + goto done; + default: + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + break; + + /* any text until end of line */ + case sw_status_text: + switch (ch) { + case CR: + state = sw_almost_done; + + break; + case LF: + goto done; + } + break; + + /* end of request line */ + case sw_almost_done: + p->status_end = pos - 1; + switch (ch) { + case LF: + goto done; + default: + return NGX_HTTP_PROXY_PARSE_NO_HEADER; + } + } + } + + u->header_in.pos = pos + 1; + r->state = state; + + return NGX_AGAIN; + +done: + + u->header_in.pos = pos + 1; + + if (p->status_end == NULL) { + p->status_end = pos; + } + + r->state = sw_start; + return NGX_OK; } @@ -596,14 +946,79 @@ ngx_http_proxy_reinit_request(ngx_http_r static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r) { - return NGX_OK; -} + ngx_int_t rc; + ngx_uint_t key; + ngx_table_elt_t *h; + ngx_http_upstream_header_t *hh; + ngx_http_upstream_main_conf_t *umcf; + + umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + hh = (ngx_http_upstream_header_t *) umcf->headers_in_hash.buckets; + + for ( ;; ) { + + rc = ngx_http_parse_header_line(r, &r->upstream->header_in); + + if (rc == NGX_OK) { + + /* a header line has been parsed successfully */ + h = ngx_list_push(&r->upstream->headers_in.headers); + if (h == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + h->hash = r->header_hash; + + h->key.len = r->header_name_end - r->header_name_start; + h->value.len = r->header_end - r->header_start; + + h->key.data = ngx_palloc(r->pool, + h->key.len + 1 + h->value.len + 1); + if (h->key.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + h->value.data = h->key.data + h->key.len + 1; -static ngx_int_t -ngx_http_proxy_send_header(ngx_http_request_t *r) -{ - return NGX_OK; + ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); + ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); + + key = h->hash % umcf->headers_in_hash.hash_size; + + if (hh[key].name.len == h->key.len + && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0) + { + if (hh[key].handler(r, h, hh[key].offset) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy header: \"%V: %V\"", + &h->key, &h->value); + + continue; + } + + if (rc == NGX_HTTP_PARSE_HEADER_DONE) { + + /* a whole header has been parsed successfully */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy header done"); + + return NGX_OK; + } + + /* there was error while a header line parsing */ + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_http_upstream_header_errors[rc + - NGX_HTTP_PARSE_HEADER_ERROR]); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } } @@ -627,57 +1042,222 @@ ngx_http_proxy_finalize_request(ngx_http } -static ngx_int_t -ngx_http_proxy_init(ngx_cycle_t *cycle) +static ngx_http_variable_value_t * +ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data) { -#if 0 - ngx_http_variable_t *var; + ngx_http_variable_value_t *vv; + ngx_http_proxy_loc_conf_t *plcf; - var = ngx_http_add_variable(cf, &ngx_http_proxy_host, 1); - if (var == NULL) { - return NGX_ERROR; + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { + return NULL; } - var->handler = ngx_http_proxy_host_variable; -#endif - - return NGX_OK; - -#if 0 - ngx_http_log_op_name_t *op; + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - for (op = ngx_http_proxy_log_fmt_ops; op->name.len; op++) { /* void */ } - op->run = NULL; + vv->value = 0; + vv->text = plcf->host_header; - for (op = ngx_http_log_fmt_ops; op->run; op++) { - if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->run; - } - } - - op->run = (ngx_http_log_op_run_pt) ngx_http_proxy_log_fmt_ops; - -#endif + return vv; } static ngx_http_variable_value_t * -ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data) +ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data) { - ngx_http_variable_value_t *var; + ngx_http_variable_value_t *vv; ngx_http_proxy_loc_conf_t *plcf; - var = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (var == NULL) { + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { return NULL; } plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - var->value = 0; - var->text = plcf->host_header; + vv->value = 0; + vv->text = plcf->port_text; + + return vv; +} + + +static ngx_http_variable_value_t * +ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, + uintptr_t data) +{ + u_char *p; + ngx_http_variable_value_t *vv; + + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { + return NULL; + } + + vv->value = 0; + + if (r->headers_in.x_forwarded_for == NULL) { + vv->text = r->connection->addr_text; + return vv; + } + + vv->text.len = r->headers_in.x_forwarded_for->value.len + + sizeof(", ") - 1 + r->connection->addr_text.len; + + p = ngx_palloc(r->pool, vv->text.len); + if (p == NULL) { + return NULL; + } + + vv->text.data = p; + + p = ngx_cpymem(p, r->headers_in.x_forwarded_for->value.data, + r->headers_in.x_forwarded_for->value.len); + + *p++ = ','; *p++ = ' '; + + ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len); + + return vv; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, + size_t prefix) +{ + ngx_int_t rc; + ngx_uint_t i; + ngx_http_proxy_loc_conf_t *plcf; + ngx_http_proxy_redirect_t *pr; + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + pr = plcf->redirects->elts; + + if (pr == NULL) { + return NGX_DECLINED; + } + + for (i = 0; i < plcf->redirects->nelts; i++) { + rc = pr->handler(r, h, prefix, pr); + + if (rc != NGX_DECLINED) { + return rc; + } + } + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h, + size_t prefix, ngx_http_proxy_redirect_t *pr) +{ + size_t len; + u_char *data, *p; + + if (pr->redirect.len > h->value.len - prefix + || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data, + pr->redirect.len) != 0) + { + return NGX_DECLINED; + } + + len = prefix + pr->replacement.text.len + h->value.len - pr->redirect.len; - return var; + data = ngx_palloc(r->pool, len); + if (data == NULL) { + return NGX_ERROR; + } + + p = data; + + if (prefix) { + p = ngx_cpymem(p, h->value.data, prefix); + } + + p = ngx_cpymem(p, pr->replacement.text.data, pr->replacement.text.len); + + ngx_memcpy(p, h->value.data + prefix + pr->redirect.len, + h->value.len - pr->redirect.len - prefix); + + h->value.len = len; + h->value.data = data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t *r, ngx_table_elt_t *h, + size_t prefix, ngx_http_proxy_redirect_t *pr) +{ + size_t len; + u_char *data, *p; + ngx_http_script_code_pt code; + ngx_http_script_engine_t e; + ngx_http_script_len_code_pt lcode; + + if (pr->redirect.len > h->value.len - prefix + || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data, + pr->redirect.len) != 0) + { + return NGX_DECLINED; + } + + ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); + + e.ip = pr->replacement.vars.lengths; + e.request = r; + + for (len = prefix; *(uintptr_t *) e.ip; len += lcode(&e)) { + lcode = *(ngx_http_script_len_code_pt *) e.ip; + } + + data = ngx_palloc(r->pool, len); + if (data == NULL) { + return NGX_ERROR; + } + + p = data; + + if (prefix) { + p = ngx_cpymem(p, h->value.data, prefix); + } + + e.ip = pr->replacement.vars.values; + e.pos = p; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code(&e); + } + + h->value.len = len; + h->value.data = data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_proxy_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_proxy_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->handler = v->handler; + var->data = v->data; + } + + return NGX_OK; } @@ -698,6 +1278,15 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ * conf->upstream.path = NULL; * conf->upstream.next_upstream = 0; * conf->upstream.temp_path = NULL; + * conf->upstream.schema = { 0, NULL }; + * conf->upstream.uri = { 0, NULL }; + * conf->upstream.location = NULL; + * + * conf->headers_source = NULL; + * conf->headers_set_len = NULL; + * conf->headers_set = NULL; + * conf->headers_set_hash = NULL; + * conf->rewrite_locations = NULL; */ conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; @@ -709,21 +1298,23 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE; conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE; + + conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET; + conf->upstream.method = NGX_CONF_UNSET_UINT; + conf->upstream.pass_request_headers = NGX_CONF_UNSET; + conf->upstream.pass_request_body = NGX_CONF_UNSET; conf->upstream.redirect_errors = NGX_CONF_UNSET; - conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET; - conf->upstream.x_powered_by = NGX_CONF_UNSET; /* "proxy_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; - conf->preserve_host = NGX_CONF_UNSET; - conf->set_x_url = NGX_CONF_UNSET; - conf->set_x_real_ip = NGX_CONF_UNSET; - conf->add_x_forwarded_for = NGX_CONF_UNSET; + conf->upstream.pass_x_powered_by = NGX_CONF_UNSET; + conf->upstream.pass_server = NGX_CONF_UNSET; + conf->upstream.pass_date = 0; + conf->upstream.pass_x_accel_expires = NGX_CONF_UNSET; - conf->pass_server = NGX_CONF_UNSET; - conf->pass_x_accel_expires = NGX_CONF_UNSET; + conf->redirect = NGX_CONF_UNSET; return conf; } @@ -735,11 +1326,16 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t ngx_http_proxy_loc_conf_t *prev = parent; ngx_http_proxy_loc_conf_t *conf = child; - size_t size; - ngx_str_t *name; - ngx_table_elt_t *src; - ngx_http_variable_t *var; - + u_char *p; + size_t size; + uintptr_t *code; + ngx_str_t *name; + ngx_uint_t i; + ngx_table_elt_t *src, *s, *h; + ngx_http_proxy_redirect_t *pr; + ngx_http_script_compile_t sc; + ngx_http_script_copy_code_t *copy; + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -841,241 +1437,297 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t |NGX_HTTP_UPSTREAM_FT_ERROR |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); - ngx_conf_merge_msec_value(conf->upstream.redirect_errors, - prev->upstream.redirect_errors, 0); + ngx_conf_merge_path_value(conf->upstream.temp_path, + prev->upstream.temp_path, + NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0, + ngx_garbage_collector_temp_handler, cf); ngx_conf_merge_msec_value(conf->upstream.pass_unparsed_uri, prev->upstream.pass_unparsed_uri, 0); - if (conf->upstream.pass_unparsed_uri && conf->location0->len > 1) { + if (conf->upstream.pass_unparsed_uri && conf->upstream.location->len > 1) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "\"proxy_pass_unparsed_uri\" can be set for " "location \"/\" or given by regular expression."); return NGX_CONF_ERROR; } - ngx_conf_merge_msec_value(conf->upstream.x_powered_by, - prev->upstream.x_powered_by, 1); + if (conf->upstream.method == NGX_CONF_UNSET_UINT) { + conf->upstream.method = prev->upstream.method; + } + + ngx_conf_merge_value(conf->upstream.pass_request_headers, + prev->upstream.pass_request_headers, 1); + ngx_conf_merge_value(conf->upstream.pass_request_body, + prev->upstream.pass_request_body, 1); + + ngx_conf_merge_msec_value(conf->upstream.redirect_errors, + prev->upstream.redirect_errors, 0); + + ngx_conf_merge_msec_value(conf->upstream.pass_x_powered_by, + prev->upstream.pass_x_powered_by, 1); + ngx_conf_merge_msec_value(conf->upstream.pass_server, + prev->upstream.pass_server, 0); + ngx_conf_merge_msec_value(conf->upstream.pass_x_accel_expires, + prev->upstream.pass_x_accel_expires, 0); + + + ngx_conf_merge_value(conf->redirect, prev->redirect, 1); + + if (conf->redirect) { - ngx_conf_merge_value(conf->preserve_host, prev->preserve_host, 0); - ngx_conf_merge_value(conf->set_x_url, prev->set_x_url, 0); - ngx_conf_merge_value(conf->set_x_real_ip, prev->set_x_real_ip, 0); - ngx_conf_merge_value(conf->add_x_forwarded_for, - prev->add_x_forwarded_for, 0); + if (conf->redirects == NULL) { + conf->redirects = prev->redirects; + } + + if (conf->redirects == NULL && conf->upstream.url.data) { + + conf->redirects = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_proxy_redirect_t)); + if (conf->redirects == NULL) { + return NGX_CONF_ERROR; + } + + pr = ngx_array_push(conf->redirects); + if (pr == NULL) { + return NGX_CONF_ERROR; + } + + pr->handler = ngx_http_proxy_rewrite_redirect_text; + pr->redirect = conf->upstream.url; + pr->replacement.text = *conf->upstream.location; + } + } + if (conf->peers == NULL) { conf->peers = prev->peers; conf->upstream = prev->upstream; } - if (conf->headers_set_hash == NULL) { + if (conf->headers_source == NULL) { + conf->headers_source = prev->headers_source; conf->headers_set_len = prev->headers_set_len; conf->headers_set = prev->headers_set; conf->headers_set_hash = prev->headers_set_hash; } - if (conf->headers_set_hash == NULL) { + if (conf->headers_set_hash) { + return NGX_CONF_OK; + } + + + conf->headers_names = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t)); + if (conf->headers_names == NULL) { + return NGX_CONF_ERROR; + } + + if (conf->headers_source == NULL) { + conf->headers_source = ngx_array_create(cf->pool, 4, + sizeof(ngx_table_elt_t)); + if (conf->headers_source == NULL) { + return NGX_CONF_ERROR; + } + } - if (conf->headers_names == NULL) { - conf->headers_names = ngx_array_create(cf->pool, 4, - sizeof(ngx_str_t)); - if (conf->headers_names == NULL) { - return NGX_CONF_ERROR; + conf->headers_set_len = ngx_array_create(cf->pool, 64, 1); + if (conf->headers_set_len == NULL) { + return NGX_CONF_ERROR; + } + + conf->headers_set = ngx_array_create(cf->pool, 512, 1); + if (conf->headers_set == NULL) { + return NGX_CONF_ERROR; + } + + + src = conf->headers_source->elts; + + for (h = ngx_http_proxy_headers; h->key.len; h++) { + + for (i = 0; i < conf->headers_source->nelts; i++) { + if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { + goto next; } } - if (conf->headers_sources == NULL) { - conf->headers_sources = ngx_array_create(cf->pool, 4, - sizeof(ngx_table_elt_t)); - if (conf->headers_sources == NULL) { - return NGX_CONF_ERROR; - } - } - - /* STUB */ - var = ngx_http_add_variable(cf, &ngx_http_proxy_host, 0); - if (var == NULL) { - return NGX_CONF_ERROR; - } - - var->handler = ngx_http_proxy_host_variable; - /**/ - - - name = ngx_array_push(conf->headers_names); - if (name == NULL) { + s = ngx_array_push(conf->headers_source); + if (s == NULL) { return NGX_CONF_ERROR; } - name->len = sizeof("Host") - 1; - name->data = (u_char *) "Host"; + *s = *h; - src = ngx_array_push(conf->headers_sources); - if (src == NULL) { - return NGX_CONF_ERROR; - } - - src->hash = 0; - src->key.len = sizeof("Host") - 1; - src->key.data = (u_char *) "Host"; - src->value.len = sizeof("$PROXY_HOST") - 1; - src->value.data = (u_char *) "$PROXY_HOST"; - + next: - name = ngx_array_push(conf->headers_names); - if (name == NULL) { - return NGX_CONF_ERROR; - } - - name->len = sizeof("Connection") - 1; - name->data = (u_char *) "Connection"; + continue; + } - src = ngx_array_push(conf->headers_sources); - if (src == NULL) { - return NGX_CONF_ERROR; - } - - src->hash = 0; - src->key.len = sizeof("Connection") - 1; - src->key.data = (u_char *) "Connection"; - src->value.len = sizeof("close") - 1; - src->value.data = (u_char *) "close"; - + for (i = 0; i < conf->headers_source->nelts; i++) { name = ngx_array_push(conf->headers_names); if (name == NULL) { return NGX_CONF_ERROR; } - name->len = 0; - name->data = NULL; + *name = src[i].key; + + if (ngx_http_script_variables_count(&src[i].value) == 0) { + copy = ngx_array_push_n(conf->headers_set_len, + sizeof(ngx_http_script_copy_code_t)); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = (ngx_http_script_code_pt) + ngx_http_script_copy_len_code; + copy->len = src[i].key.len + sizeof(": ") - 1 + + src[i].value.len + sizeof(CRLF) - 1; - if (ngx_http_script_compile_lite(cf, conf->headers_sources, - &conf->headers_set_len, &conf->headers_set, - ngx_http_proxy_compile_header_start, - ngx_http_proxy_compile_header_end) != NGX_OK) - { - return NGX_CONF_ERROR; - } + size = (sizeof(ngx_http_script_copy_code_t) + + src[i].key.len + sizeof(": ") - 1 + + src[i].value.len + sizeof(CRLF) - 1 + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + copy = ngx_array_push_n(conf->headers_set, size); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = ngx_http_script_copy_code; + copy->len = src[i].key.len + sizeof(": ") - 1 + + src[i].value.len + sizeof(CRLF) - 1; + + p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + + p = ngx_cpymem(p, src[i].key.data, src[i].key.len); + *p++ = ':'; *p++ = ' '; + p = ngx_cpymem(p, src[i].value.data, src[i].value.len); + *p++ = CR; *p = LF; + + } else { + copy = ngx_array_push_n(conf->headers_set_len, + sizeof(ngx_http_script_copy_code_t)); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = (ngx_http_script_code_pt) + ngx_http_script_copy_len_code; + copy->len = src[i].key.len + sizeof(": ") - 1; - conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash_t)); - if (conf->headers_set_hash == NULL) { - return NGX_CONF_ERROR; + size = (sizeof(ngx_http_script_copy_code_t) + + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + copy = ngx_array_push_n(conf->headers_set, size); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = ngx_http_script_copy_code; + copy->len = src[i].key.len + sizeof(": ") - 1; + + p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + p = ngx_cpymem(p, src[i].key.data, src[i].key.len); + *p++ = ':'; *p = ' '; + + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &src[i].value; + sc.lengths = &conf->headers_set_len; + sc.values = &conf->headers_set; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + + copy = ngx_array_push_n(conf->headers_set_len, + sizeof(ngx_http_script_copy_code_t)); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = (ngx_http_script_code_pt) + ngx_http_script_copy_len_code; + copy->len = sizeof(CRLF) - 1; + + + size = (sizeof(ngx_http_script_copy_code_t) + + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + copy = ngx_array_push_n(conf->headers_set, size); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = ngx_http_script_copy_code; + copy->len = sizeof(CRLF) - 1; + + p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + *p++ = CR; *p = LF; } - conf->headers_set_hash->max_size = 100; - conf->headers_set_hash->bucket_limit = 1; - conf->headers_set_hash->bucket_size = sizeof(ngx_str_t); - conf->headers_set_hash->name = "proxy_headers"; - - if (ngx_hash_init(conf->headers_set_hash, cf->pool, - conf->headers_names->elts) != NGX_OK) - { + code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); + if (code == NULL) { return NGX_CONF_ERROR; } -#if 0 - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, -#endif - ngx_log_error(NGX_LOG_NOTICE, cf->log, 0, - "proxy_headers hash size: %ui, " - "max buckets per entry: %ui", - conf->headers_set_hash->hash_size, - conf->headers_set_hash->min_buckets); + *code = (uintptr_t) NULL; + + code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_CONF_ERROR; + } + + *code = (uintptr_t) NULL; } - return NGX_CONF_OK; -} - - -static ngx_int_t -ngx_http_proxy_compile_header_start(ngx_table_elt_t *h, - ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value) -{ - u_char *p; - size_t size; - ngx_http_script_copy_code_t *copy; - - copy = ngx_array_push_n(lengths, sizeof(ngx_http_script_copy_code_t)); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len; - copy->len = h->key.len + sizeof(": ") - 1; - - if (value) { - copy->len += h->value.len + sizeof(CRLF) - 1; - } - - size = (copy->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); - - copy = ngx_array_push_n(values, - sizeof(ngx_http_script_copy_code_t) + size); - if (copy == NULL) { - return NGX_ERROR; + code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_CONF_ERROR; } - copy->code = ngx_http_script_copy; - copy->len = h->key.len + sizeof(": ") - 1; - - if (value) { - copy->len += h->value.len + sizeof(CRLF) - 1; - } - - p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); - - p = ngx_cpymem(p, h->key.data, h->key.len); - p = ngx_cpymem(p, ": ", sizeof(": ") - 1); - - if (value) { - p = ngx_cpymem(p, h->value.data, h->value.len); - ngx_memcpy(p, CRLF, sizeof(CRLF) - 1); - } - - return NGX_OK; -} + *code = (uintptr_t) NULL; -static ngx_int_t -ngx_http_proxy_compile_header_end(ngx_array_t *lengths, ngx_array_t *values) -{ - size_t size; - ngx_http_script_copy_code_t *copy; - - copy = ngx_array_push_n(lengths, sizeof(ngx_http_script_copy_code_t)); - if (copy == NULL) { - return NGX_ERROR; + conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash_t)); + if (conf->headers_set_hash == NULL) { + return NGX_CONF_ERROR; } - copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len; - copy->len = sizeof(CRLF) - 1; + conf->headers_set_hash->max_size = 100; + conf->headers_set_hash->bucket_limit = 1; + conf->headers_set_hash->bucket_size = sizeof(ngx_str_t); + conf->headers_set_hash->name = "proxy_headers"; - size = (sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - copy = ngx_array_push_n(values, - sizeof(ngx_http_script_copy_code_t) + size); - if (copy == NULL) { - return NGX_ERROR; + if (ngx_hash_init(conf->headers_set_hash, cf->pool, + conf->headers_names->elts, conf->headers_names->nelts) != NGX_OK) + { + return NGX_CONF_ERROR; } - copy->code = ngx_http_script_copy; - copy->len = sizeof(CRLF) - 1; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "proxy_headers hash size: %ui, " + "max buckets per entry: %ui", + conf->headers_set_hash->hash_size, + conf->headers_set_hash->min_buckets); - ngx_memcpy((u_char *) copy + sizeof(ngx_http_script_copy_code_t), - CRLF, sizeof(CRLF) - 1); - - return NGX_OK; + return NGX_CONF_OK; } static char * ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_proxy_loc_conf_t *lcf = conf; + ngx_http_proxy_loc_conf_t *plcf = conf; ngx_uint_t i; ngx_str_t *value, *url; @@ -1105,20 +1757,16 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ unix_upstream.url.data = url->data + 7; unix_upstream.uri_part = 1; - lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); - if (lcf->peers == NULL) { + plcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); + if (plcf->peers == NULL) { return NGX_CONF_ERROR; } - lcf->peers->peer[0].uri_separator = ":"; + plcf->peers->peer[0].uri_separator = ":"; - lcf->host_header.len = sizeof("localhost") - 1; - lcf->host_header.data = (u_char *) "localhost"; - lcf->uri0 = unix_upstream.uri; -#if 0 - STUB - lcf->upstream->default_port = 1; -#endif + plcf->host_header.len = sizeof("localhost") - 1; + plcf->host_header.data = (u_char *) "localhost"; + plcf->upstream.uri = unix_upstream.uri; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -1137,34 +1785,35 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ inet_upstream.default_port_value = 80; inet_upstream.uri_part = 1; - lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); - if (lcf->peers == NULL) { + plcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); + if (plcf->peers == NULL) { return NGX_CONF_ERROR; } - for (i = 0; i < lcf->peers->number; i++) { - lcf->peers->peer[i].uri_separator = ":"; + for (i = 0; i < plcf->peers->number; i++) { + plcf->peers->peer[i].uri_separator = ":"; } - lcf->host_header = inet_upstream.host_header; - lcf->uri0 = inet_upstream.uri; -#if 0 - STUB - lcf->port_text = inet_upstream.port_text; - lcf->upstream->default_port = inet_upstream.default_port; -#endif + plcf->host_header = inet_upstream.host_header; + plcf->port_text = inet_upstream.port_text; + plcf->upstream.uri = inet_upstream.uri; } + plcf->upstream.schema.len = sizeof("http://") - 1; + plcf->upstream.schema.data = (u_char *) "http://"; + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf->handler = ngx_http_proxy_handler; #if (NGX_PCRE) - lcf->location0 = clcf->regex ? &ngx_http_proxy_uri : &clcf->name; + plcf->upstream.location = clcf->regex ? &ngx_http_proxy_uri : &clcf->name; #else - lcf->location0 = &clcf->name; + plcf->upstream.location = &clcf->name; #endif + plcf->upstream.url = *url; + if (clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; } @@ -1174,8 +1823,84 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ static char * -ngx_http_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_proxy_loc_conf_t *plcf = conf; + + ngx_str_t *value; + ngx_array_t *vars_lengths, *vars_values; + ngx_http_script_compile_t sc; + ngx_http_proxy_redirect_t *pr; + + if (plcf->redirect == 0) { + return NGX_CONF_OK; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + plcf->redirect = 0; + plcf->redirects = NULL; + return NGX_CONF_OK; + } + + if (plcf->redirects == NULL) { + plcf->redirects = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_proxy_redirect_t)); + if (plcf->redirects == NULL) { + return NGX_CONF_ERROR; + } + } + + pr = ngx_array_push(plcf->redirects); + if (pr == NULL) { + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "default") == 0) { + if (plcf->upstream.url.data == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_rewrite_location default\" must go " + "after the \"proxy_pass\" directive"); + return NGX_CONF_ERROR; + } + + pr->handler = ngx_http_proxy_rewrite_redirect_text; + pr->redirect = plcf->upstream.url; + pr->replacement.text = *plcf->upstream.location; + + return NGX_CONF_OK; + } + + if (ngx_http_script_variables_count(&value[2]) == 0) { + pr->handler = ngx_http_proxy_rewrite_redirect_text; + pr->redirect = value[1]; + pr->replacement.text = value[2]; + + return NGX_CONF_OK; + } + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + vars_lengths = NULL; + vars_values = NULL; + + sc.cf = cf; + sc.source = &value[2]; + sc.lengths = &vars_lengths; + sc.values = &vars_values; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + pr->handler = ngx_http_proxy_rewrite_redirect_vars; + pr->redirect = value[1]; + pr->replacement.vars.lengths = vars_lengths->elts; + pr->replacement.vars.values = vars_values->elts; + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -54,7 +54,8 @@ static ngx_int_t ngx_http_range_body_fil static ngx_http_module_t ngx_http_range_header_filter_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -68,7 +69,7 @@ static ngx_http_module_t ngx_http_range ngx_module_t ngx_http_range_header_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_range_header_filter_module_ctx, /* module context */ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -78,7 +79,8 @@ ngx_module_t ngx_http_range_header_filt static ngx_http_module_t ngx_http_range_body_filter_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -92,7 +94,7 @@ static ngx_http_module_t ngx_http_range ngx_module_t ngx_http_range_body_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_range_body_filter_module_ctx, /* module context */ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -120,6 +122,7 @@ ngx_http_range_header_filter(ngx_http_re if (r->http_version < NGX_HTTP_VERSION_10 || r->headers_out.status != NGX_HTTP_OK + || r->main || r->headers_out.content_length_n == -1 || !r->filter_allow_ranges) { @@ -136,6 +139,7 @@ ngx_http_range_header_filter(ngx_http_re return NGX_ERROR; } + r->headers_out.accept_ranges->hash = 1; r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; @@ -269,6 +273,7 @@ ngx_http_range_header_filter(ngx_http_re r->headers_out.content_range = content_range; + content_range->hash = 1; content_range->key.len = sizeof("Content-Range") - 1; content_range->key.data = (u_char *) "Content-Range"; @@ -303,6 +308,7 @@ ngx_http_range_header_filter(ngx_http_re r->headers_out.content_range = content_range; + content_range->hash = 1; content_range->key.len = sizeof("Content-Range") - 1; content_range->key.data = (u_char *) "Content-Range"; @@ -338,7 +344,7 @@ ngx_http_range_header_filter(ngx_http_re len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof(CRLF "Content-Type: ") - 1 - + r->headers_out.content_type->value.len + + r->headers_out.content_type.len + sizeof(CRLF "Content-Range: bytes ") - 1; if (r->headers_out.charset.len) { @@ -366,7 +372,7 @@ ngx_http_range_header_filter(ngx_http_re "Content-Type: %V; charset=%V" CRLF "Content-Range: bytes ", boundary, - &r->headers_out.content_type->value, + &r->headers_out.content_type, &r->headers_out.charset) - ctx->boundary_header.data; @@ -378,26 +384,26 @@ ngx_http_range_header_filter(ngx_http_re "Content-Type: %V" CRLF "Content-Range: bytes ", boundary, - &r->headers_out.content_type->value) + &r->headers_out.content_type) - ctx->boundary_header.data; } - r->headers_out.content_type->value.data = - ngx_palloc(r->pool, - sizeof("Content-Type: multipart/byteranges; boundary=") - 1 - + NGX_ATOMIC_T_LEN); + r->headers_out.content_type.data = + ngx_palloc(r->pool, + sizeof("Content-Type: multipart/byteranges; boundary=") - 1 + + NGX_ATOMIC_T_LEN); - if (r->headers_out.content_type->value.data == NULL) { + if (r->headers_out.content_type.data == NULL) { return NGX_ERROR; } /* "Content-Type: multipart/byteranges; boundary=0123456789" */ - r->headers_out.content_type->value.len = - ngx_sprintf(r->headers_out.content_type->value.data, + r->headers_out.content_type.len = + ngx_sprintf(r->headers_out.content_type.data, "multipart/byteranges; boundary=%0muA", boundary) - - r->headers_out.content_type->value.data; + - r->headers_out.content_type.data; /* the size of the last boundary CRLF "--0123456789--" CRLF */ diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -9,136 +9,36 @@ #include -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_str_t name; - ngx_uint_t wildcard; + ngx_str_t name; + ngx_uint_t wildcard; } ngx_http_rewrite_referer_t; typedef struct { - ngx_str_t *name; - ngx_http_variable_value_t *value; + ngx_str_t *name; + ngx_http_variable_value_t *value; } ngx_http_rewrite_variable_t; typedef struct { - ngx_array_t *codes; /* uintptr_t */ - ngx_array_t *referers; /* ngx_http_rewrite_referer_t */ + ngx_array_t *codes; /* uintptr_t */ + ngx_array_t *referers; /* ngx_http_rewrite_referer_t */ - ngx_uint_t max_captures; - ngx_uint_t stack_size; + ngx_uint_t max_captures; + ngx_uint_t stack_size; - ngx_flag_t log; + ngx_flag_t log; - ngx_flag_t no_referer; - ngx_flag_t blocked_referer; + ngx_flag_t no_referer; + ngx_flag_t blocked_referer; } ngx_http_rewrite_loc_conf_t; -typedef struct { - ngx_http_rewrite_code_pt code; - ngx_regex_t *regex; - uintptr_t size; - uintptr_t ncaptures; - uintptr_t status; - uintptr_t next; - - uintptr_t test:1; - uintptr_t uri:1; - - /* add the r->args to the new arguments */ - uintptr_t args:1; - - uintptr_t redirect:1; - uintptr_t break_cycle:1; - - ngx_str_t name; -} ngx_http_rewrite_regex_code_t; - - -typedef struct { - ngx_http_rewrite_code_pt code; - - uintptr_t uri:1; - - /* 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; - - -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 value; - uintptr_t text_len; - uintptr_t text_data; -} ngx_http_rewrite_value_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; - ngx_http_variable_value_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 ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle); 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); @@ -150,12 +50,8 @@ static char *ngx_http_rewrite_variable(n ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value); static char *ngx_http_rewrite_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static char * ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, +static char *ngx_http_rewrite_set(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, - void *code); static ngx_command_t ngx_http_rewrite_commands[] = { @@ -211,7 +107,8 @@ static ngx_command_t ngx_http_rewrite_c ngx_http_module_t ngx_http_rewrite_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -225,7 +122,7 @@ ngx_http_module_t ngx_http_rewrite_modu ngx_module_t ngx_http_rewrite_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_rewrite_module_ctx, /* module context */ ngx_http_rewrite_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -234,19 +131,15 @@ ngx_module_t ngx_http_rewrite_module = }; -#define ngx_http_rewrite_exit (u_char *) &ngx_http_rewrite_exit_code - -uintptr_t ngx_http_rewrite_exit_code = (uintptr_t) NULL; - static ngx_http_variable_value_t ngx_http_rewrite_null_value = - { 0, ngx_string("") }; + { 0, ngx_string("") }; static ngx_int_t ngx_http_rewrite_handler(ngx_http_request_t *r) { - ngx_http_rewrite_code_pt code; - ngx_http_rewrite_engine_t *e; + ngx_http_script_code_pt code; + ngx_http_script_engine_t *e; ngx_http_rewrite_loc_conf_t *cf; cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module); @@ -255,13 +148,13 @@ ngx_http_rewrite_handler(ngx_http_reques return NGX_DECLINED; } - e = ngx_palloc(r->pool, sizeof(ngx_http_rewrite_engine_t)); + e = ngx_pcalloc(r->pool, sizeof(ngx_http_script_engine_t)); if (e == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - e->sp = ngx_palloc(r->pool, - cf->stack_size * sizeof(ngx_http_variable_value_t)); + e->sp = ngx_pcalloc(r->pool, + cf->stack_size * sizeof(ngx_http_variable_value_t)); if (e->sp == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -277,18 +170,13 @@ ngx_http_rewrite_handler(ngx_http_reques } e->ip = cf->codes->elts; - e->buf.len = 0; - e->buf.data = NULL; - e->line = NULL; - e->pos = NULL; - e->args = NULL; + e->request = r; e->quote = 1; + e->log = cf->log; e->status = NGX_DECLINED; - e->request = r; - e->conf = cf; while (*(uintptr_t *) e->ip) { - code = *(ngx_http_rewrite_code_pt *) e->ip; + code = *(ngx_http_script_code_pt *) e->ip; code(e); } @@ -297,392 +185,7 @@ ngx_http_rewrite_handler(ngx_http_reques 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 regex: \"%V\"", &code->name); - - if (code->uri) { - e->line = &r->uri; - } else { - e->sp--; - e->line = &e->sp->text; - } - - 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\" does not match \"%V\"", &code->name, e->line); - } - - if (code->test) { - e->sp->value = 0; - e->sp->text.len = 0; - e->sp->text.data = (u_char *) ""; - e->sp++; - - e->ip += sizeof(ngx_http_rewrite_regex_code_t); - return; - } - - 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); - } - - if (code->test) { - e->sp->value = 1; - e->sp->text.len = 1; - e->sp->text.data = (u_char *) "1"; - e->sp++; - - e->ip += sizeof(ngx_http_rewrite_regex_code_t); - return; - } - - if (code->status) { - e->status = code->status; - - if (!code->redirect) { - e->ip = ngx_http_rewrite_exit; - return; - } - } - - e->buf.len = code->size; - - if (code->uri) { - if (!code->break_cycle) { - r->uri_changed = 1; - r->valid_unparsed_uri = 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); - } - } - - for (n = 1; n < (ngx_uint_t) rc; n++) { - e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n]; - } - - if (code->args && r->args.len) { - e->buf.len += r->args.len + 1; - } - - e->buf.data = ngx_palloc(r->pool, e->buf.len); - if (e->buf.data == NULL) { - e->ip = ngx_http_rewrite_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } - - e->quote = code->redirect; - - 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 regex 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); - } - - r->args.len = e->pos - e->args; - r->args.data = e->args; - - e->args = NULL; - - } else { - if (code->args && r->args.len) { - *e->pos++ = '?'; - e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len); - } - - e->buf.len = e->pos - e->buf.data; - } - - if (!code->redirect) { - if (e->conf->log) { - ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, - "rewritten data: \"%V\", args: \"%V\"", - &e->buf, &r->args); - } - - if (code->uri) { - r->uri = e->buf; - - 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; - } - - ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, - "rewritten redirect: \"%V\"", &e->buf); - - r->headers_out.location = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.location == NULL) { - 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 void -ngx_http_rewrite_copy_capture_code(ngx_http_rewrite_engine_t *e) -{ - 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_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite capture: \"%V\"", &e->buf); -} - - -static void -ngx_http_rewrite_copy_code(ngx_http_rewrite_engine_t *e) -{ - ngx_http_rewrite_copy_code_t *code; - - 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"); - - e->sp--; - - if (e->sp->value) { - if (code->loc_conf) { - e->request->loc_conf = code->loc_conf; - } - - e->ip += sizeof(ngx_http_rewrite_if_code_t); - return; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite if false"); - - e->ip += code->next; -} - - -static void -ngx_http_rewrite_value_code(ngx_http_rewrite_engine_t *e) -{ - ngx_http_rewrite_value_code_t *code; - - code = (ngx_http_rewrite_value_code_t *) e->ip; - - e->ip += sizeof(ngx_http_rewrite_value_code_t); - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite value"); - - e->sp->value = (ngx_uint_t) code->value; - e->sp->text.len = (size_t) code->text_len; - e->sp->text.data = (u_char *) code->text_data; - e->sp++; -} - - -static void -ngx_http_rewrite_set_var_code(ngx_http_rewrite_engine_t *e) -{ - ngx_http_request_t *r; - ngx_http_variable_value_t *value; - ngx_http_core_main_conf_t *cmcf; - ngx_http_rewrite_var_code_t *code; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite set var"); - - code = (ngx_http_rewrite_var_code_t *) e->ip; - - e->ip += sizeof(ngx_http_rewrite_var_code_t); - - r = e->request; - - if (r->variables == NULL) { - cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - - r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts - * sizeof(ngx_http_variable_value_t *)); - if (r->variables == NULL) { - e->ip = ngx_http_rewrite_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } - } - - value = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (value == NULL) { - e->ip = ngx_http_rewrite_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } - - e->sp--; - - *value = *e->sp; - - r->variables[code->index] = value; -} - - -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->ip += sizeof(ngx_http_rewrite_var_code_t); - - value = ngx_http_get_indexed_variable(e->request, code->index); - - if (value == NULL || value == NGX_HTTP_VARIABLE_NOT_FOUND) { - e->sp->value = 0; - e->sp->text.len = 0; - e->sp->text.data = (u_char *) ""; - e->sp++; - - return; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite var: %ui, \"%V\"", value->value, &value->text); - - *e->sp = *value; - e->sp++; -} - - -static void -ngx_http_rewrite_invalid_referer_code(ngx_http_rewrite_engine_t *e) +ngx_http_rewrite_invalid_referer_code(ngx_http_script_engine_t *e) { u_char *ref; size_t len; @@ -804,13 +307,6 @@ ngx_http_rewrite_invalid_referer_code(ng } -static void -ngx_http_rewrite_nop_code(ngx_http_rewrite_engine_t *e) -{ - e->ip += sizeof(uintptr_t); -} - - static ngx_http_variable_value_t * ngx_http_rewrite_var(ngx_http_request_t *r, uintptr_t data) { @@ -834,25 +330,6 @@ ngx_http_rewrite_var(ngx_http_request_t } -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_array_push(&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) { @@ -878,8 +355,7 @@ ngx_http_rewrite_merge_loc_conf(ngx_conf ngx_http_rewrite_loc_conf_t *prev = parent; ngx_http_rewrite_loc_conf_t *conf = child; - uintptr_t *code, *last; - ngx_http_rewrite_regex_code_t *regex; + uintptr_t *code; ngx_conf_merge_value(conf->log, prev->log, 0); ngx_conf_merge_unsigned_value(conf->stack_size, prev->stack_size, 10); @@ -906,65 +382,6 @@ ngx_http_rewrite_merge_loc_conf(ngx_conf return NGX_CONF_OK; } - code = conf->codes->elts; - last = (uintptr_t *) ((u_char *) code + conf->codes->nelts); - - while (code < last) { - if (*code == (uintptr_t) NULL) { - return NGX_CONF_OK; - } - - 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); - continue; - } - - if (*code == (uintptr_t) &ngx_http_rewrite_if_code) { - code += sizeof(ngx_http_rewrite_if_code_t) / sizeof(uintptr_t); - continue; - } - - if (*code == (uintptr_t) &ngx_http_rewrite_return_code) { - code += sizeof(ngx_http_rewrite_return_code_t) / sizeof(uintptr_t); - continue; - } - - if (*code == (uintptr_t) &ngx_http_rewrite_set_var_code) { - code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t); - continue; - } - - if (*code == (uintptr_t) &ngx_http_rewrite_var_code) { - code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t); - continue; - } - - if (*code == (uintptr_t) &ngx_http_rewrite_value_code) { - code += sizeof(ngx_http_rewrite_value_code_t) / sizeof(uintptr_t); - continue; - } - - if (*code == (uintptr_t) &ngx_http_rewrite_invalid_referer_code) { - code++; - continue; - } - - if (*code == (uintptr_t) &ngx_http_rewrite_nop_code) { - code++; - continue; - } - -#if (NGX_DEBUG) - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "unknown rewrite code: %p", *code); - return NGX_CONF_ERROR; -#endif - } - code = ngx_array_push_n(conf->codes, sizeof(uintptr_t)); if (code == NULL) { return NGX_CONF_ERROR; @@ -976,29 +393,47 @@ ngx_http_rewrite_merge_loc_conf(ngx_conf } +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_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_rewrite_handler; + + return NGX_OK; +} + + static char * ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_rewrite_loc_conf_t *lcf = conf; - u_char *data; - size_t len, size; - ngx_str_t *value, err; - ngx_int_t n; - ngx_uint_t i, 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]; + ngx_str_t *value, err; + ngx_int_t n; + ngx_uint_t last; + ngx_http_script_code_pt *code; + ngx_http_script_compile_t sc; + ngx_http_script_regex_code_t *regex; + ngx_http_script_regex_end_code_t *regex_end; + u_char errstr[NGX_MAX_CONF_ERRSTR]; - regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_regex_code_t)); + regex = ngx_http_script_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_script_regex_code_t)); if (regex == NULL) { return NGX_CONF_ERROR; } + ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t)); + value = cf->args->elts; err.len = NGX_MAX_CONF_ERRSTR; @@ -1013,17 +448,19 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com return NGX_CONF_ERROR; } - regex->code = ngx_http_rewrite_regex_start_code; - regex->size = 0; - regex->ncaptures = 0; - regex->status = 0; - regex->test = 0; + regex->code = ngx_http_script_regex_start_code; regex->uri = 1; - regex->args = 1; - regex->redirect = 0; - regex->break_cycle = 0; regex->name = value[1]; + if (value[2].data[value[2].len - 1] == '?') { + + /* the last "?" drops the original arguments */ + value[2].len--; + + } else { + regex->add_args = 1; + } + last = 0; if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0) { @@ -1057,113 +494,29 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com } } - i = 0; - - while (i < value[2].len) { - - data = &value[2].data[i]; - - if (value[2].data[i] == '$' && i < value[2].len - && value[2].data[i + 1] >= '1' && value[2].data[i + 1] <= '9') - { - - /* the "$1" - "$9" captures */ - - copy_capture = ngx_http_rewrite_add_code(lcf->codes, - sizeof(ngx_http_rewrite_copy_capture_code_t), - ®ex); - if (copy_capture == NULL) { - return NGX_CONF_ERROR; - } - - i++; - - copy_capture->code = ngx_http_rewrite_copy_capture_code; - copy_capture->n = value[2].data[i] - '0'; + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - if (regex->ncaptures < copy_capture->n) { - regex->ncaptures = copy_capture->n; - } - - copy_capture->n *= 2; - - i++; - - 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), - ®ex); - if (code == NULL) { - return NGX_CONF_ERROR; - } - - *code = ngx_http_rewrite_start_args_code; + sc.cf = cf; + sc.source = &value[2]; + sc.lengths = ®ex->lengths; + sc.values = &lcf->codes; + sc.variables = ngx_http_script_variables_count(&value[2]); + sc.main = regex; + sc.complete_lengths = 1; + sc.compile_args = !regex->redirect; - i++; - - continue; - } - } - - i++; - - /* the substituion strings */ + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } - while (i < value[2].len && value[2].data[i] != '$') { - - if (value[2].data[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; - } + regex = sc.main; - if (!regex->redirect) { - break; - } - } - - i++; - } - - len = &value[2].data[i] - data; - - if (len == 0) { - continue; - } + regex->ncaptures = sc.ncaptures; + regex->size = sc.size; + regex->args = sc.args; - regex->size += len; - - size = (len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); - - copy = ngx_http_rewrite_add_code(lcf->codes, - sizeof(ngx_http_rewrite_copy_code_t) + size, - ®ex); - if (copy == NULL) { - return NGX_CONF_ERROR; - } - - copy->code = ngx_http_rewrite_copy_code; - copy->len = len; - - ngx_memcpy((u_char *) copy + sizeof(ngx_http_rewrite_copy_code_t), - data, len); + if (sc.variables == 0) { + regex->lengths = NULL; } n = ngx_regex_capture_count(regex->regex); @@ -1191,21 +544,26 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com regex->ncaptures = (regex->ncaptures + 1) * 3; } - regex_end = ngx_http_rewrite_add_code(lcf->codes, - sizeof(ngx_http_rewrite_regex_end_code_t), - ®ex); + if (lcf->max_captures < regex->ncaptures) { + lcf->max_captures = regex->ncaptures; + } + + regex_end = ngx_http_script_add_code(lcf->codes, + sizeof(ngx_http_script_regex_end_code_t), + ®ex); if (regex_end == NULL) { return NGX_CONF_ERROR; } - regex_end->code = ngx_http_rewrite_regex_end_code; + regex_end->code = ngx_http_script_regex_end_code; regex_end->uri = regex->uri; regex_end->args = regex->args; + regex_end->add_args = regex->add_args; regex_end->redirect = regex->redirect; if (last) { - code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t), - ®ex); + code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), + ®ex); if (code == NULL) { return NGX_CONF_ERROR; } @@ -1225,18 +583,18 @@ ngx_http_rewrite_return(ngx_conf_t *cf, { ngx_http_rewrite_loc_conf_t *lcf = conf; - ngx_str_t *value; - ngx_http_rewrite_return_code_t *ret; + ngx_str_t *value; + ngx_http_script_return_code_t *ret; - ret = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_return_code_t)); + ret = ngx_http_script_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_script_return_code_t)); if (ret == NULL) { return NGX_CONF_ERROR; } value = cf->args->elts; - ret->code = ngx_http_rewrite_return_code; + ret->code = ngx_http_script_return_code; ret->null = (uintptr_t) NULL; ret->status = ngx_atoi(value[1].data, value[1].len); @@ -1262,7 +620,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx, *pctx; ngx_http_core_loc_conf_t *clcf, *pclcf, **clcfp; - ngx_http_rewrite_if_code_t *if_code; + ngx_http_script_if_code_t *if_code; ngx_http_rewrite_loc_conf_t *nlcf; ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); @@ -1324,12 +682,12 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } - if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_rewrite_if_code_t)); + if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t)); if (if_code == NULL) { return NULL; } - if_code->code = ngx_http_rewrite_if_code; + if_code->code = ngx_http_script_if_code; elts = lcf->codes->elts; @@ -1362,7 +720,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ if (elts != lcf->codes->elts) { - if_code = (ngx_http_rewrite_if_code_t *) + if_code = (ngx_http_script_if_code_t *) ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts)); } @@ -1376,10 +734,10 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf) { - ngx_str_t *value, err; - ngx_uint_t cur, last; - ngx_http_rewrite_regex_code_t *regex; - u_char errstr[NGX_MAX_CONF_ERRSTR]; + ngx_str_t *value, err; + ngx_uint_t cur, last; + ngx_http_script_regex_code_t *regex; + u_char errstr[NGX_MAX_CONF_ERRSTR]; value = cf->args->elts; last = cf->args->nelts - 1; @@ -1440,12 +798,14 @@ ngx_http_rewrite_if_condition(ngx_conf_t return NGX_CONF_ERROR; } - regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_regex_code_t)); + regex = ngx_http_script_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_script_regex_code_t)); if (regex == NULL) { return NGX_CONF_ERROR; } + ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t)); + err.len = NGX_MAX_CONF_ERRSTR; err.data = errstr; @@ -1458,16 +818,9 @@ ngx_http_rewrite_if_condition(ngx_conf_t return NGX_CONF_ERROR; } - regex->code = ngx_http_rewrite_regex_start_code; - regex->size = 0; - regex->ncaptures = 0; - regex->status = 0; - regex->next = sizeof(ngx_http_rewrite_regex_code_t); + regex->code = ngx_http_script_regex_start_code; + regex->next = sizeof(ngx_http_script_regex_code_t); regex->test = 1; - regex->uri = 0; - regex->args = 0; - regex->redirect = 0; - regex->break_cycle = 0; regex->name = value[last]; return NGX_CONF_OK; @@ -1484,9 +837,9 @@ static char * ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value) { - ngx_http_variable_t *var; - ngx_http_rewrite_code_pt *code; - ngx_http_rewrite_var_code_t *var_code; + ngx_int_t index; + ngx_http_script_code_pt *code; + ngx_http_script_var_code_t *var_code; value->len--; value->data++; @@ -1495,8 +848,8 @@ ngx_http_rewrite_variable(ngx_conf_t *cf && ngx_strncmp(value->data, "invalid_referer", sizeof("invalid_referer") - 1) == 0) { - code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_code_pt)); + code = ngx_http_script_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_script_code_pt)); if (code == NULL) { return NGX_CONF_ERROR; } @@ -1504,20 +857,20 @@ ngx_http_rewrite_variable(ngx_conf_t *cf *code = ngx_http_rewrite_invalid_referer_code; } else { - var = ngx_http_add_variable(cf, value, 0); + index = ngx_http_get_variable_index(cf, value); - if (var == NULL) { + if (index == NGX_ERROR) { return NGX_CONF_ERROR; } - var_code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_var_code_t)); + var_code = ngx_http_script_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_script_var_code_t)); if (var_code == NULL) { return NGX_CONF_ERROR; } - var_code->code = ngx_http_rewrite_var_code; - var_code->index = var->index; + var_code->code = ngx_http_script_var_code; + var_code->index = index; } return NGX_CONF_OK; @@ -1624,11 +977,11 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx { ngx_http_rewrite_loc_conf_t *lcf = conf; - ngx_int_t n; - ngx_str_t *value; - ngx_http_variable_t *v; - ngx_http_rewrite_var_code_t *var; - ngx_http_rewrite_value_code_t *val; + ngx_int_t n, index; + ngx_str_t *value; + ngx_http_variable_t *v; + ngx_http_script_var_code_t *var; + ngx_http_script_value_code_t *val; value = cf->args->elts; @@ -1641,16 +994,21 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx value[1].len--; value[1].data++; - v = ngx_http_add_variable(cf, &value[1], 1); + v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGABLE); if (v == NULL) { return NGX_CONF_ERROR; } - v->handler = ngx_http_rewrite_var; - v->data = v->index; + index = ngx_http_get_variable_index(cf, &value[1]); + if (index == NGX_ERROR) { + return NGX_CONF_ERROR; + } - val = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_value_code_t)); + v->handler = ngx_http_rewrite_var; + v->data = index; + + val = ngx_http_script_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_script_value_code_t)); if (val == NULL) { return NGX_CONF_ERROR; } @@ -1661,55 +1019,19 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx n = 0; } - val->code = ngx_http_rewrite_value_code; + val->code = ngx_http_script_value_code; val->value = (uintptr_t) n; val->text_len = (uintptr_t) value[2].len; val->text_data = (uintptr_t) value[2].data; - var = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_var_code_t)); + var = ngx_http_script_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_script_var_code_t)); if (var == NULL) { return NGX_CONF_ERROR; } - var->code = ngx_http_rewrite_set_var_code; - var->index = (uintptr_t) v->index; + var->code = ngx_http_script_set_var_code; + var->index = (uintptr_t) index; return NGX_CONF_OK; } - - -static void * -ngx_http_rewrite_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size) -{ - if (*codes == NULL) { - *codes = ngx_array_create(pool, 256, 1); - if (*codes == NULL) { - return NULL; - } - } - - return ngx_array_push_n(*codes, size); -} - - -static void * -ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size, void *code) -{ - u_char *elts, **p; - void *new; - - elts = codes->elts; - - new = ngx_array_push_n(codes, size); - if (new == NULL) { - return NGX_CONF_ERROR; - } - - if (elts != codes->elts) { - p = code; - *p += (u_char *) codes->elts - elts; - } - - return new; -} diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -16,10 +16,13 @@ #define NGX_HTTP_SSI_ERROR 1 +#define NGX_HTTP_SSI_DATE_LEN 2048 + typedef struct { ngx_flag_t enable; ngx_flag_t silent_errors; + ngx_flag_t ignore_recycled_buffers; size_t min_file_chunk; size_t value_len; @@ -50,6 +53,10 @@ typedef struct { size_t looked; size_t value_len; + + ngx_uint_t output; /* unsigned output:1; */ + + ngx_str_t timefmt; } ngx_http_ssi_ctx_t; @@ -70,7 +77,8 @@ typedef struct { ngx_http_ssi_command_pt handler; ngx_http_ssi_param_t *params; - ngx_uint_t flush; /* unsigned flush:1; */ + unsigned conditional:1; + unsigned flush:1; } ngx_http_ssi_command_t; @@ -98,12 +106,28 @@ typedef enum { } ngx_http_ssi_state_e; +static ngx_int_t ngx_http_ssi_output(ngx_http_request_t *r, + ngx_http_ssi_ctx_t *ctx); static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx); static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); +static ngx_int_t ngx_http_ssi_config(ngx_http_request_t *r, + ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); +static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, + ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); +static ngx_int_t ngx_http_ssi_if(ngx_http_request_t *r, + ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); +static ngx_int_t ngx_http_ssi_else(ngx_http_request_t *r, + ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); +static ngx_int_t ngx_http_ssi_endif(ngx_http_request_t *r, + ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); +static ngx_http_variable_value_t * + ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt); + +static ngx_int_t ngx_http_ssi_add_variables(ngx_conf_t *cf); static void *ngx_http_ssi_create_conf(ngx_conf_t *cf); static char *ngx_http_ssi_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -126,6 +150,13 @@ static ngx_command_t ngx_http_ssi_filte offsetof(ngx_http_ssi_conf_t, silent_errors), NULL }, + { ngx_string("ssi_ignore_recycled_buffers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_ssi_conf_t, ignore_recycled_buffers), + NULL }, + { ngx_string("ssi_min_file_chunk"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_size_slot, @@ -139,7 +170,8 @@ static ngx_command_t ngx_http_ssi_filte static ngx_http_module_t ngx_http_ssi_filter_module_ctx = { - NULL, /* pre conf */ + ngx_http_ssi_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -153,7 +185,7 @@ static ngx_http_module_t ngx_http_ssi_f ngx_module_t ngx_http_ssi_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_ssi_filter_module_ctx, /* module context */ ngx_http_ssi_filter_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -174,8 +206,16 @@ static u_char ngx_http_ssi_error_string[ static ngx_str_t ngx_http_ssi_none = ngx_string("(none)"); -#define NGX_HTTP_SSI_ECHO_VAR 0 -#define NGX_HTTP_SSI_ECHO_DEFAULT 1 +#define NGX_HTTP_SSI_ECHO_VAR 0 +#define NGX_HTTP_SSI_ECHO_DEFAULT 1 + +#define NGX_HTTP_SSI_CONFIG_TIMEFMT 0 + +#define NGX_HTTP_SSI_INCLUDE_VIRTUAL 0 +#define NGX_HTTP_SSI_INCLUDE_FILE 1 + +#define NGX_HTTP_SSI_IF_EXPR 0 + static ngx_http_ssi_param_t ngx_http_ssi_echo_params[] = { { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1 }, @@ -183,13 +223,60 @@ static ngx_http_ssi_param_t ngx_http_ss { ngx_null_string, 0, 0 } }; +static ngx_http_ssi_param_t ngx_http_ssi_include_params[] = { + { ngx_string("virtual"), NGX_HTTP_SSI_INCLUDE_VIRTUAL, 0 }, +#if 0 + { ngx_string("file"), NGX_HTTP_SSI_INCLUDE_FILE, 0 }, +#endif + { ngx_null_string, 0, 0 } +}; + + +static ngx_http_ssi_param_t ngx_http_ssi_config_params[] = { + { ngx_string("timefmt"), NGX_HTTP_SSI_CONFIG_TIMEFMT, 0 }, + { ngx_null_string, 0, 0 } +}; + + +static ngx_http_ssi_param_t ngx_http_ssi_if_params[] = { + { ngx_string("expr"), NGX_HTTP_SSI_IF_EXPR, 0 }, + { ngx_null_string, 0, 0 } +}; + + +static ngx_http_ssi_param_t ngx_http_ssi_no_params[] = { + { ngx_null_string, 0, 0 } +}; + static ngx_http_ssi_command_t ngx_http_ssi_commands[] = { - { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0 }, - { ngx_null_string, NULL, NULL, 0 } + { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0, 0 }, + { ngx_string("config"), ngx_http_ssi_config, + ngx_http_ssi_config_params, 0, 0 }, + { ngx_string("include"), ngx_http_ssi_include, + ngx_http_ssi_include_params, 0, 1 }, + + { ngx_string("if"), ngx_http_ssi_if, ngx_http_ssi_if_params, 0, 0 }, + { ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params, 1, 0 }, + { ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params, 1, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0 } }; +static ngx_http_variable_t ngx_http_ssi_vars[] = { + + { ngx_string("date_local"), ngx_http_ssi_date_gmt_local_variable, 0, + NGX_HTTP_VAR_NOCACHABLE }, + + { ngx_string("date_gmt"), ngx_http_ssi_date_gmt_local_variable, 1, + NGX_HTTP_VAR_NOCACHABLE }, + + { ngx_null_string, NULL, 0, 0 } +}; + + + static ngx_int_t ngx_http_ssi_header_filter(ngx_http_request_t *r) { @@ -204,9 +291,9 @@ ngx_http_ssi_header_filter(ngx_http_requ /* TODO: "text/html" -> custom types */ - if (r->headers_out.content_type - && ngx_strncasecmp(r->headers_out.content_type->value.data, - "text/html", 5) != 0) + if (r->headers_out.content_type.len == 0 + || ngx_strncasecmp(r->headers_out.content_type.data, "text/html", 5) + != 0) { return ngx_http_next_header_filter(r); } @@ -223,26 +310,33 @@ ngx_http_ssi_header_filter(ngx_http_requ ctx->value_len = conf->value_len; ctx->last_out = &ctx->out; + ctx->output = 1; + ctx->params.elts = ctx->params_array; ctx->params.size = sizeof(ngx_table_elt_t); ctx->params.nalloc = NGX_HTTP_SSI_PARAMS_N; ctx->params.pool = r->pool; - r->headers_out.content_length_n = -1; - if (r->headers_out.content_length) { - r->headers_out.content_length->key.len = 0; - r->headers_out.content_length = NULL; - } - - r->headers_out.last_modified_time = -1; - if (r->headers_out.last_modified) { - r->headers_out.last_modified->key.len = 0; - r->headers_out.last_modified = NULL; - } + ctx->timefmt.len = sizeof("%A, %d-%b-%Y %H:%M:%S %Z") - 1; + ctx->timefmt.data = (u_char *) "%A, %d-%b-%Y %H:%M:%S %Z"; r->filter_need_in_memory = 1; r->filter_ssi_need_in_memory = 1; + if (r->main == NULL) { + r->headers_out.content_length_n = -1; + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; + } + + r->headers_out.last_modified_time = -1; + if (r->headers_out.last_modified) { + r->headers_out.last_modified->hash = 0; + r->headers_out.last_modified = NULL; + } + } + return ngx_http_next_header_filter(r); } @@ -277,8 +371,8 @@ ngx_http_ssi_body_filter(ngx_http_reques conf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module); - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http ssi filter"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http ssi filter \"%V\"", &r->uri); while (ctx->in || ctx->buf) { @@ -312,19 +406,50 @@ ngx_http_ssi_body_filter(ngx_http_reques if (ctx->copy_start != ctx->copy_end) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "saved: %d", ctx->saved); + if (ctx->output) { + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "saved: %d", ctx->saved); + + if (ctx->saved) { + + if (ctx->free) { + cl = ctx->free; + ctx->free = ctx->free->next; + b = cl->buf; + ngx_memzero(b, sizeof(ngx_buf_t)); - if (ctx->saved) { + } else { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + } + + b->memory = 1; + b->pos = ngx_http_ssi_string; + b->last = ngx_http_ssi_string + ctx->saved; + + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + ctx->saved = 0; + } if (ctx->free) { cl = ctx->free; ctx->free = ctx->free->next; b = cl->buf; - ngx_memzero(b, sizeof(ngx_buf_t)); } else { - b = ngx_calloc_buf(r->pool); + b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } @@ -337,56 +462,31 @@ ngx_http_ssi_body_filter(ngx_http_reques cl->buf = b; } - b->memory = 1; - b->pos = ngx_http_ssi_string; - b->last = ngx_http_ssi_string + ctx->saved; + ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t)); + + b->last_buf = 0; + b->recycled = 0; + b->pos = ctx->copy_start; + b->last = ctx->copy_end; + if (b->in_file) { + if (conf->min_file_chunk < (size_t) (b->last - b->pos)) + { + b->file_last = b->file_pos + (b->last - b->start); + b->file_pos += b->pos - b->start; + + } else { + b->in_file = 0; + } + } + + cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; + } else { ctx->saved = 0; } - - if (ctx->free) { - cl = ctx->free; - ctx->free = ctx->free->next; - b = cl->buf; - - } else { - b = ngx_alloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - } - - ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t)); - - b->last_buf = 0; - b->recycled = 0; - b->pos = ctx->copy_start; - b->last = ctx->copy_end; - - if (b->in_file) { - - if (conf->min_file_chunk < (size_t) (b->last - b->pos)) { - b->file_last = b->file_pos + (b->last - b->start); - b->file_pos += b->pos - b->start; - - } else { - b->in_file = 0; - } - } - - cl->next = NULL; - *ctx->last_out = cl; - ctx->last_out = &cl->next; } if (ctx->state == ssi_start_state) { @@ -420,12 +520,16 @@ ngx_http_ssi_body_filter(ngx_http_reques break; } - if (cmd->name.len == 0) { + if (cmd->name.len == 0 && ctx->output) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid SSI command: \"%V\"", &ctx->command); goto ssi_error; } + if (!ctx->output && !cmd->conditional) { + continue; + } + ngx_memzero(params, NGX_HTTP_SSI_MAX_PARAMS * sizeof(ngx_str_t *)); @@ -479,6 +583,14 @@ ngx_http_ssi_body_filter(ngx_http_reques } } + if (cmd->flush && ctx->out) { + rc = ngx_http_ssi_output(r, ctx); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + } + if (cmd->handler(r, ctx, params) == NGX_OK) { continue; } @@ -525,9 +637,9 @@ ngx_http_ssi_body_filter(ngx_http_reques continue; } - if (ctx->buf->recycled || ctx->buf->last_buf) { + if (ctx->buf->last_buf || ctx->buf->recycled) { + if (b == NULL) { - if (ctx->free) { cl = ctx->free; ctx->free = ctx->free->next; @@ -548,14 +660,19 @@ ngx_http_ssi_body_filter(ngx_http_reques cl->buf = b; } + b->sync = 1; + cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; } b->last_buf = ctx->buf->last_buf; - b->flush = ctx->buf->recycled; b->shadow = ctx->buf; + + if (conf->ignore_recycled_buffers == 0) { + b->recycled = ctx->buf->recycled; + } } ctx->buf = NULL; @@ -567,6 +684,17 @@ ngx_http_ssi_body_filter(ngx_http_reques return NGX_OK; } + return ngx_http_ssi_output(r, ctx); +} + + +static ngx_int_t +ngx_http_ssi_output(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx) +{ + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t *cl; + rc = ngx_http_next_body_filter(r, ctx->out); if (ctx->busy == NULL) { @@ -1154,7 +1282,7 @@ ngx_http_ssi_echo(ngx_http_request_t *r, var = params[NGX_HTTP_SSI_ECHO_VAR]; for (i = 0; i < var->len; i++) { - var->data[i] = ngx_toupper(var->data[i]); + var->data[i] = ngx_tolower(var->data[i]); } vv = ngx_http_get_variable(r, var); @@ -1163,7 +1291,7 @@ ngx_http_ssi_echo(ngx_http_request_t *r, return NGX_HTTP_SSI_ERROR; } - if (vv == NGX_HTTP_VARIABLE_NOT_FOUND) { + if (vv == NGX_HTTP_VAR_NOT_FOUND) { value = params[NGX_HTTP_SSI_ECHO_DEFAULT]; if (value == NULL) { @@ -1204,6 +1332,325 @@ ngx_http_ssi_echo(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_ssi_config(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, + ngx_str_t **params) +{ + ngx_str_t *value; + + value = params[NGX_HTTP_SSI_CONFIG_TIMEFMT]; + + if (value) { + ctx->timefmt = *value; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, + ngx_str_t **params) +{ + u_char ch, *p, **value; + size_t *size, len; + ngx_uint_t i, j, n, bracket; + ngx_str_t uri, args, name; + ngx_array_t lengths, values; + ngx_http_variable_value_t *vv; + + /* TODO: file, virtual vs file */ + + uri = *params[NGX_HTTP_SSI_INCLUDE_VIRTUAL]; + args.len = 0; + args.data = NULL; + + n = ngx_http_script_variables_count(&uri); + + if (n > 0) { + + if (ngx_array_init(&lengths, r->pool, 8, sizeof(size_t *)) != NGX_OK) { + return NGX_HTTP_SSI_ERROR; + } + + if (ngx_array_init(&values, r->pool, 8, sizeof(u_char *)) != NGX_OK) { + return NGX_HTTP_SSI_ERROR; + } + + len = 0; + + for (i = 0; i < uri.len; /* void */ ) { + + name.len = 0; + + if (uri.data[i] == '$') { + + if (++i == uri.len) { + goto invalid_variable; + } + + if (uri.data[i] == '{') { + bracket = 1; + + if (++i == uri.len) { + goto invalid_variable; + } + + name.data = &uri.data[i]; + + } else { + bracket = 0; + name.data = &uri.data[i]; + } + + for ( /* void */ ; i < uri.len; i++, name.len++) { + ch = uri.data[i]; + + if (ch == '}' && bracket) { + i++; + bracket = 0; + break; + } + + if ((ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') + || (ch >= '0' && ch <= '9') + || ch == '_') + { + continue; + } + + break; + } + + if (bracket) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "the closing bracket in \"%V\" " + "variable is missing", &name); + return NGX_HTTP_SSI_ERROR; + } + + if (name.len == 0) { + goto invalid_variable; + } + + for (j = 0; j < name.len; j++) { + name.data[j] = ngx_tolower(name.data[j]); + } + + vv = ngx_http_get_variable(r, &name); + + if (vv == NULL) { + return NGX_HTTP_SSI_ERROR; + } + + if (vv == NGX_HTTP_VAR_NOT_FOUND) { + continue; + } + + name = vv->text; + + } else { + name.data = &uri.data[i]; + + while (i < uri.len && uri.data[i] != '$') { + i++; + name.len++; + } + } + + len += name.len; + + size = ngx_array_push(&lengths); + if (size == NULL) { + return NGX_HTTP_SSI_ERROR; + } + + *size = name.len; + + value = ngx_array_push(&values); + if (value == NULL) { + return NGX_HTTP_SSI_ERROR; + } + + *value = name.data; + } + + p = ngx_palloc(r->pool, len); + if (p == NULL) { + return NGX_HTTP_SSI_ERROR; + } + + uri.len = len; + uri.data = p; + + size = lengths.elts; + value = values.elts; + + for (i = 0; i < values.nelts; i++) { + p = ngx_cpymem(p, value[i], size[i]); + } + } + + for (i = 0; i < uri.len; i++) { + if (uri.data[i] == '?') { + args.len = uri.len - i - 1; + args.data = &uri.data[i + 1]; + uri.len -= args.len + 1; + + break; + } + } + + if (ngx_http_subrequest(r, &uri, &args) != NGX_OK) { + return NGX_HTTP_SSI_ERROR; + } + + return NGX_OK; + +invalid_variable: + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid variable name in \"%V\"", &uri); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, + ngx_str_t **params) +{ + ngx_str_t *expr, var; + ngx_uint_t i; + ngx_http_variable_value_t *vv; + + expr = params[NGX_HTTP_SSI_IF_EXPR]; + + if (expr->data[0] != '$') { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid variable name in \"%V\"", expr); + return NGX_HTTP_SSI_ERROR; + } + + var.len = expr->len - 1; + var.data = expr->data + 1; + + for (i = 0; i < var.len; i++) { + var.data[i] = ngx_tolower(var.data[i]); + } + + vv = ngx_http_get_variable(r, &var); + + if (vv == NULL) { + return NGX_HTTP_SSI_ERROR; + } + + if (vv != NGX_HTTP_VAR_NOT_FOUND && vv->text.len != 0) { + ctx->output = 1; + + } else { + ctx->output = 0; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_ssi_else(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, + ngx_str_t **params) +{ + ctx->output = !ctx->output; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_ssi_endif(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, + ngx_str_t **params) +{ + ctx->output = 1; + + return NGX_OK; +} + + +static ngx_http_variable_value_t * +ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt) +{ + ngx_http_ssi_ctx_t *ctx; + ngx_http_variable_value_t *vv; + struct tm tm; + char buf[NGX_HTTP_SSI_DATE_LEN]; + + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { + return NULL; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module); + + if (ctx->timefmt.len == sizeof("%s") - 1 + && ctx->timefmt.data[0] == '%' && ctx->timefmt.data[1] == 's') + { + vv->value = ngx_time() + (gmt ? 0 : ngx_gmtoff); + + vv->text.data = ngx_palloc(r->pool, NGX_TIME_T_LEN); + if (vv->text.data == NULL) { + return NULL; + } + + vv->text.len = ngx_sprintf(vv->text.data, "%T", vv->value) + - vv->text.data; + return vv; + } + + if (gmt) { + ngx_libc_gmtime(&tm); + } else { + ngx_libc_localtime(&tm); + } + + vv->value = ngx_time() + (gmt ? 0 : ngx_gmtoff); + + vv->text.len = strftime(buf, NGX_HTTP_SSI_DATE_LEN, + (char *) ctx->timefmt.data, &tm); + if (vv->text.len == 0) { + return NULL; + } + + vv->text.data = ngx_palloc(r->pool, vv->text.len); + if (vv->text.data == NULL) { + return NULL; + } + + ngx_memcpy(vv->text.data, buf, vv->text.len); + + return vv; +} + + +static ngx_int_t +ngx_http_ssi_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_ssi_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->handler = v->handler; + var->data = v->data; + } + + return NGX_OK; +} + + static void * ngx_http_ssi_create_conf(ngx_conf_t *cf) { @@ -1216,6 +1663,7 @@ ngx_http_ssi_create_conf(ngx_conf_t *cf) conf->enable = NGX_CONF_UNSET; conf->silent_errors = NGX_CONF_UNSET; + conf->ignore_recycled_buffers = NGX_CONF_UNSET; conf->min_file_chunk = NGX_CONF_UNSET_SIZE; conf->value_len = NGX_CONF_UNSET_SIZE; @@ -1232,6 +1680,8 @@ ngx_http_ssi_merge_conf(ngx_conf_t *cf, ngx_conf_merge_value(conf->enable, prev->enable, 0); ngx_conf_merge_value(conf->silent_errors, prev->silent_errors, 0); + ngx_conf_merge_value(conf->ignore_recycled_buffers, + prev->ignore_recycled_buffers, 0); ngx_conf_merge_size_value(conf->min_file_chunk, prev->min_file_chunk, 1024); ngx_conf_merge_size_value(conf->value_len, prev->value_len, 256); diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -64,7 +64,8 @@ static ngx_command_t ngx_http_ssl_comma static ngx_http_module_t ngx_http_ssl_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ ngx_http_ssl_create_main_conf, /* create main configuration */ ngx_http_ssl_init_main_conf, /* init main configuration */ @@ -78,7 +79,7 @@ static ngx_http_module_t ngx_http_ssl_m ngx_module_t ngx_http_ssl_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_ssl_module_ctx, /* module context */ ngx_http_ssl_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -197,6 +198,13 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * return NGX_CONF_ERROR; } + if (ngx_pool_cleanup_add(cf->pool, ngx_ssl_cleanup_ctx, conf->ssl_ctx) + == NULL) + { + return NGX_CONF_ERROR; + } + + #if 0 SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL); SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_NO_SSLv3); diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -17,7 +17,7 @@ typedef struct { static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r); static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); + void *parent, void *child); static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle); @@ -38,9 +38,9 @@ static ngx_command_t ngx_http_static_co }; - ngx_http_module_t ngx_http_static_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -54,7 +54,7 @@ ngx_http_module_t ngx_http_static_modul ngx_module_t ngx_http_static_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_static_module_ctx, /* module context */ ngx_http_static_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -63,7 +63,8 @@ ngx_module_t ngx_http_static_module = { }; -static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) +static ngx_int_t +ngx_http_static_handler(ngx_http_request_t *r) { u_char *last; ngx_fd_t fd; @@ -75,16 +76,8 @@ static ngx_int_t ngx_http_static_handler ngx_buf_t *b; ngx_chain_t out; ngx_file_info_t fi; - ngx_http_cleanup_t *file_cleanup; -#if (NGX_HTTP_CACHE) - ngx_http_cleanup_t *redirect_cleanup; -#endif + ngx_pool_cleanup_file_t *cln; ngx_http_core_loc_conf_t *clcf; -#if (NGX_HTTP_CACHE) - ngx_http_static_loc_conf_t *slcf; - uint32_t file_crc, redirect_crc; - ngx_http_cache_t *file, *redirect; -#endif if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; @@ -105,19 +98,6 @@ static ngx_int_t ngx_http_static_handler return rc; } -#if (NGX_HTTP_CACHE) - - /* - * there is a valid cached open file, i.e by the index handler, - * and it should be already registered in r->cleanup - */ - - if (r->cache && !r->cache->expired) { - return ngx_http_send_cached(r); - } - -#endif - log = r->connection->log; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -127,7 +107,19 @@ static ngx_int_t ngx_http_static_handler * in a possible redirect and for the last '\0' */ - if (clcf->alias) { + if (!clcf->alias) { + name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2); + if (name.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len); + last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); + + name.len = last - name.data; + location.len = last - location.data + 1; + + } else { name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2 - clcf->name.len); if (name.data == NULL) { @@ -147,119 +139,16 @@ static ngx_int_t ngx_http_static_handler last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); -#if 0 - /* - * aliases usually have trailling "/", - * set it in the start of the possible redirect - */ - - if (*location.data != '/') { - location.data--; - } -#endif - - location.len = last - location.data + 1; - - } else { - name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2); - if (name.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len); - last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); - - name.len = last - name.data; location.len = last - location.data + 1; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", name.data); - - /* allocate cleanups */ - - file_cleanup = ngx_array_push(&r->cleanup); - if (file_cleanup == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - file_cleanup->valid = 0; - -#if (NGX_HTTP_CACHE) - - slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module); - if (slcf->redirect_cache) { - redirect_cleanup = ngx_array_push(&r->cleanup); - if (redirect_cleanup == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - redirect_cleanup->valid = 0; - - } else { - redirect_cleanup = NULL; - } - - /* look up an open files cache */ - - if (clcf->open_files) { - file = ngx_http_cache_get(clcf->open_files, file_cleanup, - &name, &file_crc); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http open file cache get: %p", file); - - if (file && !file->expired) { - r->cache = file; - return ngx_http_send_cached(r); - } - - } else { - file = NULL; - } - - - /* look up an redirect cache */ - - if (slcf->redirect_cache) { - redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup, - &name, &redirect_crc); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http redirect cache get: %p", redirect); - - if (redirect && !redirect->expired) { - - /* - * We do not copy a cached value so the cache entry is locked - * until the end of the request. In a single threaded model - * the redirected request should complete before other event - * will be processed. In a multithreaded model this locking - * should keep more popular redirects in cache. - */ - - r->headers_out.location = ngx_http_add_header(&r->headers_out, - ngx_http_headers_out); - if (r->headers_out.location == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->headers_out.location->value = redirect->data.value; - - return NGX_HTTP_MOVED_PERMANENTLY; - } - - } else { - redirect = NULL; - } - -#endif - /* open file */ #if (NGX_WIN9X) - /* TODO: redirect cache */ - if (ngx_win32_version < NGX_WIN_NT) { /* @@ -285,9 +174,6 @@ static ngx_int_t ngx_http_static_handler } if (ngx_is_dir(&fi)) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "HTTP DIR: \"%s\"", name.data); - r->headers_out.location = ngx_http_add_header(&r->headers_out, ngx_http_headers_out); if (r->headers_out.location == NULL) { @@ -356,59 +242,17 @@ static ngx_int_t ngx_http_static_handler *last++ = '/'; *last = '\0'; - r->headers_out.location = ngx_list_push(&r->headers_out.headers); + r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); if (r->headers_out.location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - r->headers_out.location->value = location; - -#if (NGX_HTTP_CACHE) - - if (slcf->redirect_cache) { - if (redirect) { - if (location.len == redirect->data.value.len - && ngx_memcmp(redirect->data.value.data, location.data, - location.len) == 0) - { - redirect->accessed = ngx_cached_time; - redirect->updated = ngx_cached_time; - - /* - * we can unlock the cache entry because - * we have the local copy anyway - */ - - ngx_http_cache_unlock(slcf->redirect_cache, redirect, log); - redirect_cleanup->valid = 0; + /* + * we do not need to set the r->headers_out.location->hash and + * r->headers_out.location->key fields + */ - return NGX_HTTP_MOVED_PERMANENTLY; - } - } - - location.len++; - redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect, - redirect_cleanup, - &name, redirect_crc, - &location, log); - location.len--; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http redirect cache alloc: %p", redirect); - - if (redirect) { - redirect->fd = NGX_INVALID_FILE; - redirect->accessed = ngx_cached_time; - redirect->last_modified = 0; - redirect->updated = ngx_cached_time; - redirect->memory = 1; - ngx_http_cache_unlock(slcf->redirect_cache, redirect, log); - redirect_cleanup->valid = 0; - } - - } - -#endif + r->headers_out.location->value = location; return NGX_HTTP_MOVED_PERMANENTLY; } @@ -429,68 +273,20 @@ static ngx_int_t ngx_http_static_handler #endif - -#if (NGX_HTTP_CACHE) - - if (clcf->open_files) { - -#if (NGX_USE_HTTP_FILE_CACHE_UNIQ) - - if (file && file->uniq == ngx_file_uniq(&fi)) { - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", name.data); - } - file->accessed = ngx_cached_time; - file->updated = ngx_cached_time; - file->expired = 0; - r->cache = file; - - return ngx_http_send_cached(r); - - } else { - if (file) { - ngx_http_cache_unlock(clcf->open_files, file, log); - file = NULL; - } + log->action = "sending response to client"; - file = ngx_http_cache_alloc(clcf->open_files, file, - file_cleanup, - &name, file_crc, NULL, log); - if (file) { - file->uniq = ngx_file_uniq(&fi); - } - } - -#else - file = ngx_http_cache_alloc(clcf->open_files, file, - file_cleanup, - &name, file_crc, NULL, log); -#endif - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http open file cache alloc: %p", file); - - if (file) { - file->fd = fd; - file->data.size = ngx_file_size(&fi); - file->accessed = ngx_cached_time; - file->last_modified = ngx_file_mtime(&fi); - file->updated = ngx_cached_time; - r->cache = file; - } - - return ngx_http_send_cached(r); + cln = ngx_palloc(r->pool, sizeof(ngx_pool_cleanup_file_t)); + if (cln == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; } -#endif - - log->action = "sending response to client"; + cln->fd = fd; + cln->name = name.data; + cln->log = r->pool->log; - file_cleanup->data.file.fd = fd; - file_cleanup->data.file.name = name.data; - file_cleanup->valid = 1; - file_cleanup->cache = 0; + if (ngx_pool_cleanup_add(r->pool, ngx_pool_cleanup_file, cln) == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = ngx_file_size(&fi); @@ -532,10 +328,12 @@ static ngx_int_t ngx_http_static_handler b->in_file = 1; - if (!r->main) { + if (r->main == NULL) { b->last_buf = 1; } + b->last_in_chain = 1; + b->file_pos = 0; b->file_last = ngx_file_size(&fi); @@ -550,7 +348,8 @@ static ngx_int_t ngx_http_static_handler } -static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf) +static void * +ngx_http_static_create_loc_conf(ngx_conf_t *cf) { ngx_http_static_loc_conf_t *conf; @@ -565,8 +364,8 @@ static void *ngx_http_static_create_loc_ } -static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child) +static char * +ngx_http_static_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) { ngx_http_static_loc_conf_t *prev = parent; ngx_http_static_loc_conf_t *conf = child; @@ -579,7 +378,8 @@ static char *ngx_http_static_merge_loc_c } -static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle) +static ngx_int_t +ngx_http_static_init(ngx_cycle_t *cycle) { ngx_http_handler_pt *h; ngx_http_core_main_conf_t *cmcf; diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -22,7 +22,8 @@ static ngx_command_t ngx_http_status_co ngx_http_module_t ngx_http_stub_status_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -36,7 +37,7 @@ ngx_http_module_t ngx_http_stub_status_ ngx_module_t ngx_http_stub_status_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_stub_status_module_ctx, /* module context */ ngx_http_status_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -63,15 +64,8 @@ static ngx_int_t ngx_http_status_handler return rc; } - r->headers_out.content_type = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.content_type == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->headers_out.content_type->key.len = 0; - r->headers_out.content_type->key.data = NULL; - r->headers_out.content_type->value.len = sizeof("text/plain") - 1; - r->headers_out.content_type->value.data = (u_char *) "text/plain"; + r->headers_out.content_type.len = sizeof("text/plain") - 1; + r->headers_out.content_type.data = (u_char *) "text/plain"; if (r->method == NGX_HTTP_HEAD) { r->headers_out.status = NGX_HTTP_OK; @@ -103,14 +97,14 @@ static ngx_int_t ngx_http_status_handler rd = *ngx_stat_reading; wr = *ngx_stat_writing; - b->last = ngx_sprintf(b->last, "Active connections: %A \n", ac); + b->last = ngx_sprintf(b->last, "Active connections: %uA \n", ac); b->last = ngx_cpymem(b->last, "server accepts handled requests\n", sizeof("server accepts handled requests\n") - 1); - b->last = ngx_sprintf(b->last, " %A %A %A \n", ap, hn, rq); + b->last = ngx_sprintf(b->last, " %uA %uA %uA \n", ap, hn, rq); - b->last = ngx_sprintf(b->last, "Reading: %A Writing: %A Waiting: %A \n", + b->last = ngx_sprintf(b->last, "Reading: %uA Writing: %uA Waiting: %uA \n", rd, wr, ac - (rd + wr)); r->headers_out.status = NGX_HTTP_OK; diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -19,7 +19,7 @@ typedef struct { - ngx_flag_t enable; + ngx_uint_t enable; ngx_int_t service; @@ -83,7 +83,7 @@ static ngx_conf_enum_t ngx_http_userid_ static ngx_conf_post_handler_pt ngx_http_userid_domain_p = - ngx_http_userid_domain; + ngx_http_userid_domain; static ngx_conf_post_handler_pt ngx_http_userid_path_p = ngx_http_userid_path; static ngx_conf_post_handler_pt ngx_http_userid_p3p_p = ngx_http_userid_p3p; @@ -145,7 +145,8 @@ static ngx_command_t ngx_http_userid_co ngx_http_module_t ngx_http_userid_filter_module_ctx = { - ngx_http_userid_add_log_formats, /* pre conf */ + ngx_http_userid_add_log_formats, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -159,7 +160,7 @@ ngx_http_module_t ngx_http_userid_filte ngx_module_t ngx_http_userid_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_userid_filter_module_ctx, /* module context */ ngx_http_userid_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -186,6 +187,10 @@ ngx_http_userid_filter(ngx_http_request_ ngx_http_userid_ctx_t *ctx; ngx_http_userid_conf_t *conf; + if (r->main) { + return ngx_http_next_header_filter(r); + } + conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); if (conf->enable == NGX_HTTP_USERID_OFF) { @@ -225,81 +230,46 @@ static ngx_int_t ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf) { - u_char *start, *last, *end; - ngx_uint_t i; + ngx_int_t n; ngx_str_t src, dst; ngx_table_elt_t **cookies; - cookies = r->headers_in.cookies.elts; - - for (i = 0; i < r->headers_in.cookies.nelts; i++) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "cookie: \"%V\"", &cookies[i]->value); - - if (conf->name.len >= cookies[i]->value.len) { - continue; - } - - start = cookies[i]->value.data; - end = cookies[i]->value.data + cookies[i]->value.len; - - while (start < end) { - - if (ngx_strncmp(start, conf->name.data, conf->name.len) != 0) { + n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name, + &src); + if (n == NGX_DECLINED) { + return NGX_OK; + } - while (start < end && *start++ != ';') { /* void */ } - while (start < end && *start == ' ') { start++; } - - continue; - } - - start += conf->name.len; - - while (start < end && *start == ' ') { start++; } - - if (start == end || *start++ != '=') { - /* the invalid "Cookie" header */ - break; - } - - while (start < end && *start == ' ') { start++; } + if (src.len < 22) { + cookies = r->headers_in.cookies.elts; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client sent too short userid cookie \"%V\"", + &cookies[n]->value); + return NGX_OK; + } - last = start; - - while (last < end && *last++ != ';') { /* void */ } + /* + * we have to limit encoded string to 22 characters + * because there are already the millions cookies with a garbage + * instead of the correct base64 trail "==" + */ - if (last - start < 22) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "client sent too short userid cookie \"%V\"", - &cookies[i]->value); - break; - } + src.len = 22; - /* - * we have to limit encoded string to 22 characters - * because there are already the millions cookies with a garbage - * instead of the correct base64 trail "==" - */ + dst.data = (u_char *) ctx->uid_got; - src.len = 22; - src.data = start; - dst.data = (u_char *) ctx->uid_got; + if (ngx_decode_base64(&dst, &src) == NGX_ERROR) { + cookies = r->headers_in.cookies.elts; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client sent invalid userid cookie \"%V\"", + &cookies[n]->value); + return NGX_OK; + } - if (ngx_decode_base64(&dst, &src) == NGX_ERROR) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "client sent invalid userid cookie \"%V\"", - &cookies[i]->value); - break; - } - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "uid: %08XD%08XD%08XD%08XD", - ctx->uid_got[0], ctx->uid_got[1], - ctx->uid_got[2], ctx->uid_got[3]); - - return NGX_OK; - } - } + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "uid: %08XD%08XD%08XD%08XD", + ctx->uid_got[0], ctx->uid_got[1], + ctx->uid_got[2], ctx->uid_got[3]); return NGX_OK; } @@ -404,6 +374,7 @@ ngx_http_userid_set_uid(ngx_http_request return NGX_ERROR; } + set_cookie->hash = 1; set_cookie->key.len = sizeof("Set-Cookie") - 1; set_cookie->key.data = (u_char *) "Set-Cookie"; set_cookie->value.len = p - cookie; @@ -421,6 +392,7 @@ ngx_http_userid_set_uid(ngx_http_request return NGX_ERROR; } + p3p->hash = 1; p3p->key.len = sizeof("P3P") - 1; p3p->key.data = (u_char *) "P3P"; p3p->value = conf->p3p; @@ -570,7 +542,7 @@ ngx_http_userid_create_conf(ngx_conf_t * * conf->p3p.date = NULL; */ - conf->enable = NGX_CONF_UNSET; + conf->enable = NGX_CONF_UNSET_UINT; conf->service = NGX_CONF_UNSET; conf->expires = NGX_CONF_UNSET; @@ -584,7 +556,8 @@ ngx_http_userid_merge_conf(ngx_conf_t *c ngx_http_userid_conf_t *prev = parent; ngx_http_userid_conf_t *conf = child; - ngx_conf_merge_value(conf->enable, prev->enable, NGX_HTTP_USERID_OFF); + ngx_conf_merge_unsigned_value(conf->enable, prev->enable, + NGX_HTTP_USERID_OFF); ngx_conf_merge_str_value(conf->name, prev->name, "uid"); ngx_conf_merge_str_value(conf->domain, prev->domain, ""); diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c --- a/src/http/modules/proxy/ngx_http_proxy_handler.c +++ b/src/http/modules/proxy/ngx_http_proxy_handler.c @@ -311,7 +311,7 @@ static ngx_http_log_op_name_t ngx_http_p -ngx_http_header_t ngx_http_proxy_headers_in[] = { +ngx_http_header0_t ngx_http_proxy_headers_in[] = { { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) }, { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) }, @@ -490,13 +490,25 @@ static ngx_int_t ngx_http_proxy_cache_ge #endif -void ngx_http_proxy_check_broken_connection(ngx_event_t *ev) +void ngx_http_proxy_rd_check_broken_connection(ngx_http_request_t *r) +{ + ngx_http_proxy_check_broken_connection(r, r->connection->read); +} + + +void ngx_http_proxy_wr_check_broken_connection(ngx_http_request_t *r) +{ + ngx_http_proxy_check_broken_connection(r, r->connection->read); +} + + +void ngx_http_proxy_check_broken_connection(ngx_http_request_t *r, + ngx_event_t *ev) { int n; char buf[1]; ngx_err_t err; ngx_connection_t *c; - ngx_http_request_t *r; ngx_http_proxy_ctx_t *p; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, @@ -510,8 +522,7 @@ void ngx_http_proxy_check_broken_connect return; } - c = ev->data; - r = c->data; + c = r->connection; p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); ev->eof = 1; @@ -542,8 +553,7 @@ void ngx_http_proxy_check_broken_connect #endif - c = ev->data; - r = c->data; + c = r->connection; p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); n = recv(c->fd, buf, 1, MSG_PEEK); @@ -712,13 +722,6 @@ void ngx_http_proxy_finalize_request(ngx p->cache->ctx.file.fd); } - if (p->upstream && p->upstream->event_pipe) { - r->file.fd = p->upstream->event_pipe->temp_file->file.fd; - - } else if (p->cache) { - r->file.fd = p->cache->ctx.file.fd; - } - if (rc == 0 && r->main == NULL) { rc = ngx_http_send_last(r); } diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.h b/src/http/modules/proxy/ngx_http_proxy_handler.h --- a/src/http/modules/proxy/ngx_http_proxy_handler.h +++ b/src/http/modules/proxy/ngx_http_proxy_handler.h @@ -249,7 +249,10 @@ void ngx_http_proxy_cache_busy_lock(ngx_ #endif -void ngx_http_proxy_check_broken_connection(ngx_event_t *ev); +void ngx_http_proxy_rd_check_broken_connection(ngx_http_request_t *r); +void ngx_http_proxy_wr_check_broken_connection(ngx_http_request_t *r); +void ngx_http_proxy_check_broken_connection(ngx_http_request_t *r, + ngx_event_t *ev); void ngx_http_proxy_busy_lock_handler(ngx_event_t *rev); void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p); @@ -265,7 +268,7 @@ int ngx_http_proxy_copy_header(ngx_http_ extern ngx_module_t ngx_http_proxy_module; -extern ngx_http_header_t ngx_http_proxy_headers_in[]; +extern ngx_http_header0_t ngx_http_proxy_headers_in[]; diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c --- a/src/http/modules/proxy/ngx_http_proxy_upstream.c +++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c @@ -24,6 +24,7 @@ static void ngx_http_proxy_process_upstr static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev); static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *); static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p); +static void ngx_http_proxy_process_downstream(ngx_http_request_t *r); static void ngx_http_proxy_process_body(ngx_event_t *ev); static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, ngx_uint_t ft_type); @@ -112,7 +113,7 @@ static ngx_chain_t *ngx_http_proxy_creat len = http_methods[p->upstream->method - 1].len + uc->uri.len; } else { - len = r->method_name.len + uc->uri.len; + len = r->method_name.len + 1 + uc->uri.len; } if (p->lcf->pass_unparsed_uri && r->valid_unparsed_uri) { @@ -261,7 +262,8 @@ static ngx_chain_t *ngx_http_proxy_creat http_methods[p->upstream->method - 1].data, http_methods[p->upstream->method - 1].len); } else { - b->last = ngx_cpymem(b->last, r->method_name.data, r->method_name.len); + b->last = ngx_cpymem(b->last, r->method_name.data, + r->method_name.len + 1); } b->last = ngx_cpymem(b->last, uc->uri.data, uc->uri.len); @@ -502,12 +504,11 @@ static void ngx_http_proxy_init_upstream ngx_del_timer(r->connection->read); } - r->connection->read->event_handler = ngx_http_proxy_check_broken_connection; + r->read_event_handler = ngx_http_proxy_rd_check_broken_connection; if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { - r->connection->write->event_handler = - ngx_http_proxy_check_broken_connection; + r->write_event_handler = ngx_http_proxy_wr_check_broken_connection; if (!r->connection->write->active) { if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT, @@ -770,8 +771,8 @@ static void ngx_http_proxy_connect(ngx_h c = p->upstream->peer.connection; c->data = p; - c->write->event_handler = ngx_http_proxy_send_request_handler; - c->read->event_handler = ngx_http_proxy_process_upstream_status_line; + c->write->handler = ngx_http_proxy_send_request_handler; + c->read->handler = ngx_http_proxy_process_upstream_status_line; c->sendfile = r->connection->sendfile; @@ -925,9 +926,9 @@ static void ngx_http_proxy_send_request( } #endif - c->write->event_handler = ngx_http_proxy_dummy_handler; + c->write->handler = ngx_http_proxy_dummy_handler; - if (ngx_handle_level_write_event(c->write) == NGX_ERROR) { + if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -1124,7 +1125,7 @@ static void ngx_http_proxy_process_upstr } - c->read->event_handler = ngx_http_proxy_process_upstream_headers; + c->read->handler = ngx_http_proxy_process_upstream_headers; ngx_http_proxy_process_upstream_headers(rev); } @@ -1174,7 +1175,7 @@ static void ngx_http_proxy_process_upstr rc = ngx_http_parse_header_line(p->request, p->header_in); - if (rc == NGX_OK) { + if (rc == NGX_OK && !r->invalid_header) { /* a header line has been parsed successfully */ @@ -1241,6 +1242,10 @@ static void ngx_http_proxy_process_upstr } else if (rc != NGX_AGAIN) { + if (r->invalid_header) { + rc = NGX_HTTP_PARSE_INVALID_HEADER; + } + /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_ERR, rev->log, 0, @@ -1465,9 +1470,8 @@ static void ngx_http_proxy_send_response ep->send_timeout = clcf->send_timeout; ep->send_lowat = clcf->send_lowat; - p->upstream->peer.connection->read->event_handler = - ngx_http_proxy_process_body; - r->connection->write->event_handler = ngx_http_proxy_process_body; + p->upstream->peer.connection->read->handler = ngx_http_proxy_process_body; + r->write_event_handler = ngx_http_proxy_process_downstream; ngx_http_proxy_process_body(p->upstream->peer.connection->read); @@ -1475,6 +1479,12 @@ static void ngx_http_proxy_send_response } +static void ngx_http_proxy_process_downstream(ngx_http_request_t *r) +{ + ngx_http_proxy_process_body(r->connection->write); +} + + static void ngx_http_proxy_process_body(ngx_event_t *ev) { ngx_connection_t *c; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -53,7 +53,7 @@ static ngx_core_module_t ngx_http_modul ngx_module_t ngx_http_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_module_ctx, /* module context */ ngx_http_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ @@ -85,11 +85,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ngx_iocp_conf_t *iocpcf; #endif -#if (NGX_SUPPRESS_WARN) - /* MSVC thinks "in_ports" may be used without having been initialized */ - ngx_memzero(&in_ports, sizeof(ngx_array_t)); -#endif - /* the main http context */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); @@ -156,12 +151,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma module = ngx_modules[m]->ctx; mi = ngx_modules[m]->ctx_index; - if (module->pre_conf) { - if (module->pre_conf(cf) != NGX_OK) { - return NGX_CONF_ERROR; - } - } - if (module->create_main_conf) { ctx->main_conf[mi] = module->create_main_conf(cf); if (ctx->main_conf[mi] == NULL) { @@ -184,11 +173,26 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } } + pcf = *cf; + cf->ctx = ctx; + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_HTTP_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + mi = ngx_modules[m]->ctx_index; + + if (module->preconfiguration) { + if (module->preconfiguration(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + } /* parse inside the http{} block */ - pcf = *cf; - cf->ctx = ctx; cf->module_type = NGX_HTTP_MODULE; cf->cmd_type = NGX_HTTP_MAIN_CONF; rv = ngx_conf_parse(cf, NULL); @@ -264,11 +268,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } - /* we needed http{}'s cf->ctx while the merging configuration */ - - *cf = pcf; - - /* init lists of the handlers */ if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers, @@ -321,7 +320,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma cmcf->headers_in_hash.bucket_size = sizeof(ngx_http_header_t); cmcf->headers_in_hash.name = "http headers_in"; - if (ngx_hash_init(&cmcf->headers_in_hash, cf->pool, ngx_http_headers_in) + if (ngx_hash_init(&cmcf->headers_in_hash, cf->pool, ngx_http_headers_in, 0) != NGX_OK) { return NGX_CONF_ERROR; @@ -329,8 +328,32 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, "http headers_in hash size: %ui, max buckets per entry: %ui", - cmcf->headers_in_hash.hash_size, - cmcf->headers_in_hash.min_buckets); + cmcf->headers_in_hash.hash_size, + cmcf->headers_in_hash.min_buckets); + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_HTTP_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + mi = ngx_modules[m]->ctx_index; + + if (module->postconfiguration) { + if (module->postconfiguration(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + } + + + /* + * http{}'s cf->ctx was needed while the configuration merging + * and in postconfiguration process + */ + + *cf = pcf; + /* * create the lists of ports, addresses and server names diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -12,11 +12,16 @@ #include #include -typedef struct ngx_http_request_s ngx_http_request_t; -typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; -typedef struct ngx_http_cleanup_s ngx_http_cleanup_t; -typedef struct ngx_http_in_addr_s ngx_http_in_addr_t; -typedef struct ngx_http_variable_value_s ngx_http_variable_value_t; + +typedef struct ngx_http_request_s ngx_http_request_t; +typedef struct ngx_http_upstream_s ngx_http_upstream_t; +typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; +typedef struct ngx_http_in_addr_s ngx_http_in_addr_t; + +typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r, u_char *buf, + size_t len); #if (NGX_HTTP_CACHE) @@ -25,13 +30,13 @@ typedef struct ngx_http_variable_value_s /* STUB */ #include +#include +#include #include -#include #include #include #include #include -#include #include #if (NGX_HTTP_SSL) @@ -58,16 +63,18 @@ void ngx_http_init_connection(ngx_connec ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b); ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r); ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b); +ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers, + ngx_str_t *name, ngx_str_t *value); ngx_int_t ngx_http_find_server_conf(ngx_http_request_t *r); void ngx_http_handler(ngx_http_request_t *r); -void ngx_http_finalize_request(ngx_http_request_t *r, int error); -void ngx_http_writer(ngx_event_t *wev); +void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc); void ngx_http_empty_handler(ngx_event_t *wev); +void ngx_http_request_empty_handler(ngx_http_request_t *r); ngx_int_t ngx_http_send_last(ngx_http_request_t *r); -void ngx_http_close_request(ngx_http_request_t *r, int error); +void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error); void ngx_http_close_connection(ngx_connection_t *c); u_char * ngx_http_log_error_info(ngx_http_request_t *r, u_char *buf, size_t len); diff --git a/src/http/ngx_http_busy_lock.c b/src/http/ngx_http_busy_lock.c --- a/src/http/ngx_http_busy_lock.c +++ b/src/http/ngx_http_busy_lock.c @@ -46,8 +46,10 @@ int ngx_http_busy_lock(ngx_http_busy_loc if (bl->waiting < bl->max_waiting) { bl->waiting++; +#if 0 ngx_add_timer(bc->event, 1000); bc->event->event_handler = bc->event_handler; +#endif /* TODO: ngx_handle_level_read_event() */ @@ -95,9 +97,11 @@ int ngx_http_busy_lock_cachable(ngx_http } if (bl->waiting < bl->max_waiting) { +#if 0 bl->waiting++; ngx_add_timer(bc->event, 1000); bc->event->event_handler = bc->event_handler; +#endif /* TODO: ngx_handle_level_read_event() */ diff --git a/src/http/ngx_http_config.h b/src/http/ngx_http_config.h --- a/src/http/ngx_http_config.h +++ b/src/http/ngx_http_config.h @@ -20,7 +20,8 @@ typedef struct { typedef struct { - ngx_int_t (*pre_conf)(ngx_conf_t *cf); + ngx_int_t (*preconfiguration)(ngx_conf_t *cf); + ngx_int_t (*postconfiguration)(ngx_conf_t *cf); void *(*create_main_conf)(ngx_conf_t *cf); char *(*init_main_conf)(ngx_conf_t *cf, void *conf); diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -34,7 +34,8 @@ static ngx_command_t ngx_http_copy_filt static ngx_http_module_t ngx_http_copy_filter_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -48,7 +49,7 @@ static ngx_http_module_t ngx_http_copy_ ngx_module_t ngx_http_copy_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_copy_filter_module_ctx, /* module context */ ngx_http_copy_filter_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -63,6 +64,7 @@ static ngx_http_output_body_filter_pt static ngx_int_t ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) { + ngx_int_t rc; ngx_output_chain_ctx_t *ctx; ngx_http_copy_filter_conf_t *conf; @@ -70,12 +72,13 @@ ngx_http_copy_filter(ngx_http_request_t return NGX_ERROR; } - ctx = ngx_http_get_module_ctx(r->main ? r->main : r, - ngx_http_copy_filter_module); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "copy filter: \"%V\"", &r->uri); + + ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); if (ctx == NULL) { - conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, - ngx_http_copy_filter_module); + conf = ngx_http_get_module_loc_conf(r, ngx_http_copy_filter_module); ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); if (ctx == NULL) { @@ -97,7 +100,12 @@ ngx_http_copy_filter(ngx_http_request_t } - return ngx_output_chain(ctx, in); + rc = ngx_output_chain(ctx, in); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "copy filter: %i \"%V\"", rc, &r->uri); + + return rc; } diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -17,11 +17,12 @@ #define NGX_HTTP_LOCATION_REGEX 4 -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 ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf); +static ngx_int_t ngx_http_core_postconfiguration(ngx_conf_t *cf); 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); static void *ngx_http_core_create_srv_conf(ngx_conf_t *cf); @@ -54,9 +55,10 @@ static char *ngx_http_core_error_log(ngx void *conf); static char *ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_core_internal(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data); -static ngx_int_t ngx_http_core_init(ngx_cycle_t *cycle); static ngx_conf_post_t ngx_http_core_lowat_post = { ngx_http_core_lowat_check }; @@ -183,7 +185,8 @@ static ngx_command_t ngx_http_core_comm NULL }, { ngx_string("root"), - 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_http_core_root, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -281,6 +284,13 @@ static ngx_command_t ngx_http_core_comm 0, NULL }, + { ngx_string("internal"), + NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, + ngx_http_core_internal, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("lingering_time"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -310,7 +320,8 @@ static ngx_command_t ngx_http_core_comm NULL }, { ngx_string("error_page"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_2MORE, ngx_http_core_error_page, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -339,7 +350,8 @@ static ngx_command_t ngx_http_core_comm ngx_http_module_t ngx_http_core_module_ctx = { - NULL, /* pre conf */ + ngx_http_core_preconfiguration, /* preconfiguration */ + ngx_http_core_postconfiguration, /* postconfiguration */ ngx_http_core_create_main_conf, /* create main configuration */ ngx_http_core_init_main_conf, /* init main configuration */ @@ -353,11 +365,11 @@ ngx_http_module_t ngx_http_core_module_ ngx_module_t ngx_http_core_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_core_module_ctx, /* module context */ ngx_http_core_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ - ngx_http_core_init, /* init module */ + NULL, /* init module */ NULL /* init process */ }; @@ -413,11 +425,12 @@ ngx_http_handler(ngx_http_request_t *r) /* TEST STUB */ r->lingering_close = 1; #endif - r->connection->write->event_handler = ngx_http_core_phase_event_handler; + r->write_event_handler = ngx_http_core_run_phases; r->valid_unparsed_uri = 1; + r->valid_location = 1; r->uri_changed = 1; - r->uri_changes = 11; + r->uri_changes = NGX_HTTP_MAX_REWRITE_CYCLES + 1; r->phase = NGX_HTTP_REWRITE_PHASE; r->phase_handler = 0; @@ -427,21 +440,6 @@ ngx_http_handler(ngx_http_request_t *r) static void -ngx_http_core_phase_event_handler(ngx_event_t *ev) -{ - ngx_connection_t *c; - ngx_http_request_t *r; - - c = ev->data; - r = c->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "phase event handler"); - - ngx_http_core_run_phases(r); -} - - -static void ngx_http_core_run_phases(ngx_http_request_t *r) { ngx_int_t rc; @@ -449,6 +447,9 @@ ngx_http_core_run_phases(ngx_http_reques ngx_http_core_loc_conf_t *clcf; ngx_http_core_main_conf_t *cmcf; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http phase handler"); + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); for (/* void */; r->phase < NGX_HTTP_LAST_PHASE; r->phase++) { @@ -478,7 +479,7 @@ ngx_http_core_run_phases(ngx_http_reques } if (r->phase == NGX_HTTP_CONTENT_PHASE && r->content_handler) { - r->connection->write->event_handler = ngx_http_empty_handler; + r->write_event_handler = ngx_http_request_empty_handler; ngx_http_finalize_request(r, r->content_handler(r)); return; } @@ -564,6 +565,10 @@ ngx_http_find_location_config(ngx_http_r clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + if (!r->internal && clcf->internal) { + return NGX_HTTP_NOT_FOUND; + } + r->connection->log->file = clcf->err_log->file; if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { r->connection->log->log_level = clcf->err_log->log_level; @@ -608,6 +613,11 @@ ngx_http_find_location_config(ngx_http_r return NGX_HTTP_INTERNAL_SERVER_ERROR; } + /* + * we do not need to set the r->headers_out.location->hash and + * r->headers_out.location->key fields + */ + r->headers_out.location->value = clcf->name; return NGX_HTTP_MOVED_PERMANENTLY; @@ -765,16 +775,6 @@ ngx_http_set_content_type(ngx_http_reque ngx_http_type_t *type; ngx_http_core_loc_conf_t *clcf; - r->headers_out.content_type = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.content_type == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->headers_out.content_type->key.len = 0; - r->headers_out.content_type->key.data = NULL; - r->headers_out.content_type->value.len = 0; - r->headers_out.content_type->value.data = NULL; - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->exten.len) { @@ -810,9 +810,6 @@ ngx_http_set_content_type(ngx_http_reque r->low_case_exten = 1; } -#if 0 - key = ngx_crc(r->exten.data, r->exten.key); -#endif ngx_http_types_hash_key(key, r->exten); type = clcf->types[key].elts; @@ -824,14 +821,14 @@ ngx_http_set_content_type(ngx_http_reque if (ngx_memcmp(r->exten.data, type[i].exten.data, r->exten.len) == 0) { - r->headers_out.content_type->value = type[i].type; + r->headers_out.content_type = type[i].type; break; } } } - if (r->headers_out.content_type->value.len == 0) { - r->headers_out.content_type->value = clcf->default_type; + if (r->headers_out.content_type.len == 0) { + r->headers_out.content_type= clcf->default_type; } return NGX_OK; @@ -841,10 +838,6 @@ ngx_http_set_content_type(ngx_http_reque ngx_int_t ngx_http_send_header(ngx_http_request_t *r) { - if (r->main) { - return NGX_OK; - } - if (r->err_ctx) { r->headers_out.status = r->err_status; r->headers_out.status_line.len = 0; @@ -863,12 +856,13 @@ ngx_http_output_filter(ngx_http_request_ return NGX_ERROR; } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http output filter \"%V\"", &r->uri); + rc = ngx_http_top_body_filter(r, in); if (rc == NGX_ERROR) { - /* NGX_ERROR may be returned by any filter */ - r->connection->write->error = 1; } @@ -924,6 +918,114 @@ ngx_http_set_exten(ngx_http_request_t *r ngx_int_t +ngx_http_subrequest(ngx_http_request_t *r, + ngx_str_t *uri, ngx_str_t *args) +{ + ngx_http_request_t *sr; + ngx_http_core_srv_conf_t *cscf; + ngx_http_postponed_request_t *pr, *p; + + sr = ngx_pcalloc(r->pool, sizeof(ngx_http_request_t)); + if (sr == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + sr->signature = NGX_HTTP_MODULE; + sr->connection = r->connection; + + sr->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); + if (sr->ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (ngx_list_init(&sr->headers_out.headers, r->pool, 20, + sizeof(ngx_table_elt_t)) == NGX_ERROR) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + sr->main_conf = cscf->ctx->main_conf; + sr->srv_conf = cscf->ctx->srv_conf; + sr->loc_conf = cscf->ctx->loc_conf; + + sr->pool = r->pool; + + sr->headers_in = r->headers_in; + + sr->start_time = ngx_time(); + sr->headers_out.content_length_n = -1; + sr->headers_out.last_modified_time = -1; + + sr->request_body = r->request_body; + + sr->method = NGX_HTTP_GET; + sr->http_version = r->http_version; + sr->http_major = r->http_minor; + + sr->request_line = r->request_line; + sr->uri = *uri; + if (args) { + sr->args = *args; + } + sr->unparsed_uri = r->unparsed_uri; + sr->method_name = r->method_name; + sr->http_protocol = r->http_protocol; + + if (ngx_http_set_exten(sr) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + sr->main = r->main ? r->main : r; + sr->parent = r; + sr->read_event_handler = ngx_http_request_empty_handler; + sr->write_event_handler = ngx_http_request_empty_handler; + + if (r->connection->data == r) { + sr->connection->data = sr; + } + + sr->in_addr = r->in_addr; + sr->port = r->port; + sr->port_text = r->port_text; + sr->server_name = r->server_name; + + sr->variables = r->variables; + + sr->log_handler = r->log_handler; + + pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t)); + if (pr == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + pr->request = sr; + pr->out = NULL; + pr->next = NULL; + + if (r->postponed) { + for (p = r->postponed; p->next; p = p->next) { /* void */ } + p->next = pr; + + } else { + r->postponed = pr; + } + + sr->internal = 1; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http subrequest \"%V\"", uri); + + ngx_http_handler(sr); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http subrequest \"%V\" done", uri); + + return NGX_OK; +} + + +ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args) { @@ -936,6 +1038,10 @@ ngx_http_internal_redirect(ngx_http_requ if (args) { r->args = *args; + + } else { + r->args.len = 0; + r->args.data = NULL; } if (ngx_http_set_exten(r) != NGX_OK) { @@ -961,6 +1067,8 @@ ngx_http_internal_redirect(ngx_http_requ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); r->loc_conf = cscf->ctx->loc_conf; + r->internal = 1; + ngx_http_handler(r); return NGX_DONE; @@ -1376,6 +1484,20 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c } +static ngx_int_t +ngx_http_core_preconfiguration(ngx_conf_t *cf) +{ + return ngx_http_variables_add_core_vars(cf); +} + + +static ngx_int_t +ngx_http_core_postconfiguration(ngx_conf_t *cf) +{ + return ngx_http_variables_init_vars(cf); +} + + static void * ngx_http_core_create_main_conf(ngx_conf_t *cf) { @@ -1575,6 +1697,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t lcf->client_max_body_size = NGX_CONF_UNSET_SIZE; lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE; lcf->client_body_timeout = NGX_CONF_UNSET_MSEC; + lcf->internal = NGX_CONF_UNSET; lcf->sendfile = NGX_CONF_UNSET; lcf->tcp_nopush = NGX_CONF_UNSET; lcf->tcp_nodelay = NGX_CONF_UNSET; @@ -1673,9 +1796,12 @@ ngx_http_core_merge_loc_conf(ngx_conf_t (size_t) 2 * ngx_pagesize); ngx_conf_merge_msec_value(conf->client_body_timeout, prev->client_body_timeout, 60000); + + ngx_conf_merge_value(conf->internal, prev->internal, 0); ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0); ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 0); + ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 60000); ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0); ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, @@ -1963,6 +2089,20 @@ ngx_http_core_error_page(ngx_conf_t *cf, 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; + + lcf->err_log = ngx_log_create_errlog(cf->cycle, cf->args); + if (lcf->err_log == NULL) { + return NGX_CONF_ERROR; + } + + return ngx_set_error_log_levels(cf, lcf->err_log); +} + + +static char * ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *lcf = conf; @@ -2004,16 +2144,17 @@ ngx_http_core_keepalive(ngx_conf_t *cf, static char * -ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_http_core_internal(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *lcf = conf; - lcf->err_log = ngx_log_create_errlog(cf->cycle, cf->args); - if (lcf->err_log == NULL) { - return NGX_CONF_ERROR; + if (lcf->internal != NGX_CONF_UNSET) { + return "is duplicate"; } - return ngx_set_error_log_levels(cf, lcf->err_log); + lcf->internal = 1; + + return NGX_CONF_OK; } @@ -2044,10 +2185,3 @@ ngx_http_core_lowat_check(ngx_conf_t *cf return NGX_CONF_OK; } - - -static ngx_int_t -ngx_http_core_init(ngx_cycle_t *cycle) -{ - return ngx_http_variables_init(cycle); -} diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -49,6 +49,7 @@ typedef struct { ngx_array_t index_handlers; ngx_hash_t headers_in_hash; + ngx_hash_t variables_hash; ngx_uint_t server_names_hash; ngx_uint_t server_names_hash_threshold; @@ -56,6 +57,7 @@ typedef struct { size_t max_server_name_len; ngx_array_t variables; /* ngx_http_variable_t */ + ngx_array_t all_variables; /* ngx_http_variable_t */ } ngx_http_core_main_conf_t; @@ -197,6 +199,7 @@ struct ngx_http_core_loc_conf_s { time_t keepalive_header; /* keepalive_timeout */ + ngx_flag_t internal; /* internal */ ngx_flag_t sendfile; /* sendfile */ ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ @@ -230,6 +233,8 @@ ngx_int_t ngx_http_find_location_config( 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); +ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, + ngx_str_t *uri, ngx_str_t *args); ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args); diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -15,7 +15,8 @@ static ngx_int_t ngx_http_header_filter( static ngx_http_module_t ngx_http_header_filter_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -29,7 +30,7 @@ static ngx_http_module_t ngx_http_heade ngx_module_t ngx_http_header_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_header_filter_module_ctx, /* module context */ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -38,10 +39,10 @@ ngx_module_t ngx_http_header_filter_mod }; -static char server_string[] = "Server: " NGINX_VER CRLF; +static char ngx_http_server_string[] = "Server: " NGINX_VER CRLF; -static ngx_str_t http_codes[] = { +static ngx_str_t ngx_http_status_lines[] = { ngx_string("200 OK"), ngx_null_string, /* "201 Created" */ @@ -115,11 +116,13 @@ static ngx_str_t http_codes[] = { }; -ngx_http_header_t ngx_http_headers_out[] = { +ngx_http_header0_t ngx_http_headers_out[] = { { ngx_string("Server"), offsetof(ngx_http_headers_out_t, server) }, { ngx_string("Date"), offsetof(ngx_http_headers_out_t, date) }, +#if 0 { ngx_string("Content-Type"), offsetof(ngx_http_headers_out_t, content_type) }, +#endif { ngx_string("Content-Length"), offsetof(ngx_http_headers_out_t, content_length) }, { ngx_string("Content-Encoding"), @@ -150,6 +153,10 @@ ngx_http_header_filter(ngx_http_request_ ngx_table_elt_t *header; ngx_http_core_loc_conf_t *clcf; + if (r->main) { + return NGX_OK; + } + if (r->http_version < NGX_HTTP_VERSION_10) { return NGX_OK; } @@ -209,44 +216,44 @@ ngx_http_header_filter(ngx_http_request_ + NGX_HTTP_LEVEL_400; } - len += http_codes[status].len; + len += ngx_http_status_lines[status].len; } - if (r->headers_out.server && r->headers_out.server->key.len) { - len += r->headers_out.server->key.len - + r->headers_out.server->value.len + 2; - } else { - len += sizeof(server_string) - 1; + if (r->headers_out.server == NULL) { + len += sizeof(ngx_http_server_string) - 1; } - if (r->headers_out.date && r->headers_out.date->key.len) { - len += r->headers_out.date->key.len - + r->headers_out.date->value.len + 2; - } else { + if (r->headers_out.date == NULL) { len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; } - if (r->headers_out.content_length == NULL) { - if (r->headers_out.content_length_n >= 0) { - len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2; - } - } - - if (r->headers_out.content_type && r->headers_out.content_type->value.len) { - r->headers_out.content_type->key.len = 0; + if (r->headers_out.content_type.len) { len += sizeof("Content-Type: ") - 1 - + r->headers_out.content_type->value.len + 2; + + r->headers_out.content_type.len + 2; if (r->headers_out.charset.len) { len += sizeof("; charset=") - 1 + r->headers_out.charset.len; } } + if (r->headers_out.content_length == NULL + && r->headers_out.content_length_n >= 0) + { + len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2; + } + + if (r->headers_out.last_modified == NULL + && r->headers_out.last_modified_time != -1) + { + len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; + } + if (r->headers_out.location && r->headers_out.location->value.len && r->headers_out.location->value.data[0] == '/') { - r->headers_out.location->key.len = 0; + r->headers_out.location->hash = 0; + len += sizeof("Location: http://") - 1 + r->server_name.len + r->headers_out.location->value.len + 2; @@ -255,14 +262,6 @@ ngx_http_header_filter(ngx_http_request_ } } - if (r->headers_out.last_modified && r->headers_out.last_modified->key.len) { - len += r->headers_out.last_modified->key.len - + r->headers_out.last_modified->value.len + 2; - - } else if (r->headers_out.last_modified_time != -1) { - len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; - } - if (r->chunked) { len += sizeof("Transfer-Encoding: chunked" CRLF) - 1; } @@ -303,7 +302,7 @@ ngx_http_header_filter(ngx_http_request_ i = 0; } - if (header[i].key.len == 0) { + if (header[i].hash == 0) { continue; } @@ -325,16 +324,17 @@ ngx_http_header_filter(ngx_http_request_ r->headers_out.status_line.len); } else { - b->last = ngx_cpymem(b->last, http_codes[status].data, - http_codes[status].len); + b->last = ngx_cpymem(b->last, ngx_http_status_lines[status].data, + ngx_http_status_lines[status].len); } *b->last++ = CR; *b->last++ = LF; - if (!(r->headers_out.server && r->headers_out.server->key.len)) { - b->last = ngx_cpymem(b->last, server_string, sizeof(server_string) - 1); + if (r->headers_out.server == NULL) { + b->last = ngx_cpymem(b->last, ngx_http_server_string, + sizeof(ngx_http_server_string) - 1); } - if (!(r->headers_out.date && r->headers_out.date->key.len)) { + if (r->headers_out.date == NULL) { b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1); b->last = ngx_cpymem(b->last, ngx_cached_http_time.data, ngx_cached_http_time.len); @@ -342,19 +342,12 @@ ngx_http_header_filter(ngx_http_request_ *b->last++ = CR; *b->last++ = LF; } - if (r->headers_out.content_length == NULL) { - if (r->headers_out.content_length_n >= 0) { - b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF, - r->headers_out.content_length_n); - } - } - - if (r->headers_out.content_type && r->headers_out.content_type->value.len) { + if (r->headers_out.content_type.len) { b->last = ngx_cpymem(b->last, "Content-Type: ", sizeof("Content-Type: ") - 1); p = b->last; - b->last = ngx_cpymem(b->last, r->headers_out.content_type->value.data, - r->headers_out.content_type->value.len); + b->last = ngx_cpymem(b->last, r->headers_out.content_type.data, + r->headers_out.content_type.len); if (r->headers_out.charset.len) { b->last = ngx_cpymem(b->last, "; charset=", @@ -362,13 +355,32 @@ ngx_http_header_filter(ngx_http_request_ b->last = ngx_cpymem(b->last, r->headers_out.charset.data, r->headers_out.charset.len); - r->headers_out.content_type->value.len = b->last - p; - r->headers_out.content_type->value.data = p; + /* update r->headers_out.content_type for possible logging */ + + r->headers_out.content_type.len = b->last - p; + r->headers_out.content_type.data = p; } *b->last++ = CR; *b->last++ = LF; } + if (r->headers_out.content_length == NULL + && r->headers_out.content_length_n >= 0) + { + b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF, + r->headers_out.content_length_n); + } + + if (r->headers_out.last_modified == NULL + && r->headers_out.last_modified_time != -1) + { + b->last = ngx_cpymem(b->last, "Last-Modified: ", + sizeof("Last-Modified: ") - 1); + b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); + + *b->last++ = CR; *b->last++ = LF; + } + if (r->headers_out.location && r->headers_out.location->value.len && r->headers_out.location->value.data[0] == '/') @@ -386,22 +398,14 @@ ngx_http_header_filter(ngx_http_request_ b->last = ngx_cpymem(b->last, r->headers_out.location->value.data, r->headers_out.location->value.len); + /* update r->headers_out.location->value for possible logging */ + r->headers_out.location->value.len = b->last - p; r->headers_out.location->value.data = p; *b->last++ = CR; *b->last++ = LF; } - if (!(r->headers_out.last_modified && r->headers_out.last_modified->key.len) - && r->headers_out.last_modified_time != -1) - { - b->last = ngx_cpymem(b->last, "Last-Modified: ", - sizeof("Last-Modified: ") - 1); - b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); - - *b->last++ = CR; *b->last++ = LF; - } - if (r->chunked) { b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF, sizeof("Transfer-Encoding: chunked" CRLF) - 1); @@ -436,7 +440,7 @@ ngx_http_header_filter(ngx_http_request_ i = 0; } - if (header[i].key.len == 0) { + if (header[i].hash == 0) { continue; } diff --git a/src/http/ngx_http_log_module.c b/src/http/ngx_http_log_module.c --- a/src/http/ngx_http_log_module.c +++ b/src/http/ngx_http_log_module.c @@ -106,7 +106,8 @@ static ngx_command_t ngx_http_log_comma ngx_http_module_t ngx_http_log_module_ctx = { - ngx_http_log_set_formats, /* pre conf */ + ngx_http_log_set_formats, /* preconfiguration */ + NULL, /* postconfiguration */ ngx_http_log_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ @@ -120,7 +121,7 @@ ngx_http_module_t ngx_http_log_module_c ngx_module_t ngx_http_log_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_log_module_ctx, /* module context */ ngx_http_log_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -391,6 +392,11 @@ ngx_http_log_header_in_compile(ngx_conf_ continue; } + /* STUB: "Cookie" speacial handling */ + if (ngx_http_headers_in[i].offset == 0) { + continue; + } + if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, value->data, value->len) == 0) { @@ -733,22 +739,17 @@ static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, ngx_str_t *value) { - ngx_uint_t i; - ngx_http_variable_t *var; + ngx_int_t index; - for (i = 0; i < value->len; i++) { - value->data[i] = ngx_toupper(value->data[i]); - } - - var = ngx_http_add_variable(cf, value, 0); - if (var == NULL) { + index = ngx_http_get_variable_index(cf, value); + if (index == NGX_ERROR) { return NGX_ERROR; } op->len = 0; op->getlen = ngx_http_log_variable_getlen; op->run = ngx_http_log_variable; - op->data = var->index; + op->data = index; return NGX_OK; } @@ -762,7 +763,7 @@ ngx_http_log_variable_getlen(ngx_http_re value = ngx_http_get_indexed_variable(r, data); if (value == NULL - || value == NGX_HTTP_VARIABLE_NOT_FOUND + || value == NGX_HTTP_VAR_NOT_FOUND || value->text.len == 0) { return 1; @@ -780,7 +781,7 @@ ngx_http_log_variable(ngx_http_request_t value = ngx_http_get_indexed_variable(r, op->data); if (value == NULL - || value == NGX_HTTP_VARIABLE_NOT_FOUND + || value == NGX_HTTP_VAR_NOT_FOUND || value->text.len == 0) { *buf = '-'; diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -9,7 +9,8 @@ #include -ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) +ngx_int_t +ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) { u_char c, ch, *p, *m; enum { @@ -63,7 +64,7 @@ ngx_int_t ngx_http_parse_request_line(ng case sw_method: if (ch == ' ') { - r->method_end = p; + r->method_end = p - 1; m = r->request_start; if (p - m == 3) { @@ -502,7 +503,8 @@ done: } -ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) +ngx_int_t +ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) { u_char c, ch, *p; ngx_uint_t hash; @@ -513,7 +515,6 @@ ngx_int_t ngx_http_parse_header_line(ngx sw_value, sw_space_after_value, sw_ignore_line, - sw_skip_line, sw_almost_done, sw_header_almost_done } state; @@ -528,8 +529,6 @@ ngx_int_t ngx_http_parse_header_line(ngx /* first char */ case sw_start: - r->invalid_header = 0; - switch (ch) { case CR: r->header_end = p; @@ -548,18 +547,11 @@ ngx_int_t ngx_http_parse_header_line(ngx break; } - if (ch == '-') { - hash = ch; - break; - } - if (ch >= '0' && ch <= '9') { hash = ch; break; } - r->invalid_header = 1; - state = sw_skip_line; break; } @@ -589,18 +581,31 @@ ngx_int_t ngx_http_parse_header_line(ngx break; } + if (ch == CR) { + r->header_name_end = p; + r->header_start = p; + r->header_end = p; + state = sw_almost_done; + break; + } + + if (ch == LF) { + r->header_name_end = p; + r->header_start = p; + r->header_end = p; + goto done; + } + /* IIS may send the duplicate "HTTP/1.1 ..." lines */ if (ch == '/' - && r->proxy - && p - r->header_start == 4 - && ngx_strncmp(r->header_start, "HTTP", 4) == 0) + && r->upstream + && p - r->header_name_start == 4 + && ngx_strncmp(r->header_name_start, "HTTP", 4) == 0) { state = sw_ignore_line; break; } - r->invalid_header = 1; - state = sw_skip_line; break; /* space* before header value */ @@ -609,11 +614,13 @@ ngx_int_t ngx_http_parse_header_line(ngx case ' ': break; case CR: - r->header_start = r->header_end = p; + r->header_start = p; + r->header_end = p; state = sw_almost_done; break; case LF: - r->header_start = r->header_end = p; + r->header_start = p; + r->header_end = p; goto done; default: r->header_start = p; @@ -666,21 +673,6 @@ ngx_int_t ngx_http_parse_header_line(ngx } break; - /* skip header line */ - case sw_skip_line: - switch (ch) { - case CR: - r->header_end = p; - state = sw_almost_done; - break; - case LF: - r->header_end = p; - goto done; - default: - break; - } - break; - /* end of header line */ case sw_almost_done: switch (ch) { @@ -724,7 +716,8 @@ header_done: } -ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) +ngx_int_t +ngx_http_parse_complex_uri(ngx_http_request_t *r) { u_char c, ch, decoded, *p, *u; enum { @@ -1001,3 +994,75 @@ done: return NGX_OK; } + + +ngx_int_t +ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, + ngx_str_t *value) +{ + ngx_uint_t i; + u_char *start, *last, *end, ch; + ngx_table_elt_t **h; + + h = headers->elts; + + for (i = 0; i < headers->nelts; i++) { + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0, + "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value); + + if (name->len > h[i]->value.len) { + continue; + } + + start = h[i]->value.data; + end = h[i]->value.data + h[i]->value.len; + + while (start < end) { + + if (ngx_strncasecmp(start, name->data, name->len) != 0) { + goto skip; + } + + for (start += name->len; start < end && *start == ' '; start++) { + /* void */ + } + + if (value == NULL) { + if (start == end || *start == ',') { + return i; + } + + goto skip; + } + + if (start == end || *start++ != '=') { + /* the invalid header value */ + goto skip; + } + + while (start < end && *start == ' ') { start++; } + + for (last = start; last < end && *last != ';'; last++) { + /* void */ + } + + value->len = last - start; + value->data = start; + + return i; + + skip: + while (start < end) { + ch = *start++; + if (ch == ';' || ch == ',') { + break; + } + } + + while (start < end && *start == ' ') { start++; } + } + } + + return NGX_DECLINED; +} diff --git a/src/http/ngx_http_postpone_filter_module.c b/src/http/ngx_http_postpone_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_postpone_filter_module.c @@ -0,0 +1,126 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +static ngx_int_t ngx_http_postpone_filter_init(ngx_cycle_t *cycle); + + +static ngx_http_module_t ngx_http_postpone_filter_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + 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_postpone_filter_module = { + NGX_MODULE_V1, + &ngx_http_postpone_filter_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_postpone_filter_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_output_body_filter_pt ngx_http_next_filter; + + +static ngx_int_t +ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_int_t rc; + ngx_chain_t *out; + ngx_http_postponed_request_t *pr, **ppr; + + if (r->connection->write->error) { + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postpone filter \"%V\" %p", &r->uri, in); + + if (r != r->connection->data || (r->postponed && in)) { + + if (r->postponed) { + for (pr = r->postponed; pr->next; pr = pr->next) { /* void */ } + + ppr = pr->request ? &pr->next : NULL; + + } else { + ppr = &r->postponed; +#if (NGX_SUPPRESS_WARN) + pr = NULL; +#endif + } + + if (ppr) { + pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t)); + if (pr == NULL) { + return NGX_ERROR; + } + + *ppr = pr; + + pr->request = NULL; + pr->out = NULL; + pr->next = NULL; + } + + if (ngx_chain_add_copy(r->pool, &pr->out, in) == NGX_ERROR) { + return NGX_ERROR; + } + + if (r != r->connection->data || r->postponed->request) { + return NGX_AGAIN; + } + } + + if (r->postponed) { + out = r->postponed->out; + r->postponed = r->postponed->next; + + } else { + out = in; + } + + if (out == NULL && r->out == NULL) { + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postpone filter out \"%V\"", &r->uri); + + rc = ngx_http_next_filter(r->main ? r->main : r, out); + + if (rc == NGX_ERROR) { + /* NGX_ERROR may be returned by any filter */ + r->connection->write->error = 1; + } + + return rc; +} + + +static ngx_int_t +ngx_http_postpone_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_next_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_postpone_filter; + + return NGX_OK; +} diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -19,13 +19,22 @@ static void ngx_http_process_request_hea static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, ngx_uint_t request_line); + +static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_process_cookie(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); + static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r); static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r); +static void ngx_http_request_handler(ngx_event_t *ev); static void ngx_http_set_write_handler(ngx_http_request_t *r); - -static void ngx_http_block_read(ngx_event_t *ev); -static void ngx_http_read_discarded_body_event(ngx_event_t *rev); +static void ngx_http_writer(ngx_http_request_t *r); +static ngx_int_t ngx_http_postponed_handler(ngx_http_request_t *r); + +static void ngx_http_block_read(ngx_http_request_t *r); +static void ngx_http_read_discarded_body_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_read_discarded_body(ngx_http_request_t *r); static void ngx_http_set_keepalive(ngx_http_request_t *r); @@ -34,6 +43,8 @@ static void ngx_http_set_lingering_close static void ngx_http_lingering_close_handler(ngx_event_t *ev); static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len); +static u_char *ngx_http_log_error_handler(ngx_http_request_t *r, u_char *buf, + size_t len); static char *ngx_http_client_errors[] = { @@ -50,59 +61,81 @@ static char *ngx_http_client_errors[] = ngx_http_header_t ngx_http_headers_in[] = { - { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host) }, - { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection) }, + { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host), + ngx_http_process_header_line }, + + { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection), + ngx_http_process_header_line }, + { ngx_string("If-Modified-Since"), - offsetof(ngx_http_headers_in_t, if_modified_since) }, - { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent) }, - { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer) }, + offsetof(ngx_http_headers_in_t, if_modified_since), + ngx_http_process_header_line }, + + { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent), + ngx_http_process_header_line }, + + { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer), + ngx_http_process_header_line }, + { ngx_string("Content-Length"), - offsetof(ngx_http_headers_in_t, content_length) }, + offsetof(ngx_http_headers_in_t, content_length), + ngx_http_process_header_line }, + { ngx_string("Content-Type"), - offsetof(ngx_http_headers_in_t, content_type) }, - - { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range) }, + offsetof(ngx_http_headers_in_t, content_type), + ngx_http_process_header_line }, + + { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range), + ngx_http_process_header_line }, + #if 0 - { ngx_string("If-Range"), offsetof(ngx_http_headers_in_t, if_range) }, + { ngx_string("If-Range"), offsetof(ngx_http_headers_in_t, if_range), + ngx_http_process_header_line }, #endif #if (NGX_HTTP_GZIP) { ngx_string("Accept-Encoding"), - offsetof(ngx_http_headers_in_t, accept_encoding) }, - { ngx_string("Via"), offsetof(ngx_http_headers_in_t, via) }, + offsetof(ngx_http_headers_in_t, accept_encoding), + ngx_http_process_header_line }, + + { ngx_string("Via"), offsetof(ngx_http_headers_in_t, via), + ngx_http_process_header_line }, #endif { ngx_string("Authorization"), - offsetof(ngx_http_headers_in_t, authorization) }, - - { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive) }, + offsetof(ngx_http_headers_in_t, authorization), + ngx_http_process_header_line }, + + { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive), + ngx_http_process_header_line }, #if (NGX_HTTP_PROXY) { ngx_string("X-Forwarded-For"), - offsetof(ngx_http_headers_in_t, x_forwarded_for) }, - { ngx_string("X-Real-IP"), offsetof(ngx_http_headers_in_t, x_real_ip) }, - { ngx_string("X-URL"), offsetof(ngx_http_headers_in_t, x_url) }, + offsetof(ngx_http_headers_in_t, x_forwarded_for), + ngx_http_process_header_line }, + + { ngx_string("X-Real-IP"), offsetof(ngx_http_headers_in_t, x_real_ip), + ngx_http_process_header_line }, + + { ngx_string("X-URL"), offsetof(ngx_http_headers_in_t, x_url), + ngx_http_process_header_line }, #endif #if (NGX_HTTP_HEADERS) - { ngx_string("Accept"), offsetof(ngx_http_headers_in_t, accept) }, + { ngx_string("Accept"), offsetof(ngx_http_headers_in_t, accept), + ngx_http_process_header_line }, + { ngx_string("Accept-Language"), - offsetof(ngx_http_headers_in_t, accept_language) }, + offsetof(ngx_http_headers_in_t, accept_language), + ngx_http_process_header_line }, #endif - { ngx_null_string, 0 } + { ngx_string("Cookie"), 0, ngx_http_process_cookie }, + + { ngx_null_string, 0, NULL } }; -#if 0 -static void -ngx_http_dummy(ngx_event_t *wev) -{ - return; -} -#endif - - void ngx_http_init_connection(ngx_connection_t *c) { @@ -126,9 +159,9 @@ ngx_http_init_connection(ngx_connection_ c->log_error = NGX_ERROR_INFO; rev = c->read; - rev->event_handler = ngx_http_init_request; - - /* STUB: epoll edge */ c->write->event_handler = ngx_http_empty_handler; + rev->handler = ngx_http_init_request; + + /* STUB: epoll edge */ c->write->handler = ngx_http_empty_handler; if (rev->ready) { /* the deferred accept(), rtsig, aio, iocp */ @@ -165,18 +198,6 @@ ngx_http_init_connection(ngx_connection_ return; } -#if 0 - /* TODO: learn SO_SNDBUF (to use in zerocopy) via kqueue's EV_CLEAR event */ - - c->write->ready = 0; - c->write->event_handler = ngx_http_dummy; - - if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { - ngx_http_close_connection(c); - return; - } -#endif - #if (NGX_STAT_STUB) ngx_atomic_inc(ngx_stat_reading); #endif @@ -335,7 +356,7 @@ void ngx_http_init_request(ngx_event_t * r->srv_conf = cscf->ctx->srv_conf; r->loc_conf = cscf->ctx->loc_conf; - rev->event_handler = ngx_http_process_request_line; + rev->handler = ngx_http_process_request_line; #if (NGX_HTTP_SSL) @@ -350,7 +371,7 @@ void ngx_http_init_request(ngx_event_t * return; } - rev->event_handler = ngx_http_ssl_handshake; + rev->handler = ngx_http_ssl_handshake; /* * The majority of browsers do not send the "close notify" alert. @@ -396,17 +417,9 @@ void ngx_http_init_request(ngx_event_t * return; } - if (ngx_array_init(&r->cleanup, r->pool, 4, sizeof(ngx_http_cleanup_t)) - == NGX_ERROR) - { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - ngx_http_close_connection(c); - return; - } - if (ngx_list_init(&r->headers_out.headers, r->pool, 20, - sizeof(ngx_table_elt_t)) == NGX_ERROR) + sizeof(ngx_table_elt_t)) == NGX_ERROR) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ngx_http_close_connection(c); @@ -426,8 +439,6 @@ void ngx_http_init_request(ngx_event_t * r->start_time = ngx_time(); - r->file.fd = NGX_INVALID_FILE; - r->headers_in.content_length_n = -1; r->headers_in.keep_alive_n = -1; r->headers_out.content_length_n = -1; @@ -437,6 +448,7 @@ void ngx_http_init_request(ngx_event_t * ctx = c->log->data; ctx->request = r; + r->log_handler = ngx_http_log_error_handler; #if (NGX_STAT_STUB) ngx_atomic_inc(ngx_stat_reading); @@ -444,7 +456,7 @@ void ngx_http_init_request(ngx_event_t * ngx_atomic_inc(ngx_stat_requests); #endif - rev->event_handler(rev); + rev->handler(rev); } @@ -507,7 +519,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev) } } - rev->event_handler = ngx_http_process_request_line; + rev->handler = ngx_http_process_request_line; ngx_http_process_request_line(rev); } @@ -593,10 +605,8 @@ ngx_http_process_request_line(ngx_event_ r->unparsed_uri.data = r->uri_start; - if (r->method == 0) { - r->method_name.len = r->method_end - r->request_start + 1; - r->method_name.data = r->request_line.data; - } + r->method_name.len = r->method_end - r->request_start + 1; + r->method_name.data = r->request_line.data; if (r->http_protocol.data) { @@ -634,7 +644,7 @@ ngx_http_process_request_line(ngx_event_ "http exten: \"%V\"", &r->exten); if (r->http_version < NGX_HTTP_VERSION_10) { - rev->event_handler = ngx_http_block_read; + r->read_event_handler = ngx_http_block_read; ngx_http_handler(r); return; } @@ -659,7 +669,7 @@ ngx_http_process_request_line(ngx_event_ c->log->action = "reading client request headers"; - rev->event_handler = ngx_http_process_request_headers; + rev->handler = ngx_http_process_request_headers; ngx_http_process_request_headers(rev); return; @@ -711,7 +721,7 @@ ngx_http_process_request_headers(ngx_eve ngx_int_t rc, rv; ngx_uint_t key; ngx_str_t header; - ngx_table_elt_t *h, **cookie; + ngx_table_elt_t *h; ngx_connection_t *c; ngx_http_header_t *hh; ngx_http_request_t *r; @@ -773,6 +783,7 @@ ngx_http_process_request_headers(ngx_eve if (rc == NGX_OK) { +#if 0 if (r->invalid_header) { /* there was error while a header line parsing */ @@ -785,11 +796,10 @@ ngx_http_process_request_headers(ngx_eve &header); continue; } +#endif /* a header line has been parsed successfully */ - r->headers_n++; - h = ngx_list_push(&r->headers_in.headers); if (h == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -807,27 +817,14 @@ ngx_http_process_request_headers(ngx_eve h->value.data = r->header_start; h->value.data[h->value.len] = '\0'; - if (h->key.len == sizeof("Cookie") - 1 - && ngx_strcasecmp(h->key.data, "Cookie") == 0) + key = h->hash % cmcf->headers_in_hash.hash_size; + + if (hh[key].name.len == h->key.len + && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0) { - cookie = ngx_array_push(&r->headers_in.cookies); - if (cookie == NULL) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - ngx_http_close_connection(c); + if (hh[key].handler(r, h, hh[key].offset) != NGX_OK) { return; } - - *cookie = h; - - } else { - key = h->hash % cmcf->headers_in_hash.hash_size; - - if (hh[key].name.len == h->key.len - && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0) - { - *((ngx_table_elt_t **) - ((char *) &r->headers_in + hh[key].offset)) = h; - } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -865,7 +862,10 @@ ngx_http_process_request_headers(ngx_eve r->stat_writing = 1; #endif - rev->event_handler = ngx_http_block_read; + rev->handler = ngx_http_request_handler; + c->write->handler = ngx_http_request_handler; + r->read_event_handler = ngx_http_block_read; + ngx_http_handler(r); return; } @@ -1091,6 +1091,41 @@ ngx_http_alloc_large_header_buffer(ngx_h static ngx_int_t +ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t **ph; + + ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset); + + if (*ph == NULL) { + *ph = h; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_process_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t **cookie; + + cookie = ngx_array_push(&r->headers_in.cookies); + if (cookie == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_close_connection(r->connection); + return NGX_ERROR; + } + + *cookie = h; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r) { size_t len; @@ -1108,6 +1143,10 @@ ngx_http_process_request_header(ngx_http r->headers_in.host->value.data[len] = ngx_tolower(ch); } + if (r->headers_in.host->value.data[len - 1] == '.') { + len--; + } + r->headers_in.host_name_len = len; if (ngx_http_find_virtual_server(r) != NGX_OK) { @@ -1167,13 +1206,13 @@ ngx_http_process_request_header(ngx_http if (r->headers_in.connection) { if (r->headers_in.connection->value.len == 5 && ngx_strcasecmp(r->headers_in.connection->value.data, "close") - == 0) + == 0) { r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; } else if (r->headers_in.connection->value.len == 10 && ngx_strcasecmp(r->headers_in.connection->value.data, - "keep-alive") == 0) + "keep-alive") == 0) { r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; @@ -1237,7 +1276,7 @@ static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r) { ngx_int_t rc; - ngx_uint_t i, n, key, found; + ngx_uint_t i, n, key; ngx_http_server_name_t *name; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; @@ -1259,8 +1298,6 @@ ngx_http_find_virtual_server(ngx_http_re n = r->virtual_names->names.nelts; } - found = 0; - for (i = 0; i < n; i++) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1275,9 +1312,7 @@ ngx_http_find_virtual_server(ngx_http_re if (rc == 0) { r->server_name = name[i].name; - - found = 1; - break; + goto found; } if (rc < 0) { @@ -1286,7 +1321,7 @@ ngx_http_find_virtual_server(ngx_http_re } } - if (!found && r->virtual_names->wildcards.nelts) { + if (r->virtual_names->wildcards.nelts) { name = r->virtual_names->wildcards.elts; for (i = 0; i < r->virtual_names->wildcards.nelts; i++) { @@ -1310,49 +1345,110 @@ ngx_http_find_virtual_server(ngx_http_re r->server_name.len = r->headers_in.host_name_len; r->server_name.data = r->headers_in.host->value.data; - found = 1; - break; + goto found; } } } - if (found) { - r->srv_conf = name[i].core_srv_conf->ctx->srv_conf; - r->loc_conf = name[i].core_srv_conf->ctx->loc_conf; - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - r->connection->log->file = clcf->err_log->file; - - if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - r->connection->log->log_level = clcf->err_log->log_level; - } - + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + if (cscf->restrict_host_names == NGX_HTTP_RESTRICT_HOST_OFF) { return NGX_OK; } - cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); - - if (cscf->restrict_host_names != NGX_HTTP_RESTRICT_HOST_OFF) { - return NGX_ERROR; + return NGX_ERROR; + +found: + + r->srv_conf = name[i].core_srv_conf->ctx->srv_conf; + r->loc_conf = name[i].core_srv_conf->ctx->loc_conf; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + r->connection->log->file = clcf->err_log->file; + + if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { + r->connection->log->log_level = clcf->err_log->log_level; } return NGX_OK; } +static void +ngx_http_request_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + + c = ev->data; + r = c->data; + + if (ev->write) { + r->write_event_handler(r); + + } else { + r->read_event_handler(r); + } +} + + void -ngx_http_finalize_request(ngx_http_request_t *r, int rc) +ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) { + ngx_http_request_t *pr; ngx_http_core_loc_conf_t *clcf; - /* r may be already destroyed when rc == NGX_DONE */ - - if (rc == NGX_DONE || r->main) { + if (rc == NGX_DONE) { + /* r may be already destroyed when rc == NGX_DONE */ + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http finalize request: %d, \"%V\"", rc, &r->uri); + + if (r->parent && rc >= NGX_HTTP_SPECIAL_RESPONSE) { + ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc)); return; } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http finalize request: %d", rc); + if (r->parent || rc == NGX_AGAIN) { + r->write_event_handler = ngx_http_writer; + } + + r->done = 1; + + if (r != r->connection->data) { + return; + } + + if (r->parent) { + + pr = r->parent; + + if (rc != NGX_AGAIN) { + pr->connection->data = pr; + } + + if (pr->postponed) { + + if (rc != NGX_AGAIN && pr->postponed->request == r) { + pr->postponed = pr->postponed->next; + + if (pr->postponed == NULL) { + return; + } + } + + if (pr->done) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http wake request: \"%V\"", &pr->uri); + + pr->write_event_handler(pr); + } + } + + return; + } if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -1379,7 +1475,7 @@ ngx_http_finalize_request(ngx_http_reque ngx_http_close_connection(r->connection); return; - } else if (rc == NGX_AGAIN) { + } else if (rc == NGX_AGAIN || r->out) { ngx_http_set_write_handler(r); return; } @@ -1430,17 +1526,15 @@ ngx_http_set_write_handler(ngx_http_requ ngx_event_t *wev; ngx_http_core_loc_conf_t *clcf; + r->http_state = NGX_HTTP_WRITING_REQUEST_STATE; + wev = r->connection->write; - wev->event_handler = ngx_http_writer; - - r->http_state = NGX_HTTP_WRITING_REQUEST_STATE; if (wev->ready && wev->delayed) { return; } - clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, - ngx_http_core_module); + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (!wev->delayed) { ngx_add_timer(wev, clcf->send_timeout); } @@ -1449,23 +1543,22 @@ ngx_http_set_write_handler(ngx_http_requ ngx_http_close_request(r, 0); ngx_http_close_connection(r->connection); } - - return; } -void -ngx_http_writer(ngx_event_t *wev) +static void +ngx_http_writer(ngx_http_request_t *r) { int rc; + ngx_event_t *wev; ngx_connection_t *c; - ngx_http_request_t *r; ngx_http_core_loc_conf_t *clcf; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http writer handler"); - - c = wev->data; - r = c->data; + c = r->connection; + wev = c->write; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, wev->log, 0, + "http writer handler: \"%V\"", &r->uri); if (wev->timedout) { if (!wev->delayed) { @@ -1510,10 +1603,21 @@ ngx_http_writer(ngx_event_t *wev) } } - rc = ngx_http_output_filter(r, NULL); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http writer output filter: %d", rc); + if (r->postponed) { + rc = ngx_http_postponed_handler(r); + + if (rc == NGX_DONE) { + /* r may be already destroyed when rc == NGX_DONE */ + return; + } + + } else { + rc = ngx_http_output_filter(r, NULL); + + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http writer output filter: %d, \"%V\"", rc, &r->uri); if (rc == NGX_AGAIN) { clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, @@ -1530,28 +1634,81 @@ ngx_http_writer(ngx_event_t *wev) return; } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http writer done"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, wev->log, 0, + "http writer done: \"%V\"", &r->uri); ngx_http_finalize_request(r, rc); } +static ngx_int_t +ngx_http_postponed_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_postponed_request_t *pr; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postpone handler \"%V\"", &r->uri); + + pr = r->postponed; + + if (pr->request == NULL) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postponed data \"%V\" %p", &r->uri, pr->out); + + rc = ngx_http_output_filter(r, NULL); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postponed output filter: %d", rc); + + if (rc == NGX_AGAIN) { + return rc; + } + + if (rc == NGX_ERROR) { + /* NGX_ERROR may be returned by any filter */ + r->connection->write->error = 1; + + ngx_http_finalize_request(r, rc); + + return NGX_DONE; + } + + pr = r->postponed; + + if (pr == NULL) { + return NGX_OK; + } + } + + r = pr->request; + r->connection->data = r; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postponed request \"%V\"", &r->uri); + + r->write_event_handler(r); + + return NGX_DONE; +} + + static void -ngx_http_block_read(ngx_event_t *rev) +ngx_http_block_read(ngx_http_request_t *r) { - ngx_connection_t *c; - ngx_http_request_t *r; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http read blocked"); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http read blocked"); /* aio does not call this handler */ - if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) { - if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { - c = rev->data; - r = c->data; + if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) + && r->connection->read->active) + { + if (ngx_del_event(r->connection->read, NGX_READ_EVENT, 0) + == NGX_ERROR) + { ngx_http_close_request(r, 0); - ngx_http_close_connection(c); + ngx_http_close_connection(r->connection); } } } @@ -1588,9 +1745,9 @@ ngx_http_discard_body(ngx_http_request_t } } - rev->event_handler = ngx_http_read_discarded_body_event; - - if (ngx_handle_level_read_event(rev) == NGX_ERROR) { + r->read_event_handler = ngx_http_read_discarded_body_handler; + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -1599,28 +1756,23 @@ ngx_http_discard_body(ngx_http_request_t static void -ngx_http_read_discarded_body_event(ngx_event_t *rev) +ngx_http_read_discarded_body_handler(ngx_http_request_t *r) { - ngx_int_t rc; - ngx_connection_t *c; - ngx_http_request_t *r; - - c = rev->data; - r = c->data; + ngx_int_t rc; rc = ngx_http_read_discarded_body(r); if (rc == NGX_AGAIN) { - if (ngx_handle_level_read_event(rev) == NGX_ERROR) { + if (ngx_handle_read_event(r->connection->read, 0) == NGX_ERROR) { ngx_http_close_request(r, rc); - ngx_http_close_connection(c); + ngx_http_close_connection(r->connection); return; } } if (rc != NGX_OK) { ngx_http_close_request(r, rc); - ngx_http_close_connection(c); + ngx_http_close_connection(r->connection); } } @@ -1737,13 +1889,13 @@ ngx_http_set_keepalive(ngx_http_request_ ngx_add_timer(rev, clcf->keepalive_timeout); - if (ngx_handle_level_read_event(rev) == NGX_ERROR) { + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { ngx_http_close_connection(c); return; } wev = c->write; - wev->event_handler = ngx_http_empty_handler; + wev->handler = ngx_http_empty_handler; if (b->pos < b->last) { @@ -1809,7 +1961,7 @@ ngx_http_set_keepalive(ngx_http_request_ hc->nbusy = 0; } - rev->event_handler = ngx_http_keepalive_handler; + rev->handler = ngx_http_keepalive_handler; if (wev->active) { if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { @@ -1944,7 +2096,7 @@ ngx_http_keepalive_handler(ngx_event_t * c->log_error = NGX_ERROR_INFO; if (n == NGX_AGAIN) { - if (ngx_handle_level_read_event(rev) == NGX_ERROR) { + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { ngx_http_close_connection(c); } @@ -1986,19 +2138,19 @@ ngx_http_set_lingering_close(ngx_http_re clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); rev = c->read; - rev->event_handler = ngx_http_lingering_close_handler; + rev->handler = ngx_http_lingering_close_handler; r->lingering_time = ngx_time() + clcf->lingering_time / 1000; ngx_add_timer(rev, clcf->lingering_timeout); - if (ngx_handle_level_read_event(rev) == NGX_ERROR) { + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { ngx_http_close_request(r, 0); ngx_http_close_connection(c); return; } wev = c->write; - wev->event_handler = ngx_http_empty_handler; + wev->handler = ngx_http_empty_handler; if (wev->active) { if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { @@ -2075,7 +2227,7 @@ ngx_http_lingering_close_handler(ngx_eve } while (rev->ready); - if (ngx_handle_level_read_event(rev) == NGX_ERROR) { + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { ngx_http_close_request(r, 0); ngx_http_close_connection(c); return; @@ -2102,6 +2254,16 @@ ngx_http_empty_handler(ngx_event_t *wev) } +void +ngx_http_request_empty_handler(ngx_http_request_t *r) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http requets empty handler"); + + return; +} + + ngx_int_t ngx_http_send_last(ngx_http_request_t *r) { @@ -2122,14 +2284,12 @@ ngx_http_send_last(ngx_http_request_t *r void -ngx_http_close_request(ngx_http_request_t *r, int error) +ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error) { - ngx_uint_t i; ngx_log_t *log; + struct linger linger; ngx_http_log_ctx_t *ctx; - ngx_http_cleanup_t *cleanup; ngx_http_core_loc_conf_t *clcf; - struct linger l; log = r->connection->log; @@ -2157,62 +2317,15 @@ ngx_http_close_request(ngx_http_request_ ngx_http_log_handler(r); - cleanup = r->cleanup.elts; - for (i = 0; i < r->cleanup.nelts; i++) { - if (!cleanup[i].valid) { - continue; - } - -#if (NGX_HTTP_CACHE) - - if (cleanup[i].cache) { - ngx_http_cache_unlock(cleanup[i].data.cache.hash, - cleanup[i].data.cache.cache, log); - continue; - } - -#endif - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http cleanup fd: %d", - cleanup[i].data.file.fd); - - if (ngx_close_file(cleanup[i].data.file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - cleanup[i].data.file.name); - } - } - - /* STUB */ - if (r->file.fd != NGX_INVALID_FILE) { - if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%V\" failed", &r->file.name); - } - } - - if (r->request_body - && r->request_body->temp_file - && r->request_body->temp_file->file.fd != NGX_INVALID_FILE) - { - if (ngx_close_file(r->request_body->temp_file->file.fd) - == NGX_FILE_ERROR) - { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " deleted file \"%V\" failed", - &r->request_body->temp_file->file.name); - } - } - if (r->connection->timedout) { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->reset_timedout_connection) { - l.l_onoff = 1; - l.l_linger = 0; + linger.l_onoff = 1; + linger.l_linger = 0; if (setsockopt(r->connection->fd, SOL_SOCKET, SO_LINGER, - (const void *) &l, sizeof(struct linger)) == -1) + (const void *) &linger, sizeof(struct linger)) == -1) { ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, "setsockopt(SO_LINGER) failed"); @@ -2220,7 +2333,7 @@ ngx_http_close_request(ngx_http_request_ } } - /* the variuos request strings were allocated from r->pool */ + /* the various request strings were allocated from r->pool */ ctx = log->data; ctx->request = NULL; @@ -2263,8 +2376,8 @@ ngx_http_close_connection(ngx_connection if (c->ssl) { if (ngx_ssl_shutdown(c) == NGX_AGAIN) { - c->read->event_handler = ngx_ssl_close_handler; - c->write->event_handler = ngx_ssl_close_handler; + c->read->handler = ngx_ssl_close_handler; + c->write->handler = ngx_ssl_close_handler; return; } } @@ -2290,26 +2403,31 @@ ngx_http_log_error(ngx_log_t *log, u_cha ngx_http_request_t *r; ngx_http_log_ctx_t *ctx; - p = buf; - - ctx = log->data; - if (log->action) { - p = ngx_snprintf(p, len, " while %s", log->action); + p = ngx_snprintf(buf, len, " while %s", log->action); len -= p - buf; buf = p; } + ctx = log->data; + p = ngx_snprintf(buf, len, ", client: %V", ctx->client); + len -= p - buf; r = ctx->request; - if (r == NULL) { - return p; + if (r) { + return r->log_handler(r, p, len); } - len -= p - buf; - buf = p; + return p; +} + + +static u_char * +ngx_http_log_error_handler(ngx_http_request_t *r, u_char *buf, size_t len) +{ + u_char *p; if (r->server_name.data) { p = ngx_snprintf(buf, len, ", server: %V", &r->server_name); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -8,6 +8,9 @@ #define _NGX_HTTP_REQUEST_H_INCLUDED_ +#define NGX_HTTP_MAX_REWRITE_CYCLES 10 + + #define NGX_HTTP_DISCARD_BUFFER_SIZE 4096 #define NGX_HTTP_LINGERING_BUFFER_SIZE 4096 @@ -114,10 +117,17 @@ typedef enum { typedef struct { ngx_str_t name; ngx_uint_t offset; + ngx_http_header_handler_pt handler; } ngx_http_header_t; typedef struct { + ngx_str_t name; + ngx_uint_t offset; +} ngx_http_header0_t; + + +typedef struct { ngx_list_t headers; ngx_table_elt_t *host; @@ -183,7 +193,6 @@ typedef struct { ngx_table_elt_t *server; ngx_table_elt_t *date; - ngx_table_elt_t *content_type; ngx_table_elt_t *content_length; ngx_table_elt_t *content_encoding; ngx_table_elt_t *location; @@ -192,12 +201,14 @@ typedef struct { ngx_table_elt_t *accept_ranges; ngx_table_elt_t *www_authenticate; ngx_table_elt_t *expires; - ngx_table_elt_t *cache_control; ngx_table_elt_t *etag; + ngx_str_t content_type; ngx_str_t charset; ngx_array_t ranges; + ngx_array_t cache_control; + off_t content_length_n; time_t date_time; time_t last_modified_time; @@ -215,24 +226,6 @@ typedef struct { } ngx_http_request_body_t; -struct ngx_http_cleanup_s { - union { - struct { - ngx_fd_t fd; - u_char *name; - } file; - - struct { - ngx_http_cache_hash_t *hash; - ngx_http_cache_entry_t *cache; - } cache; - } data; - - unsigned valid:1; - unsigned cache:1; -}; - - typedef struct { ngx_http_request_t *request; @@ -246,7 +239,18 @@ typedef struct { } ngx_http_connection_t; +typedef struct ngx_http_postponed_request_s ngx_http_postponed_request_t; + +struct ngx_http_postponed_request_s { + ngx_http_request_t *request; + ngx_chain_t *out; + ngx_http_postponed_request_t *next; +}; + + typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r); +typedef void (*ngx_http_event_handler_pt)(ngx_http_request_t *r); + struct ngx_http_request_s { uint32_t signature; /* "HTTP" */ @@ -258,12 +262,13 @@ struct ngx_http_request_s { void **srv_conf; void **loc_conf; + ngx_http_event_handler_pt read_event_handler; + ngx_http_event_handler_pt write_event_handler; + ngx_http_cache_t *cache; ngx_http_upstream_t *upstream; - ngx_file_t file; - ngx_pool_t *pool; ngx_buf_t *header_in; @@ -289,7 +294,10 @@ struct ngx_http_request_s { ngx_str_t method_name; ngx_str_t http_protocol; + ngx_chain_t *out; ngx_http_request_t *main; + ngx_http_request_t *parent; + ngx_http_postponed_request_t *postponed; uint32_t in_addr; ngx_uint_t port; @@ -303,19 +311,18 @@ struct ngx_http_request_s { ngx_http_variable_value_t **variables; - ngx_array_t cleanup; - /* used to learn the Apache compatible response length without a header */ size_t header_size; size_t request_length; - u_char *discarded_buffer; void **err_ctx; ngx_uint_t err_status; ngx_http_connection_t *http_connection; + ngx_http_log_handler_pt log_handler; + unsigned http_state:4; /* URI with "/." and on Win32 with "//" */ @@ -330,12 +337,11 @@ struct ngx_http_request_s { /* URI with "\0" or "%00" */ unsigned zero_in_uri:1; + unsigned valid_location:1; unsigned valid_unparsed_uri:1; unsigned uri_changed:1; unsigned uri_changes:4; - unsigned invalid_header:1; - unsigned low_case_exten:1; unsigned header_timeout_set:1; @@ -346,14 +352,16 @@ struct ngx_http_request_s { #if 0 unsigned cachable:1; #endif + unsigned pipeline:1; - unsigned plain_http:1; unsigned chunked:1; unsigned header_only:1; unsigned keepalive:1; unsigned lingering_close:1; + unsigned internal:1; unsigned closed:1; + unsigned done:1; unsigned filter_need_in_memory:1; unsigned filter_ssi_need_in_memory:1; @@ -365,8 +373,6 @@ struct ngx_http_request_s { unsigned stat_writing:1; #endif - ngx_uint_t headers_n; - /* used to parse HTTP headers */ ngx_uint_t state; u_char *uri_start; @@ -391,8 +397,7 @@ struct ngx_http_request_s { extern ngx_http_header_t ngx_http_headers_in[]; -extern ngx_http_header_t ngx_http_headers_out[]; - +extern ngx_http_header0_t ngx_http_headers_out[]; #endif /* _NGX_HTTP_REQUEST_H_INCLUDED_ */ diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -10,9 +10,8 @@ #include -static void ngx_http_read_client_request_body_handler(ngx_event_t *rev); -static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r, - ngx_connection_t *c); +static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); /* * on completion ngx_http_read_client_request_body() adds to @@ -29,10 +28,14 @@ ngx_http_read_client_request_body(ngx_ht ssize_t size; ngx_buf_t *b; ngx_chain_t *cl; - ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; + if (r->request_body) { + post_handler(r); + return NGX_OK; + } + rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -40,16 +43,6 @@ ngx_http_read_client_request_body(ngx_ht r->request_body = rb; - /* STUB */ - if (r->file.fd != NGX_INVALID_FILE) { - if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, - ngx_close_file_n " \"%V\" failed", &r->file.name); - } - r->file.fd = NGX_INVALID_FILE; - } - /**/ - if (r->headers_in.content_length_n <= 0) { post_handler(r); return NGX_OK; @@ -138,30 +131,23 @@ ngx_http_read_client_request_body(ngx_ht rb->bufs = cl; } - c = r->connection; + r->read_event_handler = ngx_http_read_client_request_body_handler; - c->read->event_handler = ngx_http_read_client_request_body_handler; - - return ngx_http_do_read_client_request_body(r, c); + return ngx_http_do_read_client_request_body(r); } static void -ngx_http_read_client_request_body_handler(ngx_event_t *rev) +ngx_http_read_client_request_body_handler(ngx_http_request_t *r) { - ngx_int_t rc; - ngx_connection_t *c; - ngx_http_request_t *r; + ngx_int_t rc; - c = rev->data; - r = c->data; - - if (rev->timedout) { + if (r->connection->read->timedout) { ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); return; } - rc = ngx_http_do_read_client_request_body(r, c); + rc = ngx_http_do_read_client_request_body(r); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { ngx_http_finalize_request(r, rc); @@ -170,16 +156,17 @@ ngx_http_read_client_request_body_handle static ngx_int_t -ngx_http_do_read_client_request_body(ngx_http_request_t *r, - ngx_connection_t *c) +ngx_http_do_read_client_request_body(ngx_http_request_t *r) { size_t size; ssize_t n; ngx_buf_t *b; ngx_temp_file_t *tf; + ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; + c = r->connection; rb = r->request_body; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -218,8 +205,6 @@ ngx_http_do_read_client_request_body(ngx } rb->temp_file->offset += n; - - rb->buf->pos = rb->buf->start; rb->buf->last = rb->buf->start; } diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -9,107 +9,274 @@ #include -ngx_int_t -ngx_http_script_compile_lite(ngx_conf_t *cf, ngx_array_t *sources, - ngx_array_t **lengths, ngx_array_t **values, - ngx_http_script_compile_lite_start_pt start, - ngx_http_script_compile_lite_end_pt end) +#define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code + +static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL; + + +ngx_uint_t +ngx_http_script_variables_count(ngx_str_t *value) { - uintptr_t *code; - ngx_uint_t i; - ngx_table_elt_t *src; - ngx_http_variable_t *var; - ngx_http_script_var_code_t *var_code; + ngx_uint_t i, n; - if (sources->nelts == 0) { - return NGX_OK; + for (n = 0, i = 0; i < value->len; i++) { + if (value->data[i] == '$') { + n++; + } } - if (*lengths == NULL) { - *lengths = ngx_array_create(cf->pool, 64, 1); - if (*lengths == NULL) { + return n; +} + + +ngx_int_t +ngx_http_script_compile(ngx_http_script_compile_t *sc) +{ + u_char ch; + size_t size; + ngx_int_t index; + ngx_str_t name; + uintptr_t *code; + ngx_uint_t i, n, bracket; + ngx_http_script_var_code_t *var_code; + ngx_http_script_copy_code_t *copy; + ngx_http_script_copy_capture_code_t *copy_capture; + + if (*sc->lengths == NULL) { + n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) + + sizeof(ngx_http_script_var_code_t)) + + sizeof(uintptr_t); + + *sc->lengths = ngx_array_create(sc->cf->pool, n, 1); + if (*sc->lengths == NULL) { + return NGX_ERROR; + } + } + + + if (*sc->values == NULL) { + n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) + + sizeof(ngx_http_script_var_code_t)) + + sizeof(uintptr_t) + + sc->source->len + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + *sc->values = ngx_array_create(sc->cf->pool, n, 1); + if (*sc->values == NULL) { return NGX_ERROR; } } - if (*values == NULL) { - *values = ngx_array_create(cf->pool, 256, 1); - if (*values == NULL) { - return NGX_ERROR; - } - } + sc->variables = 0; + + for (i = 0; i < sc->source->len; /* void */ ) { + + name.len = 0; + + if (sc->source->data[i] == '$') { + + if (++i == sc->source->len) { + goto invalid_variable; + } + + if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { + + copy_capture = ngx_http_script_add_code(*sc->lengths, + sizeof(ngx_http_script_copy_capture_code_t), + NULL); + if (copy_capture == NULL) { + return NGX_ERROR; + } + + copy_capture->code = (ngx_http_script_code_pt) + ngx_http_script_copy_capture_len_code; + copy_capture->n = 2 * (sc->source->data[i] - '0'); + + copy_capture = ngx_http_script_add_code(*sc->values, + sizeof(ngx_http_script_copy_capture_code_t), + &sc->main); + if (copy_capture == NULL) { + return NGX_ERROR; + } + + copy_capture->code = ngx_http_script_copy_capture_code; + copy_capture->n = sc->source->data[i] - '0'; + + if (sc->ncaptures < copy_capture->n) { + sc->ncaptures = copy_capture->n; + } + + copy_capture->n *= 2; - src = sources->elts; - for (i = 0; i < sources->nelts; i++) { + i++; + + continue; + } + + if (sc->source->data[i] == '{') { + bracket = 1; + + if (++i == sc->source->len) { + goto invalid_variable; + } + + name.data = &sc->source->data[i]; + + } else { + bracket = 0; + name.data = &sc->source->data[i]; + } + + for ( /* void */ ; i < sc->source->len; i++, name.len++) { + ch = sc->source->data[i]; - if (src[i].value.data[0] == '$') { - if (start(&src[i], *lengths, *values, 0) != NGX_OK) { + if (ch == '}' && bracket) { + i++; + bracket = 0; + break; + } + + if ((ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') + || (ch >= '0' && ch <= '9') + || ch == '_') + { + continue; + } + + break; + } + + if (bracket) { + ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, + "the closing bracket in \"%V\" " + "variable is missing", &name); return NGX_ERROR; } - src[i].value.len--; - src[i].value.data++; + if (name.len == 0) { + goto invalid_variable; + } - var = ngx_http_add_variable(cf, &src[i].value, 0); + sc->variables++; - if (var == NULL) { + index = ngx_http_get_variable_index(sc->cf, &name); + + if (index == NGX_ERROR) { return NGX_ERROR; } - var_code = ngx_array_push_n(*lengths, - sizeof(ngx_http_script_var_code_t)); + var_code = ngx_http_script_add_code(*sc->lengths, + sizeof(ngx_http_script_var_code_t), + NULL); if (var_code == NULL) { return NGX_ERROR; } var_code->code = (ngx_http_script_code_pt) - ngx_http_script_copy_var_len; - var_code->index = var->index; + ngx_http_script_copy_var_len_code; + var_code->index = (uintptr_t) index; - var_code = ngx_array_push_n(*values, - sizeof(ngx_http_script_var_code_t)); + var_code = ngx_http_script_add_code(*sc->values, + sizeof(ngx_http_script_var_code_t), + &sc->main); if (var_code == NULL) { return NGX_ERROR; } - var_code->code = ngx_http_script_copy_var; - var_code->index = var->index; + var_code->code = ngx_http_script_copy_var_code; + var_code->index = (uintptr_t) index; + + continue; + } + if (sc->source->data[i] == '?' && sc->compile_args) { + sc->args = 1; + sc->compile_args = 0; - if (end(*lengths, *values) != NGX_OK) { + code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), + &sc->main); + if (code == NULL) { return NGX_ERROR; } + *code = (uintptr_t) ngx_http_script_start_args_code; + + i++; + continue; } - if (start(&src[i], *lengths, *values, 1) != NGX_OK) { + name.data = &sc->source->data[i]; + + while (i < sc->source->len + && sc->source->data[i] != '$' + && !(sc->source->data[i] == '?' && sc->compile_args)) + { + i++; + name.len++; + } + + sc->size += name.len; + + copy = ngx_http_script_add_code(*sc->lengths, + sizeof(ngx_http_script_copy_code_t), + NULL); + if (copy == NULL) { return NGX_ERROR; } - } + + copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; + copy->len = name.len; + + size = (sizeof(ngx_http_script_copy_code_t) + name.len + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); - code = ngx_array_push_n(*lengths, sizeof(uintptr_t)); - if (code == NULL) { - return NGX_ERROR; + copy = ngx_http_script_add_code(*sc->values, size, &sc->main); + if (copy == NULL) { + return NGX_ERROR; + } + + copy->code = ngx_http_script_copy_code; + copy->len = name.len; + + ngx_memcpy((u_char *) copy + sizeof(ngx_http_script_copy_code_t), + name.data, name.len); } - *code = (uintptr_t) NULL; + if (sc->complete_lengths) { + code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL); + if (code == NULL) { + return NGX_ERROR; + } - code = ngx_array_push_n(*values, sizeof(uintptr_t)); - if (code == NULL) { - return NGX_ERROR; + *code = (uintptr_t) NULL; } - *code = (uintptr_t) NULL; + if (sc->complete_values) { + code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + } return NGX_OK; + +invalid_variable: + + ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name"); + + return NGX_ERROR; } -#if 0 - -static void * +void * ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size) { if (*codes == NULL) { @@ -122,51 +289,79 @@ ngx_http_script_start_code(ngx_pool_t *p return ngx_array_push_n(*codes, size); } -#endif + +void * +ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code) +{ + u_char *elts, **p; + void *new; + + elts = codes->elts; + + new = ngx_array_push_n(codes, size); + if (new == NULL) { + return NGX_CONF_ERROR; + } + + if (code) { + if (elts != codes->elts) { + p = code; + *p += (u_char *) codes->elts - elts; + } + } + + return new; +} size_t -ngx_http_script_copy_len(ngx_http_script_engine_t *e) +ngx_http_script_copy_len_code(ngx_http_script_engine_t *e) { ngx_http_script_copy_code_t *code; - code = (ngx_http_script_copy_code_t *) e->lite.ip; + code = (ngx_http_script_copy_code_t *) e->ip; - e->lite.ip += sizeof(ngx_http_script_copy_code_t); + e->ip += sizeof(ngx_http_script_copy_code_t); return code->len; } void -ngx_http_script_copy(ngx_http_script_engine_t *e) +ngx_http_script_copy_code(ngx_http_script_engine_t *e) { ngx_http_script_copy_code_t *code; - code = (ngx_http_script_copy_code_t *) e->lite.ip; + code = (ngx_http_script_copy_code_t *) e->ip; + + if (!e->skip) { + e->pos = ngx_cpymem(e->pos, e->ip + sizeof(ngx_http_script_copy_code_t), + code->len); + } - e->lite.pos = ngx_cpymem(e->lite.pos, - e->lite.ip + sizeof(ngx_http_script_copy_code_t), - code->len); + e->ip += sizeof(ngx_http_script_copy_code_t) + + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); - e->lite.ip += sizeof(ngx_http_script_copy_code_t) - + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); + if (e->log) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script copy: \"%V\"", &e->buf); + } } size_t -ngx_http_script_copy_var_len(ngx_http_script_engine_t *e) +ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e) { ngx_http_variable_value_t *value; ngx_http_script_var_code_t *code; - code = (ngx_http_script_var_code_t *) e->lite.ip; + code = (ngx_http_script_var_code_t *) e->ip; - e->lite.ip += sizeof(ngx_http_script_var_code_t); + e->ip += sizeof(ngx_http_script_var_code_t); - value = ngx_http_get_indexed_variable(e->lite.request, code->index); + value = ngx_http_get_indexed_variable(e->request, code->index); - if (value == NULL || value == NGX_HTTP_VARIABLE_NOT_FOUND) { + if (value == NULL || value == NGX_HTTP_VAR_NOT_FOUND) { return 0; } @@ -175,20 +370,456 @@ ngx_http_script_copy_var_len(ngx_http_sc void -ngx_http_script_copy_var(ngx_http_script_engine_t *e) +ngx_http_script_copy_var_code(ngx_http_script_engine_t *e) { ngx_http_variable_value_t *value; ngx_http_script_var_code_t *code; - code = (ngx_http_script_var_code_t *) e->lite.ip; + code = (ngx_http_script_var_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_var_code_t); + + if (!e->skip) { + value = ngx_http_get_indexed_variable(e->request, code->index); + + if (value == NULL || value == NGX_HTTP_VAR_NOT_FOUND) { + return; + } + + e->pos = ngx_cpymem(e->pos, value->text.data, value->text.len); + + if (e->log) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script var: \"%V\"", &e->buf); + } + } +} + + +size_t +ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e) +{ + ngx_http_script_copy_capture_code_t *code; + + code = (ngx_http_script_copy_capture_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_copy_capture_code_t); + + if ((e->args || e->quote) + && (e->request->quoted_uri || e->request->plus_in_uri)) + { + return e->captures[code->n + 1] - e->captures[code->n] + + ngx_escape_uri(NULL, + &e->line->data[e->captures[code->n]], + e->captures[code->n + 1] - e->captures[code->n], + NGX_ESCAPE_ARGS); + } else { + return e->captures[code->n + 1] - e->captures[code->n]; + } +} + + +void +ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e) +{ + ngx_http_script_copy_capture_code_t *code; + + code = (ngx_http_script_copy_capture_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_copy_capture_code_t); - e->lite.ip += sizeof(ngx_http_script_var_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_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script capture: \"%V\"", &e->buf); +} + + +void +ngx_http_script_start_args_code(ngx_http_script_engine_t *e) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script args"); + + e->args = e->pos; + e->ip += sizeof(uintptr_t); +} + + +void +ngx_http_script_regex_start_code(ngx_http_script_engine_t *e) +{ + size_t len; + ngx_int_t rc; + ngx_uint_t n; + ngx_http_request_t *r; + ngx_http_script_engine_t le; + ngx_http_script_len_code_pt lcode; + ngx_http_script_regex_code_t *code; + + code = (ngx_http_script_regex_code_t *) e->ip; + + r = e->request; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http script regex: \"%V\"", &code->name); + + if (code->uri) { + e->line = &r->uri; + } else { + e->sp--; + e->line = &e->sp->text; + } - value = ngx_http_get_indexed_variable(e->lite.request, code->index); + rc = ngx_regex_exec(code->regex, e->line, e->captures, code->ncaptures); + + if (rc == NGX_REGEX_NO_MATCHED) { + if (e->log) { + ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, + "\"%V\" does not match \"%V\"", &code->name, e->line); + } + + if (code->test) { + e->sp->value = 0; + e->sp->text.len = 0; + e->sp->text.data = (u_char *) ""; + e->sp++; + + e->ip += sizeof(ngx_http_script_regex_code_t); + return; + } + + 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_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + + if (e->log) { + ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, + "\"%V\" matches \"%V\"", &code->name, e->line); + } + + if (code->test) { + e->sp->value = 1; + e->sp->text.len = 1; + e->sp->text.data = (u_char *) "1"; + e->sp++; + + e->ip += sizeof(ngx_http_script_regex_code_t); + return; + } + + if (code->status) { + e->status = code->status; - if (value == NULL || value == NGX_HTTP_VARIABLE_NOT_FOUND) { + if (!code->redirect) { + e->ip = ngx_http_script_exit; + return; + } + } + + if (code->uri) { + r->internal = 1; + r->valid_unparsed_uri = 0; + + if (code->break_cycle) { + r->valid_location = 0; + + } else { + r->uri_changed = 1; + } + } + + if (code->lengths == NULL) { + e->buf.len = code->size; + + if (code->uri) { + 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); + } + } + + for (n = 1; n < (ngx_uint_t) rc; n++) { + e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n]; + } + + } else { + ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); + + le.ip = code->lengths->elts; + le.request = r; + le.captures = e->captures; + + len = 1; /* reserve 1 byte for possible "?" */ + + while (*(uintptr_t *) le.ip) { + lcode = *(ngx_http_script_len_code_pt *) le.ip; + len += lcode(&le); + } + + e->buf.len = len; + } + + if (code->args && code->add_args && r->args.len) { + e->buf.len += r->args.len + 1; + } + + e->buf.data = ngx_palloc(r->pool, e->buf.len); + if (e->buf.data == NULL) { + e->ip = ngx_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; return; } - e->lite.pos = ngx_cpymem(e->lite.pos, value->text.data, value->text.len); + e->quote = code->redirect; + + e->pos = e->buf.data; + + e->ip += sizeof(ngx_http_script_regex_code_t); +} + + +void +ngx_http_script_regex_end_code(ngx_http_script_engine_t *e) +{ + ngx_http_request_t *r; + ngx_http_script_regex_end_code_t *code; + + code = (ngx_http_script_regex_end_code_t *) e->ip; + + r = e->request; + + e->quote = 0; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http script regex end"); + + if (code->redirect) { + + if (code->add_args && r->args.len) { + *e->pos++ = (u_char) (code->args ? '&' : '?'); + e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len); + } + + e->buf.len = e->pos - e->buf.data; + + if (e->log) { + ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, + "rewritten redirect: \"%V\"", &e->buf); + } + + r->headers_out.location = ngx_list_push(&r->headers_out.headers); + if (r->headers_out.location == NULL) { + e->ip = ngx_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + + r->headers_out.location->hash = 1; + 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_script_regex_end_code_t); + return; + } + + if (e->args) { + e->buf.len = e->args - e->buf.data; + + if (code->add_args && r->args.len) { + *e->pos++ = '&'; + e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len); + } + + r->args.len = e->pos - e->args; + r->args.data = e->args; + + e->args = NULL; + + } else { + e->buf.len = e->pos - e->buf.data; + } + + if (e->log) { + ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, + "rewritten data: \"%V\", args: \"%V\"", + &e->buf, &r->args); + } + + if (code->uri) { + r->uri = e->buf; + + if (ngx_http_set_exten(r) != NGX_OK) { + e->ip = ngx_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + } + + e->ip += sizeof(ngx_http_script_regex_end_code_t); +} + + +void +ngx_http_script_return_code(ngx_http_script_engine_t *e) +{ + ngx_http_script_return_code_t *code; + + code = (ngx_http_script_return_code_t *) e->ip; + + e->status = code->status; + + e->ip += sizeof(ngx_http_script_return_code_t) - sizeof(uintptr_t); } + + +void +ngx_http_script_if_code(ngx_http_script_engine_t *e) +{ + ngx_http_script_if_code_t *code; + + code = (ngx_http_script_if_code_t *) e->ip; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script if"); + + e->sp--; + + if (e->sp->value) { + if (code->loc_conf) { + e->request->loc_conf = code->loc_conf; + } + + e->ip += sizeof(ngx_http_script_if_code_t); + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script if false"); + + e->ip += code->next; +} + + +void +ngx_http_script_value_code(ngx_http_script_engine_t *e) +{ + ngx_http_script_value_code_t *code; + + code = (ngx_http_script_value_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_value_code_t); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script value"); + + e->sp->value = (ngx_uint_t) code->value; + e->sp->text.len = (size_t) code->text_len; + e->sp->text.data = (u_char *) code->text_data; + e->sp++; +} + + +void +ngx_http_script_set_var_code(ngx_http_script_engine_t *e) +{ + ngx_http_request_t *r; + ngx_http_variable_value_t *value; + ngx_http_core_main_conf_t *cmcf; + ngx_http_script_var_code_t *code; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script set var"); + + code = (ngx_http_script_var_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_var_code_t); + + r = e->request; + + if (r->variables == NULL) { + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts + * sizeof(ngx_http_variable_value_t *)); + if (r->variables == NULL) { + e->ip = ngx_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + } + + value = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (value == NULL) { + e->ip = ngx_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + + e->sp--; + + *value = *e->sp; + + r->variables[code->index] = value; +} + + +void +ngx_http_script_var_code(ngx_http_script_engine_t *e) +{ + ngx_http_variable_value_t *value; + ngx_http_script_var_code_t *code; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script var"); + + code = (ngx_http_script_var_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_var_code_t); + + value = ngx_http_get_indexed_variable(e->request, code->index); + + if (value == NULL || value == NGX_HTTP_VAR_NOT_FOUND) { + e->sp->value = 0; + e->sp->text.len = 0; + e->sp->text.data = (u_char *) ""; + e->sp++; + + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script var: %ui, \"%V\"", value->value, &value->text); + + *e->sp = *value; + e->sp++; +} + + +void +ngx_http_script_nop_code(ngx_http_script_engine_t *e) +{ + e->ip += sizeof(uintptr_t); +} diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -16,23 +16,48 @@ typedef struct { u_char *ip; u_char *pos; - ngx_http_request_t *request; -} ngx_http_script_lite_engine_t; + ngx_http_variable_value_t *sp; + + ngx_str_t buf; + ngx_str_t *line; + + /* the start of the rewritten arguments */ + u_char *args; + unsigned skip:1; + unsigned quote:1; + unsigned log:1; -typedef struct { - ngx_http_script_lite_engine_t lite; + int *captures; + + ngx_int_t status; + ngx_http_request_t *request; } ngx_http_script_engine_t; -typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e); -typedef size_t (*ngx_http_script_len_code_pt) - (ngx_http_script_lite_engine_t *e); +typedef struct { + ngx_conf_t *cf; + ngx_str_t *source; + ngx_array_t **lengths; + ngx_array_t **values; + + ngx_uint_t variables; + ngx_uint_t ncaptures; + ngx_uint_t size; + + void *main; -typedef ngx_int_t (*ngx_http_script_compile_lite_start_pt) (ngx_table_elt_t *h, - ngx_array_t *lengths, ngx_array_t *values, ngx_uint_t value); -typedef ngx_int_t (*ngx_http_script_compile_lite_end_pt) (ngx_array_t *lengths, - ngx_array_t *values); + unsigned compile_args:1; + unsigned compile_null:1; + unsigned complete_lengths:1; + unsigned complete_values:1; + + unsigned args:1; +} ngx_http_script_compile_t; + + +typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e); +typedef size_t (*ngx_http_script_len_code_pt) (ngx_http_script_engine_t *e); typedef struct { @@ -47,20 +72,93 @@ typedef struct { } ngx_http_script_var_code_t; -ngx_int_t ngx_http_script_compile_lite(ngx_conf_t *cf, ngx_array_t *sources, - ngx_array_t **lengths, ngx_array_t **values, - ngx_http_script_compile_lite_start_pt start, - ngx_http_script_compile_lite_end_pt end); +typedef struct { + ngx_http_script_code_pt code; + uintptr_t n; +} ngx_http_script_copy_capture_code_t; + + +typedef struct { + ngx_http_script_code_pt code; + ngx_regex_t *regex; + ngx_array_t *lengths; + uintptr_t size; + uintptr_t ncaptures; + uintptr_t status; + uintptr_t next; + + uintptr_t test:1; + uintptr_t uri:1; + uintptr_t args:1; + + /* add the r->args to the new arguments */ + uintptr_t add_args:1; + + uintptr_t redirect:1; + uintptr_t break_cycle:1; + + ngx_str_t name; +} ngx_http_script_regex_code_t; + + +typedef struct { + ngx_http_script_code_pt code; + + uintptr_t uri:1; + uintptr_t args:1; + + /* add the r->args to the new arguments */ + uintptr_t add_args:1; + + uintptr_t redirect:1; +} ngx_http_script_regex_end_code_t; -static void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, - size_t size); +typedef struct { + ngx_http_script_code_pt code; + uintptr_t status; + uintptr_t null; +} ngx_http_script_return_code_t; + + +typedef struct { + ngx_http_script_code_pt code; + uintptr_t next; + void **loc_conf; +} ngx_http_script_if_code_t; + + +typedef struct { + ngx_http_script_code_pt code; + uintptr_t value; + uintptr_t text_len; + uintptr_t text_data; +} ngx_http_script_value_code_t; + -size_t ngx_http_script_copy_len(ngx_http_script_engine_t *e); -void ngx_http_script_copy(ngx_http_script_engine_t *e); -size_t ngx_http_script_copy_var_len(ngx_http_script_engine_t *e); -void ngx_http_script_copy_var(ngx_http_script_engine_t *e); +ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value); +ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc); + +void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, + size_t size); +void *ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code); +size_t ngx_http_script_copy_len_code(ngx_http_script_engine_t *e); +void ngx_http_script_copy_code(ngx_http_script_engine_t *e); +size_t ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e); +void ngx_http_script_copy_var_code(ngx_http_script_engine_t *e); +size_t ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e); +void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e); +void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e); +void ngx_http_script_regex_end_code(ngx_http_script_engine_t *e); +void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e); +void ngx_http_script_start_args_code(ngx_http_script_engine_t *e); +void ngx_http_script_return_code(ngx_http_script_engine_t *e); +void ngx_http_script_if_code(ngx_http_script_engine_t *e); +void ngx_http_script_value_code(ngx_http_script_engine_t *e); +void ngx_http_script_set_var_code(ngx_http_script_engine_t *e); +void ngx_http_script_var_code(ngx_http_script_engine_t *e); +void ngx_http_script_nop_code(ngx_http_script_engine_t *e); #endif /* _NGX_HTTP_SCRIPT_H_INCLUDED_ */ diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -331,22 +331,15 @@ ngx_http_special_response_handler(ngx_ht msie_padding = 1; } - r->headers_out.content_type = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.content_type == NULL) { - return NGX_ERROR; - } - - r->headers_out.content_type->key.len = sizeof("Content-Type") - 1; - r->headers_out.content_type->key.data = (u_char *) "Content-Type"; - r->headers_out.content_type->value.len = sizeof("text/html") - 1; - r->headers_out.content_type->value.data = (u_char *) "text/html"; + r->headers_out.content_type.len = sizeof("text/html") - 1; + r->headers_out.content_type.data = (u_char *) "text/html"; } else { r->headers_out.content_length_n = -1; } if (r->headers_out.content_length) { - r->headers_out.content_length->key.len = 0; + r->headers_out.content_length->hash = 0; r->headers_out.content_length = NULL; } @@ -415,7 +408,11 @@ ngx_http_special_response_handler(ngx_ht cl->buf = b; } - b->last_buf = 1; + if (r->main == NULL) { + b->last_buf = 1; + } + + b->last_in_chain = 1; cl->next = NULL; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -6,14 +6,17 @@ #include #include +#include #include -#include -static void ngx_http_upstream_check_broken_connection(ngx_event_t *ev); +static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r); +static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r); +static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, + ngx_event_t *ev); static void ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u); -static void ngx_http_upstream_reinit(ngx_http_request_t *r, +static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u); static void ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u); @@ -21,6 +24,7 @@ static void ngx_http_upstream_send_reque 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); +static void ngx_http_upstream_process_downstream(ngx_http_request_t *r); static void ngx_http_upstream_process_body(ngx_event_t *ev); static void ngx_http_upstream_dummy_handler(ngx_event_t *wev); static void ngx_http_upstream_next(ngx_http_request_t *r, @@ -28,19 +32,125 @@ static void ngx_http_upstream_next(ngx_h static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t rc); +static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t + ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t + ngx_http_upstream_conditional_copy_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t + ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +#if (NGX_HTTP_GZIP) +static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +#endif + static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r, uintptr_t data); static u_char *ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); +static u_char *ngx_http_upstream_log_error(ngx_http_request_t *r, u_char *buf, + size_t len); static ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf); +static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf); +static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf); + + +ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { + + { ngx_string("Status"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, status), + /* STUB */ ngx_http_upstream_ignore_header_line, 0 }, + + { ngx_string("Content-Type"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, content_type), + ngx_http_upstream_copy_content_type, 0 }, + + { ngx_string("Content-Length"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, content_length), + ngx_http_upstream_copy_content_length, 0 }, + + { ngx_string("Date"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, date), + ngx_http_upstream_conditional_copy_header_line, + offsetof(ngx_http_upstream_conf_t, pass_date) }, + + { ngx_string("Server"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, server), + ngx_http_upstream_conditional_copy_header_line, + offsetof(ngx_http_upstream_conf_t, pass_server) }, + + { ngx_string("Location"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_rewrite_location, 0 }, + + { ngx_string("Refresh"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_rewrite_refresh, 0 }, + + { ngx_string("Cache-Control"), + ngx_http_upstream_process_multi_header_lines, + offsetof(ngx_http_upstream_headers_in_t, cache_control), + ngx_http_upstream_copy_multi_header_lines, + offsetof(ngx_http_headers_out_t, cache_control) }, + + { ngx_string("Connection"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_ignore_header_line, 0 }, + + { ngx_string("X-Pad"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_ignore_header_line, 0 }, + + { ngx_string("X-Powered-By"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_conditional_copy_header_line, + offsetof(ngx_http_upstream_conf_t, pass_x_powered_by) }, + + { ngx_string("X-Accel-Expires"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, x_accel_expires), + ngx_http_upstream_conditional_copy_header_line, + offsetof(ngx_http_upstream_conf_t, pass_x_accel_expires) }, + +#if (NGX_HTTP_GZIP) + { ngx_string("Content-Encoding"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, content_encoding), + ngx_http_upstream_copy_content_encoding, 0 }, +#endif + + { ngx_null_string, NULL, 0, NULL, 0 } +}; ngx_http_module_t ngx_http_upstream_module_ctx = { - ngx_http_upstream_add_log_formats, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ + ngx_http_upstream_add_log_formats, /* preconfiguration */ + NULL, /* postconfiguration */ + + ngx_http_upstream_create_main_conf, /* create main configuration */ + ngx_http_core_init_main_conf, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ @@ -51,7 +161,7 @@ ngx_http_module_t ngx_http_upstream_mod ngx_module_t ngx_http_upstream_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_upstream_module_ctx, /* module context */ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -77,8 +187,9 @@ char *ngx_http_upstream_header_errors[] void ngx_http_upstream_init(ngx_http_request_t *r) { - ngx_connection_t *c; - ngx_http_upstream_t *u; + ngx_connection_t *c; + ngx_http_upstream_t *u; + ngx_http_core_loc_conf_t *clcf; c = r->connection; @@ -89,11 +200,11 @@ ngx_http_upstream_init(ngx_http_request_ ngx_del_timer(c->read); } - c->read->event_handler = ngx_http_upstream_check_broken_connection; + r->read_event_handler = ngx_http_upstream_rd_check_broken_connection; if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { - c->write->event_handler = ngx_http_upstream_check_broken_connection; + r->write_event_handler = ngx_http_upstream_wr_check_broken_connection; if (!c->write->active) { if (ngx_add_event(c->write, NGX_WRITE_EVENT, @@ -107,7 +218,14 @@ ngx_http_upstream_init(ngx_http_request_ u = r->upstream; - u->method = r->method; + u->request_bufs = r->request_body->bufs; + + if (u->conf->method == NGX_CONF_UNSET_UINT) { + u->method = r->method; + + } else { + u->method = u->conf->method; + } if (u->create_request(r) == NGX_ERROR) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -115,14 +233,15 @@ ngx_http_upstream_init(ngx_http_request_ } u->peer.log = r->connection->log; - u->saved_log_ctx = r->connection->log->data; - u->saved_log_handler = r->connection->log->handler; - r->connection->log->data = u->log_ctx; - r->connection->log->handler = u->log_handler; + u->saved_log_handler = r->log_handler; + r->log_handler = ngx_http_upstream_log_error; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); u->output.sendfile = r->connection->sendfile; u->output.pool = r->pool; u->output.bufs.num = 1; + u->output.bufs.size = clcf->client_body_buffer_size; u->output.output_filter = ngx_chain_writer; u->output.filter_ctx = &u->writer; @@ -148,20 +267,33 @@ ngx_http_upstream_init(ngx_http_request_ static void -ngx_http_upstream_check_broken_connection(ngx_event_t *ev) +ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r) +{ + ngx_http_upstream_check_broken_connection(r, r->connection->read); +} + + +static void +ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r) +{ + ngx_http_upstream_check_broken_connection(r, r->connection->write); +} + + +static void +ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, + ngx_event_t *ev) { int n; char buf[1]; ngx_err_t err; ngx_connection_t *c; - ngx_http_request_t *r; ngx_http_upstream_t *u; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, "http upstream check client, write event:%d", ev->write); - c = ev->data; - r = c->data; + c = r->connection; u = r->upstream; if (u->peer.connection == NULL) { @@ -296,8 +428,8 @@ ngx_http_upstream_connect(ngx_http_reque c = u->peer.connection; c->data = r; - c->write->event_handler = ngx_http_upstream_send_request_handler; - c->read->event_handler = ngx_http_upstream_process_header; + c->write->handler = ngx_http_upstream_send_request_handler; + c->read->handler = ngx_http_upstream_process_header; c->sendfile = r->connection->sendfile; @@ -312,11 +444,20 @@ ngx_http_upstream_connect(ngx_http_reque u->writer.limit = 0; if (u->request_sent) { - ngx_http_upstream_reinit(r, u); + if (ngx_http_upstream_reinit(r, u) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } } - if (r->request_body->buf) { - if (r->request_body->temp_file) { + if (r->request_body) { + if (r->request_body->temp_file && r->main == NULL) { + + /* + * the r->request_body->buf can be reused for one request only, + * the subrequests should allocate their own temporay bufs + */ u->output.free = ngx_alloc_chain_link(r->pool); if (u->output.free == NULL) { @@ -332,9 +473,6 @@ ngx_http_upstream_connect(ngx_http_reque r->request_body->buf->pos = r->request_body->buf->start; r->request_body->buf->last = r->request_body->buf->start; r->request_body->buf->tag = u->output.tag; - - } else { - r->request_body->buf->pos = r->request_body->buf->start; } } @@ -351,29 +489,51 @@ ngx_http_upstream_connect(ngx_http_reque } -static void +static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_chain_t *cl; - if (u->reinit_request(r) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + if (u->reinit_request(r) != NGX_OK) { + return NGX_ERROR; + } + + ngx_memzero(&r->upstream->headers_in, + sizeof(ngx_http_upstream_headers_in_t)); + + if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 8, + sizeof(ngx_table_elt_t)) != NGX_OK) + { + return NGX_ERROR; } /* reinit the request chain */ - for (cl = r->request_body->bufs; cl; cl = cl->next) { + for (cl = u->request_bufs; cl; cl = cl->next) { cl->buf->pos = cl->buf->start; cl->buf->file_pos = 0; } - /* reinit the ngx_output_chain() context */ + /* reinit the subrequest's ngx_output_chain() context */ + + if (r->request_body) { + if (r->request_body->temp_file && r->main && u->output.buf) { + + u->output.free = ngx_alloc_chain_link(r->pool); + if (u->output.free == NULL) { + return NGX_ERROR; + } + + u->output.free->buf = u->output.buf; + u->output.free->next = NULL; + + u->output.buf->pos = u->output.buf->start; + u->output.buf->last = u->output.buf->start; + } + } u->output.buf = NULL; u->output.in = NULL; - u->output.free = NULL; u->output.busy = NULL; /* reinit u->header_in buffer */ @@ -388,20 +548,22 @@ ngx_http_upstream_reinit(ngx_http_reques u->header_in.last = u->header_in.start; } #else + u->header_in.pos = u->header_in.start; u->header_in.last = u->header_in.start; + #endif /* add one more state */ u->state = ngx_array_push(&u->states); if (u->state == NULL) { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + return NGX_ERROR; } ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); + + return NGX_OK; } @@ -433,8 +595,7 @@ ngx_http_upstream_send_request(ngx_http_ c->log->action = "sending request to upstream"; - rc = ngx_output_chain(&u->output, - u->request_sent ? NULL : r->request_body->bufs); + rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs); u->request_sent = 1; @@ -494,9 +655,9 @@ ngx_http_upstream_send_request(ngx_http_ } #endif - c->write->event_handler = ngx_http_upstream_dummy_handler; + c->write->handler = ngx_http_upstream_dummy_handler; - if (ngx_handle_level_write_event(c->write) == NGX_ERROR) { + if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -575,6 +736,14 @@ ngx_http_upstream_process_header(ngx_eve u->header_in.tag = u->output.tag; + if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 8, + sizeof(ngx_table_elt_t)) == NGX_ERROR) + { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + #if 0 if (u->cache) { u->header_in.pos += u->cache->ctx.header_size; @@ -631,7 +800,7 @@ ngx_http_upstream_process_header(ngx_eve ngx_add_timer(rev, u->read_timeout); #endif - if (u->header_in.last == u->header_in.end) { + if (u->header_in.pos == u->header_in.end) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "upstream sent too big header"); @@ -661,6 +830,38 @@ ngx_http_upstream_process_header(ngx_eve /* rc == NGX_OK */ + if (r->headers_out.status == NGX_HTTP_INTERNAL_SERVER_ERROR) { + + if (u->peer.tries > 1 + && (u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_HTTP_500)) + { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_500); + return; + } + +#if (NGX_HTTP_CACHE) + + if (u->peer.tries == 0 + && u->stale + && (u->conf->use_stale & NGX_HTTP_UPSTREAM_FT_HTTP_500)) + { + ngx_http_upstream_finalize_request(r, u, + ngx_http_send_cached_response(r)); + return; + } + +#endif + } + + if (r->headers_out.status == NGX_HTTP_NOT_FOUND + && u->peer.tries > 1 + && u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_HTTP_404) + { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_404); + return; + } + + if (r->headers_out.status >= NGX_HTTP_BAD_REQUEST && u->conf->redirect_errors && r->err_ctx == NULL) @@ -687,11 +888,55 @@ ngx_http_upstream_process_header(ngx_eve 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; + ngx_int_t rc; + ngx_uint_t i, key; + ngx_list_part_t *part; + ngx_table_elt_t *h; + ngx_event_pipe_t *p; + ngx_http_core_loc_conf_t *clcf; + ngx_http_upstream_header_t *hh; + ngx_http_upstream_main_conf_t *umcf; + + umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + hh = (ngx_http_upstream_header_t *) umcf->headers_in_hash.buckets; + + part = &r->upstream->headers_in.headers.part; + h = part->elts; + + for (i = 0; /* void */; i++) { - rc = u->send_header(r); + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + h = part->elts; + i = 0; + } + + key = h[i].hash % umcf->headers_in_hash.hash_size; + + if (hh[key].name.len == h[i].key.len + && ngx_strcasecmp(hh[key].name.data, h[i].key.data) == 0) + { + if (hh[key].copy_handler(r, &h[i], hh[key].conf) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + continue; + } + + if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + + rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK) { ngx_http_upstream_finalize_request(r, u, rc); @@ -820,20 +1065,27 @@ ngx_http_upstream_send_response(ngx_http p->send_timeout = clcf->send_timeout; p->send_lowat = clcf->send_lowat; - u->peer.connection->read->event_handler = ngx_http_upstream_process_body; - r->connection->write->event_handler = ngx_http_upstream_process_body; + u->peer.connection->read->handler = ngx_http_upstream_process_body; + r->write_event_handler = ngx_http_upstream_process_downstream; ngx_http_upstream_process_body(u->peer.connection->read); } static void +ngx_http_upstream_process_downstream(ngx_http_request_t *r) +{ + ngx_http_upstream_process_body(r->connection->write); +} + + +static void ngx_http_upstream_process_body(ngx_event_t *ev) { + ngx_event_pipe_t *p; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_upstream_t *u; - ngx_event_pipe_t *p; c = ev->data; r = c->data; @@ -1046,11 +1298,6 @@ ngx_http_upstream_finalize_request(ngx_h rc = 0; } - if (u->saved_log_ctx) { - r->connection->log->data = u->saved_log_ctx; - r->connection->log->handler = u->saved_log_handler; - } - if (u->pipe.temp_file) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream temp fd: %d", @@ -1065,15 +1312,7 @@ ngx_http_upstream_finalize_request(ngx_h } #endif - if (u->pipe.temp_file) { - r->file.fd = u->pipe.temp_file->file.fd; - -#if 0 - } else if (u->cache) { - r->file.fd = u->cache->ctx.file.fd; -#endif - } - + r->log_handler = u->saved_log_handler; r->connection->log->action = "sending to client"; if (rc == 0 && r->main == NULL) { @@ -1084,6 +1323,260 @@ ngx_http_upstream_finalize_request(ngx_h } +static ngx_int_t +ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t **ph; + + ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset); + + if (*ph == NULL) { + *ph = h; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_array_t *pa; + ngx_table_elt_t **ph; + + pa = (ngx_array_t *) ((char *) &r->upstream->headers_in + offset); + + if (pa->elts == NULL) { + if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) + { + return NGX_ERROR; + } + } + + ph = ngx_array_push(pa); + if (ph == NULL) { + return NGX_ERROR; + } + + *ph = h; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_conditional_copy_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_flag_t *f; + ngx_table_elt_t *ho; + + f = (ngx_flag_t *) ((char *) r->upstream->conf + offset); + + if (*f == 0) { + return NGX_OK; + } + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_array_t *pa; + ngx_table_elt_t *ho, **ph; + + pa = (ngx_array_t *) ((char *) &r->headers_out + offset); + + if (pa->elts == NULL) { + if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) + { + return NGX_ERROR; + } + } + + ph = ngx_array_push(pa); + if (ph == NULL) { + return NGX_ERROR; + } + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + *ph = ho; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + r->headers_out.content_type = h->value; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_copy_content_length(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + r->headers_out.content_length = ho; + r->headers_out.content_length_n = ngx_atoof(h->value.data, h->value.len); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_int_t rc; + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + if (r->upstream->rewrite_redirect) { + rc = r->upstream->rewrite_redirect(r, ho, 0); + + if (rc == NGX_OK) { + r->headers_out.location = ho; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "rewritten location: \"%V\"", &ho->value); + } + + return rc; + } + + /* + * we do not set r->headers_out.location here to avoid the handling + * the local redirects without a host name by ngx_http_header_filter() + */ + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + u_char *p; + ngx_int_t rc; + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + if (r->upstream->rewrite_redirect) { + + p = (u_char *) ngx_strstr(ho->value.data, "url="); + + if (p) { + rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data); + + } else { + return NGX_OK; + } + +#if (NGX_DEBUG) + if (rc == NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "rewritten refresh: \"%V\"", &ho->value); + } +#endif + + return rc; + } + + return NGX_OK; +} + + +#if (NGX_HTTP_GZIP) + +static ngx_int_t +ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + r->headers_out.content_encoding = ho; + + return NGX_OK; +} + +#endif + + static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r, uintptr_t data) { @@ -1131,51 +1624,45 @@ ngx_http_upstream_log_status(ngx_http_re } -u_char * -ngx_http_upstream_log_error(ngx_log_t *log, u_char *buf, size_t len) +static u_char * +ngx_http_upstream_log_error(ngx_http_request_t *r, u_char *buf, size_t len) { u_char *p; uintptr_t escape; - ngx_http_log_ctx_t *ctx; - ngx_http_request_t *r; ngx_http_upstream_t *u; ngx_peer_connection_t *peer; - ctx = log->data; - r = ctx->request; u = r->upstream; peer = &u->peer; p = ngx_snprintf(buf, len, - " while %s, client: %V, server: %V, URL: \"%V\"," + ", server: %V, URL: \"%V\"," " upstream: %V%V%s%V", - log->action, - &r->connection->addr_text, &r->server_name, &r->unparsed_uri, - &u->schema0, + &u->conf->schema, &peer->peers->peer[peer->cur_peer].name, peer->peers->peer[peer->cur_peer].uri_separator, - &u->uri0); + &u->conf->uri); len -= p - buf; buf = p; if (r->quoted_uri) { - escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location0->len, - r->uri.len - u->location0->len, + escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->conf->location->len, + r->uri.len - u->conf->location->len, NGX_ESCAPE_URI); } else { escape = 0; } if (escape) { - if (len >= r->uri.len - u->location0->len + escape) { + if (len >= r->uri.len - u->conf->location->len + escape) { - ngx_escape_uri(buf, r->uri.data + u->location0->len, - r->uri.len - u->location0->len, NGX_ESCAPE_URI); + ngx_escape_uri(buf, r->uri.data + u->conf->location->len, + r->uri.len - u->conf->location->len, NGX_ESCAPE_URI); - buf += r->uri.len - u->location0->len + escape; - len -= r->uri.len - u->location0->len + escape; + buf += r->uri.len - u->conf->location->len + escape; + len -= r->uri.len - u->conf->location->len + escape; if (r->args.len) { p = ngx_snprintf(buf, len, "?%V", &r->args); @@ -1186,19 +1673,19 @@ ngx_http_upstream_log_error(ngx_log_t *l return ngx_http_log_error_info(r, buf, len); } - p = ngx_palloc(r->pool, r->uri.len - u->location0->len + escape); + p = ngx_palloc(r->pool, r->uri.len - u->conf->location->len + escape); if (p == NULL) { return buf; } - ngx_escape_uri(p, r->uri.data + u->location0->len, - r->uri.len - u->location0->len, NGX_ESCAPE_URI); + ngx_escape_uri(p, r->uri.data + u->conf->location->len, + r->uri.len - u->conf->location->len, NGX_ESCAPE_URI); - p = ngx_cpymem(buf, p, r->uri.len - u->location0->len + escape); + p = ngx_cpymem(buf, p, r->uri.len - u->conf->location->len + escape); } else { - p = ngx_cpymem(buf, r->uri.data + u->location0->len, - r->uri.len - u->location0->len); + p = ngx_cpymem(buf, r->uri.data + u->conf->location->len, + r->uri.len - u->conf->location->len); } len -= p - buf; @@ -1232,3 +1719,43 @@ ngx_http_upstream_add_log_formats(ngx_co return NGX_OK; } + + +static void * +ngx_http_upstream_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_upstream_main_conf_t *umcf; + + umcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_main_conf_t)); + if (umcf == NULL) { + return NULL; + } + + return umcf; +} + + +static char * +ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_http_upstream_main_conf_t *umcf = conf; + + umcf->headers_in_hash.max_size = 100; + umcf->headers_in_hash.bucket_limit = 1; + umcf->headers_in_hash.bucket_size = sizeof(ngx_http_upstream_header_t); + umcf->headers_in_hash.name = "upstream_headers_in"; + + if (ngx_hash_init(&umcf->headers_in_hash, cf->pool, + ngx_http_upstream_headers_in, 0) != NGX_OK) + { + return NGX_CONF_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "http upstream headers_in hash size: %ui, " + "max buckets per entry: %ui", + umcf->headers_in_hash.hash_size, + umcf->headers_in_hash.min_buckets); + + return NGX_CONF_OK; +} diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -29,87 +29,140 @@ typedef struct { - time_t bl_time; - ngx_uint_t bl_state; + time_t bl_time; + ngx_uint_t bl_state; - ngx_uint_t status; - time_t time; + ngx_uint_t status; + time_t time; - ngx_str_t *peer; + ngx_str_t *peer; } ngx_http_upstream_state_t; typedef struct { - ngx_msec_t connect_timeout; - ngx_msec_t send_timeout; - ngx_msec_t read_timeout; + ngx_hash_t headers_in_hash; +} ngx_http_upstream_main_conf_t; + + +typedef struct { + ngx_msec_t connect_timeout; + ngx_msec_t send_timeout; + ngx_msec_t read_timeout; - size_t send_lowat; - size_t header_buffer_size; - size_t busy_buffers_size; - size_t max_temp_file_size; - size_t temp_file_write_size; + size_t send_lowat; + size_t header_buffer_size; + size_t busy_buffers_size; + size_t max_temp_file_size; + size_t temp_file_write_size; + + ngx_uint_t next_upstream; + ngx_uint_t method; - ngx_uint_t next_upstream; + ngx_bufs_t bufs; - ngx_bufs_t bufs; + ngx_flag_t pass_request_headers; + ngx_flag_t pass_request_body; + + ngx_flag_t redirect_errors; + ngx_flag_t pass_unparsed_uri; + ngx_flag_t cyclic_temp_file; - ngx_flag_t redirect_errors; - ngx_flag_t pass_unparsed_uri; - ngx_flag_t x_powered_by; - ngx_flag_t cyclic_temp_file; + ngx_flag_t pass_x_powered_by; + ngx_flag_t pass_server; + ngx_flag_t pass_date; + ngx_flag_t pass_x_accel_expires; - ngx_path_t *temp_path; + ngx_path_t *temp_path; + + ngx_str_t schema; + ngx_str_t uri; + ngx_str_t *location; + ngx_str_t url; /* used in proxy_rewrite_location */ } ngx_http_upstream_conf_t; -typedef struct ngx_http_upstream_s ngx_http_upstream_t; +typedef struct { + ngx_str_t name; + ngx_http_header_handler_pt handler; + ngx_uint_t offset; + ngx_http_header_handler_pt copy_handler; + ngx_uint_t conf; +} ngx_http_upstream_header_t; + + +typedef struct { + ngx_list_t headers; + + ngx_table_elt_t *status; + ngx_table_elt_t *date; + ngx_table_elt_t *server; + ngx_table_elt_t *connection; + + ngx_table_elt_t *expires; + ngx_table_elt_t *etag; + ngx_table_elt_t *x_accel_expires; + + ngx_table_elt_t *content_type; + ngx_table_elt_t *content_length; + + ngx_table_elt_t *last_modified; + ngx_table_elt_t *location; + ngx_table_elt_t *accept_ranges; + +#if (NGX_HTTP_GZIP) + ngx_table_elt_t *content_encoding; +#endif + + ngx_array_t cache_control; +} ngx_http_upstream_headers_in_t; + struct ngx_http_upstream_s { - ngx_http_request_t *request; + ngx_http_request_t *request; + + ngx_peer_connection_t peer; - ngx_peer_connection_t peer; + ngx_event_pipe_t pipe; - ngx_event_pipe_t pipe; + ngx_chain_t *request_bufs; - ngx_output_chain_ctx_t output; - ngx_chain_writer_ctx_t writer; + ngx_output_chain_ctx_t output; + ngx_chain_writer_ctx_t writer; - ngx_http_upstream_conf_t *conf; + ngx_http_upstream_conf_t *conf; - ngx_buf_t header_in; + ngx_http_upstream_headers_in_t headers_in; + + ngx_buf_t header_in; - ngx_int_t (*create_request)(ngx_http_request_t *r); - ngx_int_t (*reinit_request)(ngx_http_request_t *r); - ngx_int_t (*process_header)(ngx_http_request_t *r); - ngx_int_t (*send_header)(ngx_http_request_t *r); - void (*abort_request)(ngx_http_request_t *r); - void (*finalize_request)(ngx_http_request_t *r, - ngx_int_t rc); - ngx_uint_t method; + ngx_int_t (*create_request)(ngx_http_request_t *r); + ngx_int_t (*reinit_request)(ngx_http_request_t *r); + ngx_int_t (*process_header)(ngx_http_request_t *r); + void (*abort_request)(ngx_http_request_t *r); + void (*finalize_request)(ngx_http_request_t *r, + ngx_int_t rc); + ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix); - ngx_str_t schema0; - ngx_str_t uri0; - ngx_str_t *location0; + ngx_uint_t method; - ngx_http_log_ctx_t *log_ctx; - ngx_log_handler_pt log_handler; - ngx_http_log_ctx_t *saved_log_ctx; - ngx_log_handler_pt saved_log_handler; + ngx_http_log_handler_pt saved_log_handler; + + ngx_http_upstream_state_t *state; + ngx_array_t states; /* of ngx_http_upstream_state_t */ - ngx_http_upstream_state_t *state; - ngx_array_t states; /* of ngx_http_upstream_state_t */ + unsigned cachable:1; + unsigned accel:1; - unsigned cachable:1; - - unsigned request_sent:1; - unsigned header_sent:1; + unsigned request_sent:1; + unsigned header_sent:1; }; void ngx_http_upstream_init(ngx_http_request_t *r); -u_char *ngx_http_upstream_log_error(ngx_log_t *log, u_char *buf, size_t len); + +extern ngx_module_t ngx_http_upstream_module; extern char *ngx_http_upstream_header_errors[]; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -10,66 +10,157 @@ #include -#define NGX_HTTP_VARS_HASH_PRIME 29 - -#define ngx_http_vars_hash_key(key, vn) \ - { \ - ngx_uint_t n; \ - for (key = 0, n = 0; n < (vn)->len; n++) { \ - key += (vn)->data[n]; \ - } \ - key %= NGX_HTTP_VARS_HASH_PRIME; \ - } - - +static ngx_http_variable_value_t * + ngx_http_variable_request(ngx_http_request_t *r, uintptr_t data); static ngx_http_variable_value_t * ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data); static ngx_http_variable_value_t * ngx_http_variable_unknown_header(ngx_http_request_t *r, uintptr_t data); static ngx_http_variable_value_t * + ngx_http_variable_host(ngx_http_request_t *r, uintptr_t data); +static ngx_http_variable_value_t * ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data); static ngx_http_variable_value_t * - ngx_http_variable_uri(ngx_http_request_t *r, uintptr_t data); + ngx_http_variable_remote_port(ngx_http_request_t *r, uintptr_t data); +static ngx_http_variable_value_t * + ngx_http_variable_server_addr(ngx_http_request_t *r, uintptr_t data); static ngx_http_variable_value_t * - ngx_http_variable_query_string(ngx_http_request_t *r, uintptr_t data); - - -static ngx_array_t *ngx_http_core_variables_hash; + ngx_http_variable_server_port(ngx_http_request_t *r, uintptr_t data); +static ngx_http_variable_value_t * + ngx_http_variable_document_root(ngx_http_request_t *r, uintptr_t data); +static ngx_http_variable_value_t * + ngx_http_variable_request_filename(ngx_http_request_t *r, uintptr_t data); -static ngx_http_core_variable_t ngx_http_core_variables[] = { - - { ngx_string("HTTP_HOST"), ngx_http_variable_header, - offsetof(ngx_http_headers_in_t, host) }, +/* + * TODO: + * Apache CGI: AUTH_TYPE, PATH_INFO (null), PATH_TRANSLATED + * REMOTE_HOST (null), REMOTE_IDENT (null), + * SERVER_SOFTWARE + * + * Apache SSI: DATE_GMT, DOCUMENT_NAME, LAST_MODIFIED, + * USER_NAME (file owner) + */ - { ngx_string("HTTP_USER_AGENT"), ngx_http_variable_header, - offsetof(ngx_http_headers_in_t, user_agent) }, +static ngx_http_variable_t ngx_http_core_variables[] = { + + { ngx_string("http_host"), ngx_http_variable_header, + offsetof(ngx_http_request_t, headers_in.host), 0 }, - { ngx_string("HTTP_REFERER"), ngx_http_variable_header, - offsetof(ngx_http_headers_in_t, referer) }, + { ngx_string("http_user_agent"), ngx_http_variable_header, + offsetof(ngx_http_request_t, headers_in.user_agent), 0 }, + + { ngx_string("http_referer"), ngx_http_variable_header, + offsetof(ngx_http_request_t, headers_in.referer), 0 }, #if (NGX_HTTP_GZIP) - { ngx_string("HTTP_VIA"), ngx_http_variable_header, - offsetof(ngx_http_headers_in_t, via) }, + { ngx_string("http_via"), ngx_http_variable_header, + offsetof(ngx_http_request_t, headers_in.via), 0 }, #endif #if (NGX_HTTP_PROXY) - { ngx_string("HTTP_X_FORWARDED_FOR"), ngx_http_variable_header, - offsetof(ngx_http_headers_in_t, x_forwarded_for) }, + { ngx_string("http_x_forwarded_for"), ngx_http_variable_header, + offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0 }, #endif - { ngx_string("REMOTE_ADDR"), ngx_http_variable_remote_addr, 0 }, + { ngx_string("content_length"), ngx_http_variable_header, + offsetof(ngx_http_request_t, headers_in.content_length), 0 }, + + { ngx_string("content_type"), ngx_http_variable_header, + offsetof(ngx_http_request_t, headers_in.content_type), 0 }, + + { ngx_string("host"), ngx_http_variable_host, 0, 0 }, + + { ngx_string("remote_addr"), ngx_http_variable_remote_addr, 0, 0 }, - { ngx_string("DOCUMENT_URI"), ngx_http_variable_uri, 0 }, + { ngx_string("remote_port"), ngx_http_variable_remote_port, 0, 0 }, + + { ngx_string("server_addr"), ngx_http_variable_server_addr, 0, 0 }, + + { ngx_string("server_port"), ngx_http_variable_server_port, 0, 0 }, + + { ngx_string("server_protocol"), ngx_http_variable_request, + offsetof(ngx_http_request_t, http_protocol), 0 }, + + { ngx_string("request_uri"), ngx_http_variable_request, + offsetof(ngx_http_request_t, unparsed_uri), 0 }, - { ngx_string("QUERY_STRING"), ngx_http_variable_query_string, 0 }, + { ngx_string("document_uri"), ngx_http_variable_request, + offsetof(ngx_http_request_t, uri), 0 }, + + { ngx_string("document_root"), ngx_http_variable_document_root, 0, 0 }, + + { ngx_string("query_string"), ngx_http_variable_request, + offsetof(ngx_http_request_t, args), + NGX_HTTP_VAR_NOCACHABLE }, - { ngx_null_string, NULL, 0 } + { ngx_string("request_filename"), ngx_http_variable_request_filename, 0, + NGX_HTTP_VAR_NOCACHABLE }, + + { ngx_string("server_name"), ngx_http_variable_request, + offsetof(ngx_http_request_t, server_name), 0 }, + + { ngx_string("request_method"), ngx_http_variable_request, + offsetof(ngx_http_request_t, method_name), 0 }, + + { ngx_string("remote_user"), ngx_http_variable_request, + offsetof(ngx_http_request_t, headers_in.user), 0 }, + + { ngx_null_string, NULL, 0, 0 } }; ngx_http_variable_t * -ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t set) +ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags) +{ + ngx_uint_t i; + ngx_http_variable_t *v; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + v = cmcf->all_variables.elts; + for (i = 0; i < cmcf->all_variables.nelts; i++) { + if (name->len != v[i].name.len + || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0) + { + continue; + } + + if (!(v[i].flags & NGX_HTTP_VAR_CHANGABLE)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the duplicate \"%V\" variable", name); + return NULL; + } + + return &v[i]; + } + + v = ngx_array_push(&cmcf->all_variables); + if (v == NULL) { + return NULL; + } + + v->name.len = name->len; + v->name.data = ngx_palloc(cf->pool, name->len); + if (v->name.data == NULL) { + return NULL; + } + + for (i = 0; i < name->len; i++) { + v->name.data[i] = ngx_tolower(name->data[i]); + } + + v->handler = NULL; + v->data = 0; + v->flags = flags; + + return v; +} + + +ngx_int_t +ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name) { ngx_uint_t i; ngx_http_variable_t *v; @@ -83,7 +174,7 @@ ngx_http_add_variable(ngx_conf_t *cf, ng if (ngx_array_init(&cmcf->variables, cf->pool, 4, sizeof(ngx_http_variable_t)) == NGX_ERROR) { - return NULL; + return NGX_ERROR; } } else { @@ -94,36 +185,30 @@ ngx_http_add_variable(ngx_conf_t *cf, ng continue; } - if (set && v[i].handler) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the duplicate \"%V\" variable", name); - return NULL; - } - - return &v[i]; + return i; } } v = ngx_array_push(&cmcf->variables); if (v == NULL) { - return NULL; + return NGX_ERROR; } v->name.len = name->len; v->name.data = ngx_palloc(cf->pool, name->len); if (v->name.data == NULL) { - return NULL; + return NGX_ERROR; } for (i = 0; i < name->len; i++) { - v->name.data[i] = ngx_toupper(name->data[i]); + v->name.data[i] = ngx_tolower(name->data[i]); } - v->index = cmcf->variables.nelts - 1; v->handler = NULL; v->data = 0; + v->flags = 0; - return v; + return cmcf->variables.nelts - 1; } @@ -158,7 +243,9 @@ ngx_http_get_indexed_variable(ngx_http_r } } - r->variables[index] = vv; + if (!(v[index].flags & NGX_HTTP_VAR_NOCACHABLE)) { + r->variables[index] = vv; + } return vv; } @@ -169,43 +256,56 @@ ngx_http_get_variable(ngx_http_request_t { ngx_uint_t i, key; ngx_http_variable_t *v; - ngx_http_core_variable_t *cv; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - v = cmcf->variables.elts; - for (i = 0; i < cmcf->variables.nelts; i++) { - if (v[i].name.len != name->len) { - continue; - } - - if (ngx_strncmp(v[i].name.data, name->data, name->len) == 0) { - return ngx_http_get_indexed_variable(r, v[i].index); - } + key = 0; + for (i = 0; i < name->len; i++) { + key += name->data[i]; } - ngx_http_vars_hash_key(key, name); + key %= cmcf->variables_hash.hash_size; + v = (ngx_http_variable_t *) cmcf->variables_hash.buckets; - cv = ngx_http_core_variables_hash[key].elts; - for (i = 0; i < ngx_http_core_variables_hash[key].nelts; i++) { - if (cv[i].name.len != name->len) { - continue; - } - - if (ngx_strncmp(cv[i].name.data, name->data, name->len) == 0) { - return cv[i].handler(r, cv[i].data); - } + if (v[key].name.len == name->len + && ngx_strncmp(v[key].name.data, name->data, name->len) == 0) + { + return v[key].handler(r, v[key].data); } - if (ngx_strncmp(name->data, "HTTP_", 5) == 0) { + if (ngx_strncmp(name->data, "http_", 5) == 0) { return ngx_http_variable_unknown_header(r, (uintptr_t) name); } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "unknown \"%V\" variable", name); - return NGX_HTTP_VARIABLE_NOT_FOUND; + return NGX_HTTP_VAR_NOT_FOUND; +} + + +static ngx_http_variable_value_t * +ngx_http_variable_request(ngx_http_request_t *r, uintptr_t data) +{ + ngx_str_t *s; + ngx_http_variable_value_t *vv; + + s = (ngx_str_t *) ((char *) r + data); + + if (s->data == NULL) { + return NGX_HTTP_VAR_NOT_FOUND; + } + + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { + return NULL; + } + + vv->value = 0; + vv->text = *s; + + return vv; } @@ -215,10 +315,10 @@ ngx_http_variable_header(ngx_http_reques ngx_table_elt_t *h; ngx_http_variable_value_t *vv; - h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); + h = *(ngx_table_elt_t **) ((char *) r + data); if (h == NULL) { - return NGX_HTTP_VARIABLE_NOT_FOUND; + return NGX_HTTP_VAR_NOT_FOUND; } vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); @@ -259,12 +359,11 @@ ngx_http_variable_unknown_header(ngx_htt i = 0; } - for (n = 0; n + 5 < var->len && n < header[i].key.len; n++) - { + for (n = 0; n + 5 < var->len && n < header[i].key.len; n++) { ch = header[i].key.data[n]; - if (ch >= 'a' && ch <= 'z') { - ch &= ~0x20; + if (ch >= 'A' && ch <= 'Z') { + ch |= 0x20; } else if (ch == '-') { ch = '_'; @@ -287,7 +386,31 @@ ngx_http_variable_unknown_header(ngx_htt } } - return NGX_HTTP_VARIABLE_NOT_FOUND; + return NGX_HTTP_VAR_NOT_FOUND; +} + + +static ngx_http_variable_value_t * +ngx_http_variable_host(ngx_http_request_t *r, uintptr_t data) +{ + ngx_http_variable_value_t *vv; + + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { + return NULL; + } + + vv->value = 0; + + if (r->headers_in.host) { + vv->text.len = r->headers_in.host_name_len; + vv->text.data = r->headers_in.host->value.data; + + } else { + vv->text = r->server_name; + } + + return vv; } @@ -309,8 +432,49 @@ ngx_http_variable_remote_addr(ngx_http_r static ngx_http_variable_value_t * -ngx_http_variable_uri(ngx_http_request_t *r, uintptr_t data) +ngx_http_variable_remote_port(ngx_http_request_t *r, uintptr_t data) { + ngx_uint_t port; + struct sockaddr_in *sin; + ngx_http_variable_value_t *vv; + + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { + return NULL; + } + + vv->value = 0; + vv->text.len = 0; + + vv->text.data = ngx_palloc(r->pool, sizeof("65535") - 1); + if (vv->text.data == NULL) { + return NULL; + } + + /* AF_INET only */ + + if (r->connection->sockaddr->sa_family == AF_INET) { + sin = (struct sockaddr_in *) r->connection->sockaddr; + + port = ntohs(sin->sin_port); + + if (port > 0 && port < 65536) { + vv->value = port; + vv->text.len = ngx_sprintf(vv->text.data, "%ui", port) + - vv->text.data; + } + } + + return vv; +} + + +static ngx_http_variable_value_t * +ngx_http_variable_server_addr(ngx_http_request_t *r, uintptr_t data) +{ + socklen_t len; + ngx_connection_t *c; + struct sockaddr_in sin; ngx_http_variable_value_t *vv; vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); @@ -319,15 +483,75 @@ ngx_http_variable_uri(ngx_http_request_t } vv->value = 0; - vv->text = r->uri; + + vv->text.data = ngx_palloc(r->pool, INET_ADDRSTRLEN); + if (vv->text.data == NULL) { + return NULL; + } + + c = r->connection; + + if (r->in_addr == 0) { + len = sizeof(struct sockaddr_in); + if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { + ngx_log_error(NGX_LOG_CRIT, c->log, + ngx_socket_errno, "getsockname() failed"); + return NULL; + } + + r->in_addr = sin.sin_addr.s_addr; + } + + vv->text.len = ngx_inet_ntop(c->listening->family, &r->in_addr, + vv->text.data, INET_ADDRSTRLEN); return vv; } static ngx_http_variable_value_t * -ngx_http_variable_query_string(ngx_http_request_t *r, uintptr_t data) +ngx_http_variable_server_port(ngx_http_request_t *r, uintptr_t data) +{ + ngx_http_variable_value_t *vv; + + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { + return NULL; + } + + vv->value = r->port; + vv->text.len = r->port_text->len - 1; + vv->text.data = r->port_text->data + 1; + + return vv; +} + + +static ngx_http_variable_value_t * +ngx_http_variable_document_root(ngx_http_request_t *r, uintptr_t data) { + ngx_http_core_loc_conf_t *clcf; + ngx_http_variable_value_t *vv; + + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { + return NULL; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + vv->value = 0; + vv->text = clcf->root; + + return vv; +} + + +static ngx_http_variable_value_t * +ngx_http_variable_request_filename(ngx_http_request_t *r, uintptr_t data) +{ + u_char *p; + ngx_http_core_loc_conf_t *clcf; ngx_http_variable_value_t *vv; vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); @@ -336,84 +560,130 @@ ngx_http_variable_query_string(ngx_http_ } vv->value = 0; - vv->text = r->args; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (!clcf->alias) { + vv->text.len = clcf->root.len + r->uri.len; + vv->text.data = ngx_palloc(r->pool, vv->text.len); + if (vv->text.data == NULL) { + return NULL; + } + + p = ngx_cpymem(vv->text.data, clcf->root.data, clcf->root.len); + ngx_memcpy(p, r->uri.data, r->uri.len + 1); + + } else { + vv->text.len = clcf->root.len + r->uri.len + 2 - clcf->name.len; + vv->text.data = ngx_palloc(r->pool, vv->text.len); + if (vv->text.data == NULL) { + return NULL; + } + + p = ngx_cpymem(vv->text.data, clcf->root.data, clcf->root.len); + ngx_memcpy(p, r->uri.data + clcf->name.len, + r->uri.len + 1 - clcf->name.len); + } return vv; } ngx_int_t -ngx_http_variables_init(ngx_cycle_t *cycle) +ngx_http_variables_add_core_vars(ngx_conf_t *cf) { - ngx_uint_t i, j, key; - ngx_http_variable_t *v; - ngx_http_core_variable_t *cv, *vp; + ngx_http_variable_t *v, *cv; ngx_http_core_main_conf_t *cmcf; - ngx_http_core_variables_hash = ngx_palloc(cycle->pool, - NGX_HTTP_VARS_HASH_PRIME - * sizeof(ngx_array_t)); - if (ngx_http_core_variables_hash == NULL) { + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + if (ngx_array_init(&cmcf->all_variables, cf->pool, 32, + sizeof(ngx_http_variable_t)) == NGX_ERROR) + { return NGX_ERROR; } - for (i = 0; i < NGX_HTTP_VARS_HASH_PRIME; i++) { - if (ngx_array_init(&ngx_http_core_variables_hash[i], cycle->pool, 4, - sizeof(ngx_http_core_variable_t)) == NGX_ERROR) - { - return NGX_ERROR; - } - } - for (cv = ngx_http_core_variables; cv->name.len; cv++) { - ngx_http_vars_hash_key(key, &cv->name); - - vp = ngx_array_push(&ngx_http_core_variables_hash[key]); - if (vp == NULL) { + v = ngx_array_push(&cmcf->all_variables); + if (v == NULL) { return NGX_ERROR; } - *vp = *cv; - } - - - cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); - - v = cmcf->variables.elts; - for (i = 0; i < cmcf->variables.nelts; i++) { - - if (v[i].handler) { - continue; - } - - ngx_http_vars_hash_key(key, &v[i].name); - - cv = ngx_http_core_variables_hash[key].elts; - for (j = 0; j < ngx_http_core_variables_hash[key].nelts; j++) { - if (cv[j].name.len != v[i].name.len) { - continue; - } - - if (ngx_strncmp(cv[j].name.data, v[i].name.data, v[i].name.len) - == 0) - { - v[i].handler = cv[j].handler; - v[i].data = cv[j].data; - continue; - } - } - - if (ngx_strncmp(v[i].name.data, "HTTP_", 5) == 0) { - v[i].handler = ngx_http_variable_unknown_header; - v[i].data = (uintptr_t) &v[i].name; - continue; - } - - ngx_log_error(NGX_LOG_ERR, cycle->log, 0, - "unknown \"%V\" variable", &v[i].name); - - return NGX_ERROR; + *v = *cv; } return NGX_OK; } + + +ngx_int_t +ngx_http_variables_init_vars(ngx_conf_t *cf) +{ + ngx_uint_t i, n; + ngx_http_variable_t *v, *av; + ngx_http_core_main_conf_t *cmcf; + + /* set the handlers for the indexed http variables */ + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + v = cmcf->variables.elts; + av = cmcf->all_variables.elts; + + for (i = 0; i < cmcf->variables.nelts; i++) { + + for (n = 0; n < cmcf->all_variables.nelts; n++) { + + if (v[i].name.len == av[n].name.len + && ngx_strncmp(v[i].name.data, av[n].name.data, v[i].name.len) + == 0) + { + v[i].handler = av[n].handler; + v[i].data = av[n].data; + v[i].flags = av[n].flags; + + goto next; + } + } + + if (ngx_strncmp(v[i].name.data, "http_", 5) == 0) { + v[i].handler = ngx_http_variable_unknown_header; + v[i].data = (uintptr_t) &v[i].name; + + continue; + } + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "unknown \"%V\" variable", &v[i].name); + + return NGX_ERROR; + + next: + continue; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "http variables: %ui", cmcf->variables.nelts); + + + /* init the all http variables hash */ + + cmcf->variables_hash.max_size = 500; + cmcf->variables_hash.bucket_limit = 1; + cmcf->variables_hash.bucket_size = sizeof(ngx_http_variable_t); + cmcf->variables_hash.name = "http variables"; + + if (ngx_hash_init(&cmcf->variables_hash, cf->pool, + cmcf->all_variables.elts, cmcf->all_variables.nelts) != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "http variables hash size: %ui for %ui values, " + "max buckets per entry: %ui", + cmcf->variables_hash.hash_size, cmcf->all_variables.nelts, + cmcf->variables_hash.min_buckets); + + return NGX_OK; +} diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -14,13 +14,13 @@ #include -#define NGX_HTTP_VARIABLE_NOT_FOUND (ngx_http_variable_value_t *) -1 +#define NGX_HTTP_VAR_NOT_FOUND (ngx_http_variable_value_t *) -1 -struct ngx_http_variable_value_s { +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; @@ -28,30 +28,28 @@ typedef ngx_http_variable_value_t * (*ngx_http_get_variable_pt) (ngx_http_request_t *r, uintptr_t data); +#define NGX_HTTP_VAR_CHANGABLE 1 +#define NGX_HTTP_VAR_NOCACHABLE 2 + + struct ngx_http_variable_s { - ngx_str_t name; - ngx_uint_t index; + ngx_str_t name; /* must be first to build the hash */ ngx_http_get_variable_pt handler; uintptr_t data; + ngx_uint_t flags; }; -typedef struct { - ngx_str_t name; - ngx_http_get_variable_pt handler; - uintptr_t data; -} ngx_http_core_variable_t; - - ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, - ngx_uint_t set); -ngx_int_t ngx_http_get_variable_index(ngx_http_core_main_conf_t *cmcf, - ngx_str_t *name); + ngx_uint_t flags); +ngx_int_t ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name); ngx_http_variable_value_t *ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index); ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name); -ngx_int_t ngx_http_variables_init(ngx_cycle_t *cycle); + +ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf); +ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf); #endif /* _NGX_HTTP_VARIABLES_H_INCLUDED_ */ diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -10,16 +10,12 @@ #include -typedef struct { - ngx_chain_t *out; -} ngx_http_write_filter_ctx_t; - - static ngx_int_t ngx_http_write_filter_init(ngx_cycle_t *cycle); ngx_http_module_t ngx_http_write_filter_module_ctx = { - NULL, /* pre conf */ + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -33,7 +29,7 @@ ngx_http_module_t ngx_http_write_filter ngx_module_t ngx_http_write_filter_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_write_filter_module_ctx, /* module context */ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -45,34 +41,20 @@ ngx_module_t ngx_http_write_filter_modu ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) { - off_t size, sent; - ngx_uint_t last, flush; - ngx_chain_t *cl, *ln, **ll, *chain; - ngx_connection_t *c; - ngx_http_core_loc_conf_t *clcf; - ngx_http_write_filter_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r->main ? r->main : r, - ngx_http_write_filter_module); - - if (ctx == NULL) { - - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_write_filter_ctx_t)); - if (ctx == NULL) { - return NGX_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_write_filter_module); - } + off_t size, sent; + ngx_uint_t last, flush; + ngx_chain_t *cl, *ln, **ll, *chain; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; size = 0; flush = 0; last = 0; - ll = &ctx->out; + ll = &r->out; /* find the size, the flush point and the last link of the saved chain */ - for (cl = ctx->out; cl; cl = cl->next) { + for (cl = r->out; cl; cl = cl->next) { ll = &cl->next; ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, @@ -174,11 +156,10 @@ ngx_http_write_filter(ngx_http_request_t ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http write filter: l:%d f:%d s:%O", last, flush, size); - clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, - ngx_http_core_module); + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); /* - * avoid the output if there is no last buf, no flush point, + * avoid the output if there are no last buf, no flush point, * there are the incoming bufs and the size of all bufs * is smaller than "postpone_output" directive */ @@ -187,20 +168,30 @@ ngx_http_write_filter(ngx_http_request_t return NGX_OK; } + /* + * avoid the output if there are no incoming bufs but there are + * the postponed requests or data + */ + + if (in == NULL && r->postponed) { + return NGX_OK; + } + if (c->write->delayed) { return NGX_AGAIN; } if (size == 0 && !c->buffered) { if (last) { + r->out = NULL; return NGX_OK; } if (flush) { do { - ctx->out = ctx->out->next; + r->out = r->out->next; } - while (ctx->out); + while (r->out); return NGX_OK; } @@ -215,7 +206,7 @@ ngx_http_write_filter(ngx_http_request_t sent = c->sent; - chain = c->send_chain(c, ctx->out, clcf->limit_rate); + chain = c->send_chain(c, r->out, clcf->limit_rate); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http write filter %p", chain); @@ -231,13 +222,13 @@ ngx_http_write_filter(ngx_http_request_t return NGX_ERROR; } - for (cl = ctx->out; cl && cl != chain; /* void */) { + for (cl = r->out; cl && cl != chain; /* void */) { ln = cl; cl = cl->next; ngx_free_chain(r->pool, ln); } - ctx->out = chain; + r->out = chain; if (chain || (last && c->buffered)) { return NGX_AGAIN; diff --git a/src/imap/ngx_imap.c b/src/imap/ngx_imap.c --- a/src/imap/ngx_imap.c +++ b/src/imap/ngx_imap.c @@ -34,7 +34,7 @@ static ngx_core_module_t ngx_imap_modul ngx_module_t ngx_imap_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_imap_module_ctx, /* module context */ ngx_imap_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c --- a/src/imap/ngx_imap_handler.c +++ b/src/imap/ngx_imap_handler.c @@ -47,7 +47,7 @@ void ngx_imap_init_connection(ngx_connec return; } - c->read->event_handler = ngx_imap_init_session; + c->read->handler = ngx_imap_init_session; ngx_add_timer(c->read, /* STUB */ 60000); @@ -93,7 +93,7 @@ static void ngx_imap_init_session(ngx_ev return; } - c->read->event_handler = ngx_pop3_auth_state; + c->read->handler = ngx_pop3_auth_state; ngx_pop3_auth_state(rev); } diff --git a/src/imap/ngx_imap_proxy.c b/src/imap/ngx_imap_proxy.c --- a/src/imap/ngx_imap_proxy.c +++ b/src/imap/ngx_imap_proxy.c @@ -82,9 +82,9 @@ void ngx_imap_proxy_init(ngx_imap_sessio p->upstream.connection->data = s; p->upstream.connection->pool = s->connection->pool; - s->connection->read->event_handler = ngx_imap_proxy_block_read; - p->upstream.connection->read->event_handler = ngx_imap_proxy_auth_handler; - p->upstream.connection->write->event_handler = ngx_imap_proxy_dummy_handler; + s->connection->read->handler = ngx_imap_proxy_block_read; + p->upstream.connection->read->handler = ngx_imap_proxy_auth_handler; + p->upstream.connection->write->handler = ngx_imap_proxy_dummy_handler; } @@ -200,10 +200,10 @@ static void ngx_imap_proxy_auth_handler( s->proxy->buffer->pos = s->proxy->buffer->start; s->proxy->buffer->last = s->proxy->buffer->start; - s->connection->read->event_handler = ngx_imap_proxy_handler; - s->connection->write->event_handler = ngx_imap_proxy_handler; - rev->event_handler = ngx_imap_proxy_handler; - c->write->event_handler = ngx_imap_proxy_handler; + s->connection->read->handler = ngx_imap_proxy_handler; + s->connection->write->handler = ngx_imap_proxy_handler; + rev->handler = ngx_imap_proxy_handler; + c->write->handler = ngx_imap_proxy_handler; } diff --git a/src/os/unix/ngx_channel.c b/src/os/unix/ngx_channel.c --- a/src/os/unix/ngx_channel.c +++ b/src/os/unix/ngx_channel.c @@ -137,7 +137,7 @@ ngx_int_t ngx_read_channel(ngx_socket_t if (ch->command == NGX_CMD_OPEN_CHANNEL) { - if (cmsg.cm.cmsg_len < sizeof(cmsg)) { + if (cmsg.cm.cmsg_len < (socklen_t) sizeof(cmsg)) { ngx_log_error(NGX_LOG_ALERT, log, 0, "recvmsg() returned too small ancillary data"); return NGX_ERROR; @@ -215,7 +215,7 @@ ngx_int_t ngx_add_channel_event(ngx_cycl ev = (event == NGX_READ_EVENT) ? rev : wev; - ev->event_handler = handler; + ev->handler = handler; if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) { diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -97,9 +97,6 @@ pid_t rfork_thread(int flags, void *stac #endif -#define ngx_setproctitle setproctitle - - extern char *malloc_options; diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -97,10 +97,5 @@ extern ssize_t sendfile(int s, int fd, i #define NGX_HAVE_SELECT_CHANGE_TIMEOUT 1 #endif -#ifndef NGX_SETPROCTITLE_USES_ENV -#define NGX_SETPROCTITLE_USES_ENV 1 -#define NGX_SETPROCTITLE_PAD '\0' -#endif - #endif /* _NGX_LINUX_CONFIG_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c --- a/src/os/unix/ngx_linux_init.c +++ b/src/os/unix/ngx_linux_init.c @@ -73,8 +73,6 @@ ngx_os_init(ngx_log_t *log) ngx_linux_rtsig_max = 0; } - ngx_init_setproctitle(log); - return ngx_posix_init(log); } diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -102,13 +102,6 @@ #endif -#if (NGX_HAVE_SETPROCTITLE) -#define ngx_setproctitle setproctitle -#else -#define ngx_setproctitle(title) -#endif - - #define NGX_POSIX_IO 1 diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -6,6 +6,7 @@ #include #include +#include ngx_int_t ngx_ncpu; @@ -97,6 +98,8 @@ ngx_int_t ngx_posix_init(ngx_log_t *log) ngx_signal_t *sig; struct sigaction sa; + ngx_init_setproctitle(log); + ngx_pagesize = getpagesize(); if (ngx_ncpu == 0) { diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h --- a/src/os/unix/ngx_process.h +++ b/src/os/unix/ngx_process.h @@ -62,12 +62,6 @@ void ngx_debug_point(void); #endif -#if !defined(ngx_setproctitle) -ngx_int_t ngx_init_setproctitle(ngx_log_t *log); -void ngx_setproctitle(char *title); -#endif - - extern int ngx_argc; extern char **ngx_argv; extern char **ngx_os_argv; diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -7,6 +7,7 @@ #include #include #include +#include #include diff --git a/src/os/unix/ngx_send.c b/src/os/unix/ngx_send.c --- a/src/os/unix/ngx_send.c +++ b/src/os/unix/ngx_send.c @@ -63,7 +63,7 @@ ssize_t ngx_unix_send(ngx_connection_t * } else { wev->error = 1; - ngx_connection_error(c, err, "recv() failed"); + ngx_connection_error(c, err, "send() failed"); return NGX_ERROR; } } diff --git a/src/os/unix/ngx_setproctitle.c b/src/os/unix/ngx_setproctitle.c --- a/src/os/unix/ngx_setproctitle.c +++ b/src/os/unix/ngx_setproctitle.c @@ -6,6 +6,7 @@ #include #include +#include #if (NGX_SETPROCTITLE_USES_ENV) @@ -131,19 +132,4 @@ ngx_setproctitle(char *title) "setproctitle: \"%s\"", ngx_os_argv[0]); } - -#elif !defined(ngx_setproctitle) - -ngx_int_t -ngx_init_setproctitle(ngx_log_t *log) -{ - return NGX_OK; -} - -void -ngx_setproctitle(char *title) -{ - return; -} - -#endif +#endif /* NGX_SETPROCTITLE_USES_ENV */ diff --git a/src/os/unix/ngx_setproctitle.h b/src/os/unix/ngx_setproctitle.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_setproctitle.h @@ -0,0 +1,45 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_SETPROCTITLE_H_INCLUDED_ +#define _NGX_SETPROCTITLE_H_INCLUDED_ + + +#if (NGX_HAVE_SETPROCTITLE) + +/* FreeBSD, NetBSD, OpenBSD */ + +#define ngx_init_setproctitle(log) +#define ngx_setproctitle setproctitle + + +#elif !defined NGX_SETPROCTITLE_USES_ENV + +#define NGX_SETPROCTITLE_USES_ENV 1 + +#if (NGX_SOLARIS) + +#define NGX_SETPROCTITLE_PAD ' ' + +#elif (NGX_LINUX) || (NGX_DARWIN) + +#define NGX_SETPROCTITLE_PAD '\0' + +#endif + +ngx_int_t ngx_init_setproctitle(ngx_log_t *log); +void ngx_setproctitle(char *title); + + +#else /* !NGX_SETPROCTITLE_USES_ENV */ + +#define ngx_init_setproctitle(log) +#define ngx_setproctitle(title) + +#endif + + +#endif /* _NGX_SETPROCTITLE_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -83,10 +83,4 @@ #endif -#ifndef NGX_SETPROCTITLE_USES_ENV -#define NGX_SETPROCTITLE_USES_ENV 1 -#define NGX_SETPROCTITLE_PAD ' ' -#endif - - #endif /* _NGX_SOLARIS_CONFIG_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_solaris_init.c b/src/os/unix/ngx_solaris_init.c --- a/src/os/unix/ngx_solaris_init.c +++ b/src/os/unix/ngx_solaris_init.c @@ -53,8 +53,6 @@ ngx_int_t ngx_os_init(ngx_log_t *log) return NGX_ERROR; } - ngx_init_setproctitle(log); - return ngx_posix_init(log); } diff --git a/src/os/unix/ngx_time.c b/src/os/unix/ngx_time.c --- a/src/os/unix/ngx_time.c +++ b/src/os/unix/ngx_time.c @@ -29,3 +29,43 @@ void ngx_localtime(ngx_tm_t *tm) tm->ngx_tm_mon++; tm->ngx_tm_year += 1900; } + + +void ngx_libc_localtime(struct tm *tm) +{ +#if (NGX_HAVE_LOCALTIME_R) + time_t now; + + now = ngx_time(); + localtime_r(&now, tm); + +#else + time_t now; + struct tm *t; + + now = ngx_time(); + t = localtime(&now); + *tm = *t; + +#endif +} + + +void ngx_libc_gmtime(struct tm *tm) +{ +#if (NGX_HAVE_LOCALTIME_R) + time_t now; + + now = ngx_time(); + gmtime_r(&now, tm); + +#else + time_t now; + struct tm *t; + + now = ngx_time(); + t = gmtime(&now); + *tm = *t; + +#endif +} diff --git a/src/os/unix/ngx_time.h b/src/os/unix/ngx_time.h --- a/src/os/unix/ngx_time.h +++ b/src/os/unix/ngx_time.h @@ -54,6 +54,8 @@ typedef struct tm ngx_tm_t; void ngx_localtime(ngx_tm_t *tm); +void ngx_libc_localtime(struct tm *tm); +void ngx_libc_gmtime(struct tm *tm); #define ngx_gettimeofday(tp) gettimeofday(tp, NULL); #define ngx_msleep(ms) usleep(ms * 1000) diff --git a/src/os/unix/ngx_user.c b/src/os/unix/ngx_user.c --- a/src/os/unix/ngx_user.c +++ b/src/os/unix/ngx_user.c @@ -27,11 +27,18 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, { char *value; size_t len; + ngx_err_t err; struct crypt_data cd; + ngx_set_errno(0); + + cd.initialized = 0; + value = crypt_r((char *) key, (char *) salt, &cd); - if (value) { + err = ngx_errno; + + if (err == 0) { len = ngx_strlen(value); *encrypted = ngx_palloc(pool, len); @@ -41,6 +48,8 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, } } + ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt_r() failed"); + return NGX_ERROR; } @@ -51,7 +60,7 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, { char *value; size_t len; - ngx_int_t rc; + ngx_err_t err; #if (NGX_THREADS && NGX_NONREENTRANT_CRYPT) @@ -63,7 +72,7 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, #endif - rc = NGX_ERROR; + ngx_set_errno(0); value = crypt((char *) key, (char *) salt); @@ -73,15 +82,23 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, *encrypted = ngx_palloc(pool, len); if (*encrypted) { ngx_memcpy(*encrypted, value, len + 1); - rc = NGX_OK; } + +#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT) + ngx_mutex_unlock(ngx_crypt_mutex); +#endif + return NGX_OK; } + err = ngx_errno; + #if (NGX_THREADS && NGX_NONREENTRANT_CRYPT) ngx_mutex_unlock(ngx_crypt_mutex); #endif - return rc; + ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt() failed"); + + return NGX_ERROR; } #endif diff --git a/src/os/win32/ngx_gui.c b/src/os/win32/ngx_gui.c --- a/src/os/win32/ngx_gui.c +++ b/src/os/win32/ngx_gui.c @@ -11,7 +11,8 @@ #define NGX_MAX_TEXT 2048 -void ngx_cdecl ngx_message_box(char *title, ngx_uint_t type, ngx_err_t err, +void __cdecl +ngx_message_box(char *title, ngx_uint_t type, ngx_err_t err, const char *fmt, ...) { va_list args; diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c --- a/src/os/win32/ngx_process_cycle.c +++ b/src/os/win32/ngx_process_cycle.c @@ -12,7 +12,7 @@ static void *ngx_worker_thread_cycle(void *data); static long __stdcall ngx_window_procedure(HWND window, u_int message, - u_int wparam, long lparam); + u_int wparam, long lparam); #if 0 ngx_pid_t ngx_new_binary; @@ -45,7 +45,8 @@ sig_atomic_t ngx_change_binary; static HMENU ngx_menu; -void ngx_master_process_cycle(ngx_cycle_t *cycle) +void +ngx_master_process_cycle(ngx_cycle_t *cycle) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "master mode is not supported"); @@ -53,7 +54,8 @@ void ngx_master_process_cycle(ngx_cycle_ } -void ngx_single_process_cycle(ngx_cycle_t *cycle) +void +ngx_single_process_cycle(ngx_cycle_t *cycle) { int rc; ngx_int_t i; @@ -165,7 +167,7 @@ void ngx_single_process_cycle(ngx_cycle_ if (ngx_system_tray_icon(window, NIM_ADD, tray, (u_char *) " nginx") - == NGX_ERROR) + != NGX_OK) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "Shell_NotifyIcon(NIM_ADD) failed"); @@ -200,7 +202,8 @@ void ngx_single_process_cycle(ngx_cycle_ } -static void *ngx_worker_thread_cycle(void *data) +static void * +ngx_worker_thread_cycle(void *data) { ngx_cycle_t *cycle; @@ -216,8 +219,8 @@ static void *ngx_worker_thread_cycle(voi } -static long __stdcall ngx_window_procedure(HWND window, u_int message, - u_int wparam, long lparam) +static long __stdcall +ngx_window_procedure(HWND window, u_int message, u_int wparam, long lparam) { POINT mouse; @@ -251,13 +254,13 @@ static long __stdcall ngx_window_procedu case WM_COMMAND: if (wparam == NGX_WM_ABOUT) { ngx_message_box("nginx", MB_OK, 0, - NGINX_VER CRLF "(C) 2002-2004 Igor Sysoev"); + NGINX_VER CRLF "(C) 2002-2005 Igor Sysoev"); return 0; } if (wparam == NGX_WM_EXIT) { if (ngx_system_tray_icon(window, NIM_DELETE, NULL, NULL) - == NGX_ERROR) + != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, "Shell_NotifyIcon(NIM_DELETE) failed"); diff --git a/src/os/win32/ngx_time.c b/src/os/win32/ngx_time.c --- a/src/os/win32/ngx_time.c +++ b/src/os/win32/ngx_time.c @@ -36,6 +36,28 @@ void ngx_gettimeofday(struct timeval *tp } +void ngx_libc_localtime(struct tm *tm) +{ + time_t now; + struct tm *t; + + now = ngx_time(); + t = localtime(&now); + *tm = *t; +} + + +void ngx_libc_gmtime(struct tm *tm) +{ + time_t now; + struct tm *t; + + now = ngx_time(); + t = gmtime(&now); + *tm = *t; +} + + ngx_int_t ngx_gettimezone(void) { TIME_ZONE_INFORMATION tz; diff --git a/src/os/win32/ngx_time.h b/src/os/win32/ngx_time.h --- a/src/os/win32/ngx_time.h +++ b/src/os/win32/ngx_time.h @@ -42,6 +42,8 @@ typedef FILETIME ngx_mtime_t; #define NGX_HAVE_GETTIMEZONE 1 ngx_int_t ngx_gettimezone(void); +void ngx_libc_localtime(struct tm *tm); +void ngx_libc_gmtime(struct tm *tm); void ngx_gettimeofday(struct timeval *tp); diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h --- a/src/os/win32/ngx_win32_config.h +++ b/src/os/win32/ngx_win32_config.h @@ -29,6 +29,14 @@ #include #include +#ifdef __WATCOMC__ +#define _TIME_T_DEFINED +typedef long time_t; +/* OpenWatcom defines time_t as "unsigned long" */ +#endif + +#include /* localtime(), strftime() */ + #ifdef _MSC_VER @@ -51,11 +59,6 @@ /* FD_SET() and FD_CLR(): conditional expression is constant */ #pragma warning(disable:4127) -#if 0 -/* assignment within conditional expression */ -#pragma warning(disable:4706) -#endif - /* function 'ngx_handle_write_event' not inlined */ #pragma warning(disable:4710) @@ -81,11 +84,6 @@ /* unreferenced formal parameter */ #pragma warn -8057 -#if 0 -/* assignment within conditional expression */ -#pragma warn -8060 -#endif - #endif @@ -117,7 +115,6 @@ typedef unsigned __int64 uint64_t; typedef u_int uintptr_t; typedef int ssize_t; -typedef long time_t; typedef __int64 off_t; typedef uint32_t in_addr_t; typedef u_short in_port_t;