# HG changeset patch # User Igor Sysoev # Date 1115841600 -14400 # Node ID b55cbf18157e67fbebcdfb4b99993b977e302176 # Parent 5df375c55338db6dbaeacaa20de4763c21313a40 nginx 0.1.29 *) 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; bug 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/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,90 @@ + +Changes with nginx 0.1.29 12 May 2005 + + *) 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" is + 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_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; bug 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. + Changes with nginx 0.1.28 08 Apr 2005 @@ -180,7 +267,7 @@ Changes with nginx 0.1.18 Changes with nginx 0.1.17 03 Feb 2005 - *) Feature: the ngx_http_rewrite_module was rewritten from the scratch. + *) Change: the ngx_http_rewrite_module was rewritten from the scratch. Now it is possible to redirect, to return the error codes, to check the variables and referrers. The directives can be used inside locations. The redirect directive was canceled. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,91 @@ + +Изменения в nginx 0.1.29 12.05.2005 + + *) Добавление: модуль ngx_http_ssi_module поддерживает команду include + virtual. + + *) Добавление: модуль ngx_http_ssi_module поддерживает условную команду + вида 'if expr="$NAME"' и команды else и endif. Допускается только + один уровень вложенности. + + *) Добавление: модуль ngx_http_ssi_module поддерживает две переменные + DATE_LOCAL и DATE_GMT и команду config timefmt. + + *) Добавление: директива ssi_ignore_recycled_buffers. + + *) Исправление: если переменная QUERY_STRING не была определена, то в + команде echo не ставилось значение по умолчанию. + + *) Изменение: модуль ngx_http_proxy_module полностью переписан. + + *) Добавление: директивы proxy_redirect, proxy_pass_request_headers, + proxy_pass_request_body и proxy_method. + + *) Добавление: директива proxy_set_header. Директива proxy_x_var + упразднена и должна быть заменена директивой proxy_set_header. + + *) Изменение: директива proxy_preserve_host упразднена и должна быть + заменена директивами "proxy_set_header Host $host" и "proxy_redirect + off" или директивой "proxy_set_header Host $host:$proxy_port" и + соответствующими ей директивами proxy_redirect. + + *) Изменение: директива proxy_set_x_real_ip упразднена и должна быть + заменена директивой "proxy_set_header X-Real-IP $remote_addr". + + *) Изменение: директива proxy_add_x_forwarded_for упразднена и должна + быть заменена директивой + "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for". + + *) Изменение: директива proxy_set_x_url упразднена и должна быть + заменена директивой + "proxy_set_header X-URL http://$host:$server_port$request_uri". + + *) Добавление: директива fastcgi_param. + + *) Изменение: директивы fastcgi_set_var и fastcgi_params упразднены и + должны быть замены директивами fastcgi_param. + + *) Добавление: директива index может использовать переменные. + + *) Добавление: директива index может быть указана на уровне http и + server. + + *) Изменение: только последний параметр в директиве index может быть + абсолютным. + + *) Добавление: в директиве rewrite могут использоваться переменные. + + *) Добавление: директива internal. + + *) Добавление: переменные CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, + SERVER_ADDR, SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, + SERVER_NAME, REQUEST_METHOD, REQUEST_URI и REMOTE_USER. + + *) Изменение: nginx теперь передаёт неверные строки в заголовках + запроса клиента и ответа бэкенда. + + *) Исправление: если бэкенд долго не передавал ответ и send_timeout был + меньше, чем proxy_read_timeout, то клиенту возвращался ответ 408. + + *) Исправление: если бэкенд передавал неверную строку в заголовке + ответа, то происходил segmentation fault; ошибка появилась в 0.1.26. + + *) Исправление: при использовании отказоустойчивой конфигурации в + FastCGI мог происходить segmentation fault. + + *) Исправление: директива expires не удаляла уже установленные строки + заголовка "Expires" и "Cache-Control". + + *) Исправление: nginx не учитывал завершающую точку в строке заголовка + запроса "Host". + + *) Исправление: модуль ngx_http_auth_module не работал на Linux. + + *) Исправление: директива rewrite неверно работала, если в запросе + присутствовали аргументы. + + *) Исправление: nginx не собирался на MacOS X. + Изменения в nginx 0.1.28 08.04.2005 @@ -181,7 +269,7 @@ Изменения в nginx 0.1.17 03.02.2005 - *) Добавление: модуль ngx_http_rewrite_module полностью переписан. + *) Изменение: модуль ngx_http_rewrite_module полностью переписан. Теперь можно делать редиректы, возвращать коды ошибок и проверять переменные и рефереры. Эти директивы можно использовать внутри location. Директива redirect упразднена. 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/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_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_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 new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_proxy_module.c @@ -0,0 +1,1934 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +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); + +struct ngx_http_proxy_redirect_s { + ngx_http_proxy_redirect_pt handler; + ngx_str_t redirect; + + union { + ngx_str_t text; + + struct { + void *lengths; + void *values; + } vars; + + void *regex; + } replacement; +}; + + +typedef struct { + ngx_http_upstream_conf_t upstream; + + ngx_peers_t *peers; + + 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_array_t *redirects; + + ngx_str_t host_header; + ngx_str_t port_text; + + ngx_flag_t redirect; +} ngx_http_proxy_loc_conf_t; + + +typedef struct { + ngx_uint_t status; + ngx_uint_t status_count; + u_char *status_start; + u_char *status_end; +} ngx_http_proxy_ctx_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 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_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_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_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 }; + +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 }, + { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, + { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, + { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_proxy_commands[] = { + + { ngx_string("proxy_pass"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_proxy_pass, + NGX_HTTP_LOC_CONF_OFFSET, + 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, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout), + NULL }, + + { ngx_string("proxy_send_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout), + NULL }, + + { ngx_string("proxy_send_lowat"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + 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, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_unparsed_uri), + NULL }, + + { 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, headers_source), + NULL }, + + { 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, upstream.pass_request_headers), + NULL }, + + { 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, upstream.pass_request_body), + NULL }, + + { ngx_string("proxy_header_buffer_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.header_buffer_size), + NULL }, + + { ngx_string("proxy_read_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout), + NULL }, + + { ngx_string("proxy_buffers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_bufs_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs), + NULL }, + + { ngx_string("proxy_busy_buffers_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size), + NULL }, + + { ngx_string("proxy_temp_path"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, + ngx_conf_set_path_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path), + (void *) ngx_garbage_collector_temp_handler }, + + { ngx_string("proxy_max_temp_file_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size), + NULL }, + + { ngx_string("proxy_temp_file_write_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size), + NULL }, + + { ngx_string("proxy_next_upstream"), + 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_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, 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, upstream.pass_x_accel_expires), + NULL }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_proxy_module_ctx = { + ngx_http_proxy_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_proxy_create_loc_conf, /* create location configration */ + ngx_http_proxy_merge_loc_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_proxy_module = { + NGX_MODULE_V1, + &ngx_http_proxy_module_ctx, /* module context */ + ngx_http_proxy_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static ngx_str_t ngx_http_proxy_methods[] = { + ngx_string("GET "), + ngx_string("HEAD "), + ngx_string("POST ") +}; + + +static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF; + + +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) +static ngx_str_t ngx_http_proxy_uri = ngx_string("/"); +#endif + + +static ngx_int_t +ngx_http_proxy_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_upstream_t *u; + ngx_http_proxy_loc_conf_t *plcf; + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); + if (u == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + u->peer.log = r->connection->log; + u->peer.log_error = NGX_ERROR_ERR; + u->peer.peers = plcf->peers; + u->peer.tries = plcf->peers->number; +#if (NGX_THREADS) + u->peer.lock = &r->connection->lock; +#endif + + u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module; + + u->conf = &plcf->upstream; + + u->create_request = ngx_http_proxy_create_request; + u->reinit_request = ngx_http_proxy_reinit_request; + 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->accel = 1; + + r->upstream = u; + + rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_proxy_create_request(ngx_http_request_t *r) +{ + 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; + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + len = sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1; + + if (u->method) { + len += ngx_http_proxy_methods[u->method - 1].len + u->conf->uri.len; + } else { + 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 + loc_len, + r->uri.len - loc_len, NGX_ESCAPE_URI); + } + + len += r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len; + } + + ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); + + le.ip = plcf->headers_set_len->elts; + le.request = r; + + 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); + } + + + hh = (ngx_str_t *) plcf->headers_set_hash->buckets; + + 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; + } + + part = part->next; + header = part->elts; + i = 0; + } + + 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; + } + + 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) { + return NGX_ERROR; + } + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + + + /* the request line */ + + if (u->method) { + b->last = ngx_cpymem(b->last, + 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 + 1); + } + + 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 + 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 + loc_len, + r->uri.len - loc_len); + } + + if (r->args.len > 0) { + *b->last++ = '?'; + b->last = ngx_cpymem(b->last, r->args.data, r->args.len); + } + } + + b->last = ngx_cpymem(b->last, ngx_http_proxy_version, + sizeof(ngx_http_proxy_version) - 1); + + + e.ip = plcf->headers_set->elts; + e.pos = b->last; + e.request = r; + + 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; + + + 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; + } + + part = part->next; + header = part->elts; + i = 0; + } + + 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; + } + + b->last = ngx_cpymem(b->last, header[i].key.data, + header[i].key.len); + + *b->last++ = ':'; *b->last++ = ' '; + + b->last = ngx_cpymem(b->last, header[i].value.data, + header[i].value.len); + + *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); + } + } + + /* add "\r\n" at the header end */ + *b->last++ = CR; *b->last++ = LF; + +#if (NGX_DEBUG) + { + ngx_str_t s; + + s.len = b->last - b->pos; + s.data = b->pos; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy header:\n\"%V\"", &s); + } +#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; +} + + +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; +} + + +static ngx_int_t +ngx_http_proxy_process_header(ngx_http_request_t *r) +{ + 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; + + 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; + } +} + + +static void +ngx_http_proxy_abort_request(ngx_http_request_t *r) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "abort http proxy request"); + + return; +} + + +static void +ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "finalize http proxy request"); + + return; +} + + +static ngx_http_variable_value_t * +ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data) +{ + ngx_http_variable_value_t *vv; + ngx_http_proxy_loc_conf_t *plcf; + + 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); + + vv->value = 0; + vv->text = plcf->host_header; + + return vv; +} + + +static ngx_http_variable_value_t * +ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data) +{ + ngx_http_variable_value_t *vv; + ngx_http_proxy_loc_conf_t *plcf; + + 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); + + 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; + + 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; +} + + +static void * +ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_proxy_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->upstream.bufs.num = 0; + * 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; + conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + + conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; + conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE; + 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; + + /* "proxy_cyclic_temp_file" is disabled */ + conf->upstream.cyclic_temp_file = 0; + + 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->redirect = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_proxy_loc_conf_t *prev = parent; + ngx_http_proxy_loc_conf_t *conf = child; + + 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); + + ngx_conf_merge_msec_value(conf->upstream.send_timeout, + prev->upstream.send_timeout, 60000); + + ngx_conf_merge_msec_value(conf->upstream.read_timeout, + prev->upstream.read_timeout, 60000); + + ngx_conf_merge_size_value(conf->upstream.send_lowat, + prev->upstream.send_lowat, 0); + + ngx_conf_merge_size_value(conf->upstream.header_buffer_size, + prev->upstream.header_buffer_size, + (size_t) ngx_pagesize); + + ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, + 8, ngx_pagesize); + + if (conf->upstream.bufs.num < 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "there must be at least 2 \"proxy_buffers\""); + return NGX_CONF_ERROR; + } + + + size = conf->upstream.header_buffer_size; + if (size < conf->upstream.bufs.size) { + size = conf->upstream.bufs.size; + } + + + ngx_conf_merge_size_value(conf->upstream.busy_buffers_size, + prev->upstream.busy_buffers_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.busy_buffers_size == NGX_CONF_UNSET_SIZE) { + conf->upstream.busy_buffers_size = 2 * size; + + } else if (conf->upstream.busy_buffers_size < size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_busy_buffers_size\" must be equal or bigger than " + "maximum of the value of \"proxy_header_buffer_size\" and " + "one of the \"proxy_buffers\""); + + return NGX_CONF_ERROR; + + } else if (conf->upstream.busy_buffers_size + > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_busy_buffers_size\" must be less than " + "the size of all \"proxy_buffers\" minus one buffer"); + + return NGX_CONF_ERROR; + } + + + ngx_conf_merge_size_value(conf->upstream.temp_file_write_size, + prev->upstream.temp_file_write_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.temp_file_write_size == NGX_CONF_UNSET_SIZE) { + conf->upstream.temp_file_write_size = 2 * size; + + } else if (conf->upstream.temp_file_write_size < size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_temp_file_write_size\" must be equal or bigger than " + "maximum of the value of \"proxy_header_buffer_size\" and " + "one of the \"proxy_buffers\""); + + return NGX_CONF_ERROR; + } + + + ngx_conf_merge_size_value(conf->upstream.max_temp_file_size, + prev->upstream.max_temp_file_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.max_temp_file_size == NGX_CONF_UNSET_SIZE) { + + conf->upstream.max_temp_file_size = 1024 * 1024 * 1024; + + } else if (conf->upstream.max_temp_file_size != 0 + && conf->upstream.max_temp_file_size < size) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_max_temp_file_size\" must be equal to zero to disable " + "the temporary files usage or must be equal or bigger than " + "maximum of the value of \"fastcgi_header_buffer_size\" and " + "one of the \"fastcgi_buffers\""); + + return NGX_CONF_ERROR; + } + + ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, + prev->upstream.next_upstream, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_UPSTREAM_FT_ERROR + |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); + + 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->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; + } + + 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) { + + 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_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) { + 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; + } + } + + 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; + } + } + + s = ngx_array_push(conf->headers_source); + if (s == NULL) { + return NGX_CONF_ERROR; + } + + *s = *h; + + next: + + continue; + } + + for (i = 0; i < conf->headers_source->nelts; i++) { + + name = ngx_array_push(conf->headers_names); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + *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; + + + 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; + + + 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; + } + + code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_CONF_ERROR; + } + + *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; + } + + code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_CONF_ERROR; + } + + *code = (uintptr_t) NULL; + + + conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash_t)); + if (conf->headers_set_hash == NULL) { + return NGX_CONF_ERROR; + } + + 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, conf->headers_names->nelts) != NGX_OK) + { + return NGX_CONF_ERROR; + } + + 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); + + 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 *plcf = conf; + + ngx_uint_t i; + ngx_str_t *value, *url; + 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; + + url = &value[1]; + + if (ngx_strncasecmp(url->data, "http://", 7) != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix"); + return NGX_CONF_ERROR; + } + + if (ngx_strncasecmp(url->data + 7, "unix:", 5) == 0) { + +#if (NGX_HAVE_UNIX_DOMAIN) + + ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); + + unix_upstream.name = *url; + unix_upstream.url.len = url->len - 7; + unix_upstream.url.data = url->data + 7; + unix_upstream.uri_part = 1; + + plcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); + if (plcf->peers == NULL) { + return NGX_CONF_ERROR; + } + + plcf->peers->peer[0].uri_separator = ":"; + + 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, + "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 = *url; + inet_upstream.url.len = url->len - 7; + inet_upstream.url.data = url->data + 7; + inet_upstream.default_port_value = 80; + inet_upstream.uri_part = 1; + + plcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); + if (plcf->peers == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; i < plcf->peers->number; i++) { + plcf->peers->peer[i].uri_separator = ":"; + } + + 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) + plcf->upstream.location = clcf->regex ? &ngx_http_proxy_uri : &clcf->name; +#else + plcf->upstream.location = &clcf->name; +#endif + + plcf->upstream.url = *url; + + if (clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + + return NGX_CONF_OK; +} + + +static char * +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; +} + + +static char * +ngx_http_proxy_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, + "\"proxy_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, + "\"proxy_send_lowat\" is not supported, ignored"); + + *np = 0; + +#endif + + 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_cache.c b/src/http/modules/proxy/ngx_http_proxy_cache.c deleted file mode 100644 --- a/src/http/modules/proxy/ngx_http_proxy_cache.c +++ /dev/null @@ -1,628 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include - - -static int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p, - int rc); -static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p); -static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p); - - -int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p) -{ - char *last; - ngx_http_request_t *r; - ngx_http_proxy_cache_t *c; - ngx_http_proxy_upstream_conf_t *u; - - r = p->request; - - if (!(c = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_cache_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - p->cache = c; - - c->ctx.file.fd = NGX_INVALID_FILE; - c->ctx.file.log = r->connection->log; - c->ctx.path = p->lcf->cache_path; - - u = p->lcf->upstream; - - c->ctx.key.len = u->url.len + r->uri.len - u->location->len + r->args.len; - if (!(c->ctx.key.data = ngx_palloc(r->pool, c->ctx.key.len + 1))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - last = ngx_cpymem(c->ctx.key.data, u->url.data, u->url.len); - - last = ngx_cpymem(last, r->uri.data + u->location->len, - r->uri.len - u->location->len); - - if (r->args.len > 0) { - *(last++) = '?'; - last = ngx_cpymem(last, r->args.data, r->args.len); - } - *last = '\0'; - - p->header_in = ngx_create_temp_hunk(r->pool, p->lcf->header_buffer_size); - if (p->header_in == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module; - - c->ctx.buf = p->header_in; - c->ctx.log = r->connection->log; - - return ngx_http_proxy_process_cached_response(p, - ngx_http_cache_get_file(r, &c->ctx)); -} - - -static int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p, - int rc) -{ - if (rc == NGX_OK) { - p->state->cache_state = NGX_HTTP_PROXY_CACHE_HIT; - p->header_in->pos = p->header_in->start + p->cache->ctx.header_size; - - if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - p->valid_header_in = 1; - - return ngx_http_proxy_send_cached_response(p); - } - - if (rc == NGX_HTTP_CACHE_STALE) { - p->state->cache_state = NGX_HTTP_PROXY_CACHE_EXPR; - - } else if (rc == NGX_HTTP_CACHE_AGED) { - p->state->cache_state = NGX_HTTP_PROXY_CACHE_AGED; - } - - if (rc == NGX_HTTP_CACHE_STALE || rc == NGX_HTTP_CACHE_AGED) { - p->state->expired = ngx_time() - p->cache->ctx.expires; - p->header_in->pos = p->header_in->start + p->cache->ctx.header_size; - - if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - p->header_in->pos = p->header_in->start + p->cache->ctx.header_size; - p->header_in->last = p->header_in->pos; - - p->stale = 1; - p->valid_header_in = 1; - - } else if (rc == NGX_DECLINED) { - p->state->cache_state = NGX_HTTP_PROXY_CACHE_MISS; - p->header_in->pos = p->header_in->start + p->cache->ctx.header_size; - p->header_in->last = p->header_in->pos; - } - - if (p->lcf->busy_lock) { - p->try_busy_lock = 1; - - p->header_in->pos = p->header_in->start; - p->header_in->last = p->header_in->start; - - p->busy_lock.time = 0; - p->busy_lock.event = p->request->connection->read; - p->busy_lock.event_handler = ngx_http_proxy_busy_lock_handler; - p->busy_lock.md5 = p->cache->ctx.md5; - - ngx_http_proxy_cache_busy_lock(p); - return NGX_DONE; - } - - return ngx_http_proxy_request_upstream(p); -} - - -static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p) -{ - int rc, i; - ngx_table_elt_t *h; - ngx_http_request_t *r; - ngx_http_proxy_cache_t *c; - - rc = ngx_http_proxy_parse_status_line(p); - - c = p->cache; - r = p->request; - - if (rc == NGX_AGAIN) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "\"proxy_header_buffer_size\" " - "is too small to read header from \"%s\"", - c->ctx.file.name.data); - return NGX_ERROR; - } - - if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "no valid HTTP/1.0 header in \"%s\"", - c->ctx.file.name.data); - return NGX_ERROR; - } - - /* rc == NGX_OK */ - - c->status = p->status; - c->status_line.len = p->status_end - p->status_start; - c->status_line.data = ngx_palloc(r->pool, c->status_line.len + 1); - if (c->status_line.data == NULL) { - return NGX_ERROR; - } - - /* reset for the possible parsing the upstream header */ - - p->status = 0; - p->status_count = 0; - - ngx_cpystrn(c->status_line.data, p->status_start, c->status_line.len + 1); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http cache status %ui \"%V\"", - c->status, &c->status_line); - - /* TODO: ngx_init_table */ - c->headers_in.headers = ngx_create_table(r->pool, 20); - - for ( ;; ) { - rc = ngx_http_parse_header_line(r, p->header_in); - - if (rc == NGX_OK) { - - /* a header line has been parsed successfully */ - - h = ngx_http_add_header(&c->headers_in, ngx_http_proxy_headers_in); - if (h == NULL) { - return NGX_ERROR; - } - - 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_ERROR; - } - - h->value.data = h->key.data + h->key.len + 1; - 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_proxy_headers_in[i].name.len != 0; i++) { - if (ngx_http_proxy_headers_in[i].name.len != h->key.len) { - continue; - } - - if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data, - h->key.data) == 0) - { - *((ngx_table_elt_t **) ((char *) &c->headers_in - + ngx_http_proxy_headers_in[i].offset)) = h; - break; - } - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http cache header: \"%V: %V\"", &h->key, &h->value); - - continue; - - } else 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 cache header done"); - - c->ctx.file_start = p->header_in->pos - p->header_in->start; - - return NGX_OK; - - } else if (rc == NGX_HTTP_PARSE_INVALID_HEADER) { - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid header in \"%s\"", - c->ctx.file.name.data); - return NGX_ERROR; - } - - /* rc == NGX_AGAIN || rc == NGX_HTTP_PARSE_TOO_LONG_HEADER */ - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "\"proxy_header_buffer_size\" " - "is too small to read header from \"%s\"", - c->ctx.file.name.data); - return NGX_ERROR; - } -} - - -void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p) -{ - int rc, ft_type; - - rc = ngx_http_busy_lock_cachable(p->lcf->busy_lock, &p->busy_lock, - p->try_busy_lock); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0, - "http cache busy lock cachable: %d", rc); - - if (rc == NGX_OK) { - if (p->try_busy_lock) { - p->busy_locked = 1; - p->header_in->pos = p->header_in->start + p->cache->ctx.header_size; - p->header_in->last = p->header_in->pos; - - ngx_http_proxy_request_upstream(p); - return; - } - - ngx_http_proxy_cache_look_complete_request(p); - return; - } - - p->try_busy_lock = 0; - - if (p->cache->ctx.file.fd != NGX_INVALID_FILE - && !p->cache->ctx.file.info_valid) - { - if (ngx_fd_info(p->cache->ctx.file.fd, &p->cache->ctx.file.info) - == NGX_FILE_ERROR) - { - ngx_log_error(NGX_LOG_CRIT, p->request->connection->log, ngx_errno, - ngx_fd_info_n " \"%s\" failed", - p->cache->ctx.file.name.data); - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - p->cache->ctx.file.info_valid = 1; - } - - if (rc == NGX_AGAIN) { - - if ((ngx_event_flags & (NGX_USE_CLEAR_EVENT|NGX_USE_KQUEUE_EVENT)) - && !p->request->connection->write->active) - { - /* - * kqueue allows to detect when client closes prematurely - * connection - */ - - p->request->connection->write->event_handler = - ngx_http_proxy_check_broken_connection; - - if (ngx_add_event(p->request->connection->write, NGX_WRITE_EVENT, - NGX_CLEAR_EVENT) == NGX_ERROR) - { - ngx_http_proxy_finalize_request(p, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - } - - return; - } - - ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock); - - if (rc == NGX_DONE) { - ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK; - - } else { - /* rc == NGX_ERROR */ - ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING; - } - - if (p->stale && (p->lcf->use_stale & ft_type)) { - ngx_http_proxy_finalize_request(p, - ngx_http_proxy_send_cached_response(p)); - return; - } - - p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE; - ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE); -} - - -static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p) -{ - int rc; - ngx_http_cache_ctx_t *ctx; - - if (!(ctx = ngx_pcalloc(p->request->pool, sizeof(ngx_http_cache_ctx_t)))) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - *ctx = p->cache->ctx; - - rc = ngx_http_cache_open_file(ctx, ngx_file_uniq(&p->cache->ctx.file.info)); - - if (rc == NGX_DECLINED || rc == NGX_HTTP_CACHE_THE_SAME) { - p->try_busy_lock = 1; - p->busy_lock.time = 0; - ngx_http_proxy_cache_busy_lock(p); - return; - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0, - "http cache old fd:%d, new fd:%d", - p->cache->ctx.file.fd, ctx->file.fd); - - if (p->cache->ctx.file.fd != NGX_INVALID_FILE) { - if (ngx_close_file(p->cache->ctx.file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, p->request->connection->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - p->cache->ctx.file.name.data); - } - } - - p->cache->ctx = *ctx; - - p->status = 0; - p->status_count = 0; - - ngx_http_proxy_finalize_request(p, - ngx_http_proxy_process_cached_response(p, rc)); -} - - -int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p) -{ - int rc, len, i; - off_t rest; - ngx_hunk_t *h0, *h1; - ngx_chain_t out[2]; - ngx_http_request_t *r; - - r = p->request; - - r->headers_out.status = p->cache->status; - -#if 0 - r->headers_out.content_length_n = -1; - r->headers_out.content_length = NULL; -#endif - - /* copy an cached header to r->headers_out */ - - if (ngx_http_proxy_copy_header(p, &p->cache->headers_in) == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - /* we need to allocate all before the header would be sent */ - - len = p->header_in->end - (p->header_in->start + p->cache->ctx.file_start); - - h0 = NULL; - h1 = NULL; - - if (len) { - if (!((h0 = ngx_calloc_hunk(r->pool)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (!((h0->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - } - - if (len < p->cache->ctx.length) { - if (!((h1 = ngx_calloc_hunk(r->pool)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (!((h1->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - } - - rc = ngx_http_send_header(r); - - /* NEEDED ??? */ p->header_sent = 1; - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - rest = p->cache->ctx.length; - - if (len) { - if (p->valid_header_in) { - h0->pos = p->header_in->start + p->cache->ctx.file_start; - - if (len > p->cache->ctx.length) { - h0->last = h0->pos + p->cache->ctx.length; - - } else { - h0->last = p->header_in->end; - } - - h0->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP; - } - - h0->type |= NGX_HUNK_FILE; - h0->file_pos = p->cache->ctx.file_start; - - h0->file->fd = p->cache->ctx.file.fd; - h0->file->log = r->connection->log; - - if (len > p->cache->ctx.length) { - h0->file_last = h0->file_pos + p->cache->ctx.length; - rest = 0; - - } else { - h0->file_last = h0->file_pos + len; - rest -= len; - } - - out[0].hunk = h0; - out[0].next = &out[1]; - i = 0; - - } else { - i = -1; - } - - if (rest) { - h1->file_pos = p->cache->ctx.file_start + len; - h1->file_last = h1->file_pos + rest; - h1->type = NGX_HUNK_FILE; - - h1->file->fd = p->cache->ctx.file.fd; - h1->file->log = r->connection->log; - - out[++i].hunk = h1; - } - - out[i].next = NULL; - if (!r->main) { - out[i].hunk->type |= NGX_HUNK_LAST; - } - - r->file.fd = p->cache->ctx.file.fd; - - return ngx_http_output_filter(r, out); -} - - -int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p) -{ - time_t date, last_modified, expires, t; - ngx_http_proxy_headers_in_t *h; - - switch (p->upstream->status) { - case NGX_HTTP_OK: - case NGX_HTTP_MOVED_PERMANENTLY: - case NGX_HTTP_MOVED_TEMPORARILY: - break; - -#if 0 - case NGX_HTTP_NOT_MODIFIED: - return 1; -#endif - - default: - return 0; - } - - h = &p->upstream->headers_in; - - date = NGX_ERROR; - if (h->date) { - date = ngx_http_parse_time(h->date->value.data, h->date->value.len); - } - if (date == NGX_ERROR) { - date = ngx_time(); - } - p->cache->ctx.date = date; - - last_modified = NGX_ERROR; - if (h->last_modified) { - last_modified = ngx_http_parse_time(h->last_modified->value.data, - h->last_modified->value.len); - p->cache->ctx.last_modified = last_modified; - } - - if (h->x_accel_expires) { - expires = ngx_atoi(h->x_accel_expires->value.data, - h->x_accel_expires->value.len); - if (expires != NGX_ERROR) { - p->state->reason = NGX_HTTP_PROXY_CACHE_XAE; - p->state->expires = expires; - p->cache->ctx.expires = date + expires; - return (expires > 0); - } - } - - if (!p->lcf->ignore_expires) { - - /* TODO: Cache-Control: no-cache, max-age= */ - - if (h->expires) { - expires = ngx_http_parse_time(h->expires->value.data, - h->expires->value.len); - if (expires != NGX_ERROR) { - p->state->reason = NGX_HTTP_PROXY_CACHE_EXP; - p->state->expires = expires - date; - p->cache->ctx.expires = expires; - return (date < expires); - } - } - } - - if (p->upstream->status == NGX_HTTP_MOVED_PERMANENTLY) { - p->state->reason = NGX_HTTP_PROXY_CACHE_MVD; - p->state->expires = /* STUB: 1 hour */ 60 * 60; - p->cache->ctx.expires = /* STUB: 1 hour */ 60 * 60; - return 1; - } - - if (p->upstream->status == NGX_HTTP_MOVED_TEMPORARILY) { - return 1; - } - - if (last_modified != NGX_ERROR && p->lcf->lm_factor > 0) { - - /* FIXME: time_t == int_64_t, we can use fpu */ - - p->state->reason = NGX_HTTP_PROXY_CACHE_LMF; - t = (time_t) - ((((int64_t) (date - last_modified)) * p->lcf->lm_factor) / 100); - p->state->expires = t; - p->cache->ctx.expires = ngx_time() + t; - return 1; - } - - if (p->lcf->default_expires > 0) { - p->state->reason = NGX_HTTP_PROXY_CACHE_PDE; - p->state->expires = p->lcf->default_expires; - p->cache->ctx.expires = ngx_time() + p->lcf->default_expires; - return 1; - } - - return 0; -} - - -int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p) -{ - ngx_event_pipe_t *ep; - - if (p->cache == NULL) { - return NGX_OK; - } - - ep = p->upstream->event_pipe; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0, - "http cache update len: %O:%O", - p->cache->ctx.length, ep->read_length); - - if (p->cache->ctx.length == -1) { - /* TODO: test rc */ - ngx_write_file(&ep->temp_file->file, - (char *) &ep->read_length, sizeof(off_t), - offsetof(ngx_http_cache_header_t, length)); - } - - return ngx_http_cache_update_file(p->request, &p->cache->ctx, - &ep->temp_file->file.name); -} diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c deleted file mode 100644 --- a/src/http/modules/proxy/ngx_http_proxy_handler.c +++ /dev/null @@ -1,1509 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include - - -static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r); -#if 0 -static ngx_int_t ngx_http_proxy_cache_get(ngx_http_proxy_ctx_t *p); -#endif - -static size_t ngx_http_proxy_log_proxy_state_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r, - u_char *buf, - ngx_http_log_op_t *op); - -#if 0 -static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r, - u_char *buf, uintptr_t data); -static u_char *ngx_http_proxy_log_reason(ngx_http_request_t *r, u_char *buf, - uintptr_t data); -#endif - -static ngx_int_t ngx_http_proxy_add_log_formats(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_set_pass(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 } ; - - -static ngx_conf_bitmask_t next_upstream_masks[] = { - { ngx_string("error"), NGX_HTTP_PROXY_FT_ERROR }, - { ngx_string("timeout"), NGX_HTTP_PROXY_FT_TIMEOUT }, - { ngx_string("invalid_header"), NGX_HTTP_PROXY_FT_INVALID_HEADER }, - { ngx_string("http_500"), NGX_HTTP_PROXY_FT_HTTP_500 }, - { ngx_string("http_404"), NGX_HTTP_PROXY_FT_HTTP_404 }, - { ngx_null_string, 0 } -}; - - -static ngx_conf_bitmask_t use_stale_masks[] = { - { ngx_string("error"), NGX_HTTP_PROXY_FT_ERROR }, - { ngx_string("timeout"), NGX_HTTP_PROXY_FT_TIMEOUT }, - { ngx_string("invalid_header"), NGX_HTTP_PROXY_FT_INVALID_HEADER }, - { ngx_string("http_500"), NGX_HTTP_PROXY_FT_HTTP_500 }, - { ngx_string("busy_lock"), NGX_HTTP_PROXY_FT_BUSY_LOCK }, - { ngx_string("max_waiting"), NGX_HTTP_PROXY_FT_MAX_WAITING }, - { ngx_null_string, 0 } -}; - - -static ngx_conf_num_bounds_t ngx_http_proxy_lm_factor_bounds = { - ngx_conf_check_num_bounds, 0, 100 -}; - - -static ngx_command_t ngx_http_proxy_commands[] = { - - { ngx_string("proxy_pass"), - NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_proxy_set_pass, - 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, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, connect_timeout), - NULL }, - - { ngx_string("proxy_send_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, send_timeout), - NULL }, - - { ngx_string("proxy_send_lowat"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, send_lowat), - &ngx_http_proxy_lowat_post }, - - { 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_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, preserve_host), - 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, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, pass_unparsed_uri), - NULL }, - - { ngx_string("proxy_set_x_url"), - 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), - NULL }, - - { ngx_string("proxy_set_x_real_ip"), - 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), - NULL }, - - { ngx_string("proxy_header_buffer_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, header_buffer_size), - NULL }, - - { ngx_string("proxy_read_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, read_timeout), - NULL }, - - { ngx_string("proxy_buffers"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_conf_set_bufs_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, bufs), - NULL }, - - { ngx_string("proxy_busy_buffers_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, busy_buffers_size), - NULL }, - -#if 0 - - { ngx_string("proxy_cache_path"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, - ngx_conf_set_path_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, cache_path), - (void *) ngx_http_cache_cleaner_handler }, - -#endif - - { ngx_string("proxy_temp_path"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, - ngx_conf_set_path_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, temp_path), - (void *) ngx_garbage_collector_temp_handler }, - - { ngx_string("proxy_max_temp_file_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, max_temp_file_size), - NULL }, - - { ngx_string("proxy_temp_file_write_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, temp_file_write_size), - NULL }, - - { ngx_string("proxy_cache"), - 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, cache), - NULL }, - - - { ngx_string("proxy_busy_lock"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13, - ngx_http_set_busy_lock_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, busy_lock), - 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), - 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), - NULL }, - - { ngx_string("proxy_ignore_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, ignore_expires), - NULL }, - - { ngx_string("proxy_lm_factor"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, lm_factor), - &ngx_http_proxy_lm_factor_bounds }, - - { ngx_string("proxy_default_expires"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_sec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, default_expires), - NULL }, - - { ngx_string("proxy_next_upstream"), - 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_proxy_loc_conf_t, next_upstream), - &next_upstream_masks }, - - { ngx_string("proxy_use_stale"), - 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_proxy_loc_conf_t, use_stale), - &use_stale_masks }, - - ngx_null_command -}; - - -ngx_http_module_t ngx_http_proxy_module_ctx = { - ngx_http_proxy_add_log_formats, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_proxy_create_loc_conf, /* create location configration */ - ngx_http_proxy_merge_loc_conf /* merge location configration */ -}; - - -ngx_module_t ngx_http_proxy_module = { - NGX_MODULE, - &ngx_http_proxy_module_ctx, /* module context */ - ngx_http_proxy_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init module */ - NULL /* init process */ -}; - - - -static ngx_http_log_op_name_t ngx_http_proxy_log_fmt_ops[] = { - { ngx_string("proxy"), 0, NULL, - ngx_http_proxy_log_proxy_state_getlen, - ngx_http_proxy_log_proxy_state }, - -#if 0 - { ngx_string("proxy_cache_state"), 0, ngx_http_proxy_log_cache_state }, - { ngx_string("proxy_reason"), 0, ngx_http_proxy_log_reason }, -#endif - - { ngx_null_string, 0, NULL, NULL, NULL } -}; - - - -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 } -}; - - -static ngx_str_t cache_states[] = { - ngx_string("PASS"), - ngx_string("BYPASS"), - ngx_string("AUTH"), - ngx_string("PGNC"), - ngx_string("MISS"), - ngx_string("EXPR"), - ngx_string("AGED"), - ngx_string("HIT") -}; - - -static ngx_str_t cache_reasons[] = { - ngx_string("BPS"), - ngx_string("XAE"), - ngx_string("CTL"), - ngx_string("EXP"), - ngx_string("MVD"), - ngx_string("LMF"), - ngx_string("PDE") -}; - - -#if (NGX_PCRE) -static ngx_str_t ngx_http_proxy_uri = ngx_string("/"); -#endif - - -static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r) -{ - ngx_http_proxy_ctx_t *p; - - 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); - - - p->lcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - p->request = r; - - /* TODO: we currently support reverse proxy only */ - p->accel = 1; - - if (ngx_array_init(&p->states, r->pool, p->lcf->peers->number, - sizeof(ngx_http_proxy_state_t)) == NGX_ERROR) - { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - p->state = ngx_array_push(&p->states); - if (p->state == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_memzero(p->state, sizeof(ngx_http_proxy_state_t)); - -#if 0 - - if (!p->lcf->cache - || (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD)) - { - p->state->cache_state = NGX_HTTP_PROXY_CACHE_PASS; - - } else if (r->bypass_cache) { - p->state->cache_state = NGX_HTTP_PROXY_CACHE_BYPASS; - - } else if (r->headers_in.authorization) { - p->state->cache_state = NGX_HTTP_PROXY_CACHE_AUTH; - - } else if (r->no_cache) { - p->state->cache_state = NGX_HTTP_PROXY_CACHE_PGNC; - p->cachable = 1; - - } else { - p->cachable = 1; - } - - - if (p->state->cache_state != 0) { - return ngx_http_proxy_request_upstream(p); - } - - return ngx_http_proxy_cache_get(p); - -#else - - p->state->cache_state = NGX_HTTP_PROXY_CACHE_PASS; - - return ngx_http_proxy_request_upstream(p); - -#endif -} - - -#if 0 - -static ngx_int_t ngx_http_proxy_cache_get(ngx_http_proxy_ctx_t *p) -{ - u_char *last; - ngx_http_request_t *r; - ngx_http_cache_ctx_t ctx; - ngx_http_proxy_upstream_conf_t *u; - - r = p->request; - u = p->lcf->upstream; - - ctx.key.len = u->url.len + r->uri.len - u->location->len + r->args.len; - ctx.key.data = ngx_palloc(r->pool, ctx.key.len); - if (ctx.key.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - last = ngx_cpymem(ctx.key.data, u->url.data, u->url.len); - - last = ngx_cpymem(last, r->uri.data + u->location->len, - r->uri.len - u->location->len); - - if (r->args.len > 0) { - *(last++) = '?'; - last = ngx_cpymem(last, r->args.data, r->args.len); - } - - p->header_in = ngx_create_temp_buf(r->pool, p->lcf->header_buffer_size); - if (p->header_in == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - p->header_in->tag = (ngx_buf_tag_t) &ngx_http_proxy_module; - - ctx.buf = p->header_in; - ctx.path = p->lcf->cache_path; - ctx.file = 1; - ctx.primary = 1; - - ngx_http_cache_get(r, &ctx); - - return ngx_http_proxy_request_upstream(p); -} - -#endif - - -void ngx_http_proxy_check_broken_connection(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, - "http proxy check client, write event:%d", ev->write); - -#if (NGX_HAVE_KQUEUE) - - if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { - - if (!ev->pending_eof) { - return; - } - - c = ev->data; - r = c->data; - p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); - - ev->eof = 1; - - if (ev->kq_errno) { - ev->error = 1; - } - - if (!p->cachable && p->upstream->peer.connection) { - ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno, - "kevent() reported that client closed " - "prematurely connection, " - "so upstream connection is closed too"); - ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - - ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno, - "kevent() reported that client closed " - "prematurely connection"); - - if (p->upstream == NULL || p->upstream->peer.connection == NULL) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST); - } - - return; - } - -#endif - - c = ev->data; - r = c->data; - p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); - - n = recv(c->fd, buf, 1, MSG_PEEK); - - err = ngx_socket_errno; - - /* - * we do not need to disable the write event because - * that event has NGX_USE_CLEAR_EVENT type - */ - - if (ev->write && (n >= 0 || err == NGX_EAGAIN)) { - return; - } - - if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) { - if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - } - } - - if (n > 0) { - return; - } - - ev->eof = 1; - - if (n == -1) { - if (err == NGX_EAGAIN) { - return; - } - - ev->error = 1; - - } else { - /* n == 0 */ - err = 0; - } - - if (!p->cachable && p->upstream->peer.connection) { - ngx_log_error(NGX_LOG_INFO, ev->log, err, - "client closed prematurely connection, " - "so upstream connection is closed too"); - ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - - ngx_log_error(NGX_LOG_INFO, ev->log, err, - "client closed prematurely connection"); - - if (p->upstream == NULL || p->upstream->peer.connection == NULL) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST); - } -} - - -void ngx_http_proxy_busy_lock_handler(ngx_event_t *rev) -{ - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_proxy_ctx_t *p; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http proxy busy lock"); - - c = rev->data; - r = c->data; - p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); - p->action = "waiting upstream in busy lock"; - - if (p->request->connection->write->eof) { - ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock); - ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - - if (rev->timedout) { - rev->timedout = 0; - p->busy_lock.time++; - p->state->bl_time = p->busy_lock.time; - -#if (NGX_HTTP_FILE_CACHE) - - if (p->state->cache_state < NGX_HTTP_PROXY_CACHE_MISS) { - ngx_http_proxy_upstream_busy_lock(p); - - } else { - ngx_http_proxy_cache_busy_lock(p); - } -#else - - ngx_http_proxy_upstream_busy_lock(p); - -#endif - - return; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "http proxy: client sent while busy lock"); - - /* - * TODO: kevent() notify about error, otherwise we need to - * call ngx_peek(): recv(MSG_PEEK) to get errno. THINK about aio. - * if there's no error we need to disable event. - */ - -#if 0 -#if (NGX_HAVE_KQUEUE) - - if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && rev->kq_eof) { - ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock); - - ngx_del_timer(rev); - - ngx_log_error(NGX_LOG_ERR, c->log, rev->kq_errno, - "client() closed connection"); - - if (ngx_del_event(rev, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - -#endif -#endif - -} - - -void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc) -{ - ngx_http_request_t *r; - - r = p->request; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "finalize http proxy request"); - - if (p->upstream && p->upstream->peer.connection) { - ngx_http_proxy_close_connection(p); - } - - if (p->header_sent - && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) - { - rc = 0; - } - - if (p->saved_ctx) { - r->connection->log->data = p->saved_ctx; - r->connection->log->handler = p->saved_handler; - } - - if (p->upstream && p->upstream->event_pipe) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http proxy temp fd: %d", - p->upstream->event_pipe->temp_file->file.fd); - } - - if (p->cache) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http proxy cache fd: %d", - 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); - } - - ngx_http_finalize_request(r, rc); -} - - -void ngx_http_proxy_close_connection(ngx_http_proxy_ctx_t *p) -{ - ngx_socket_t fd; - ngx_connection_t *c; - - c = p->upstream->peer.connection; - p->upstream->peer.connection = NULL; - - if (p->lcf->busy_lock) { - p->lcf->busy_lock->busy--; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http proxy close connection: %d", c->fd); - - if (c->fd == -1) { -#if 0 - ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); -#endif - return; - } - - if (c->read->timer_set) { - ngx_del_timer(c->read); - } - - if (c->write->timer_set) { - ngx_del_timer(c->write); - } - - /* TODO: move connection to the connection pool */ - - if (ngx_del_conn) { - ngx_del_conn(c, NGX_CLOSE_EVENT); - - } else { - if (c->read->active || c->read->disabled) { - ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); - } - - if (c->write->active || c->read->disabled) { - ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); - } - } - - /* - * we have to clean the connection information before the closing - * because another thread may reopen the same file descriptor - * before we clean the connection - */ - - if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_OK) { - - if (c->read->prev) { - ngx_delete_posted_event(c->read); - } - - if (c->write->prev) { - ngx_delete_posted_event(c->write); - } - - c->read->closed = 1; - c->write->closed = 1; - - ngx_mutex_unlock(ngx_posted_events_mutex); - } - - fd = c->fd; - c->fd = (ngx_socket_t) -1; - c->data = NULL; - - if (ngx_close_socket(fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, - ngx_close_socket_n " failed"); - } -} - - -u_char *ngx_http_proxy_log_error(ngx_log_t *log, u_char *buf, size_t len) -{ - u_char *p; - ngx_int_t escape; - ngx_http_request_t *r; - ngx_peer_connection_t *peer; - ngx_http_proxy_log_ctx_t *ctx; - ngx_http_proxy_upstream_conf_t *uc; - - ctx = log->data; - r = ctx->proxy->request; - uc = ctx->proxy->lcf->upstream; - peer = &ctx->proxy->upstream->peer; - - p = ngx_snprintf(buf, len, - " while %s, client: %V, server: %V, URL: \"%V\"," - " upstream: http://%V%s%V", - ctx->proxy->action, - &r->connection->addr_text, - &r->server_name, - &r->unparsed_uri, - &peer->peers->peer[peer->cur_peer].name, - ctx->proxy->lcf->upstream->uri_separator, - &ctx->proxy->lcf->upstream->uri); - len -= p - buf; - buf = p; - - if (ctx->proxy->lcf->pass_unparsed_uri && r->valid_unparsed_uri) { - p = ngx_cpymem(buf, r->unparsed_uri.data + 1, r->unparsed_uri.len - 1); - len -= p - buf; - - return ngx_http_log_error_info(r, p, len); - } - - if (r->quoted_uri) { - escape = 2 * ngx_escape_uri(NULL, r->uri.data + uc->location->len, - r->uri.len - uc->location->len, - NGX_ESCAPE_URI); - } else { - escape = 0; - } - - if (escape) { - if (len >= r->uri.len - uc->location->len + escape) { - - ngx_escape_uri(buf, r->uri.data + uc->location->len, - r->uri.len - uc->location->len, NGX_ESCAPE_URI); - - buf += r->uri.len - uc->location->len + escape; - len -= r->uri.len - uc->location->len + escape; - - if (r->args.len) { - p = ngx_snprintf(buf, len, "?%V", &r->args); - len -= p - buf; - buf = p; - } - - return ngx_http_log_error_info(r, buf, len); - } - - p = ngx_palloc(r->pool, r->uri.len - uc->location->len + escape); - if (p == NULL) { - return buf; - } - - ngx_escape_uri(p, r->uri.data + uc->location->len, - r->uri.len - uc->location->len, NGX_ESCAPE_URI); - - p = ngx_cpymem(buf, p, r->uri.len - uc->location->len + escape); - - } else { - p = ngx_cpymem(buf, r->uri.data + uc->location->len, - r->uri.len - uc->location->len); - } - - len -= p - buf; - buf = p; - - if (r->args.len) { - p = ngx_snprintf(buf, len, "?%V", &r->args); - len -= p - buf; - buf = p; - } - - return ngx_http_log_error_info(r, buf, len); -} - - -static size_t ngx_http_proxy_log_proxy_state_getlen(ngx_http_request_t *r, - uintptr_t data) -{ - ngx_http_proxy_ctx_t *p; - - p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module); - - if (p == NULL) { - return 1; - } - - return p->states.nelts * /* STUB */ 100; -} - - -static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r, - u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_uint_t i; - ngx_http_proxy_ctx_t *p; - ngx_http_proxy_state_t *state; - - p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module); - - if (p == NULL) { - *buf = '-'; - return buf + 1; - } - - i = 0; - state = p->states.elts; - - for ( ;; ) { - if (state[i].cache_state == 0) { - *buf++ = '-'; - - } else { - buf = ngx_cpymem(buf, cache_states[state[i].cache_state - 1].data, - cache_states[state[i].cache_state - 1].len); - } - - *buf++ = '/'; - - if (state[i].expired == 0) { - *buf++ = '-'; - - } else { - buf = ngx_sprintf(buf, "%T", state[i].expired); - } - - *buf++ = '/'; - - if (state[i].bl_time == 0) { - *buf++ = '-'; - - } else { - buf = ngx_sprintf(buf, "%T", state[i].bl_time); - } - - *buf++ = '/'; - - *buf++ = '*'; - - *buf++ = ' '; - - if (state[i].status == 0) { - *buf++ = '-'; - - } else { - buf = ngx_sprintf(buf, "%ui", state[i].status); - } - - *buf++ = '/'; - - if (state[i].reason == 0) { - *buf++ = '-'; - - } else { - buf = ngx_cpymem(buf, cache_reasons[state[i].reason - 1].data, - cache_reasons[state[i].reason - 1].len); - } - - *buf++ = '/'; - - if (state[i].reason < NGX_HTTP_PROXY_CACHE_XAE) { - *buf++ = '-'; - - } else { - buf = ngx_sprintf(buf, "%T", state[i].expires); - } - - *buf++ = ' '; - *buf++ = '*'; - - if (++i == p->states.nelts) { - return buf; - } - - *buf++ = ','; - *buf++ = ' '; - } -} - - -#if 0 - -static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r, - u_char *buf, uintptr_t data) -{ - ngx_uint_t i; - ngx_http_proxy_ctx_t *p; - ngx_http_proxy_state_t *state; - - p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module); - - if (p == NULL || p->state->cache_state == 0) { - if (buf == NULL) { - return (u_char *) 1; - } - - *buf = '-'; - return buf + 1; - } - - if (buf == NULL) { - /* find the request line length */ - return (u_char *) (p->states.nelts * sizeof("BYPASS") - 1); - } - - i = 0; - state = p->states.elts; - - for ( ;; ) { - buf = ngx_cpymem(buf, cache_states[state[i].cache_state - 1].data, - cache_states[state[i].cache_state - 1].len); - - if (++i == p->states.nelts) { - return buf; - } - - *buf++ = ','; - *buf++ = ' '; - } -} - - -static u_char *ngx_http_proxy_log_reason(ngx_http_request_t *r, u_char *buf, - uintptr_t data) -{ - ngx_uint_t i; - ngx_http_proxy_ctx_t *p; - ngx_http_proxy_state_t *state; - - p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module); - - if (p == NULL || p->state->reason == 0) { - if (buf == NULL) { - return (u_char *) 1; - } - - *buf = '-'; - return buf + 1; - } - - if (buf == NULL) { - /* find the request line length */ - return (u_char *) (p->states.nelts * sizeof("BPS") - 1); - } - - i = 0; - state = p->states.elts; - - for ( ;; ) { - buf = ngx_cpymem(buf, cache_reasons[state[i].reason - 1].data, - cache_reasons[state[i].reason - 1].len); - - if (++i == p->states.nelts) { - return buf; - } - - *buf++ = ','; - *buf++ = ' '; - } -} - -#endif - - -static ngx_int_t ngx_http_proxy_add_log_formats(ngx_conf_t *cf) -{ - ngx_http_log_op_name_t *op; - - for (op = ngx_http_proxy_log_fmt_ops; op->name.len; op++) { /* void */ } - op->run = NULL; - - 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; - - return NGX_OK; -} - - -static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_proxy_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)); - if (conf == NULL) { - return NGX_CONF_ERROR; - } - - /* - * set by ngx_pcalloc(): - * - * conf->bufs.num = 0; - * conf->path = NULL; - * conf->next_upstream = 0; - * conf->use_stale = 0; - * conf->upstreams = NULL; - * conf->peers = NULL; - * conf->cache_path = NULL; - * conf->temp_path = NULL; - * conf->x_vars; - * conf->busy_lock = NULL; - */ - - conf->connect_timeout = NGX_CONF_UNSET_MSEC; - conf->send_timeout = NGX_CONF_UNSET_MSEC; - conf->send_lowat = NGX_CONF_UNSET_SIZE; - - conf->pass_unparsed_uri = NGX_CONF_UNSET; - 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->header_buffer_size = NGX_CONF_UNSET_SIZE; - conf->read_timeout = NGX_CONF_UNSET_MSEC; - conf->busy_buffers_size = NGX_CONF_UNSET_SIZE; - - conf->max_temp_file_size = NGX_CONF_UNSET_SIZE; - conf->temp_file_write_size = NGX_CONF_UNSET_SIZE; - - /* "proxy_cyclic_temp_file" is disabled */ - conf->cyclic_temp_file = 0; - - conf->cache = NGX_CONF_UNSET; - - conf->pass_server = NGX_CONF_UNSET; - conf->pass_x_accel_expires = NGX_CONF_UNSET; - conf->ignore_expires = NGX_CONF_UNSET; - conf->lm_factor = NGX_CONF_UNSET; - conf->default_expires = NGX_CONF_UNSET; - - return conf; -} - - -static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child) -{ - ngx_http_proxy_loc_conf_t *prev = parent; - ngx_http_proxy_loc_conf_t *conf = child; - - size_t size; - - ngx_conf_merge_msec_value(conf->connect_timeout, - prev->connect_timeout, 60000); - 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_value(conf->pass_unparsed_uri, prev->pass_unparsed_uri, 0); - - if (conf->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_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); - - ngx_conf_merge_msec_value(conf->read_timeout, prev->read_timeout, 60000); - - ngx_conf_merge_size_value(conf->header_buffer_size, - prev->header_buffer_size, (size_t) ngx_pagesize); - - ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 8, ngx_pagesize); - - if (conf->bufs.num < 2) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "there must be at least 2 \"proxy_buffers\""); - return NGX_CONF_ERROR; - } - - size = conf->header_buffer_size; - if (size < conf->bufs.size) { - size = conf->bufs.size; - } - - - ngx_conf_merge_size_value(conf->busy_buffers_size, - prev->busy_buffers_size, NGX_CONF_UNSET_SIZE); - - if (conf->busy_buffers_size == NGX_CONF_UNSET_SIZE) { - conf->busy_buffers_size = 2 * size; - - } else if (conf->busy_buffers_size < size) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"proxy_busy_buffers_size\" must be equal or bigger than " - "maximum of the value of \"proxy_header_buffer_size\" and " - "one of the \"proxy_buffers\""); - - return NGX_CONF_ERROR; - - } else if (conf->busy_buffers_size > (conf->bufs.num - 1) * conf->bufs.size) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"proxy_busy_buffers_size\" must be less than " - "the size of all \"proxy_buffers\" minus one buffer"); - - return NGX_CONF_ERROR; - } - - - ngx_conf_merge_size_value(conf->temp_file_write_size, - prev->temp_file_write_size, NGX_CONF_UNSET_SIZE); - - if (conf->temp_file_write_size == NGX_CONF_UNSET_SIZE) { - conf->temp_file_write_size = 2 * size; - - } else if (conf->temp_file_write_size < size) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"proxy_temp_file_write_size\" must be equal or bigger than " - "maximum of the value of \"proxy_header_buffer_size\" and " - "one of the \"proxy_buffers\""); - - return NGX_CONF_ERROR; - } - - - ngx_conf_merge_size_value(conf->max_temp_file_size, - prev->max_temp_file_size, NGX_CONF_UNSET_SIZE); - - if (conf->max_temp_file_size == NGX_CONF_UNSET_SIZE) { - - /* - * "proxy_max_temp_file_size" is set to 1G for reverse proxy, - * it should be much less in the generic proxy - */ - - conf->max_temp_file_size = 1024 * 1024 * 1024; - -#if 0 - conf->max_temp_file_size = 2 * size; -#endif - - - } else if (conf->max_temp_file_size != 0 - && conf->max_temp_file_size < size) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"proxy_max_temp_file_size\" must be equal to zero to disable " - "the temporary files usage or must be equal or bigger than " - "maximum of the value of \"proxy_header_buffer_size\" and " - "one of the \"proxy_buffers\""); - - return NGX_CONF_ERROR; - } - - - ngx_conf_merge_bitmask_value(conf->next_upstream, prev->next_upstream, - (NGX_CONF_BITMASK_SET - |NGX_HTTP_PROXY_FT_ERROR - |NGX_HTTP_PROXY_FT_TIMEOUT)); - - ngx_conf_merge_bitmask_value(conf->use_stale, prev->use_stale, - NGX_CONF_BITMASK_SET); - -#if 0 - ngx_conf_merge_path_value(conf->cache_path, prev->cache_path, - NGX_HTTP_PROXY_CACHE_PATH, 1, 2, 0, - ngx_garbage_collector_temp_handler, cf); -#endif - - ngx_conf_merge_path_value(conf->temp_path, prev->temp_path, - NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0, - ngx_garbage_collector_temp_handler, cf); - - ngx_conf_merge_value(conf->cache, prev->cache, 0); - - - /* conf->cache must be merged */ - - if (conf->busy_lock == NULL) { - conf->busy_lock = prev->busy_lock; - } - - if (conf->busy_lock && conf->cache && conf->busy_lock->md5 == NULL) { - - /* ngx_calloc_shared() */ - conf->busy_lock->md5_mask = - ngx_pcalloc(cf->pool, (conf->busy_lock->max_busy + 7) / 8); - if (conf->busy_lock->md5_mask == NULL) { - return NGX_CONF_ERROR; - } - - /* 16 bytes are 128 bits of the md5 */ - - /* ngx_alloc_shared() */ - conf->busy_lock->md5 = ngx_palloc(cf->pool, - 16 * conf->busy_lock->max_busy); - if (conf->busy_lock->md5 == NULL) { - return NGX_CONF_ERROR; - } - } - - - ngx_conf_merge_value(conf->pass_server, prev->pass_server, 0); - ngx_conf_merge_value(conf->pass_x_accel_expires, - prev->pass_x_accel_expires, 0); - ngx_conf_merge_value(conf->ignore_expires, prev->ignore_expires, 0); - ngx_conf_merge_value(conf->lm_factor, prev->lm_factor, 0); - ngx_conf_merge_sec_value(conf->default_expires, prev->default_expires, 0); - - if (conf->x_vars == NULL) { - conf->x_vars = prev->x_vars; - } - - if (conf->peers == NULL) { - conf->peers = prev->peers; - conf->upstream = prev->upstream; - } - - return NULL; -} - - -static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_http_proxy_loc_conf_t *lcf = conf; - - ngx_str_t *value, *url; - 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; - - url = &value[1]; - - if (ngx_strncasecmp(url->data, "http://", 7) != 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix"); - return NGX_CONF_ERROR; - } - - lcf->upstream = ngx_pcalloc(cf->pool, - sizeof(ngx_http_proxy_upstream_conf_t)); - if (lcf->upstream == NULL) { - return NGX_CONF_ERROR; - } - - lcf->upstream->url = *url; - - if (ngx_strncasecmp(url->data + 7, "unix:", 5) == 0) { - -#if (NGX_HAVE_UNIX_DOMAIN) - - ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); - - unix_upstream.name = *url; - unix_upstream.url.len = url->len - 7; - 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) { - return NGX_CONF_ERROR; - } - - lcf->upstream->host_header.len = sizeof("localhost") - 1; - lcf->upstream->host_header.data = (u_char *) "localhost"; - lcf->upstream->uri = unix_upstream.uri; - lcf->upstream->uri_separator = ":"; - lcf->upstream->default_port = 1; - -#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 = *url; - inet_upstream.url.len = url->len - 7; - inet_upstream.url.data = url->data + 7; - inet_upstream.default_port_value = 80; - inet_upstream.uri_part = 1; - - lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); - if (lcf->peers == NULL) { - return NGX_CONF_ERROR; - } - - lcf->upstream->host_header = inet_upstream.host_header; - lcf->upstream->port_text = inet_upstream.port_text; - lcf->upstream->uri = inet_upstream.uri; - lcf->upstream->uri_separator = ""; - lcf->upstream->default_port = inet_upstream.default_port; - } - - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - - clcf->handler = ngx_http_proxy_handler; - -#if (NGX_PCRE) - lcf->upstream->location = clcf->regex ? &ngx_http_proxy_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_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_http_proxy_loc_conf_t *lcf = conf; - - ngx_uint_t i, *index; - ngx_str_t *value; - ngx_http_variable_t *var; - ngx_http_core_main_conf_t *cmcf; - - if (lcf->x_vars == NULL) { - lcf->x_vars = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_variable_t *)); - if (lcf->x_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->x_vars); - if (index == NULL) { - return NGX_CONF_ERROR; - } - - *index = var[i].index; - return NGX_CONF_OK; - } - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unknown variable name \"%V\"", &value[1]); - return NGX_CONF_ERROR; -} - - -static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data) -{ -#if (NGX_FREEBSD) - ssize_t *np = data; - - if (*np >= ngx_freebsd_net_inet_tcp_sendspace) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"proxy_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, - "\"proxy_send_lowat\" is not supported, ignored"); - - *np = 0; - -#endif - - return NGX_CONF_OK; -} diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.h b/src/http/modules/proxy/ngx_http_proxy_handler.h deleted file mode 100644 --- a/src/http/modules/proxy/ngx_http_proxy_handler.h +++ /dev/null @@ -1,272 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_ -#define _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_ - - -#include -#include -#include -#include -#include -#include - - -typedef enum { - NGX_HTTP_PROXY_CACHE_PASS = 1, - NGX_HTTP_PROXY_CACHE_BYPASS, - NGX_HTTP_PROXY_CACHE_AUTH, - NGX_HTTP_PROXY_CACHE_PGNC, - NGX_HTTP_PROXY_CACHE_MISS, - NGX_HTTP_PROXY_CACHE_EXPR, - NGX_HTTP_PROXY_CACHE_AGED, - NGX_HTTP_PROXY_CACHE_HIT -} ngx_http_proxy_state_e; - - -typedef enum { - NGX_HTTP_PROXY_CACHE_BPS = 1, - NGX_HTTP_PROXY_CACHE_XAE, - NGX_HTTP_PROXY_CACHE_CTL, - NGX_HTTP_PROXY_CACHE_EXP, - NGX_HTTP_PROXY_CACHE_MVD, - NGX_HTTP_PROXY_CACHE_LMF, - NGX_HTTP_PROXY_CACHE_PDE -} ngx_http_proxy_reason_e; - - -typedef struct { - ngx_str_t url; - ngx_str_t host; - ngx_str_t uri; - ngx_str_t host_header; - ngx_str_t port_text; - ngx_str_t *location; - - char *uri_separator; - - in_port_t port; - - unsigned default_port:1; -} ngx_http_proxy_upstream_conf_t; - - -typedef struct { - 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_msec_t connect_timeout; - ngx_msec_t send_timeout; - ngx_msec_t read_timeout; - time_t default_expires; - - ngx_int_t lm_factor; - - ngx_uint_t next_upstream; - ngx_uint_t use_stale; - - ngx_bufs_t bufs; - - ngx_flag_t cyclic_temp_file; - ngx_flag_t cache; - 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_unparsed_uri; - ngx_flag_t pass_server; - ngx_flag_t pass_x_accel_expires; - ngx_flag_t ignore_expires; - - ngx_path_t *cache_path; - ngx_path_t *temp_path; - - ngx_array_t *x_vars; - - ngx_http_busy_lock_t *busy_lock; - - ngx_http_proxy_upstream_conf_t *upstream; - ngx_peers_t *peers; -} ngx_http_proxy_loc_conf_t; - - -/* - * "EXPR/10/5/- 200/EXP/60 4" - * "MISS/-/-/B 503/-/- -" - * "EXPR/10/20/SB HIT/-/- -" - * "EXPR/10/15/NB HIT/-/- -" - */ - -typedef struct { - ngx_http_proxy_state_e cache_state; - time_t expired; - time_t bl_time; - ngx_uint_t bl_state; - - ngx_uint_t status; - ngx_http_proxy_reason_e reason; - time_t time; - time_t expires; - - ngx_str_t *peer; -} ngx_http_proxy_state_t; - - -typedef struct { - ngx_list_t headers; -#if 0 - ngx_table_t headers; /* it must be first field */ -#endif - - 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_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; - - -typedef struct { - ngx_http_cache_t ctx; - ngx_uint_t status; - ngx_str_t status_line; - - ngx_http_proxy_headers_in_t headers_in; -} ngx_http_proxy_cache_t; - - -typedef struct { - ngx_peer_connection_t peer; - ngx_uint_t status; - ngx_str_t status_line; - ngx_uint_t method; - - ngx_output_chain_ctx_t *output_chain_ctx; - ngx_event_pipe_t *event_pipe; - - ngx_http_proxy_headers_in_t headers_in; -} ngx_http_proxy_upstream_t; - - -typedef struct ngx_http_proxy_ctx_s ngx_http_proxy_ctx_t; - -struct ngx_http_proxy_ctx_s { - ngx_http_request_t *request; - ngx_http_proxy_loc_conf_t *lcf; - ngx_http_proxy_upstream_t *upstream; - ngx_http_proxy_cache_t *cache; - - ngx_buf_t *header_in; - - ngx_http_busy_lock_ctx_t busy_lock; - - unsigned accel:1; - - unsigned cachable:1; - unsigned stale:1; - unsigned try_busy_lock:1; - unsigned busy_locked:1; - unsigned valid_header_in:1; - - unsigned request_sent:1; - unsigned header_sent:1; - - - /* used to parse an upstream HTTP header */ - ngx_uint_t status; - u_char *status_start; - u_char *status_end; - ngx_uint_t status_count; - ngx_uint_t parse_state; - - ngx_http_proxy_state_t *state; - ngx_array_t states; /* of ngx_http_proxy_state_t */ - - /* - * we declare "action" as "char *" because the actions are usually - * the static strings and in the "u_char *" case we have to override - * all the time their types - */ - - char *action; - ngx_http_log_ctx_t *saved_ctx; - ngx_log_handler_pt saved_handler; -}; - - -typedef struct { - ngx_uint_t connection; - ngx_http_proxy_ctx_t *proxy; -} ngx_http_proxy_log_ctx_t; - - -#define NGX_HTTP_PROXY_PARSE_NO_HEADER 30 - - -#define NGX_HTTP_PROXY_FT_ERROR 0x02 -#define NGX_HTTP_PROXY_FT_TIMEOUT 0x04 -#define NGX_HTTP_PROXY_FT_INVALID_HEADER 0x08 -#define NGX_HTTP_PROXY_FT_HTTP_500 0x10 -#define NGX_HTTP_PROXY_FT_HTTP_404 0x20 -#define NGX_HTTP_PROXY_FT_BUSY_LOCK 0x40 -#define NGX_HTTP_PROXY_FT_MAX_WAITING 0x80 - - -int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p); - -#if (NGX_HTTP_FILE_CACHE) - -int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p); -int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p); -int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p); -int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p); - -void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p); - -#endif - -void ngx_http_proxy_check_broken_connection(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); - -u_char *ngx_http_proxy_log_error(ngx_log_t *log, u_char *buf, size_t len); -void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc); -void ngx_http_proxy_close_connection(ngx_http_proxy_ctx_t *p); - -int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p); -int ngx_http_proxy_copy_header(ngx_http_proxy_ctx_t *p, - ngx_http_proxy_headers_in_t *headers_in); - - - -extern ngx_module_t ngx_http_proxy_module; -extern ngx_http_header_t ngx_http_proxy_headers_in[]; - - - -#endif /* _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_ */ diff --git a/src/http/modules/proxy/ngx_http_proxy_header.c b/src/http/modules/proxy/ngx_http_proxy_header.c deleted file mode 100644 --- a/src/http/modules/proxy/ngx_http_proxy_header.c +++ /dev/null @@ -1,206 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include - - -static int ngx_http_proxy_rewrite_location_header(ngx_http_proxy_ctx_t *p, - ngx_table_elt_t *loc); - -int ngx_http_proxy_copy_header(ngx_http_proxy_ctx_t *p, - ngx_http_proxy_headers_in_t *headers_in) -{ - ngx_uint_t i; - ngx_list_part_t *part; - ngx_table_elt_t *ho, *h; - ngx_http_request_t *r; - - r = p->request; - - 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->connection) { - continue; - } - - if (&h[i] == headers_in->x_pad) { - continue; - } - - if (p->accel) { - if (&h[i] == headers_in->date - || &h[i] == headers_in->accept_ranges) { - continue; - } - - if (&h[i] == headers_in->x_accel_expires - && !p->lcf->pass_x_accel_expires) - { - continue; - } - - if (&h[i] == headers_in->server && !p->lcf->pass_server) { - continue; - } - - if (&h[i] == headers_in->location) { - if (ngx_http_proxy_rewrite_location_header(p, &h[i]) - == NGX_ERROR) - { - return NGX_ERROR; - } - - 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_ERROR; - } - - *ho = h[i]; - - if (&h[i] == headers_in->expires) { - r->headers_out.expires = ho; - continue; - } - - if (&h[i] == headers_in->cache_control) { - r->headers_out.cache_control = ho; - continue; - } - - if (&h[i] == headers_in->etag) { - r->headers_out.etag = ho; - continue; - } - -#if (NGX_HTTP_GZIP) - if (&h[i] == headers_in->content_encoding) { - r->headers_out.content_encoding = ho; - continue; - } -#endif - - if (&h[i] == headers_in->last_modified) { - r->headers_out.last_modified = ho; - /* TODO: update r->headers_out.last_modified_time */ - continue; - } - - /* - * ngx_http_header_filter() passes the following headers as is - * and does not handle them specially if they are set: - * r->headers_out.server, - * r->headers_out.date, - * r->headers_out.content_length - */ - - if (&h[i] == headers_in->server) { - r->headers_out.server = ho; - continue; - } - - if (&h[i] == headers_in->date) { - r->headers_out.date = ho; - continue; - } - - 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_OK; -} - - -static int ngx_http_proxy_rewrite_location_header(ngx_http_proxy_ctx_t *p, - ngx_table_elt_t *loc) -{ - u_char *last; - ngx_table_elt_t *location; - ngx_http_request_t *r; - ngx_http_proxy_upstream_conf_t *uc; - - r = p->request; - uc = p->lcf->upstream; - - location = ngx_list_push(&r->headers_out.headers); - if (location == NULL) { - return NGX_ERROR; - } - - if (p->lcf->preserve_host - || uc->url.len > loc->value.len - || ngx_rstrncmp(loc->value.data, uc->url.data, uc->url.len) != 0) - { - - /* - * 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() - */ - - *location = *loc; - return NGX_OK; - } - - /* TODO: proxy_reverse */ - - r->headers_out.location = location; - - location->key.len = 0; - location->key.data = NULL; - - location->value.len = uc->location->len - + (loc->value.len - uc->url.len) + 1; - location->value.data = ngx_palloc(r->pool, location->value.len); - if (location->value.data == NULL) { - return NGX_ERROR; - } - - last = ngx_cpymem(location->value.data, - uc->location->data, uc->location->len); - - ngx_cpystrn(last, loc->value.data + uc->url.len, - loc->value.len - uc->url.len + 1); - - return NGX_OK; -} diff --git a/src/http/modules/proxy/ngx_http_proxy_parse.c b/src/http/modules/proxy/ngx_http_proxy_parse.c deleted file mode 100644 --- a/src/http/modules/proxy/ngx_http_proxy_parse.c +++ /dev/null @@ -1,216 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include - - -int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p) -{ - u_char ch; - u_char *pos; - 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, - sw_done - } state; - - state = p->parse_state; - pos = p->header_in->pos; - - while (pos < p->header_in->last && state < sw_done) { - 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 - 3; - } - - 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: - state = sw_done; - break; - 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: - state = sw_done; - break; - } - break; - - /* end of request line */ - case sw_almost_done: - p->status_end = pos - 2; - switch (ch) { - case LF: - state = sw_done; - break; - default: - return NGX_HTTP_PROXY_PARSE_NO_HEADER; - } - break; - - /* suppress warning */ - case sw_done: - break; - } - } - - p->header_in->pos = pos; - - if (state == sw_done) { - if (p->status_end == NULL) { - p->status_end = pos - 1; - } - - p->parse_state = sw_start; - return NGX_OK; - } - - p->parse_state = state; - return NGX_AGAIN; -} diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c deleted file mode 100644 --- a/src/http/modules/proxy/ngx_http_proxy_upstream.c +++ /dev/null @@ -1,1646 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include -#include -#include -#include - - -static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p); -static void ngx_http_proxy_init_upstream(ngx_http_request_t *r); -static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p); -static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p); -static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p); -static void ngx_http_proxy_send_request_handler(ngx_event_t *wev); -static void ngx_http_proxy_dummy_handler(ngx_event_t *wev); -static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev); -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_body(ngx_event_t *ev); -static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, - ngx_uint_t ft_type); - - -static ngx_str_t http_methods[] = { - ngx_string("GET "), - ngx_string("HEAD "), - ngx_string("POST ") -}; - - -static char *upstream_header_errors[] = { - "upstream sent invalid header", - "upstream sent too long header line" -}; - - -static char http_version[] = " HTTP/1.0" CRLF; -static char host_header[] = "Host: "; -static char x_url_header[] = "X-URL: http"; -static char x_real_ip_header[] = "X-Real-IP: "; -static char x_forwarded_for_header[] = "X-Forwarded-For: "; -static char connection_close_header[] = "Connection: close" CRLF; - - -int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p) -{ - int rc; - ngx_http_request_t *r; - ngx_http_proxy_upstream_t *u; - - r = p->request; - - u = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_upstream_t)); - if (u == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - p->upstream = u; - - u->peer.log_error = NGX_ERROR_ERR; - u->peer.peers = p->lcf->peers; - u->peer.tries = p->lcf->peers->number; -#if (NGX_THREADS) - u->peer.lock = &r->connection->lock; -#endif - - u->method = r->method; - - rc = ngx_http_read_client_request_body(r, ngx_http_proxy_init_upstream); - - if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - - return NGX_DONE; -} - - -static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p) -{ - size_t len; - ngx_uint_t i, escape, *index; - ngx_buf_t *b; - ngx_chain_t *chain; - ngx_list_part_t *part; - ngx_table_elt_t *header; - ngx_http_request_t *r; - ngx_http_variable_t *var; - ngx_http_variable_value_t *value; - ngx_http_core_main_conf_t *cmcf; - ngx_http_proxy_upstream_conf_t *uc; - - r = p->request; - uc = p->lcf->upstream; - -#if (NGX_SUPPRESS_WARN) - var = NULL; - index = NULL; -#endif - - escape = 0; - - if (p->upstream->method) { - len = http_methods[p->upstream->method - 1].len + uc->uri.len; - - } else { - len = r->method_name.len + uc->uri.len; - } - - if (p->lcf->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 + uc->location->len, - r->uri.len - uc->location->len, - NGX_ESCAPE_URI); - } - - len += r->uri.len - uc->location->len + escape - + sizeof("?") - 1 + r->args.len; - } - - len += sizeof(http_version) - 1 - + sizeof(connection_close_header) - 1 - + sizeof(CRLF) - 1; - - - if (p->lcf->set_x_url) { - len += sizeof(x_url_header) - 1 - + sizeof("s://") - 1 - + r->port_text->len - + r->unparsed_uri.len - + sizeof(CRLF) - 1; - - if (r->headers_in.host) { - len += r->headers_in.host_name_len; - - } else { - len += r->server_name.len; - } - - } - - - if (p->lcf->preserve_host) { - if (r->headers_in.host) { - len += sizeof(host_header) - 1 - + r->headers_in.host_name_len + sizeof(":") - 1 - + uc->port_text.len + sizeof(CRLF) - 1; - - } else { - len += sizeof(host_header) - 1 - + r->server_name.len + sizeof(":") - 1 - + uc->port_text.len + sizeof(CRLF) - 1; - } - - } else { - len += sizeof(host_header) - 1 + uc->host_header.len - + sizeof(CRLF) - 1; - } - - - if (p->lcf->set_x_real_ip) { - len += sizeof(x_real_ip_header) - 1 + INET_ADDRSTRLEN - 1 - + sizeof(CRLF) - 1; - } - - - if (p->lcf->add_x_forwarded_for) { - if (r->headers_in.x_forwarded_for) { - len += sizeof(x_forwarded_for_header) - 1 - + r->headers_in.x_forwarded_for->value.len - + sizeof(", ") - 1 + INET_ADDRSTRLEN - 1 + sizeof(CRLF) - 1; - - } else { - len += sizeof(x_forwarded_for_header) - 1 + INET_ADDRSTRLEN - 1 - + sizeof(CRLF) - 1; - } - } - - - if (p->lcf->x_vars) { - cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - - var = cmcf->variables.elts; - index = p->lcf->x_vars->elts; - - for (i = 0; i < p->lcf->x_vars->nelts; i++) { - - value = ngx_http_get_indexed_variable(r, index[i]); - if (value == NULL) { - continue; - } - - if (value->text.len) { - len += sizeof("X-") - 1 + var[index[i]].name.len - + sizeof(": ") - 1 + value->text.len + sizeof(CRLF) - 1; - } - } - } - - - part = &r->headers_in.headers.part; - header = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - if (&header[i] == r->headers_in.host) { - continue; - } - - if (&header[i] == r->headers_in.connection) { - continue; - } - - len += header[i].key.len + sizeof(": ") - 1 - + header[i].value.len + sizeof(CRLF) - 1; - } - -#if (NGX_DEBUG) - len++; -#endif - - b = ngx_create_temp_buf(r->pool, len); - if (b == NULL) { - return NULL; - } - - chain = ngx_alloc_chain_link(r->pool); - if (chain == NULL) { - return NULL; - } - - chain->buf = b; - chain->next = NULL; - - - /* the request line */ - - if (p->upstream->method) { - b->last = ngx_cpymem(b->last, - 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, uc->uri.data, uc->uri.len); - - if (p->lcf->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 + uc->location->len, - r->uri.len - uc->location->len, NGX_ESCAPE_URI); - b->last += r->uri.len - uc->location->len + escape; - - } else { - b->last = ngx_cpymem(b->last, r->uri.data + uc->location->len, - r->uri.len - uc->location->len); - } - - if (r->args.len > 0) { - *b->last++ = '?'; - b->last = ngx_cpymem(b->last, r->args.data, r->args.len); - } - } - - b->last = ngx_cpymem(b->last, http_version, sizeof(http_version) - 1); - - - /* the "Connection: close" header */ - - b->last = ngx_cpymem(b->last, connection_close_header, - sizeof(connection_close_header) - 1); - - - /* the "Host" header */ - - b->last = ngx_cpymem(b->last, host_header, sizeof(host_header) - 1); - - if (p->lcf->preserve_host) { - if (r->headers_in.host) { - b->last = ngx_cpymem(b->last, r->headers_in.host->value.data, - r->headers_in.host_name_len); - } else { - b->last = ngx_cpymem(b->last, r->server_name.data, - r->server_name.len); - } - - if (!uc->default_port) { - *b->last++ = ':'; - b->last = ngx_cpymem(b->last, uc->port_text.data, - uc->port_text.len); - } - - } else { - b->last = ngx_cpymem(b->last, uc->host_header.data, - uc->host_header.len); - } - *b->last++ = CR; *b->last++ = LF; - - - /* the "X-URL" header */ - - if (p->lcf->set_x_url) { - - b->last = ngx_cpymem(b->last, x_url_header, - sizeof(x_url_header) - 1); - -#if (NGX_OPENSSL) - - if (r->connection->ssl) { - *b->last++ = 's'; - } - -#endif - - *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/'; - - if (r->headers_in.host) { - b->last = ngx_cpymem(b->last, r->headers_in.host->value.data, - r->headers_in.host_name_len); - } else { - b->last = ngx_cpymem(b->last, r->server_name.data, - r->server_name.len); - } - - b->last = ngx_cpymem(b->last, r->port_text->data, r->port_text->len); - b->last = ngx_cpymem(b->last, r->unparsed_uri.data, - r->unparsed_uri.len); - - *b->last++ = CR; *b->last++ = LF; - } - - - /* the "X-Real-IP" header */ - - if (p->lcf->set_x_real_ip) { - b->last = ngx_cpymem(b->last, x_real_ip_header, - sizeof(x_real_ip_header) - 1); - b->last = ngx_cpymem(b->last, r->connection->addr_text.data, - r->connection->addr_text.len); - *b->last++ = CR; *b->last++ = LF; - } - - - /* the "X-Forwarded-For" header */ - - if (p->lcf->add_x_forwarded_for) { - if (r->headers_in.x_forwarded_for) { - b->last = ngx_cpymem(b->last, x_forwarded_for_header, - sizeof(x_forwarded_for_header) - 1); - - b->last = ngx_cpymem(b->last, - r->headers_in.x_forwarded_for->value.data, - r->headers_in.x_forwarded_for->value.len); - - *b->last++ = ','; *b->last++ = ' '; - - } else { - b->last = ngx_cpymem(b->last, x_forwarded_for_header, - sizeof(x_forwarded_for_header) - 1); - } - - b->last = ngx_cpymem(b->last, r->connection->addr_text.data, - r->connection->addr_text.len); - *b->last++ = CR; *b->last++ = LF; - } - - - if (p->lcf->x_vars) { - for (i = 0; i < p->lcf->x_vars->nelts; i++) { - - value = ngx_http_get_indexed_variable(r, index[i]); - if (value == NULL) { - continue; - } - - if (value->text.len == 0) { - continue; - } - - *b->last++ = 'X'; *b->last++ = '-'; - - b->last = ngx_cpymem(b->last, var[index[i]].name.data, - var[index[i]].name.len); - - *b->last++ = ':'; *b->last++ = ' '; - - b->last = ngx_cpymem(b->last, value->text.data, value->text.len); - - *b->last++ = CR; *b->last++ = LF; - } - } - - - part = &r->headers_in.headers.part; - header = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - if (&header[i] == r->headers_in.host) { - continue; - } - - if (&header[i] == r->headers_in.connection) { - continue; - } - - if (&header[i] == r->headers_in.keep_alive) { - continue; - } - - if (&header[i] == r->headers_in.x_forwarded_for - && p->lcf->add_x_forwarded_for) - { - continue; - } - - if (&header[i] == r->headers_in.x_real_ip && p->lcf->set_x_real_ip) { - continue; - } - - if (&header[i] == r->headers_in.x_url && p->lcf->set_x_url) { - continue; - } - - b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len); - - *b->last++ = ':'; *b->last++ = ' '; - - b->last = ngx_cpymem(b->last, header[i].value.data, - header[i].value.len); - - *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); - } - - /* add "\r\n" at the header end */ - *b->last++ = CR; *b->last++ = LF; - -#if (NGX_DEBUG) - *b->last = '\0'; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http proxy header:\n\"%s\"", b->pos); -#endif - - return chain; -} - - -static void ngx_http_proxy_init_upstream(ngx_http_request_t *r) -{ - - ngx_chain_t *cl; - ngx_http_proxy_ctx_t *p; - ngx_output_chain_ctx_t *output; - ngx_chain_writer_ctx_t *writer; - ngx_http_proxy_log_ctx_t *ctx; - - p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http proxy init upstream, client timer: %d", - r->connection->read->timer_set); - - if (r->connection->read->timer_set) { - ngx_del_timer(r->connection->read); - } - - r->connection->read->event_handler = ngx_http_proxy_check_broken_connection; - - if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { - - r->connection->write->event_handler = - ngx_http_proxy_check_broken_connection; - - if (!r->connection->write->active) { - if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT, - NGX_CLEAR_EVENT) == NGX_ERROR) - { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - } - } - - - cl = ngx_http_proxy_create_request(p); - if (cl == NULL) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - if (r->request_body->bufs) { - cl->next = r->request_body->bufs; - } - - r->request_body->bufs = cl; - - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_log_ctx_t)); - if (ctx == NULL) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - ctx->connection = r->connection->number; - ctx->proxy = p; - - p->upstream->peer.log = r->connection->log; - p->saved_ctx = r->connection->log->data; - p->saved_handler = r->connection->log->handler; - r->connection->log->data = ctx; - r->connection->log->handler = ngx_http_proxy_log_error; - p->action = "connecting to upstream"; - - output = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); - if (output == NULL) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - p->upstream->output_chain_ctx = output; - - output->sendfile = r->connection->sendfile; - output->pool = r->pool; - output->bufs.num = 1; - output->tag = (ngx_buf_tag_t) &ngx_http_proxy_module; - output->output_filter = ngx_chain_writer; - - writer = ngx_palloc(r->pool, sizeof(ngx_chain_writer_ctx_t)); - if (writer == NULL) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - output->filter_ctx = writer; - writer->pool = r->pool; - -#if 0 - if (p->lcf->busy_lock && p->busy_lock == NULL) { -#else - if (p->lcf->busy_lock && !p->busy_locked) { -#endif - ngx_http_proxy_upstream_busy_lock(p); - } else { - ngx_http_proxy_connect(p); - } -} - - -static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p) -{ - ngx_chain_t *cl; - ngx_output_chain_ctx_t *output; - ngx_http_proxy_state_e state; - - /* reinit the request chain */ - - for (cl = p->request->request_body->bufs; cl; cl = cl->next) { - cl->buf->pos = cl->buf->start; - cl->buf->file_pos = 0; - } - - /* reinit the ngx_output_chain() context */ - - output = p->upstream->output_chain_ctx; - - output->buf = NULL; - output->in = NULL; - output->free = NULL; - output->busy = NULL; - - /* reinit r->header_in buffer */ - - if (p->header_in) { - if (p->cache) { - p->header_in->pos = p->header_in->start + p->cache->ctx.header_size; - p->header_in->last = p->header_in->pos; - - } else { - p->header_in->pos = p->header_in->start; - p->header_in->last = p->header_in->start; - } - } - - /* add one more state */ - - state = p->state->cache_state; - - p->state = ngx_array_push(&p->states); - if (p->state == NULL) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - ngx_memzero(p->state, sizeof(ngx_http_proxy_state_t)); - - p->state->cache_state = state; - - p->status = 0; - p->status_count = 0; -} - - -#if 0 - -void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p) -{ - ngx_int_t rc; - - rc = ngx_event_busy_lock(p->lcf->busy_lock, p->busy_lock); - - if (rc == NGX_AGAIN) { - return; - } - - if (rc == NGX_OK) { - ngx_http_proxy_connect(p); - return; - } - - if (rc == NGX_ERROR) { - p->state->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - /* rc == NGX_BUSY */ - -#if (NGX_HTTP_CACHE) - - if (p->busy_lock->timer) { - ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING; - } else { - ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK; - } - - if (p->stale && (p->lcf->use_stale & ft_type)) { - ngx_http_proxy_finalize_request(p, - ngx_http_proxy_send_cached_response(p)); - return; - } - -#endif - - p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE; - ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE); -} - -#endif - - -#if 1 - -void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p) -{ - ngx_int_t rc; -#if (NGX_HTTP_CACHE) - ngx_int_t ft_type; -#endif - - if (p->busy_lock.time == 0) { - p->busy_lock.event = p->request->connection->read; - p->busy_lock.event_handler = ngx_http_proxy_busy_lock_handler; - } - - rc = ngx_http_busy_lock(p->lcf->busy_lock, &p->busy_lock); - - if (rc == NGX_AGAIN) { - return; - } - - if (rc == NGX_OK) { - ngx_http_proxy_connect(p); - return; - } - - ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock); - -#if (NGX_HTTP_CACHE) - - if (rc == NGX_DONE) { - ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK; - - } else { - /* rc == NGX_ERROR */ - ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING; - } - - if (p->stale && (p->lcf->use_stale & ft_type)) { - ngx_http_proxy_finalize_request(p, - ngx_http_proxy_send_cached_response(p)); - return; - } - -#endif - - p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE; - ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE); -} - -#endif - - -static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p) -{ - ngx_int_t rc; - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_output_chain_ctx_t *output; - ngx_chain_writer_ctx_t *writer; - - p->action = "connecting to upstream"; - - p->request->connection->single_connection = 0; - - rc = ngx_event_connect_peer(&p->upstream->peer); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0, - "http proxy connect: %i", rc); - - if (rc == NGX_ERROR) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - p->state->peer = - &p->upstream->peer.peers->peer[p->upstream->peer.cur_peer].name; - - if (rc == NGX_CONNECT_ERROR) { - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); - return; - } - - r = p->request; - 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->sendfile = r->connection->sendfile; - - c->pool = r->pool; - c->read->log = c->write->log = c->log = r->connection->log; - - /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */ - - output = p->upstream->output_chain_ctx; - writer = output->filter_ctx; - writer->out = NULL; - writer->last = &writer->out; - writer->connection = c; - writer->limit = 0; - - if (p->request_sent) { - ngx_http_proxy_reinit_upstream(p); - } - - if (r->request_body->buf) { - if (r->request_body->temp_file) { - - output->free = ngx_alloc_chain_link(r->pool); - if (output->free == NULL) { - ngx_http_proxy_finalize_request(p, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - output->free->buf = r->request_body->buf; - output->free->next = NULL; - output->allocated = 1; - - 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 = (ngx_buf_tag_t) &ngx_http_proxy_module; - - } else { - r->request_body->buf->pos = r->request_body->buf->start; - } - } - - p->request_sent = 0; - - if (rc == NGX_AGAIN) { - ngx_add_timer(c->write, p->lcf->connect_timeout); - return; - } - - /* rc == NGX_OK */ - -#if 0 /* test only, see below about "post aio operation" */ - - if (c->read->ready) { - /* post aio operation */ - ngx_http_proxy_process_upstream_status_line(c->read); -#if 0 - return; -#endif - } - -#endif - - ngx_http_proxy_send_request(p); -} - - -static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p) -{ - int rc; - ngx_connection_t *c; - - c = p->upstream->peer.connection; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http proxy send request"); - -#if (NGX_HAVE_KQUEUE) - - if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) - && !p->request_sent - && c->write->pending_eof) - { - ngx_log_error(NGX_LOG_ERR, c->log, c->write->kq_errno, - "connect() failed"); - - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); - return; - } - -#endif - - p->action = "sending request to upstream"; - - rc = ngx_output_chain(p->upstream->output_chain_ctx, - p->request_sent ? NULL: - p->request->request_body->bufs); - - p->request_sent = 1; - - if (rc == NGX_ERROR) { - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); - return; - } - - if (c->write->timer_set) { - ngx_del_timer(c->write); - } - - if (rc == NGX_AGAIN) { - ngx_add_timer(c->write, p->lcf->send_timeout); - - if (ngx_handle_write_event(c->write, p->lcf->send_lowat) == NGX_ERROR) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - return; - } - - /* rc == NGX_OK */ - - if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { - if (ngx_tcp_push(c->fd) == NGX_ERROR) { - ngx_log_error(NGX_LOG_CRIT, c->log, - ngx_socket_errno, - ngx_tcp_push_n " failed"); - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; - return; - } - - ngx_add_timer(c->read, p->lcf->read_timeout); - -#if 1 - if (c->read->ready) { - - /* post aio operation */ - - /* - * although we can post aio operation just in the end - * of ngx_http_proxy_connect() CHECK IT !!! - * it's better to do here because we postpone header buffer allocation - */ - - ngx_http_proxy_process_upstream_status_line(c->read); - return; - } -#endif - - c->write->event_handler = ngx_http_proxy_dummy_handler; - - if (ngx_handle_level_write_event(c->write) == NGX_ERROR) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } -} - - -static void ngx_http_proxy_send_request_handler(ngx_event_t *wev) -{ - ngx_connection_t *c; - ngx_http_proxy_ctx_t *p; - - c = wev->data; - p = c->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, - "http proxy send request handler"); - - if (wev->timedout) { - p->action = "sending request to upstream"; - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT); - return; - } - - if (p->request->connection->write->eof - && (!p->cachable || !p->request_sent)) - { - ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - - ngx_http_proxy_send_request(p); -} - - -static void ngx_http_proxy_dummy_handler(ngx_event_t *wev) -{ - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http proxy dummy handler"); -} - - -static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev) -{ - int rc; - ssize_t n; - ngx_connection_t *c; - ngx_http_proxy_ctx_t *p; - - c = rev->data; - p = c->data; - p->action = "reading upstream status line"; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "http proxy process status line"); - - if (rev->timedout) { - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT); - return; - } - - if (p->header_in == NULL) { - p->header_in = ngx_create_temp_buf(p->request->pool, - p->lcf->header_buffer_size); - if (p->header_in == NULL) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - p->header_in->tag = (ngx_buf_tag_t) &ngx_http_proxy_module; - - if (p->cache) { - p->header_in->pos += p->cache->ctx.header_size; - p->header_in->last = p->header_in->pos; - } - } - - n = ngx_http_proxy_read_upstream_header(p); - - if (n == NGX_AGAIN) { - return; - } - - if (n == 0) { - ngx_log_error(NGX_LOG_ERR, rev->log, 0, - "upstream prematurely closed connection"); - } - - if (n == NGX_ERROR || n == 0) { - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); - return; - } - - p->valid_header_in = 0; - - p->upstream->peer.cached = 0; - - rc = ngx_http_proxy_parse_status_line(p); - - if (rc == NGX_AGAIN) { - if (p->header_in->pos == p->header_in->end) { - ngx_log_error(NGX_LOG_ERR, rev->log, 0, - "upstream sent too long status line"); - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER); - } - return; - } - - if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { - ngx_log_error(NGX_LOG_ERR, rev->log, 0, - "upstream sent no valid HTTP/1.0 header"); - - if (p->accel) { - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER); - - } else { - p->request->http_version = NGX_HTTP_VERSION_9; - p->upstream->status = NGX_HTTP_OK; - ngx_http_proxy_send_response(p); - } - - return; - } - - /* rc == NGX_OK */ - - p->upstream->status = p->status; - p->state->status = p->status; - - if (p->status == NGX_HTTP_INTERNAL_SERVER_ERROR) { - - if (p->upstream->peer.tries > 1 - && (p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_500)) - { - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_500); - return; - } - -#if (NGX_HTTP_CACHE) - - if (p->upstream->peer.tries == 0 - && p->stale - && (p->lcf->use_stale & NGX_HTTP_PROXY_FT_HTTP_500)) - { - ngx_http_proxy_finalize_request(p, - ngx_http_proxy_send_cached_response(p)); - - return; - } - -#endif - } - - if (p->status == NGX_HTTP_NOT_FOUND - && p->upstream->peer.tries > 1 - && p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_404) - { - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_404); - return; - } - - /* TODO: "proxy_error_page" */ - - p->upstream->status_line.len = p->status_end - p->status_start; - p->upstream->status_line.data = ngx_palloc(p->request->pool, - p->upstream->status_line.len + 1); - if (p->upstream->status_line.data == NULL) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - ngx_cpystrn(p->upstream->status_line.data, p->status_start, - p->upstream->status_line.len + 1); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "http proxy status %ui \"%V\"", - p->upstream->status, &p->upstream->status_line); - - - /* init or reinit the p->upstream->headers_in.headers table */ - - if (p->upstream->headers_in.headers.part.elts) { - p->upstream->headers_in.headers.part.nelts = 0; - p->upstream->headers_in.headers.part.next = NULL; - p->upstream->headers_in.headers.last = - &p->upstream->headers_in.headers.part; - - ngx_memzero(&p->upstream->headers_in.date, - sizeof(ngx_http_proxy_headers_in_t) - sizeof(ngx_list_t)); - - } else { - if (ngx_list_init(&p->upstream->headers_in.headers, p->request->pool, - 20, sizeof(ngx_table_elt_t)) == NGX_ERROR) - { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - } - - - c->read->event_handler = ngx_http_proxy_process_upstream_headers; - ngx_http_proxy_process_upstream_headers(rev); -} - - -static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev) -{ - int i, rc; - ssize_t n; - ngx_table_elt_t *h; - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_proxy_ctx_t *p; - - c = rev->data; - p = c->data; - r = p->request; - p->action = "reading upstream headers"; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, - "http proxy process header line"); - - if (rev->timedout) { - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT); - return; - } - - rc = NGX_AGAIN; - - for ( ;; ) { - if (rc == NGX_AGAIN) { - n = ngx_http_proxy_read_upstream_header(p); - - if (n == 0) { - ngx_log_error(NGX_LOG_ERR, rev->log, 0, - "upstream prematurely closed connection"); - } - - if (n == NGX_ERROR || n == 0) { - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); - return; - } - - if (n == NGX_AGAIN) { - return; - } - } - - rc = ngx_http_parse_header_line(p->request, p->header_in); - - if (rc == NGX_OK) { - - /* a header line has been parsed successfully */ - - h = ngx_list_push(&p->upstream->headers_in.headers); - if (h == NULL) { - ngx_http_proxy_finalize_request(p, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - 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(p->request->pool, - h->key.len + 1 + h->value.len + 1); - if (h->key.data == NULL) { - ngx_http_proxy_finalize_request(p, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - h->value.data = h->key.data + h->key.len + 1; - 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_proxy_headers_in[i].name.len != 0; i++) { - if (ngx_http_proxy_headers_in[i].name.len != h->key.len) { - continue; - } - - if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data, - h->key.data) == 0) - { - *((ngx_table_elt_t **) ((char *) &p->upstream->headers_in - + ngx_http_proxy_headers_in[i].offset)) = h; - break; - } - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http proxy header: \"%V: %V\"", &h->key, &h->value); - - continue; - - } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) { - - /* a whole header has been parsed successfully */ - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http proxy header done"); - - /* TODO: hook to process the upstream header */ - -#if (NGX_HTTP_CACHE) - - if (p->cachable) { - p->cachable = ngx_http_proxy_is_cachable(p); - } - -#endif - - ngx_http_proxy_send_response(p); - return; - - } else if (rc != NGX_AGAIN) { - - /* there was error while a header line parsing */ - - ngx_log_error(NGX_LOG_ERR, rev->log, 0, - upstream_header_errors[rc - NGX_HTTP_PARSE_HEADER_ERROR]); - - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER); - return; - } - - /* rc == NGX_AGAIN: a header line parsing is still not complete */ - - if (p->header_in->last == p->header_in->end) { - ngx_log_error(NGX_LOG_ERR, rev->log, 0, - "upstream sent too big header"); - - ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER); - return; - } - } -} - - -static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p) -{ - ssize_t n; - ngx_event_t *rev; - - rev = p->upstream->peer.connection->read; - - n = p->header_in->last - p->header_in->pos; - - if (n > 0) { - return n; - } - - n = ngx_recv(p->upstream->peer.connection, p->header_in->last, - p->header_in->end - p->header_in->last); - - if (n == NGX_AGAIN) { -#if 0 - ngx_add_timer(rev, p->lcf->read_timeout); -#endif - - if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_ERROR; - } - - return NGX_AGAIN; - } - - if (n == 0) { - ngx_log_error(NGX_LOG_ERR, rev->log, 0, - "upstream closed prematurely connection"); - } - - if (n == 0 || n == NGX_ERROR) { - return NGX_ERROR; - } - - p->header_in->last += n; - - return n; -} - - -static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p) -{ - int rc; - ngx_event_pipe_t *ep; - ngx_http_request_t *r; - ngx_http_cache_header_t *header; - ngx_http_core_loc_conf_t *clcf; - - r = p->request; - - r->headers_out.status = p->upstream->status; - r->headers_out.status_line = p->upstream->status_line; - -#if 0 - r->headers_out.content_length_n = -1; - r->headers_out.content_length = NULL; -#endif - - /* copy an upstream header to r->headers_out */ - - if (ngx_http_proxy_copy_header(p, &p->upstream->headers_in) == NGX_ERROR) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - /* TODO: preallocate event_pipe bufs, look "Content-Length" */ - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK) { - ngx_http_proxy_finalize_request(p, rc); - return; - } - - p->header_sent = 1; - - if (p->cache && p->cache->ctx.file.fd != NGX_INVALID_FILE) { - if (ngx_close_file(p->cache->ctx.file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - p->cache->ctx.file.name.data); - } - } - - if (p->cachable) { - header = (ngx_http_cache_header_t *) p->header_in->start; - - header->expires = p->cache->ctx.expires; - header->last_modified = p->cache->ctx.last_modified; - header->date = p->cache->ctx.date; - header->length = r->headers_out.content_length_n; - p->cache->ctx.length = r->headers_out.content_length_n; - - header->key_len = p->cache->ctx.key0.len; - ngx_memcpy(&header->key, p->cache->ctx.key0.data, header->key_len); - header->key[header->key_len] = LF; - } - - ep = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); - if (ep == NULL) { - ngx_http_proxy_finalize_request(p, 0); - return; - } - - p->upstream->event_pipe = ep; - - ep->input_filter = ngx_event_pipe_copy_input_filter; - ep->output_filter = (ngx_event_pipe_output_filter_pt) - ngx_http_output_filter; - ep->output_ctx = r; - ep->tag = (ngx_buf_tag_t) &ngx_http_proxy_module; - ep->bufs = p->lcf->bufs; - ep->busy_size = p->lcf->busy_buffers_size; - ep->upstream = p->upstream->peer.connection; - ep->downstream = r->connection; - ep->pool = r->pool; - ep->log = r->connection->log; - - ep->cachable = p->cachable; - - ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); - if (ep->temp_file == NULL) { - ngx_http_proxy_finalize_request(p, 0); - return; - } - - ep->temp_file->file.fd = NGX_INVALID_FILE; - ep->temp_file->file.log = r->connection->log; - ep->temp_file->path = p->lcf->temp_path; - ep->temp_file->pool = r->pool; - - if (p->cachable) { - ep->temp_file->persistent = 1; - } else { - ep->temp_file->warn = "an upstream response is buffered " - "to a temporary file"; - } - - ep->max_temp_file_size = p->lcf->max_temp_file_size; - ep->temp_file_write_size = p->lcf->temp_file_write_size; - - ep->preread_bufs = ngx_alloc_chain_link(r->pool); - if (ep->preread_bufs == NULL) { - ngx_http_proxy_finalize_request(p, 0); - return; - } - ep->preread_bufs->buf = p->header_in; - ep->preread_bufs->next = NULL; - p->header_in->recycled = 1; - - ep->preread_size = p->header_in->last - p->header_in->pos; - - if (p->cachable) { - ep->buf_to_file = ngx_calloc_buf(r->pool); - if (ep->buf_to_file == NULL) { - ngx_http_proxy_finalize_request(p, 0); - return; - } - ep->buf_to_file->pos = p->header_in->start; - ep->buf_to_file->last = p->header_in->pos; - ep->buf_to_file->temporary = 1; - } - - if (ngx_event_flags & NGX_USE_AIO_EVENT) { - /* the posted aio operation can currupt a shadow buffer */ - ep->single_buf = 1; - } - - /* TODO: ep->free_bufs = 0 if use ngx_create_chain_of_bufs() */ - ep->free_bufs = 1; - - /* - * event_pipe would do p->header_in->last += ep->preread_size - * as though these bytes were read. - */ - p->header_in->last = p->header_in->pos; - - if (p->lcf->cyclic_temp_file) { - - /* - * we need to disable the use of sendfile() if we use cyclic temp file - * because the writing a new data can interfere with sendfile() - * that uses the same kernel file pages (at least on FreeBSD) - */ - - ep->cyclic_temp_file = 1; - r->connection->sendfile = 0; - - } else { - ep->cyclic_temp_file = 0; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - ep->read_timeout = p->lcf->read_timeout; - 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; - - ngx_http_proxy_process_body(p->upstream->peer.connection->read); - - return; -} - - -static void ngx_http_proxy_process_body(ngx_event_t *ev) -{ - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_proxy_ctx_t *p; - ngx_event_pipe_t *ep; - - c = ev->data; - - if (ev->write) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, - "http proxy process downstream"); - r = c->data; - p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); - p->action = "sending to client"; - - } else { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, - "http proxy process upstream"); - p = c->data; - p->action = "reading upstream body"; - } - - ep = p->upstream->event_pipe; - - if (ev->timedout) { - if (ev->write) { - ep->downstream_error = 1; - ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, - "client timed out"); - - } else { - ep->upstream_error = 1; - ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, - "upstream timed out"); - } - - } else { - if (ngx_event_pipe(ep, ev->write) == NGX_ABORT) { - ngx_http_proxy_finalize_request(p, 0); - return; - } - } - - if (p->upstream->peer.connection) { - -#if (NGX_HTTP_FILE_CACHE) - - if (ep->upstream_done && p->cachable) { - if (ngx_http_proxy_update_cache(p) == NGX_ERROR) { - ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock); - ngx_http_proxy_finalize_request(p, 0); - return; - } - - } else if (ep->upstream_eof && p->cachable) { - - /* TODO: check length & update cache */ - - if (ngx_http_proxy_update_cache(p) == NGX_ERROR) { - ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock); - ngx_http_proxy_finalize_request(p, 0); - return; - } - } - -#endif - - if (ep->upstream_done || ep->upstream_eof || ep->upstream_error) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, - "http proxy upstream exit: %p", ep->out); - ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock); - ngx_http_proxy_finalize_request(p, 0); - return; - } - } - - if (ep->downstream_error) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, - "http proxy downstream error"); - if (!p->cachable && p->upstream->peer.connection) { - ngx_http_proxy_finalize_request(p, 0); - } - } -} - - -static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, - ngx_uint_t ft_type) -{ - ngx_uint_t status; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0, - "http proxy next upstream: %ui", ft_type); - - ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock); - - if (ft_type != NGX_HTTP_PROXY_FT_HTTP_404) { - ngx_event_connect_peer_failed(&p->upstream->peer); - } - - if (ft_type == NGX_HTTP_PROXY_FT_TIMEOUT) { - ngx_log_error(NGX_LOG_ERR, p->request->connection->log, NGX_ETIMEDOUT, - "upstream timed out"); - } - - if (p->upstream->peer.cached && ft_type == NGX_HTTP_PROXY_FT_ERROR) { - status = 0; - - } else { - switch(ft_type) { - case NGX_HTTP_PROXY_FT_TIMEOUT: - status = NGX_HTTP_GATEWAY_TIME_OUT; - break; - - case NGX_HTTP_PROXY_FT_HTTP_500: - status = NGX_HTTP_INTERNAL_SERVER_ERROR; - break; - - case NGX_HTTP_PROXY_FT_HTTP_404: - status = NGX_HTTP_NOT_FOUND; - break; - - /* - * NGX_HTTP_PROXY_FT_BUSY_LOCK and NGX_HTTP_PROXY_FT_MAX_WAITING - * never reach here - */ - - default: - status = NGX_HTTP_BAD_GATEWAY; - } - } - - if (p->upstream->peer.connection) { - ngx_http_proxy_close_connection(p); - } - - if (p->request->connection->write->eof) { - ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST); - return; - } - - if (status) { - p->state->status = status; - - if (p->upstream->peer.tries == 0 || !(p->lcf->next_upstream & ft_type)) - { - -#if (NGX_HTTP_CACHE) - - if (p->stale && (p->lcf->use_stale & ft_type)) { - ngx_http_proxy_finalize_request(p, - ngx_http_proxy_send_cached_response(p)); - return; - } - -#endif - - ngx_http_proxy_finalize_request(p, status); - return; - } - } - - if (p->lcf->busy_lock && !p->busy_locked) { - ngx_http_proxy_upstream_busy_lock(p); - } else { - ngx_http_proxy_connect(p); - } -} 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/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