# HG changeset patch # User Igor Sysoev # Date 1105995600 -10800 # Node ID 7ca9bdc82b3f8fa74c56d84dc79e0cabd2092f59 # Parent 66901c2556fdc08bbd9e3fba141be2c93a1428bb nginx 0.1.14 *) Feature: the autoconfiguration directives: --http-client-body-temp-path=PATH, --http-proxy-temp-path=PATH, and --http-fastcgi-temp-path=PATH *) Change: the directory name for the temporary files with the client request body is specified by directive client_body_temp_path, by default it is /client_body_temp. *) Feature: the ngx_http_fastcgi_module and the directives: fastcgi_pass, fastcgi_root, fastcgi_index, fastcgi_params, fastcgi_connect_timeout, fastcgi_send_timeout, fastcgi_read_timeout, fastcgi_send_lowat, fastcgi_header_buffer_size, fastcgi_buffers, fastcgi_busy_buffers_size, fastcgi_temp_path, fastcgi_max_temp_file_size, fastcgi_temp_file_write_size, fastcgi_next_upstream, and fastcgi_x_powered_by. *) Bugfix: the "[alert] zero size buf" error; bug appeared in 0.1.3. *) Change: the URI must be specified after the host name in the proxy_pass directive. *) Change: the %3F symbol in the URI was considered as the argument string start. *) Feature: the unix domain sockets support in the ngx_http_proxy_module. *) Feature: the ssl_engine and ssl_ciphers directives. Thanks to Sergey Skvortsov for SSL-accelerator. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,35 @@ + +Changes with nginx 0.1.14 18 Jan 2005 + + *) Feature: the autoconfiguration directives: + --http-client-body-temp-path=PATH, --http-proxy-temp-path=PATH, and + --http-fastcgi-temp-path=PATH + + *) Change: the directory name for the temporary files with the client + request body is specified by directive client_body_temp_path, by + default it is /client_body_temp. + + *) Feature: the ngx_http_fastcgi_module and the directives: fastcgi_pass, + fastcgi_root, fastcgi_index, fastcgi_params, fastcgi_connect_timeout, + fastcgi_send_timeout, fastcgi_read_timeout, fastcgi_send_lowat, + fastcgi_header_buffer_size, fastcgi_buffers, + fastcgi_busy_buffers_size, fastcgi_temp_path, + fastcgi_max_temp_file_size, fastcgi_temp_file_write_size, + fastcgi_next_upstream, and fastcgi_x_powered_by. + + *) Bugfix: the "[alert] zero size buf" error; bug appeared in 0.1.3. + + *) Change: the URI must be specified after the host name in the + proxy_pass directive. + + *) Change: the %3F symbol in the URI was considered as the argument + string start. + + *) Feature: the unix domain sockets support in the ngx_http_proxy_module. + + *) Feature: the ssl_engine and ssl_ciphers directives. + Thanks to Sergey Skvortsov for SSL-accelerator. + Changes with nginx 0.1.13 21 Dec 2004 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,36 @@ + +Изменения в nginx 0.1.14 18.01.2005 + + *) Добавление: параметры автоконфигурации + --http-client-body-temp-path=PATH, --http-proxy-temp-path=PATH и + --http-fastcgi-temp-path=PATH + + *) Изменение: имя каталога с временными файлами, содержащие тело запроса + клиента, задаётся директивой client_body_temp_path, по умолчанию + /client_body_temp. + + *) Добавление: модуль ngx_http_fastcgi_module и директивы fastcgi_pass, + fastcgi_root, fastcgi_index, fastcgi_params, fastcgi_connect_timeout, + fastcgi_send_timeout, fastcgi_read_timeout, fastcgi_send_lowat, + fastcgi_header_buffer_size, fastcgi_buffers, + fastcgi_busy_buffers_size, fastcgi_temp_path, + fastcgi_max_temp_file_size, fastcgi_temp_file_write_size, + fastcgi_next_upstream и fastcgi_x_powered_by. + + *) Исправление: ошибка "[alert] zero size buf"; ошибка появилась в 0.1.3. + + *) Изменение: в директиве proxy_pass нужно обязательно указывать URI + после имени хоста. + + *) Изменение: если в URI встречался символ %3F, то он считался началом + строки аргументов. + + *) Добавление: поддержка unix domain сoкетов в модуле + ngx_http_proxy_module. + + *) Добавление: директивы ssl_engine и ssl_ciphers. + Спасибо Сергею Скворцову за SSL-акселератор. + Изменения в nginx 0.1.13 21.12.2004 diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 Igor Sysoev + * Copyright (C) 2002-2005 Igor Sysoev * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/auto/cc/icc b/auto/cc/icc --- a/auto/cc/icc +++ b/auto/cc/icc @@ -57,6 +57,12 @@ fi CFLAGS="$CFLAGS -w1" #CFLAGS="$CFLAGS -w2" +# disable the ICC 8.0 errors: +# error #181: argument is incompatible with corresponding format +# string conversion +# error #269: invalid format string conversion +CFLAGS="$CFLAGS -wd181 -wd269" + # stop on warning CFLAGS="$CFLAGS -Werror" diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -13,9 +13,15 @@ if [ $OPENSSL != NONE ]; then LINK_DEPS="$LINK_DEPS $OPENSSL/libssl.a $OPENSSL/libcrypto.a" CORE_LIBS="$CORE_LIBS $OPENSSL/libssl.a $OPENSSL/libcrypto.a" ;; + esac + case "$NGX_SYSTEM" in + SunOS|Linux) + CORE_LIBS="$CORE_LIBS -ldl" + ;; esac + else if [ $NGX_PLATFORM != win32 ]; then diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make --- a/auto/lib/openssl/make +++ b/auto/lib/openssl/make @@ -6,6 +6,7 @@ case $NGX_PLATFORM in *) echo "$OPENSSL/libssl.a:" >> $MAKEFILE echo " cd $OPENSSL \\" >> $MAKEFILE + echo " && \$(MAKE) clean \\" >> $MAKEFILE echo " && CC=\"\$(CC)\" \\" >> $MAKEFILE echo " ./config threads no-shared \\" >> $MAKEFILE echo " && \$(MAKE)" >> $MAKEFILE diff --git a/auto/lib/zlib/make b/auto/lib/zlib/make --- a/auto/lib/zlib/make +++ b/auto/lib/zlib/make @@ -54,7 +54,7 @@ END $ZLIB/libz.a: $NGX_MAKEFILE cd $ZLIB \\ - && make clean \\ + && \$(MAKE) clean \\ && cp contrib/asm586/match.S . \\ && CFLAGS="$ZLIB_OPT -DASMV" CC="\$(CC)" \\ ./configure \\ @@ -71,7 +71,7 @@ END $ZLIB/libz.a: $NGX_MAKEFILE cd $ZLIB \\ - && make clean \\ + && \$(MAKE) clean \\ && cp contrib/asm686/match.S . \\ && CFLAGS="$ZLIB_OPT -DASMV" CC="\$(CC)" \\ ./configure \\ @@ -104,7 +104,7 @@ if [ $done = NO ]; then $ZLIB/libz.a: $NGX_MAKEFILE cd $ZLIB \\ - && make clean \\ + && \$(MAKE) clean \\ && CFLAGS="$ZLIB_OPT" CC="\$(CC)" \\ ./configure \\ && \$(MAKE) libz.a diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -140,6 +140,11 @@ if [ $HTTP_PROXY = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_PROXY_SRCS" fi +if [ $HTTP_FASTCGI = YES ]; then + HTTP_MODULES="$HTTP_MODULES $HTTP_FASTCGI_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_FASTCGI_SRCS" +fi + # STUB #USE_MD5=YES #HTTP_SRCS="$HTTP_SRCS $HTPP_CACHE_SRCS" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -11,7 +11,6 @@ NGX_ERROR_LOG_PATH= NGX_PID_PATH= NGX_USER= NGX_GROUP= -NGX_HTTP_LOG_PATH= CC=${CC:-gcc} CPP= @@ -40,6 +39,12 @@ EVENT_AIO=NO USE_THREADS=NO HTTP=YES + +NGX_HTTP_LOG_PATH= +NGX_HTTP_CLIENT_TEMP_PATH= +NGX_HTTP_PROXY_TEMP_PATH= +NGX_HTTP_FASTCGI_TEMP_PATH= + HTTP_CHARSET=YES HTTP_GZIP=YES HTTP_SSL=NO @@ -50,6 +55,7 @@ HTTP_AUTOINDEX=YES HTTP_STATUS=NO HTTP_REWRITE=YES HTTP_PROXY=YES +HTTP_FASTCGI=YES IMAP=NO @@ -107,6 +113,9 @@ do --without-http) HTTP=NO ;; --http-log-path=*) NGX_HTTP_LOG_PATH="$value" ;; + --http-client-body-temp-path=*) NGX_HTTP_CLIENT_TEMP_PATH="$value" ;; + --http-proxy-temp-path=*) NGX_HTTP_PROXY_TEMP_PATH="$value" ;; + --http-fastcgi-temp-path=*) NGX_HTTP_FASTCGI_TEMP_PATH="$value" ;; --with-http_ssl_module) HTTP_SSL=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; @@ -118,6 +127,7 @@ do --without-http_status_module) HTTP_STATUS=NO ;; --without-http_rewrite_module) HTTP_REWRITE=NO ;; --without-http_proxy_module) HTTP_PROXY=NO ;; + --without-http_fastcgi_module) HTTP_FASTCGI=NO ;; --with-imap) IMAP=YES ;; @@ -161,30 +171,69 @@ if [ $help = yes ]; then cat << END - --help this message + --help this message + + --prefix=PATH set the installation prefix + --sbin-path=PATH set path to the nginx binary file + --conf-path=PATH set path to the nginx.conf file + --error-log-path=PATH set path to the error log + --pid-path=PATH set path to nginx.pid file + + --user=USER set non-privilege user + for the worker processes + --group=GROUP set non-privilege group + for the worker processes + + --builddir=DIR set the build directory - --user=USER set non-privilege user - for the worker processes - --group=GROUP set non-privilege group - for the worker processes + --with-rtsig_module enable rtsig module + --with-select_module enable select module + --without-select_module disable select module + --with-poll_module enable poll module + --without-poll_module disable poll module - --with-select_module enable select module - --without-select_module disable select module - --with-poll_module enable poll module - --without-poll_module disable poll module + --with-http_ssl_module enable ngx_http_ssl_module + --without-http_charset_module disable ngx_http_charset_module + --without-http_gzip_module disable ngx_http_gzip_module + --without-http_userid_module disable ngx_http_userid_module + --without-http_access_module disable ngx_http_access_module + --without-http_autoindex_module disable ngx_http_autoindex_module + --without-http_rewrite_module disable ngx_http_rewrite_module + --without-http_proxy_module disable ngx_http_proxy_module + --without-http_fastcgi_module disable ngx_http_fastcgi_module - --without-http_charset_module disable ngx_http_charset_module - --without-http_rewrite_module disable ngx_http_rewrite_module - --without-http_gzip_module disable ngx_http_gzip_module - --without-http_proxy_module disable ngx_http_proxy_module + --http-log-path=PATH set path to the http access log + --http-client-body-temp-path=PATH set path to the http client request body + temporary files path + --http-proxy-temp-path=PATH set path to the http proxy temporary + files path + --http-fastcgi-temp-path=PATH set path to the http fastcgi temporary + files path + + --with-cc=PATH set path to C compiler + --with-cpp=PATH set path to C preprocessor + --with-cc-opt=OPTIONS set additional options for C compiler + --with-ld-opt=OPTIONS set additional options for linker + --with-cpu-opt=CPU build for specified CPU, the valid values: + pentium, pentiumpro, pentium4, sparc64 - --with-cc-opt=OPTIONS additional options for compiler - --with-ld-opt=OPTIONS additional options for linker + --without-pcre disable PCRE libarary usage + --with-pcre=DIR set path to PCRE library sources + --with-pcre-opt=OPTIONS set additional options for PCRE building + + --with-md5=DIR set path to md5 library sources + --with-md5-opt=OPTIONS set additional options for md5 building + --with-md5-asm use md5 assembler sources - --with-pcre=DIR path to PCRE library - --with-md5=DIR path to md5 library - --with-zlib=DIR path to zlib library - --with-openssl=DIR path to OpenSSL library + --with-zlib=DIR set path to zlib library sources + --with-zlib-opt=OPTIONS set additional options for zlib building + --with-zlib-asm=CPU use zlib assembler sources optimized + for specified CPU, the valid values: + pentium, pentiumpro + + --with-openssl=DIR set path to OpenSSL library sources + + --with-debug enable the debugging logging END @@ -201,6 +250,7 @@ if [ $HTTP = NO ]; then HTTP_STATUS=NO HTTP_REWRITE=NO HTTP_PROXY=NO + HTTP_FASTCGI=NO fi @@ -284,3 +334,45 @@ case ".$NGX_HTTP_LOG_PATH" in NGX_HTTP_LOG_PATH=$NGX_PREFIX/$NGX_HTTP_LOG_PATH ;; esac + + +case ".$NGX_HTTP_CLIENT_TEMP_PATH" in + ./*) + ;; + + .) + NGX_HTTP_CLIENT_TEMP_PATH=$NGX_PREFIX/client_body_temp + ;; + + *) + NGX_HTTP_CLIENT_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_CLIENT_TEMP_PATH + ;; +esac + + +case ".$NGX_HTTP_PROXY_TEMP_PATH" in + ./*) + ;; + + .) + NGX_HTTP_PROXY_TEMP_PATH=$NGX_PREFIX/proxy_temp + ;; + + *) + NGX_HTTP_PROXY_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_PROXY_TEMP_PATH + ;; +esac + + +case ".$NGX_HTTP_FASTCGI_TEMP_PATH" in + ./*) + ;; + + .) + NGX_HTTP_FASTCGI_TEMP_PATH=$NGX_PREFIX/fastcgi_temp + ;; + + *) + NGX_HTTP_FASTCGI_TEMP_PATH=$NGX_PREFIX/$NGX_HTTP_FASTCGI_TEMP_PATH + ;; +esac diff --git a/auto/os/conf b/auto/os/conf --- a/auto/os/conf +++ b/auto/os/conf @@ -5,13 +5,13 @@ if test -z "$NGX_PLATFORM"; then echo "checking for OS" - SYSTEM=`uname -s 2>/dev/null` - RELEASE=`uname -r 2>/dev/null` - MACHINE=`uname -m 2>/dev/null` + NGX_SYSTEM=`uname -s 2>/dev/null` + NGX_RELEASE=`uname -r 2>/dev/null` + NGX_MACHINE=`uname -m 2>/dev/null` - echo " + $SYSTEM $RELEASE $MACHINE" + echo " + $NGX_SYSTEM $NGX_RELEASE $NGX_MACHINE" - NGX_PLATFORM="$SYSTEM:$RELEASE:$MACHINE"; + NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE"; else echo "building for $NGX_PLATFORM" fi @@ -43,6 +43,15 @@ case $NGX_PLATFORM in esac +case $NGX_MACHINE in + + i386|i686|i86pc|amd64) + have=NGX_HAVE_NONALIGNED . auto/have + ;; + +esac + + if [ $NGX_PLATFORM != win32 ]; then NGX_USER=${NGX_USER:-nobody} diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -110,6 +110,7 @@ OPENSSL_SRCS=src/event/ngx_event_openssl UNIX_INCS="$CORE_INCS $EVENT_INCS src/os/unix" UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \ + src/core/ngx_unix_domain.h \ src/os/unix/ngx_time.h \ src/os/unix/ngx_types.h \ src/os/unix/ngx_errno.h \ @@ -125,6 +126,7 @@ UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/unix/ngx_process_cycle.h" UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ + src/core/ngx_unix_domain.c \ src/os/unix/ngx_time.c \ src/os/unix/ngx_errno.c \ src/os/unix/ngx_alloc.c \ @@ -203,9 +205,13 @@ NGX_WIN32_ICONS="src/os/win32/nginx.ico NGX_WIN32_RC="src/os/win32/nginx.rc" +# the http modules that have their logging formats +# must be after ngx_http_log_module + HTTP_MODULES="ngx_http_module \ ngx_http_core_module \ - ngx_http_log_module" + ngx_http_log_module \ + ngx_http_upstream_module" HTTP_CACHE_MODULE=ngx_http_cache_module @@ -231,6 +237,7 @@ HTTP_DEPS="src/http/ngx_http.h \ src/http/ngx_http_config.h \ src/http/ngx_http_core_module.h \ src/http/ngx_http_cache.h \ + src/http/ngx_http_upstream.h \ src/http/ngx_http_busy_lock.h \ src/http/ngx_http_log_handler.h" @@ -244,6 +251,7 @@ HTTP_SRCS="src/http/ngx_http.c \ src/http/ngx_http_copy_filter.c \ src/http/ngx_http_log_handler.c \ src/http/ngx_http_request_body.c \ + src/http/ngx_http_upstream.c \ src/http/ngx_http_parse_time.c \ src/http/modules/ngx_http_static_handler.c \ src/http/modules/ngx_http_index_handler.c \ @@ -308,6 +316,10 @@ HTTP_PROXY_SRCS="src/http/modules/proxy/ # src/http/modules/proxy/ngx_http_proxy_cache.c \ +HTTP_FASTCGI_MODULE=ngx_http_fastcgi_module +HTTP_FASTCGI_SRCS=src/http/modules/ngx_http_fastcgi_handler.c + + IMAP_INCS="src/imap" IMAP_DEPS="src/imap/ngx_imap.h" diff --git a/auto/summary b/auto/summary --- a/auto/summary +++ b/auto/summary @@ -101,14 +101,39 @@ END fi -echo " nginx path prefix: $NGX_PREFIX" -echo " nginx binary file: $NGX_SBIN_PATH" -echo " nginx configuration file: $NGX_CONF_PATH" -echo " nginx pid file: $NGX_PID_PATH" +if [ $HTTP_SSL = YES ]; then + if [ $OPENSSL = NONE -o $OPENSSL = NO ]; then + +cat << END +$0: error: the HTTP SSL module requires the OpenSSL library. +You can either do not enable the module, or install the OpenSSL library +into the system, or build the OpenSSL library statically from the source +with nginx by using --with-openssl= option. + +END + + exit 1 + fi +fi + + +cat << END + nginx path prefix: $NGX_PREFIX + nginx binary file: $NGX_SBIN_PATH + nginx configuration file: $NGX_CONF_PATH + nginx pid file: $NGX_PID_PATH +END + if test -n "$NGX_ERROR_LOG_PATH"; then echo " nginx error log file: $NGX_ERROR_LOG_PATH" else echo " nginx logs errors to stderr" fi -echo " nginx http access log file: $NGX_HTTP_LOG_PATH" -echo + +cat << END + nginx http access log file: $NGX_HTTP_LOG_PATH + nginx http client request body temporary files: $NGX_HTTP_CLIENT_TEMP_PATH + nginx http proxy temporary files: $NGX_HTTP_PROXY_TEMP_PATH + nginx http fastcgi temporary files: $NGX_HTTP_FASTCGI_TEMP_PATH + +END diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -2,6 +2,9 @@ # Copyright (C) Igor Sysoev +have=NGX_HAVE_UNIX_DOMAIN . auto/have + + CC_WARN= ngx_fmt_collect=yes diff --git a/configure b/configure --- a/configure +++ b/configure @@ -51,7 +51,14 @@ have=NGX_PID_PATH value="\"$NGX_PID_PATH if test -n "$NGX_ERROR_LOG_PATH"; then have=NGX_ERROR_LOG_PATH value="\"$NGX_ERROR_LOG_PATH\"" . auto/define fi + have=NGX_HTTP_LOG_PATH value="\"$NGX_HTTP_LOG_PATH\"" . auto/define +have=NGX_HTTP_CLIENT_TEMP_PATH value="\"$NGX_HTTP_CLIENT_TEMP_PATH\"" +. auto/define +have=NGX_HTTP_PROXY_TEMP_PATH value="\"$NGX_HTTP_PROXY_TEMP_PATH\"" +. auto/define +have=NGX_HTTP_FASTCGI_TEMP_PATH value="\"$NGX_HTTP_FASTCGI_TEMP_PATH\"" +. auto/define have=NGX_USER value="\"$NGX_USER\"" . auto/define have=NGX_GROUP value="\"$NGX_GROUP\"" . auto/define diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -451,12 +451,15 @@ static void *ngx_core_module_create_conf if (!(ccf = ngx_pcalloc(cycle->pool, sizeof(ngx_core_conf_t)))) { return NULL; } - /* set by pcalloc() + + /* + * set by pcalloc() * - * ccf->pid = NULL; - * ccf->newpid = NULL; - * ccf->priority = 0; + * ccf->pid = NULL; + * ccf->newpid = NULL; + * ccf->priority = 0; */ + ccf->daemon = NGX_CONF_UNSET; ccf->master = NGX_CONF_UNSET; ccf->worker_processes = NGX_CONF_UNSET; 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.13" +#define NGINX_VER "nginx/0.1.14" #define NGINX_VAR "NGINX" #define NGX_NEWPID_EXT ".newbin" 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 @@ -69,7 +69,7 @@ typedef struct { } ngx_bufs_t; -typedef int (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *out); +typedef ngx_int_t (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *in); typedef struct { ngx_buf_t *buf; @@ -141,7 +141,7 @@ ngx_chain_t *ngx_create_chain_of_bufs(ng ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in); -ngx_int_t ngx_chain_writer(void *data, ngx_chain_t *in); +ngx_int_t ngx_chain_writer(void *ctx, ngx_chain_t *in); ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); 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 @@ -239,8 +239,8 @@ char *ngx_conf_check_num_bounds(ngx_conf } #define ngx_conf_merge_str_value(conf, prev, default) \ - if (conf.len == 0) { \ - if (prev.len) { \ + if (conf.data == NULL) { \ + if (prev.data) { \ conf.len = prev.len; \ conf.data = prev.data; \ } else { \ diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -18,7 +18,7 @@ ngx_listening_t *ngx_listening_inet_stre { size_t len; ngx_listening_t *ls; - struct sockaddr_in *addr_in; + struct sockaddr_in *sin; if (!(ls = ngx_array_push(&cf->cycle->listening))) { return NULL; @@ -26,13 +26,13 @@ ngx_listening_t *ngx_listening_inet_stre ngx_memzero(ls, sizeof(ngx_listening_t)); - if (!(addr_in = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) { + if (!(sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) { return NULL; } - addr_in->sin_family = AF_INET; - addr_in->sin_addr.s_addr = addr; - addr_in->sin_port = htons(port); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = addr; + sin->sin_port = htons(port); ls->addr_text.data = ngx_palloc(cf->pool, @@ -50,8 +50,7 @@ ngx_listening_t *ngx_listening_inet_stre ls->fd = (ngx_socket_t) -1; ls->family = AF_INET; ls->type = SOCK_STREAM; - ls->protocol = IPPROTO_IP; - ls->sockaddr = (struct sockaddr *) addr_in; + ls->sockaddr = (struct sockaddr *) sin; ls->socklen = sizeof(struct sockaddr_in); ls->addr = offsetof(struct sockaddr_in, sin_addr); ls->addr_text_max_len = INET_ADDRSTRLEN; @@ -65,7 +64,7 @@ ngx_int_t ngx_set_inherited_sockets(ngx_ size_t len; ngx_uint_t i; ngx_listening_t *ls; - struct sockaddr_in *addr_in; + struct sockaddr_in *sin; ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { @@ -86,9 +85,9 @@ ngx_int_t ngx_set_inherited_sockets(ngx_ continue; } - addr_in = (struct sockaddr_in *) ls[i].sockaddr; + sin = (struct sockaddr_in *) ls[i].sockaddr; - if (addr_in->sin_family != AF_INET) { + if (sin->sin_family != AF_INET) { ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, "the inherited socket #%d has " "unsupported family", ls[i].fd); @@ -105,7 +104,7 @@ ngx_int_t ngx_set_inherited_sockets(ngx_ return NGX_ERROR; } - ls[i].family = addr_in->sin_family; + ls[i].family = sin->sin_family; len = ngx_sock_ntop(ls[i].family, ls[i].sockaddr, ls[i].addr_text.data, INET_ADDRSTRLEN); if (len == 0) { @@ -113,7 +112,7 @@ ngx_int_t ngx_set_inherited_sockets(ngx_ } ls[i].addr_text.len = ngx_sprintf(ls[i].addr_text.data + len, ":%d", - ntohs(addr_in->sin_port)) + ntohs(sin->sin_port)) - ls[i].addr_text.data; } @@ -163,7 +162,7 @@ ngx_int_t ngx_open_listening_sockets(ngx continue; } - s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol); + s = ngx_socket(ls[i].family, ls[i].type, 0); if (s == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, @@ -313,7 +312,7 @@ void ngx_close_connection(ngx_connection { ngx_socket_t fd; - if (c->pool == NULL) { + if (c->fd == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); return; } @@ -388,8 +387,6 @@ void ngx_close_connection(ngx_connection c->fd = (ngx_socket_t) -1; c->data = NULL; - ngx_destroy_pool(c->pool); - if (ngx_close_socket(fd) == -1) { /* we use ngx_cycle->log because c->log was in c->pool */ diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -23,7 +23,6 @@ typedef struct { int family; int type; - int protocol; void (*handler)(ngx_connection_t *c); /* handler of accepted connection */ diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -18,6 +18,7 @@ typedef struct ngx_open_file_s ngx_ope typedef struct ngx_command_s ngx_command_t; typedef struct ngx_file_s ngx_file_t; typedef struct ngx_event_s ngx_event_t; +typedef struct ngx_peers_s ngx_peers_t; typedef struct ngx_connection_s ngx_connection_t; typedef void (*ngx_event_handler_pt)(ngx_event_t *ev); @@ -60,6 +61,9 @@ typedef void (*ngx_event_handler_pt)(ngx #include #include #include +#if (NGX_HAVE_UNIX_DOMAIN) +#include +#endif #include #include #include 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 @@ -9,7 +9,7 @@ #include -static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *s1, struct sockaddr *s2); +static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2); static void ngx_clean_old_cycles(ngx_event_t *ev); @@ -531,18 +531,18 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t } -static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *s1, struct sockaddr *s2) +static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2) { struct sockaddr_in *sin1, *sin2; /* AF_INET only */ - if (s1->sa_family != AF_INET || s2->sa_family != AF_INET) { + if (sa1->sa_family != AF_INET || sa2->sa_family != AF_INET) { return NGX_DECLINED; } - sin1 = (struct sockaddr_in *) s1; - sin2 = (struct sockaddr_in *) s2; + sin1 = (struct sockaddr_in *) sa1; + sin2 = (struct sockaddr_in *) sa2; if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { return NGX_DECLINED; 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 @@ -193,7 +193,7 @@ char *ngx_conf_set_path_slot(ngx_conf_t ssize_t level; ngx_uint_t i, n; ngx_str_t *value; - ngx_path_t *path, **pp, **slot; + ngx_path_t *path, **slot; slot = (ngx_path_t **) (p + cmd->offset); @@ -209,7 +209,7 @@ char *ngx_conf_set_path_slot(ngx_conf_t path->name = value[1]; path->len = 0; - path->gc_handler = (ngx_gc_handler_pt) cmd->post; + path->cleaner = (ngx_gc_handler_pt) cmd->post; path->conf_file = cf->conf_file->file.name.data; path->line = cf->conf_file->line; @@ -227,42 +227,65 @@ char *ngx_conf_set_path_slot(ngx_conf_t path->level[i++] = 0; } + *slot = path; - pp = cf->cycle->pathes.elts; + if (ngx_add_path(cf, slot) == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot) +{ + ngx_uint_t i, n; + ngx_path_t *path, **p; + + path = *slot; + + p = cf->cycle->pathes.elts; for (i = 0; i < cf->cycle->pathes.nelts; i++) { - if (pp[i]->name.len == path->name.len - && ngx_strcmp(pp[i]->name.data, path->name.data) == 0) + if (p[i]->name.len == path->name.len + && ngx_strcmp(p[i]->name.data, path->name.data) == 0) { for (n = 0; n < 3; n++) { - if (pp[i]->level[n] != path->level[n]) { + if (p[i]->level[n] != path->level[n]) { + if (path->conf_file == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "the path name \"%V\" in %s:%ui has " + "the same name as default path but " + "the different levels, you need to " + "define default path in http section", + &p[i]->name, p[i]->conf_file, p[i]->line); + return NGX_ERROR; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the same \"%V\" path name in %s:%ui " - "has the different levels than", - &pp[i]->name, pp[i]->conf_file, pp[i]->line); - return NGX_CONF_ERROR; + "the same path name \"%V\" in %s:%ui " + "has the different levels than", + &p[i]->name, p[i]->conf_file, p[i]->line); + return NGX_ERROR; } - if (pp[i]->level[n] == 0) { + if (p[i]->level[n] == 0) { break; } } - *slot = pp[i]; + *slot = p[i]; - return NGX_CONF_OK; + return NGX_OK; } } - *slot = path; - - - if (!(pp = ngx_array_push(&cf->cycle->pathes))) { - return NGX_CONF_ERROR; + if (!(p = ngx_array_push(&cf->cycle->pathes))) { + return NGX_ERROR; } - *pp = path; + *p = path; - return NGX_CONF_OK; + return NGX_OK; } diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -35,7 +35,7 @@ struct ngx_path_s { ngx_str_t name; ngx_uint_t len; ngx_uint_t level[3]; - ngx_gc_handler_pt gc_handler; + ngx_gc_handler_pt cleaner; u_char *conf_file; ngx_uint_t line; @@ -58,6 +58,7 @@ ngx_int_t ngx_create_temp_file(ngx_file_ ngx_pool_t *pool, int persistent); void ngx_create_hashed_filename(ngx_file_t *file, ngx_path_t *path); ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path); +ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot); ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user); void ngx_init_temp_number(); @@ -66,19 +67,34 @@ ngx_uint_t ngx_next_temp_number(ngx_uint char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -#define ngx_conf_merge_path_value(conf, prev, path, l1, l2, l3, pool) \ - if (conf == NULL) { \ - if (prev == NULL) { \ - ngx_test_null(conf, ngx_palloc(pool, sizeof(ngx_path_t)), NULL); \ - conf->name.len = sizeof(path) - 1; \ - conf->name.data = (u_char *) path; \ - conf->level[0] = l1; \ - conf->level[1] = l2; \ - conf->level[2] = l3; \ - conf->len = l1 + l2 + l3 + (l1 ? 1:0) + (l2 ? 1:0) + (l3 ? 1:0); \ - } else { \ - conf = prev; \ - } \ +#define ngx_conf_merge_path_value(curr, prev, path, l1, l2, l3, clean, cf) \ + if (curr == NULL) { \ + if (prev == NULL) { \ + if (!(curr = ngx_palloc(cf->pool, sizeof(ngx_path_t)))) { \ + return NGX_CONF_ERROR; \ + } \ + \ + curr->name.len = sizeof(path) - 1; \ + curr->name.data = (u_char *) path; \ + \ + if (ngx_conf_full_name(cf->cycle, &curr->name) == NGX_ERROR) { \ + return NGX_CONF_ERROR; \ + } \ + \ + curr->level[0] = l1; \ + curr->level[1] = l2; \ + curr->level[2] = l3; \ + curr->len = l1 + l2 + l3 + (l1 ? 1:0) + (l2 ? 1:0) + (l3 ? 1:0); \ + curr->cleaner = clean; \ + curr->conf_file = NULL; \ + \ + if (ngx_add_path(cf, &curr) == NGX_ERROR) { \ + return NGX_CONF_ERROR; \ + } \ + \ + } else { \ + curr = prev; \ + } \ } 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 @@ -4,9 +4,10 @@ */ - #include #include +#include +#include /* @@ -16,7 +17,7 @@ * and they are faster by 1.5-2.5 times, so it is worth to keep them. * * By the way, the implementation using ngx_sprintf() is faster by 2.5-3 times - * than using FreeBSD libc's snrpintf(). + * than using FreeBSD libc's snprintf(). */ @@ -64,13 +65,13 @@ static ngx_inline size_t ngx_sprint_ucha /* AF_INET only */ -size_t ngx_sock_ntop(int family, struct sockaddr *addr, u_char *text, +size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len) { u_char *p; size_t n; ngx_uint_t i; - struct sockaddr_in *addr_in; + struct sockaddr_in *sin; if (len == 0) { return 0; @@ -80,8 +81,8 @@ size_t ngx_sock_ntop(int family, struct return 0; } - addr_in = (struct sockaddr_in *) addr; - p = (u_char *) &addr_in->sin_addr; + sin = (struct sockaddr_in *) sa; + p = (u_char *) &sin->sin_addr; if (len > INET_ADDRSTRLEN) { len = INET_ADDRSTRLEN; @@ -216,56 +217,259 @@ ngx_int_t ngx_ptocidr(ngx_str_t *text, v } -#if 0 - -ngx_int_t ngx_inet_addr_port(ngx_conf_t *cf, ngx_command_t *cmd, - ngx_str_t *addr_port) +ngx_peers_t *ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u) { - u_char *host; - ngx_int_t port; - ngx_uint_t p; - struct hostent *h; + char *err; + u_char *host; + in_addr_t in_addr; + ngx_uint_t i, len; + ngx_peers_t *peers; + struct hostent *h; + struct sockaddr_in *sin; + + err = ngx_inet_parse_host_port(u); + + if (err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in upstream \"%V\"", err, &u->name); + return NULL; + } + + if (u->default_port) { + if (u->default_port_value == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no port in upstream \"%V\"", &u->name); + return NULL; + } + + u->port = u->default_port_value; + + if (!(u->port_text.data = ngx_palloc(cf->pool, sizeof("65536") - 1))) { + return NULL; + } + + u->port_text.len = ngx_sprintf(u->port_text.data, "%d", + u->default_port_value) + - u->port_text.data; + + } else if (u->port) { + if (u->port == u->default_port_value) { + u->default_port = 1; + } + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no port in upstream \"%V\"", &u->name); + return NULL; + } + + if (u->host.len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no host in upstream \"%V\"", &u->name); + return NULL; + } + + u->port = htons(u->port); + + if (!(host = ngx_palloc(cf->pool, u->host.len + 1))) { + return NULL; + } + + ngx_cpystrn(host, u->host.data, u->host.len + 1); + + /* AF_INET only */ + + in_addr = inet_addr((char *) host); + + if (in_addr == INADDR_NONE) { + h = gethostbyname((char *) host); + + if (h == NULL || h->h_addr_list[0] == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "host %s is not found in upstream \"%V\"", + host, &u->name); + return NULL; + } + + for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } + + /* MP: ngx_shared_palloc() */ + + peers = ngx_pcalloc(cf->pool, + sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1)); + + if (peers == NULL) { + return NULL; + } + + peers->number = i; + peers->weight = 1; + + for (i = 0; h->h_addr_list[i] != NULL; i++) { + + if (!(sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) { + return NULL; + } + + sin->sin_family = AF_INET; + sin->sin_port = u->port; + sin->sin_addr.s_addr = *(in_addr_t *)(h->h_addr_list[i]); + + peers->peer[i].sockaddr = (struct sockaddr *) sin; + peers->peer[i].socklen = sizeof(struct sockaddr_in); + + len = INET_ADDRSTRLEN - 1 + 1 + u->port_text.len; + + if (!(peers->peer[i].name.data = ngx_palloc(cf->pool, len))) { + return NULL; + } + + len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin, + peers->peer[i].name.data, len); + + peers->peer[i].name.data[len++] = ':'; - for (p = 0; p < addr_port->len; p++) { - if (addr_port->data[p] == ':') { + ngx_memcpy(peers->peer[i].name.data + len, + u->port_text.data, u->port_text.len); + + peers->peer[i].name.len = len + u->port_text.len; + + peers->peer[i].uri_separator = ""; + + peers->peer[i].weight = 1; + peers->peer[i].max_fails = 1; + peers->peer[i].fail_timeout = 60; + } + + } else { + + /* MP: ngx_shared_palloc() */ + + if (!(peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)))) { + return NULL; + } + + if (!(sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) { + return NULL; + } + + peers->number = 1; + + sin->sin_family = AF_INET; + sin->sin_port = u->port; + sin->sin_addr.s_addr = in_addr; + + peers->peer[0].sockaddr = (struct sockaddr *) sin; + peers->peer[0].socklen = sizeof(struct sockaddr_in); + + len = u->host.len + 1 + u->port_text.len; + + peers->peer[0].name.len = len; + + if (!(peers->peer[0].name.data = ngx_palloc(cf->pool, len))) { + return NULL; + } + + len = u->host.len; + + ngx_memcpy(peers->peer[0].name.data, u->host.data, len); + + peers->peer[0].name.data[len++] = ':'; + + ngx_memcpy(peers->peer[0].name.data + len, + u->port_text.data, u->port_text.len); + + peers->peer[0].uri_separator = ""; + } + + return peers; +} + + +char *ngx_inet_parse_host_port(ngx_inet_upstream_t *u) +{ + size_t i; + ngx_int_t port; + ngx_str_t *url; + + url = &u->url; + + if (u->port_only) { + i = 0; + + } else { + if (url->data[0] == ':' || url->data[0] == '/') { + return "invalid host"; + } + + i = 1; + } + + u->host.data = url->data; + u->host_header = *url; + + for (/* void */; i < url->len; i++) { + + if (url->data[i] == ':') { + u->port_text.data = &url->data[i] + 1; + u->host.len = i; + + if (!u->uri_part) { + u->port_text.len = &url->data[url->len] - u->port_text.data; + break; + } + } + + if (url->data[i] == '/') { + u->uri.data = &url->data[i]; + u->uri.len = url->len - i; + u->host_header.len = i; + + if (u->host.len == 0) { + u->host.len = i; + } + + if (u->port_text.data == NULL) { + u->default_port = 1; + return NULL; + } + + u->port_text.len = &url->data[i] - u->port_text.data; + + if (u->port_text.len == 0) { + return "invalid port"; + } + break; } } - in_addr->host.len = p; - if (!(in_addr->host.data = ngx_palloc(pool, p + 1))) { - return NGX_ERROR; - } + if (u->port_text.data == NULL) { + port = ngx_atoi(url->data, url->len); + + if (port == NGX_ERROR) { + u->default_port = 1; + u->host.len = url->len; + + return NULL; + } - ngx_cpystrn(in_addr->host.data, addr_port->data, p + 1); + u->port_text = *url; + u->wildcard = 1; - if (p == addr_port->len) { - p = 0; + } else { + if (u->port_text.len == 0) { + return "no URI"; + } + + port = ngx_atoi(u->port_text.data, u->port_text.len); + + if (port == NGX_ERROR || port < 1 || port > 65536) { + return "invalid port"; + } } - port = ngx_atoi(&addr[p], args[1].len - p); - if (port == NGX_ERROR && p == 0) { - - /* default port */ - iap->port = 0; - - } else if ((port == NGX_ERROR && p != 0) /* "listen host:NONNUMBER" */ - || (port < 1 || port > 65536)) { /* "listen 99999" */ + u->port = (in_port_t) port; - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid port \"%s\" in \"%s\" directive, " - "it must be a number between 1 and 65535", - &addr[p], cmd->name.data); - - return NGX_CONF_ERROR; - - } else if (p == 0) { - ls->addr = INADDR_ANY; - ls->port = (in_port_t) port; - return NGX_CONF_OK; - } - - return NGX_OK; + return NULL; } - -#endif diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -8,17 +8,44 @@ #define _NGX_INET_H_INCLUDED_ +#include +#include + + typedef struct { in_addr_t addr; in_addr_t mask; } ngx_inet_cidr_t; -size_t ngx_sock_ntop(int family, struct sockaddr *addr, u_char *text, +typedef struct { + ngx_str_t name; /* "schema:host:port/uri" */ + ngx_str_t url; /* "host:port/uri" */ + ngx_str_t host; + ngx_str_t uri; + ngx_str_t host_header; /* "host:port" */ + ngx_str_t port_text; /* "port" */ + + in_port_t port; + + in_port_t default_port_value; + + unsigned default_port:1; + unsigned wildcard:1; + + unsigned uri_part:1; + unsigned port_only:1; +} ngx_inet_upstream_t; + + +size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len); size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr); +ngx_peers_t *ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u); +char *ngx_inet_parse_host_port(ngx_inet_upstream_t *u); + #endif /* _NGX_INET_H_INCLUDED_ */ 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 @@ -80,7 +80,7 @@ ngx_int_t ngx_output_chain(ngx_output_ch if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, - "zero size buf"); + "zero size buf in output"); ngx_debug_point(); diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -54,11 +54,11 @@ ngx_regex_t *ngx_regex_compile(ngx_str_t if (re == NULL) { if ((size_t) erroff == pattern->len) { ngx_snprintf(err->data, err->len - 1, - "pcre_compile() failed: %s in \"%s\"", + "pcre_compile() failed: %s in \"%s\"%Z", errstr, pattern->data); } else { ngx_snprintf(err->data, err->len - 1, - "pcre_compile() failed: %s in \"%s\" at \"%s\"", + "pcre_compile() failed: %s in \"%s\" at \"%s\"%Z", errstr, pattern->data, pattern->data + erroff); } } diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -86,7 +86,11 @@ u_char *ngx_snprintf(u_char *buf, size_t u_char *ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args) { - u_char *p, zero, *last, temp[NGX_INT64_LEN]; + u_char *p, zero, *last, temp[NGX_INT64_LEN + 1]; + /* + * really we need temp[NGX_INT64_LEN] only, + * but icc shows the warning + */ int d; size_t len; uint32_t ui32; diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -64,7 +64,7 @@ typedef struct { /* msvc and icc compile memcpy() to the inline "rep movs" */ #define ngx_memcpy(dst, src, n) memcpy(dst, src, n) -#define ngx_cpymem(dst, src, n) ((u_char *) memcpy(dst, src, n)) + n +#define ngx_cpymem(dst, src, n) ((u_char *) memcpy(dst, src, n)) + (n) /* msvc and icc compile memcmp() to the inline loop */ diff --git a/src/core/ngx_unix_domain.c b/src/core/ngx_unix_domain.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_unix_domain.c @@ -0,0 +1,84 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +/* Solaris has predefined "#define sun 1" */ +#undef sun + + +ngx_peers_t *ngx_unix_upstream_parse(ngx_conf_t *cf, + ngx_unix_domain_upstream_t *u) +{ + size_t len; + ngx_uint_t i; + ngx_peers_t *peers; + struct sockaddr_un *sun; + + len = u->url.len - 5; + + if (u->uri_part) { + for (i = 5; i < u->url.len; i++) { + if (u->url.data[i] == ':') { + len = i - 5; + u->uri.len = u->url.len - 5 - len - 1; + u->uri.data = u->url.data + 5 + len + 1; + + break; + } + } + + if (u->uri.len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the unix domain upstream \"%V\" has no URI", + &u->name); + return NULL; + } + } + + if (len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the unix domain socket \"%V\" has no path", + &u->name); + return NULL; + } + + if (len + 1 > sizeof(sun->sun_path)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the unix domain socket path \"%V\" is too long", + &u->name); + return NULL; + } + + /* MP: ngx_shared_palloc() */ + + if (!(peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)))) { + return NULL; + } + + if (!(sun = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_un)))) { + return NULL; + } + + peers->number = 1; + + sun->sun_family = AF_UNIX; + ngx_cpystrn((u_char *) sun->sun_path, u->url.data + 5, len + 1); + + peers->peer[0].sockaddr = (struct sockaddr *) sun; + peers->peer[0].socklen = sizeof(struct sockaddr_un); + + peers->peer[0].name.len = 5 + len; + peers->peer[0].name.data = u->url.data; + + peers->peer[0].uri_separator = ":"; + + return peers; +} diff --git a/src/core/ngx_unix_domain.h b/src/core/ngx_unix_domain.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_unix_domain.h @@ -0,0 +1,29 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_UNIX_DOMAIN_H_INCLUDED_ +#define _NGX_UNIX_DOMAIN_H_INCLUDED_ + + +#include +#include + + +typedef struct { + ngx_str_t name; /* "schema:unix:path:/uri" */ + ngx_str_t url; /* "unix:path:/uri" */ + ngx_str_t uri; + + ngx_uint_t uri_part; /* unsigned uri_part:1; */ +} ngx_unix_domain_upstream_t; + + +ngx_peers_t *ngx_unix_upstream_parse(ngx_conf_t *cf, + ngx_unix_domain_upstream_t *u); + + +#endif /* _NGX_UNIX_DOMAIN_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 @@ -313,12 +313,12 @@ void ngx_event_accept(ngx_event_t *ev) uint32_t *addr; in_addr_t i; - struct sockaddr_in *addr_in; + struct sockaddr_in *sin; - addr_in = (struct sockaddr_in *) sa; + sin = (struct sockaddr_in *) sa; addr = ecf->debug_connection.elts; for (i = 0; i < ecf->debug_connection.nelts; i++) { - if (addr[i] == addr_in->sin_addr.s_addr) { + if (addr[i] == sin->sin_addr.s_addr) { log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL; break; } 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 @@ -25,7 +25,6 @@ ngx_int_t ngx_event_connect_peer(ngx_pee ngx_event_t *rev, *wev; ngx_connection_t *c; ngx_event_conf_t *ecf; - struct sockaddr_in addr; now = ngx_time(); @@ -54,7 +53,7 @@ ngx_int_t ngx_event_connect_peer(ngx_pee pc->connection = NULL; if (pc->peers->number == 1) { - peer = &pc->peers->peers[0]; + peer = &pc->peers->peer[0]; } else { @@ -64,45 +63,47 @@ ngx_int_t ngx_event_connect_peer(ngx_pee /* it's a first try - get a current peer */ - pc->cur_peer = pc->peers->current++; + pc->cur_peer = pc->peers->current; + + pc->peers->weight--; + + if (pc->peers->weight == 0) { + pc->peers->current++; + } if (pc->peers->current >= pc->peers->number) { pc->peers->current = 0; } + + if (pc->peers->weight == 0) { + pc->peers->weight = pc->peers->peer[pc->peers->current].weight; + } } - if (pc->peers->max_fails == 0) { - peer = &pc->peers->peers[pc->cur_peer]; - - } else { - - /* the peers support a fault tolerance */ + for ( ;; ) { + peer = &pc->peers->peer[pc->cur_peer]; - for ( ;; ) { - peer = &pc->peers->peers[pc->cur_peer]; + if (peer->fails <= peer->max_fails) { + break; + } - if (peer->fails <= pc->peers->max_fails) { - break; - } + if (now - peer->accessed > peer->fail_timeout) { + peer->fails = 0; + break; + } - if (now - peer->accessed > pc->peers->fail_timeout) { - peer->fails = 0; - break; - } + pc->cur_peer++; - pc->cur_peer++; + if (pc->cur_peer >= pc->peers->number) { + pc->cur_peer = 0; + } - if (pc->cur_peer >= pc->peers->number) { - pc->cur_peer = 0; - } - - pc->tries--; + pc->tries--; - if (pc->tries == 0) { - /* ngx_unlock_mutex(pc->peers->mutex); */ + if (pc->tries == 0) { + /* ngx_unlock_mutex(pc->peers->mutex); */ - return NGX_ERROR; - } + return NGX_ERROR; } } } @@ -110,7 +111,7 @@ ngx_int_t ngx_event_connect_peer(ngx_pee /* ngx_unlock_mutex(pc->peers->mutex); */ - s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + s = ngx_socket(peer->sockaddr->sa_family, SOCK_STREAM, 0); if (s == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, @@ -257,16 +258,10 @@ ngx_int_t ngx_event_connect_peer(ngx_pee } } - ngx_memzero(&addr, sizeof(struct sockaddr_in)); + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "connect to %V, #%d", &peer->name, c->number); - addr.sin_family = AF_INET; - addr.sin_port = peer->port; - addr.sin_addr.s_addr = peer->addr; - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, - "connect to %V, #%d", &peer->addr_port_text, c->number); - - rc = connect(s, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)); + rc = connect(s, peer->sockaddr, peer->socklen); if (rc == -1) { err = ngx_socket_errno; @@ -367,8 +362,8 @@ void ngx_event_connect_peer_failed(ngx_p /* ngx_lock_mutex(pc->peers->mutex); */ - pc->peers->peers[pc->cur_peer].fails++; - pc->peers->peers[pc->cur_peer].accessed = now; + pc->peers->peer[pc->cur_peer].fails++; + pc->peers->peer[pc->cur_peer].accessed = now; /* ngx_unlock_mutex(pc->peers->mutex); */ diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -17,34 +17,40 @@ typedef struct { - in_addr_t addr; - ngx_str_t host; - in_port_t port; - ngx_str_t addr_port_text; + struct sockaddr *sockaddr; + socklen_t socklen; + + ngx_str_t name; + char *uri_separator; - ngx_int_t fails; - time_t accessed; + ngx_uint_t weight; + + ngx_uint_t fails; + time_t accessed; + + ngx_uint_t max_fails; + time_t fail_timeout; } ngx_peer_t; -typedef struct { - ngx_int_t current; - ngx_int_t number; - ngx_int_t max_fails; - time_t fail_timeout; - ngx_int_t last_cached; +struct ngx_peers_s { + ngx_uint_t current; + ngx_uint_t weight; + + ngx_uint_t number; + ngx_uint_t last_cached; /* ngx_mutex_t *mutex; */ ngx_connection_t **cached; - ngx_peer_t peers[1]; -} ngx_peers_t; + ngx_peer_t peer[1]; +}; typedef struct { ngx_peers_t *peers; - ngx_int_t cur_peer; - ngx_int_t tries; + ngx_uint_t cur_peer; + ngx_uint_t tries; ngx_connection_t *connection; #if (NGX_THREADS) 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 @@ -8,6 +8,8 @@ #include #include +#include + static void ngx_ssl_write_handler(ngx_event_t *wev); static ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size); @@ -16,8 +18,11 @@ static void ngx_ssl_read_handler(ngx_eve ngx_int_t ngx_ssl_init(ngx_log_t *log) { + ENGINE *engine; + SSL_library_init(); SSL_load_error_strings(); + ENGINE_load_builtin_engines(); return NGX_OK; } @@ -71,6 +76,48 @@ ssize_t ngx_ssl_recv(ngx_connection_t *c ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n); if (n > 0) { + +#if (NGX_DEBUG) + + if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->ssl)) { + char buf[129], *s, *d; + SSL_CIPHER *cipher; + + c->ssl->handshaked = 1; + + cipher = SSL_get_current_cipher(c->ssl->ssl); + + if (cipher) { + SSL_CIPHER_description(cipher, &buf[1], 128); + + for (s = &buf[1], d = buf; *s; s++) { + if (*s == ' ' && *d == ' ') { + continue; + } + + if (*s == '\n' || *s == '\r') { + continue; + } + + *++d = *s; + } + + if (*d != ' ') { + d++; + } + + *d = '\0'; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL cipher: \"%s\"", &buf[1]); + } else { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL no shared ciphers"); + } + } + +#endif + if (c->ssl->saved_write_handler) { c->write->event_handler = c->ssl->saved_write_handler; 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 @@ -25,6 +25,10 @@ typedef struct { unsigned no_rcv_shut:1; unsigned no_send_shut:1; unsigned shutdown_set:1; + +#if (NGX_DEBUG) + unsigned handshaked:1; +#endif } ngx_ssl_t; 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 @@ -379,7 +379,7 @@ ngx_int_t ngx_event_pipe_read_upstream(n ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) { - off_t bsize; + size_t bsize; ngx_uint_t flush; ngx_buf_t *b; ngx_chain_t *out, **ll, *cl, *tl; @@ -433,16 +433,18 @@ ngx_int_t ngx_event_pipe_write_to_downst break; } - /* bsize is the size of the busy bufs */ + /* bsize is the size of the busy recycled bufs */ bsize = 0; for (cl = p->busy; cl; cl = cl->next) { - bsize += cl->buf->end - cl->buf->start; + if (cl->buf->recycled) { + bsize += cl->buf->end - cl->buf->start; + } } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, - "pipe write busy: %O", bsize); + "pipe write busy: %uz", bsize); out = NULL; ll = NULL; @@ -452,19 +454,23 @@ ngx_int_t ngx_event_pipe_write_to_downst if (p->out) { cl = p->out; - if (bsize + ngx_buf_size(cl->buf) > p->busy_size) { + if (cl->buf->recycled + && bsize + cl->buf->last - cl->buf->pos > p->busy_size) + { flush = 1; break; } p->out = p->out->next; - ngx_event_pipe_free_shadow_raw_buf(&p->free_raw_bufs, - cl->buf); + + ngx_event_pipe_free_shadow_raw_buf(&p->free_raw_bufs, cl->buf); } else if (!p->cachable && p->in) { cl = p->in; - if (bsize + ngx_buf_size(cl->buf) > p->busy_size) { + if (cl->buf->recycled + && bsize + cl->buf->last - cl->buf->pos > p->busy_size) + { flush = 1; break; } @@ -475,7 +481,10 @@ ngx_int_t ngx_event_pipe_write_to_downst break; } - bsize += ngx_buf_size(cl->buf); + if (cl->buf->recycled) { + bsize += cl->buf->last - cl->buf->pos; + } + cl->next = NULL; ngx_chain_add_link(out, ll, cl); } @@ -618,8 +627,6 @@ static ngx_int_t ngx_event_pipe_write_ch b->in_file = 1; b->temp_file = 1; - b->temporary = 0; - b->recycled = 0; ngx_chain_add_link(p->out, p->last_out, cl); @@ -668,7 +675,7 @@ ngx_int_t ngx_event_pipe_copy_input_filt ngx_alloc_link_and_set_buf(cl, b, p->pool, NGX_ERROR); - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "buf #%d", b->num); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); ngx_chain_add_link(p->in, p->last_in, cl); @@ -781,7 +788,14 @@ static ngx_int_t ngx_event_pipe_drain_ch b = cl->buf->shadow; b->pos = b->last = b->start; b->shadow = NULL; - ngx_alloc_link_and_set_buf(tl, b, p->pool, NGX_ABORT); + + if (!(tl = ngx_alloc_chain_link(p->pool))) { + return NGX_ABORT; + } + + tl->buf = b; + tl->next = NULL; + ngx_event_pipe_add_free_buf(&p->free_raw_bufs, tl); cl->buf->last_shadow = 0; diff --git a/src/http/modules/ngx_http_access_handler.c b/src/http/modules/ngx_http_access_handler.c --- a/src/http/modules/ngx_http_access_handler.c +++ b/src/http/modules/ngx_http_access_handler.c @@ -80,7 +80,7 @@ ngx_module_t ngx_http_access_module = { static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r) { ngx_uint_t i; - struct sockaddr_in *addr_in; + struct sockaddr_in *sin; ngx_http_access_rule_t *rule; ngx_http_access_loc_conf_t *alcf; @@ -92,16 +92,16 @@ static ngx_int_t ngx_http_access_handler /* AF_INET only */ - addr_in = (struct sockaddr_in *) r->connection->sockaddr; + sin = (struct sockaddr_in *) r->connection->sockaddr; rule = alcf->rules->elts; for (i = 0; i < alcf->rules->nelts; i++) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "%08XD %08XD %08XD", - addr_in->sin_addr.s_addr, rule[i].mask, rule[i].addr); + sin->sin_addr.s_addr, rule[i].mask, rule[i].addr); - if ((addr_in->sin_addr.s_addr & rule[i].mask) == rule[i].addr) { + if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) { if (rule[i].deny) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "access forbidden by rule"); diff --git a/src/http/modules/ngx_http_fastcgi_handler.c b/src/http/modules/ngx_http_fastcgi_handler.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_fastcgi_handler.c @@ -0,0 +1,1968 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +typedef struct { + ngx_http_upstream_conf_t upstream; + + ngx_peers_t *peers; + + ngx_uint_t params; + + ngx_str_t root; + ngx_str_t index; + + ngx_str_t *location; +} 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, + ngx_http_fastcgi_st_request_id_hi, + ngx_http_fastcgi_st_request_id_lo, + ngx_http_fastcgi_st_content_length_hi, + ngx_http_fastcgi_st_content_length_lo, + ngx_http_fastcgi_st_padding_length, + ngx_http_fastcgi_st_reserved, + ngx_http_fastcgi_st_data, + ngx_http_fastcgi_st_padding, +} ngx_http_fastcgi_state_e; + + +typedef struct { + ngx_http_fastcgi_state_e state; + u_char *pos; + u_char *last; + ngx_uint_t type; + size_t length; + size_t padding; + + ngx_http_fastcgi_upstream_t *upstream; +} ngx_http_fastcgi_ctx_t; + + +#define NGX_HTTP_FASTCGI_REMOTE_ADDR 0x0002 +#define NGX_HTTP_FASTCGI_REMOTE_USER 0x0004 +#define NGX_HTTP_FASTCGI_SERVER_NAME 0x0008 +#define NGX_HTTP_FASTCGI_SERVER_ADDR 0x0010 +#define NGX_HTTP_FASTCGI_SERVER_PORT 0x0020 +#define NGX_HTTP_FASTCGI_SCRIPT_NAME 0x0040 +#define NGX_HTTP_FASTCGI_AUTH_TYPE 0x0080 +#define NGX_HTTP_FASTCGI_SERVER_PROTOCOL 0x0100 +#define NGX_HTTP_FASTCGI_SERVER_SOFTWARE 0x0200 +#define NGX_HTTP_FASTCGI_GATEWAY_INTERFACE 0x0400 +#define NGX_HTTP_FASTCGI_REQUEST_URI 0x0800 +#define NGX_HTTP_FASTCGI_REDIRECT_STATUS 0x1000 + + +#define NGX_HTTP_FASTCGI_RESPONDER 1 + +#define NGX_HTTP_FASTCGI_BEGIN_REQUEST 1 +#define NGX_HTTP_FASTCGI_ABORT_REQUEST 2 +#define NGX_HTTP_FASTCGI_END_REQUEST 3 +#define NGX_HTTP_FASTCGI_PARAMS 4 +#define NGX_HTTP_FASTCGI_STDIN 5 +#define NGX_HTTP_FASTCGI_STDOUT 6 +#define NGX_HTTP_FASTCGI_STDERR 7 +#define NGX_HTTP_FASTCGI_DATA 8 + + +typedef struct { + u_char version; + u_char type; + u_char request_id_hi; + u_char request_id_lo; + u_char content_length_hi; + u_char content_length_lo; + u_char padding_length; + u_char reserved; +} ngx_http_fastcgi_header_t; + + +typedef struct { + u_char role_hi; + u_char role_lo; + u_char flags; + u_char reserved[5]; +} ngx_http_fastcgi_begin_request_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, + ngx_http_fastcgi_ctx_t *f); +static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r); +static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, + ngx_int_t rc); + +static char *ngx_http_fastcgi_pass(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_str_t ngx_http_fastcgi_methods[] = { + ngx_string("GET"), + ngx_string("HEAD"), + ngx_string("POST") +}; + + +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) }, + + { 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 + + { 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 }, + { 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_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_null_string, 0 } +}; + + +static ngx_command_t ngx_http_fastcgi_commands[] = { + + { ngx_string("fastcgi_pass"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_fastcgi_pass, + NGX_HTTP_LOC_CONF_OFFSET, + 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, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, index), + NULL }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.connect_timeout), + NULL }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.send_timeout), + NULL }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.send_lowat), + &ngx_http_fastcgi_lowat_post }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.header_buffer_size), + NULL }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.x_powered_by), + NULL }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.read_timeout), + NULL }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.bufs), + NULL }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.busy_buffers_size), + NULL }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.temp_path), + (void *) ngx_garbage_collector_temp_handler }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.max_temp_file_size), + NULL }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.temp_file_write_size), + NULL }, + + { ngx_string("fastcgi_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_fastcgi_loc_conf_t, upstream.next_upstream), + &ngx_http_fastcgi_next_upstream_masks }, + + { 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 */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_fastcgi_create_loc_conf, /* create location configuration */ + ngx_http_fastcgi_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_fastcgi_module = { + NGX_MODULE, + &ngx_http_fastcgi_module_ctx, /* module context */ + ngx_http_fastcgi_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static ngx_int_t ngx_http_fastcgi_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_upstream_t *u; + ngx_http_fastcgi_loc_conf_t *flcf; + + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + if (!(u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + u->peer.log = r->connection->log; + u->peer.log_error = NGX_ERROR_ERR; + u->peer.peers = flcf->peers; + u->peer.tries = flcf->peers->number; +#if (NGX_THREADS) + u->peer.lock = &r->connection->lock; +#endif + + u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module; + + u->conf = &flcf->upstream; + + u->location = 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->schema.len = sizeof("fastcgi://") - 1; + u->schema.data = (u_char *) "fastcgi://"; + u->uri.len = sizeof("/") - 1; + u->uri.data = (u_char *) "/"; + + 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_fastcgi_create_request(ngx_http_request_t *r) +{ + u_char ch, *pos, addr_text[INET_ADDRSTRLEN]; + size_t size, len, index, padding, addr_len; + off_t file_pos; + ngx_buf_t *b; + socklen_t slen; + ngx_chain_t *cl, *body; + ngx_uint_t i, n, next; + ngx_list_part_t *part; + ngx_table_elt_t *header; + struct sockaddr_in sin; + ngx_http_fastcgi_header_t *h; + ngx_http_fastcgi_loc_conf_t *flcf; + ngx_http_fastcgi_begin_request_t *br; + + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + if ((flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) && r->in_addr == 0) { + + 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 (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; + } + + + 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; + } + + + 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->uri.len > 127) ? 4 : 1) + + sizeof("REQUEST_URI") - 1 + r->uri.len; + } + + 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; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) { + len += 1 + 1 + sizeof("SERVER_NAME") - 1 + r->server_name.len; + } + + 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; + } + + if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) { + len += 1 + 1 + sizeof("GATEWAY_INTERFACE") - 1 + sizeof("CGI/1.1") - 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; + } + + len += ((header[i].key.len > 127) ? 4 : 1) + + ((header[i].value.len > 127) ? 4 : 1) + + 5 + header[i].key.len + header[i].value.len; + } + + + if (len > 65535) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "fastcgi: the request record is too big"); + return NGX_ERROR; + } + + + padding = 8 - len % 8; + padding = (padding == 8) ? 0 : padding; + + + size = sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t) + + + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ + + len + padding + + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ + + + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */ + + + if (!(b = ngx_create_temp_buf(r->pool, size))) { + return NGX_ERROR; + } + + if (!(cl = ngx_alloc_chain_link(r->pool))) { + return NGX_ERROR; + } + + 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; + + 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; + h->reserved = 0; + + b->last = b->pos + sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t) + + sizeof(ngx_http_fastcgi_header_t); + + + *b->last++ = sizeof("PATH_TRANSLATED") - 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, "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); + + if (index) { + b->last = ngx_cpymem(b->last, flcf->index.data, index); + } + + + *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); + + b->last = ngx_cpymem(b->last, + ngx_http_fastcgi_methods[r->upstream->method - 1].data, + ngx_http_fastcgi_methods[r->upstream->method - 1].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; + } + + 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; + + 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); + + } else { + *b->last++ = (u_char) len; + } + + 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->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->uri.data, len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) { + *b->last++ = sizeof("SCRIPT_NAME") - 1; + + 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); + + 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 (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; + + 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); + } + + + 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; + } + + 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; + } + + 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; + } + + 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]; + + if (ch >= 'a' && ch <= 'z') { + ch &= ~0x20; + + } else if (ch == '-') { + ch = '_'; + } + + *b->last++ = ch; + } + + b->last = ngx_cpymem(b->last, header[i].value.data, + header[i].value.len); + } + + + 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); + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_PARAMS; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = 0; + h->padding_length = 0; + h->reserved = 0; + + 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 (NGX_SUPPRESS_WARN) + file_pos = 0; + pos = NULL; +#endif + + while (body) { + + if (body->buf->in_file) { + file_pos = body->buf->file_pos; + + } else { + pos = body->buf->pos; + } + + next = 0; + + do { + if (!(b = ngx_alloc_buf(r->pool))) { + return NGX_ERROR; + } + + 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; + } + + 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; + } + + b->last = pos; + len = (ngx_uint_t) (pos - b->pos); + } + + padding = 8 - len % 8; + padding = (padding == 8) ? 0 : padding; + + 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 (!(cl->next = ngx_alloc_chain_link(r->pool))) { + return NGX_ERROR; + } + + 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; + } + + 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); + + if (!(cl->next = ngx_alloc_chain_link(r->pool))) { + return NGX_ERROR; + } + + cl = cl->next; + cl->buf = b; + + } while (!next); + + body = body->next; + } + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_STDIN; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = 0; + h->padding_length = 0; + h->reserved = 0; + + cl->next = NULL; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r) +{ + ngx_http_fastcgi_ctx_t *f; + + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + if (f == NULL) { + return NGX_OK; + } + + f->state = ngx_http_fastcgi_st_version; + + 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, 5, + sizeof(ngx_table_elt_t)) == NGX_ERROR) + { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r) +{ + u_char *start, *last; + ngx_str_t *status_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; + + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + if (f == NULL) { + if (!(f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + 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, 5, + sizeof(ngx_table_elt_t)) == NGX_ERROR) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } + + u = r->upstream; + + for ( ;; ) { + + if (f->state < ngx_http_fastcgi_st_data) { + + f->pos = u->header_in.pos; + f->last = u->header_in.last; + + rc = ngx_http_fastcgi_process_record(r, f); + + u->header_in.pos = f->pos; + u->header_in.last = f->last; + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + + if (rc == NGX_ERROR) { + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (f->type != NGX_HTTP_FASTCGI_STDOUT) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unexpected FastCGI record: %d", + f->type); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (f->length == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream closed prematurely FastCGI stdout"); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + } + + if (f->state == ngx_http_fastcgi_st_padding) { + + if (u->header_in.pos + f->padding < u->header_in.last) { + f->state = ngx_http_fastcgi_st_version; + u->header_in.pos += f->padding; + + continue; + } + + if (u->header_in.pos + f->padding == u->header_in.last) { + f->state = ngx_http_fastcgi_st_version; + u->header_in.pos = u->header_in.last; + + return NGX_AGAIN; + } + + f->padding -= u->header_in.last - u->header_in.pos; + u->header_in.pos = u->header_in.last; + + return NGX_AGAIN; + } + + /* f->state == ngx_http_fastcgi_st_data */ + + start = u->header_in.pos; + + if (u->header_in.pos + f->length < u->header_in.last) { + + /* + * set u->header_in.last to the end of the FastCGI record data + * for ngx_http_parse_header_line() + */ + + last = u->header_in.last; + u->header_in.last = u->header_in.pos + f->length; + + } else { + last = NULL; + } + + for ( ;; ) { + + rc = ngx_http_parse_header_line(r, &u->header_in); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi parser: %d", rc); + + if (rc == NGX_AGAIN) { + break; + } + + if (rc == NGX_OK) { + + /* a header line has been parsed successfully */ + + if (!(h = ngx_list_push(&f->upstream->headers_in.headers))) { + return NGX_HTTP_INTERNAL_SERVER_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_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); + + 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; + } + + 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; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi 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 fastcgi header done"); + + if (f->upstream->headers_in.status) { + status_line = &f->upstream->headers_in.status->value; + + status = ngx_atoi(status_line->data, 3); + + if (status == NGX_ERROR) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->headers_out.status = status; + r->headers_out.status_line = *status_line; + + } else { + r->headers_out.status = 200; + r->headers_out.status_line.len = sizeof("200 OK") - 1; + r->headers_out.status_line.data = (u_char *) "200 OK"; + } + + u->state->status = r->headers_out.status; +#if 0 + if (u->cachable) { + u->cachable = ngx_http_upstream_is_cachable(r); + } +#endif + + break; + } + + /* 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; + + } + + if (last) { + u->header_in.last = last; + } + + f->length -= u->header_in.pos - start; + + if (rc == NGX_AGAIN) { + if (u->header_in.pos == u->header_in.last) { + return NGX_AGAIN; + } + + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "upstream split a header in FastCGI records"); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (f->length == 0) { + if (f->padding) { + f->state = ngx_http_fastcgi_st_padding; + } else { + f->state = ngx_http_fastcgi_st_version; + } + } + + return NGX_OK; + } +} + + +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 */ + + if (!(ho = ngx_list_push(&r->headers_out.headers))) { + 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; + ngx_buf_t *b; + ngx_str_t line; + ngx_chain_t *cl; + ngx_http_request_t *r; + ngx_http_fastcgi_ctx_t *f; + + if (buf->pos == buf->last) { + return NGX_OK; + } + + r = p->input_ctx; + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + b = NULL; + + f->pos = buf->pos; + f->last = buf->last; + + for ( ;; ) { + if (f->state < ngx_http_fastcgi_st_data) { + + rc = ngx_http_fastcgi_process_record(r, f); + + if (rc == NGX_AGAIN) { + break; + } + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) { + f->state = ngx_http_fastcgi_st_version; + p->upstream_done = 1; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, + "http fastcgi closed stdout"); + + continue; + } + + if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) { + f->state = ngx_http_fastcgi_st_version; + p->upstream_done = 1; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, + "http fastcgi sent end request"); + + break; + } + } + + + if (f->state == ngx_http_fastcgi_st_padding) { + + if (f->pos + f->padding < f->last) { + f->state = ngx_http_fastcgi_st_version; + f->pos += f->padding; + + continue; + } + + if (f->pos + f->padding == f->last) { + f->state = ngx_http_fastcgi_st_version; + + break; + } + + f->padding -= f->last - f->pos; + + break; + } + + + /* f->state == ngx_http_fastcgi_st_data */ + + if (f->type == NGX_HTTP_FASTCGI_STDERR) { + + if (f->length) { + line.data = f->pos; + + if (f->pos + f->length <= f->last) { + line.len = f->length; + f->pos += f->length; + + } else { + line.len = f->last - f->pos; + f->length -= f->last - f->pos; + f->pos = f->last; + } + + /* + * TODO: copy split stderr output into buffer, + * clean it up + */ + + ngx_log_error(NGX_LOG_ERR, p->log, 0, + "FastCGI stderr: %V", &line); + + if (f->pos == f->last) { + break; + } + } + + f->state = ngx_http_fastcgi_st_version; + + continue; + } + + + /* f->type == NGX_HTTP_FASTCGI_STDOUT */ + + if (p->free) { + b = p->free->buf; + p->free = p->free->next; + + } else { + if (!(b = ngx_alloc_buf(p->pool))) { + return NGX_ERROR; + } + } + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->pos = f->pos; + b->shadow = buf; + b->tag = p->tag; + b->temporary = 1; + b->recycled = 1; + buf->shadow = b; + + if (!(cl = ngx_alloc_chain_link(p->pool))) { + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); + + ngx_chain_add_link(p->in, p->last_in, cl); + + if (f->pos + f->length < f->last) { + + if (f->padding) { + f->state = ngx_http_fastcgi_st_padding; + } else { + f->state = ngx_http_fastcgi_st_version; + } + + f->pos += f->length; + b->last = f->pos; + + continue; + } + + if (f->pos + f->length == f->last) { + + if (f->padding) { + f->state = ngx_http_fastcgi_st_padding; + } else { + f->state = ngx_http_fastcgi_st_version; + } + + b->last = f->last; + + break; + } + + f->length -= f->last - f->pos; + + b->last = f->last; + + break; + + } + + if (b) { + b->last_shadow = 1; + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r, + ngx_http_fastcgi_ctx_t *f) +{ + u_char ch, *p; + ngx_http_upstream_t *u; + ngx_http_fastcgi_state_e state; + + u = r->upstream; + + state = f->state; + + for (p = f->pos; p < f->last; p++) { + + ch = *p; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi record byte: %02Xd", ch); + + switch (state) { + + case ngx_http_fastcgi_st_version: + if (ch != 1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unsupported FastCGI " + "protocol version: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_type; + break; + + case ngx_http_fastcgi_st_type: + switch (ch) { + case NGX_HTTP_FASTCGI_STDOUT: + case NGX_HTTP_FASTCGI_STDERR: + case NGX_HTTP_FASTCGI_END_REQUEST: + f->type = (ngx_uint_t) ch; + break; + default: + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent invalid FastCGI " + "record type: %d", ch); + return NGX_ERROR; + + } + state = ngx_http_fastcgi_st_request_id_hi; + break; + + /* we support the single request per connection */ + + case ngx_http_fastcgi_st_request_id_hi: + if (ch != 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unexpected FastCGI " + "request id high byte: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_request_id_lo; + break; + + case ngx_http_fastcgi_st_request_id_lo: + if (ch != 1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unexpected FastCGI " + "request id low byte: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_content_length_hi; + break; + + case ngx_http_fastcgi_st_content_length_hi: + f->length = ch << 8; + state = ngx_http_fastcgi_st_content_length_lo; + break; + + case ngx_http_fastcgi_st_content_length_lo: + f->length |= (size_t) ch; + state = ngx_http_fastcgi_st_padding_length; + break; + + case ngx_http_fastcgi_st_padding_length: + f->padding = (size_t) ch; + state = ngx_http_fastcgi_st_reserved; + break; + + case ngx_http_fastcgi_st_reserved: + state = ngx_http_fastcgi_st_data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi record length: %z", f->length); + + f->pos = p + 1; + f->state = state; + + return NGX_OK; + + /* suppress warning */ + case ngx_http_fastcgi_st_data: + case ngx_http_fastcgi_st_padding: + break; + } + } + + f->pos = p + 1; + f->state = state; + + return NGX_AGAIN; +} + + +static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "abort http fastcgi request"); + + return; +} + + +static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, + ngx_int_t rc) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "finalize http fastcgi request"); + + return; +} + + +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]; + + + if (!(lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream))) { + 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]; + + if (!(lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream))) { + return NGX_CONF_ERROR; + } + } + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + lcf->location = &clcf->name; + clcf->handler = ngx_http_fastcgi_handler; + + 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; +} + + +static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_fastcgi_loc_conf_t *conf; + + if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t)))) { + 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->params = 0; + * conf->root.len = 0; + * conf->root.data = NULL; + * conf->index.len = 0; + * conf->index.data = NULL; + * conf->location = NULL; + */ + + conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; + + conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE; + conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + 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.x_powered_by = NGX_CONF_UNSET; + + /* "fastcgi_cyclic_temp_file" is disabled */ + conf->upstream.cyclic_temp_file = 0; + + return conf; +} + + +static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child) +{ + ngx_http_fastcgi_loc_conf_t *prev = parent; + ngx_http_fastcgi_loc_conf_t *conf = child; + + size_t size; + + 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_size_value(conf->upstream.send_lowat, + prev->upstream.send_lowat, 0); + + ngx_conf_merge_msec_value(conf->upstream.read_timeout, + prev->upstream.read_timeout, 60000); + + ngx_conf_merge_msec_value(conf->upstream.x_powered_by, + prev->upstream.x_powered_by, 1); + + + 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 \"fastcgi_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, + "\"fastcgi_busy_buffers_size\" 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; + + } 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, + "\"fastcgi_busy_buffers_size\" must be less than " + "the size of all \"fastcgi_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, + "\"fastcgi_temp_file_write_size\" 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_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_FASTCGI_TEMP_PATH, 1, 2, 0, + ngx_garbage_collector_temp_handler, cf); + + + 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, ""); + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_gzip_filter.c b/src/http/modules/ngx_http_gzip_filter.c --- a/src/http/modules/ngx_http_gzip_filter.c +++ b/src/http/modules/ngx_http_gzip_filter.c @@ -80,12 +80,13 @@ static ngx_int_t ngx_http_gzip_proxied(n static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size); static void ngx_http_gzip_filter_free(void *opaque, void *address); -static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx); +static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx); static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); -static ngx_int_t ngx_http_gzip_pre_conf(ngx_conf_t *cf); +static ngx_int_t ngx_http_gzip_add_log_formats(ngx_conf_t *cf); + static ngx_int_t ngx_http_gzip_filter_init(ngx_cycle_t *cycle); static void *ngx_http_gzip_create_conf(ngx_conf_t *cf); static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf, @@ -205,7 +206,7 @@ static ngx_command_t ngx_http_gzip_filt static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { - ngx_http_gzip_pre_conf, /* pre conf */ + ngx_http_gzip_add_log_formats, /* pre conf */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -229,22 +230,23 @@ ngx_module_t ngx_http_gzip_filter_modul static ngx_http_log_op_name_t ngx_http_gzip_log_fmt_ops[] = { - { ngx_string("gzip_ratio"), NGX_INT32_LEN + 3, ngx_http_gzip_log_ratio }, - { ngx_null_string, 0, NULL } + { ngx_string("gzip_ratio"), NGX_INT32_LEN + 3, + NULL, NULL, ngx_http_gzip_log_ratio }, + { ngx_null_string, 0, NULL, NULL, NULL } }; static u_char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; -#if (NGX_HAVE_LITTLE_ENDIAN) +#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) struct gztrailer { uint32_t crc32; uint32_t zlen; }; -#else /* NGX_HAVE_BIG_ENDIAN */ +#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */ struct gztrailer { u_char crc32[4]; @@ -497,11 +499,13 @@ static ngx_int_t ngx_http_gzip_body_filt if (rc != Z_OK) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "deflateInit2() failed: %d", rc); - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } if (!(b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } b->memory = 1; @@ -509,7 +513,8 @@ static ngx_int_t ngx_http_gzip_body_filt b->last = b->pos + 10; if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = b; cl->next = NULL; @@ -522,7 +527,8 @@ static ngx_int_t ngx_http_gzip_body_filt */ if (ngx_http_next_body_filter(r, cl) == NGX_ERROR) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } ctx->last_out = &ctx->out; @@ -533,7 +539,8 @@ static ngx_int_t ngx_http_gzip_body_filt if (in) { if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } } @@ -607,7 +614,8 @@ static ngx_int_t ngx_http_gzip_body_filt ctx->out_buf = ngx_create_temp_buf(r->pool, conf->bufs.size); if (ctx->out_buf == NULL) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } ctx->out_buf->tag = (ngx_buf_tag_t) @@ -634,7 +642,8 @@ static ngx_int_t ngx_http_gzip_body_filt if (rc != Z_OK && rc != Z_STREAM_END) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "deflate() failed: %d, %d", ctx->flush, rc); - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -663,7 +672,8 @@ static ngx_int_t ngx_http_gzip_body_filt /* zlib wants to output some more gzipped data */ if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = ctx->out_buf; cl->next = NULL; @@ -683,7 +693,8 @@ static ngx_int_t ngx_http_gzip_body_filt ctx->flush = Z_NO_FLUSH; if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = ctx->out_buf; cl->next = NULL; @@ -703,13 +714,15 @@ static ngx_int_t ngx_http_gzip_body_filt if (rc != Z_OK) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "deflateEnd() failed: %d", rc); - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } ngx_pfree(r->pool, ctx->preallocated); if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = ctx->out_buf; cl->next = NULL; @@ -723,13 +736,15 @@ static ngx_int_t ngx_http_gzip_body_filt } else { if (!(b = ngx_create_temp_buf(r->pool, 8))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } b->last_buf = 1; if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = b; cl->next = NULL; @@ -739,19 +754,21 @@ static ngx_int_t ngx_http_gzip_body_filt b->last += 8; } -#if (NGX_HAVE_LITTLE_ENDIAN) +#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) + trailer->crc32 = ctx->crc32; trailer->zlen = ctx->zin; + #else - trailer->crc32[0] = ctx->crc32 & 0xff; - trailer->crc32[1] = (ctx->crc32 >> 8) & 0xff; - trailer->crc32[2] = (ctx->crc32 >> 16) & 0xff; - trailer->crc32[3] = (ctx->crc32 >> 24) & 0xff; + trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff); + trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff); + trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff); + trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff); - trailer->zlen[0] = ctx->zin & 0xff; - trailer->zlen[1] = (ctx->zin >> 8) & 0xff; - trailer->zlen[2] = (ctx->zin >> 16) & 0xff; - trailer->zlen[3] = (ctx->zin >> 24) & 0xff; + trailer->zlen[0] = (u_char) (ctx->zin & 0xff); + trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff); + trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff); + trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff); #endif ctx->zstream.avail_in = 0; @@ -764,7 +781,8 @@ static ngx_int_t ngx_http_gzip_body_filt if (conf->no_buffer && ctx->in == NULL) { if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = ctx->out_buf; cl->next = NULL; @@ -791,7 +809,8 @@ static ngx_int_t ngx_http_gzip_body_filt */ if (last == NGX_ERROR) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out, @@ -858,7 +877,7 @@ static void ngx_http_gzip_filter_free(vo static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { ngx_uint_t zint, zfrac; ngx_http_gzip_ctx_t *ctx; @@ -889,7 +908,7 @@ static u_char *ngx_http_gzip_log_ratio(n } -static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) +static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) { deflateEnd(&ctx->zstream); @@ -902,26 +921,24 @@ static int ngx_http_gzip_error(ngx_http_ ctx->done = 1; - return NGX_ERROR; + return; } -static ngx_int_t ngx_http_gzip_pre_conf(ngx_conf_t *cf) +static ngx_int_t ngx_http_gzip_add_log_formats(ngx_conf_t *cf) { ngx_http_log_op_name_t *op; for (op = ngx_http_gzip_log_fmt_ops; op->name.len; op++) { /* void */ } - op->op = NULL; - - op = ngx_http_log_fmt_ops; + op->run = NULL; - for (op = ngx_http_log_fmt_ops; op->op; op++) { + for (op = ngx_http_log_fmt_ops; op->run; op++) { if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->op; + op = (ngx_http_log_op_name_t *) op->run; } } - op->op = (ngx_http_log_op_pt) ngx_http_gzip_log_fmt_ops; + op->run = (ngx_http_log_op_run_pt) ngx_http_gzip_log_fmt_ops; return NGX_OK; } @@ -948,14 +965,11 @@ static void *ngx_http_gzip_create_conf(n } /* - - set by ngx_pcalloc(): - - conf->bufs.num = 0; - conf->proxied = 0; - - conf->types = NULL; - + * set by ngx_pcalloc(): + * + * conf->bufs.num = 0; + * conf->proxied = 0; + * conf->types = NULL; */ conf->enable = NGX_CONF_UNSET; 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 @@ -8,11 +8,15 @@ #include #include +#include + #define NGX_DEFLAUT_CERTIFICATE "cert.pem" #define NGX_DEFLAUT_CERTIFICATE_KEY "cert.pem" +static void *ngx_http_ssl_create_main_conf(ngx_conf_t *cf); +static char *ngx_http_ssl_init_main_conf(ngx_conf_t *cf, void *conf); static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf); static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); @@ -20,6 +24,13 @@ static char *ngx_http_ssl_merge_srv_conf static ngx_command_t ngx_http_ssl_commands[] = { + { ngx_string("ssl_engine"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_ssl_main_conf_t, engine), + NULL }, + { ngx_string("ssl"), NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -41,6 +52,13 @@ static ngx_command_t ngx_http_ssl_comma offsetof(ngx_http_ssl_srv_conf_t, certificate_key), NULL }, + { ngx_string("ssl_ciphers"), + NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, ciphers), + NULL }, + ngx_null_command }; @@ -48,8 +66,8 @@ static ngx_command_t ngx_http_ssl_comma static ngx_http_module_t ngx_http_ssl_module_ctx = { NULL, /* pre conf */ - NULL, /* create main configuration */ - NULL, /* init main configuration */ + ngx_http_ssl_create_main_conf, /* create main configuration */ + ngx_http_ssl_init_main_conf, /* init main configuration */ ngx_http_ssl_create_srv_conf, /* create server configuration */ ngx_http_ssl_merge_srv_conf, /* merge server configuration */ @@ -69,6 +87,56 @@ ngx_module_t ngx_http_ssl_module = { }; +static void *ngx_http_ssl_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_ssl_main_conf_t *mcf; + + if (!(mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_main_conf_t)))) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * mcf->engine.len = 0; + * mcf->engine.data = NULL; + */ + + return mcf; +} + + +static char *ngx_http_ssl_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_http_ssl_main_conf_t *mcf = conf; + + ENGINE *engine; + + if (mcf->engine.len == 0) { + return NGX_CONF_OK; + } + + engine = ENGINE_by_id((const char *) mcf->engine.data); + + if (engine == NULL) { + ngx_ssl_error(NGX_LOG_WARN, cf->log, 0, + "ENGINE_by_id(\"%V\") failed", &mcf->engine); + return NGX_CONF_ERROR; + } + + if (ENGINE_set_default(engine, ENGINE_METHOD_ALL) == 0) { + ngx_ssl_error(NGX_LOG_WARN, cf->log, 0, + "ENGINE_set_default(\"%V\", ENGINE_METHOD_ALL) failed", + &mcf->engine); + return NGX_CONF_ERROR; + } + + ENGINE_free(engine); + + return NGX_CONF_OK; +} + + static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) { ngx_http_ssl_srv_conf_t *scf; @@ -77,6 +145,17 @@ static void *ngx_http_ssl_create_srv_con return NGX_CONF_ERROR; } + /* + * set by ngx_pcalloc(): + * + * scf->certificate.len = 0; + * scf->certificate.data = NULL; + * scf->certificate_key.len = 0; + * scf->certificate_key.data = NULL; + * scf->ciphers.len = 0; + * scf->ciphers.data = NULL; + */ + scf->enable = NGX_CONF_UNSET; return scf; @@ -101,6 +180,9 @@ static char *ngx_http_ssl_merge_srv_conf ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, NGX_DEFLAUT_CERTIFICATE_KEY); + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, ""); + + /* TODO: configure methods */ conf->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); @@ -110,6 +192,16 @@ static char *ngx_http_ssl_merge_srv_conf return NGX_CONF_ERROR; } + if (conf->ciphers.len) { + if (SSL_CTX_set_cipher_list(conf->ssl_ctx, + (const char *) conf->ciphers.data) == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_set_cipher_list(\"%V\") failed", + &conf->ciphers); + } + } + if (SSL_CTX_use_certificate_file(conf->ssl_ctx, (char *) conf->certificate.data, SSL_FILETYPE_PEM) == 0) { diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -14,10 +14,17 @@ typedef struct { + ngx_str_t engine; +} ngx_http_ssl_main_conf_t; + + +typedef struct { ngx_flag_t enable; ngx_str_t certificate; ngx_str_t certificate_key; + ngx_str_t ciphers; + ngx_ssl_ctx_t *ssl_ctx; } ngx_http_ssl_srv_conf_t; diff --git a/src/http/modules/ngx_http_userid_filter.c b/src/http/modules/ngx_http_userid_filter.c --- a/src/http/modules/ngx_http_userid_filter.c +++ b/src/http/modules/ngx_http_userid_filter.c @@ -44,13 +44,17 @@ static ngx_int_t ngx_http_userid_set_uid ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); +static size_t ngx_http_userid_log_uid_got_getlen(ngx_http_request_t *r, + uintptr_t data); static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); +static size_t ngx_http_userid_log_uid_set_getlen(ngx_http_request_t *r, + uintptr_t data); static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); +static ngx_int_t ngx_http_userid_add_log_formats(ngx_conf_t *cf); static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle); -static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf); static void *ngx_http_userid_create_conf(ngx_conf_t *cf); static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -142,7 +146,7 @@ static ngx_command_t ngx_http_userid_co ngx_http_module_t ngx_http_userid_filter_module_ctx = { - ngx_http_userid_pre_conf, /* pre conf */ + ngx_http_userid_add_log_formats, /* pre conf */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -166,9 +170,13 @@ ngx_module_t ngx_http_userid_filter_mod static ngx_http_log_op_name_t ngx_http_userid_log_fmt_ops[] = { - { ngx_string("uid_got"), 0, ngx_http_userid_log_uid_got }, - { ngx_string("uid_set"), 0, ngx_http_userid_log_uid_set }, - { ngx_null_string, 0, NULL } + { ngx_string("uid_got"), 0, NULL, + ngx_http_userid_log_uid_got_getlen, + ngx_http_userid_log_uid_got }, + { ngx_string("uid_set"), 0, NULL, + ngx_http_userid_log_uid_set_getlen, + ngx_http_userid_log_uid_set }, + { ngx_null_string, 0, NULL, NULL, NULL } }; @@ -298,7 +306,7 @@ static ngx_int_t ngx_http_userid_set_uid u_char *cookie, *p; size_t len; socklen_t slen; - struct sockaddr_in addr_in; + struct sockaddr_in sin; ngx_str_t src, dst; ngx_table_elt_t *set_cookie, *p3p; @@ -321,14 +329,13 @@ static ngx_int_t ngx_http_userid_set_uid if (r->in_addr == 0) { slen = sizeof(struct sockaddr_in); if (getsockname(r->connection->fd, - (struct sockaddr *) &addr_in, &slen) == -1) + (struct sockaddr *) &sin, &slen) == -1) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, - ngx_socket_errno, - "getsockname() failed"); + ngx_socket_errno, "getsockname() failed"); } - r->in_addr = addr_in.sin_addr.s_addr; + r->in_addr = sin.sin_addr.s_addr; } ctx->uid_set[0] = htonl(r->in_addr); @@ -352,7 +359,7 @@ static ngx_int_t ngx_http_userid_set_uid len += sizeof(expires) - 1 + 2; } - if (conf->domain.len > 1) { + if (conf->domain.len) { len += conf->domain.len; } @@ -379,7 +386,7 @@ static ngx_int_t ngx_http_userid_set_uid p = ngx_http_cookie_time(p, ngx_time() + conf->expires); } - if (conf->domain.len > 1) { + if (conf->domain.len) { p = ngx_cpymem(p, conf->domain.data, conf->domain.len); } @@ -397,7 +404,7 @@ static ngx_int_t ngx_http_userid_set_uid ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uid cookie: \"%V\"", &set_cookie->value); - if (conf->p3p.len == 1) { + if (conf->p3p.len == 0) { return NGX_OK; } @@ -413,8 +420,8 @@ static ngx_int_t ngx_http_userid_set_uid } -static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, - uintptr_t data) +static size_t ngx_http_userid_log_uid_got_getlen(ngx_http_request_t *r, + uintptr_t data) { ngx_http_userid_ctx_t *ctx; ngx_http_userid_conf_t *conf; @@ -422,20 +429,30 @@ static u_char *ngx_http_userid_log_uid_g ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); if (ctx == NULL || ctx->uid_got[3] == 0) { - if (buf == NULL) { - return (u_char *) 1; - } + return 1; + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); + + return conf->name.len + 1 + 32; +} + +static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_http_userid_ctx_t *ctx; + ngx_http_userid_conf_t *conf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); + + if (ctx == NULL || ctx->uid_got[3] == 0) { *buf = '-'; return buf + 1; } conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - if (buf == NULL) { - return (u_char *) (conf->name.len + 1 + 32); - } - buf = ngx_cpymem(buf, conf->name.data, conf->name.len); *buf++ = '='; @@ -446,8 +463,8 @@ static u_char *ngx_http_userid_log_uid_g } -static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, - uintptr_t data) +static size_t ngx_http_userid_log_uid_set_getlen(ngx_http_request_t *r, + uintptr_t data) { ngx_http_userid_ctx_t *ctx; ngx_http_userid_conf_t *conf; @@ -455,20 +472,30 @@ static u_char *ngx_http_userid_log_uid_s ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); if (ctx == NULL || ctx->uid_set[3] == 0) { - if (buf == NULL) { - return (u_char *) 1; - } + return 1; + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); + + return conf->name.len + 1 + 32; +} + +static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_http_userid_ctx_t *ctx; + ngx_http_userid_conf_t *conf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); + + if (ctx == NULL || ctx->uid_set[3] == 0) { *buf = '-'; return buf + 1; } conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - if (buf == NULL) { - return (u_char *) (conf->name.len + 1 + 32); - } - buf = ngx_cpymem(buf, conf->name.data, conf->name.len); *buf++ = '='; @@ -479,31 +506,29 @@ static u_char *ngx_http_userid_log_uid_s } -static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle) +static ngx_int_t ngx_http_userid_add_log_formats(ngx_conf_t *cf) { - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_userid_filter; + ngx_http_log_op_name_t *op; + + for (op = ngx_http_userid_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_userid_log_fmt_ops; return NGX_OK; } -static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf) +static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle) { - ngx_http_log_op_name_t *op; - - for (op = ngx_http_userid_log_fmt_ops; op->name.len; op++) { /* void */ } - op->op = NULL; - - op = ngx_http_log_fmt_ops; - - for (op = ngx_http_log_fmt_ops; op->op; op++) { - if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->op; - } - } - - op->op = (ngx_http_log_op_pt) ngx_http_userid_log_fmt_ops; + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_userid_filter; return NGX_OK; } @@ -517,18 +542,18 @@ static void *ngx_http_userid_create_conf return NGX_CONF_ERROR; } - /* set by ngx_pcalloc(): - - conf->name.len = 0; - conf->name.date = NULL; - conf->domain.len = 0; - conf->domain.date = NULL; - conf->path.len = 0; - conf->path.date = NULL; - conf->p3p.len = 0; - conf->p3p.date = NULL; - - */ + /* + * set by ngx_pcalloc(): + * + * conf->name.len = 0; + * conf->name.date = NULL; + * conf->domain.len = 0; + * conf->domain.date = NULL; + * conf->path.len = 0; + * conf->path.date = NULL; + * conf->p3p.len = 0; + * conf->p3p.date = NULL; + */ conf->enable = NGX_CONF_UNSET; conf->service = NGX_CONF_UNSET; @@ -547,9 +572,9 @@ static char *ngx_http_userid_merge_conf( ngx_conf_merge_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, "."); + ngx_conf_merge_str_value(conf->domain, prev->domain, ""); ngx_conf_merge_str_value(conf->path, prev->path, "; path=/"); - ngx_conf_merge_str_value(conf->p3p, prev->p3p, "."); + ngx_conf_merge_str_value(conf->p3p, prev->p3p, ""); ngx_conf_merge_value(conf->service, prev->service, NGX_CONF_UNSET); ngx_conf_merge_sec_value(conf->expires, prev->expires, 0); @@ -565,8 +590,8 @@ char *ngx_http_userid_domain(ngx_conf_t u_char *p, *new; if (domain->len == 4 && ngx_strcmp(domain->data, "none") == 0) { - domain->len = 1; - domain->data = (u_char *) "."; + domain->len = 0; + domain->data = (u_char *) ""; return NGX_CONF_OK; } @@ -645,8 +670,8 @@ char *ngx_http_userid_p3p(ngx_conf_t *cf ngx_str_t *p3p = data; if (p3p->len == 4 && ngx_strcmp(p3p->data, "none") == 0) { - p3p->len = 1; - p3p->data = (u_char *) "."; + p3p->len = 0; + p3p->data = (u_char *) ""; } return NGX_CONF_OK; diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c --- a/src/http/modules/proxy/ngx_http_proxy_handler.c +++ b/src/http/modules/proxy/ngx_http_proxy_handler.c @@ -13,14 +13,20 @@ static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_proxy_cache_get(ngx_http_proxy_ctx_t *p); +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, uintptr_t data); + 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_pre_conf(ngx_conf_t *cf); +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); @@ -231,7 +237,6 @@ static ngx_command_t ngx_http_proxy_com 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, @@ -251,7 +256,7 @@ static ngx_command_t ngx_http_proxy_com ngx_http_module_t ngx_http_proxy_module_ctx = { - ngx_http_proxy_pre_conf, /* pre conf */ + ngx_http_proxy_add_log_formats, /* pre conf */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -270,16 +275,22 @@ ngx_module_t ngx_http_proxy_module = { ngx_http_proxy_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init module */ - NULL /* init child */ + NULL /* init process */ }; static ngx_http_log_op_name_t ngx_http_proxy_log_fmt_ops[] = { - { ngx_string("proxy"), 0, ngx_http_proxy_log_proxy_state }, + { 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 }, - { ngx_null_string, 0, NULL } +#endif + + { ngx_null_string, 0, NULL, NULL, NULL } }; @@ -301,8 +312,12 @@ ngx_http_header_t ngx_http_proxy_headers 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"), @@ -779,11 +794,12 @@ u_char *ngx_http_proxy_log_error(void *d peer = &ctx->proxy->upstream->peer; p = ngx_snprintf(buf, len, - " while %s, client: %V, URL: %V, upstream: %V%V", + " while %s, client: %V, URL: %V, upstream: http://%V%s%V", ctx->proxy->action, &r->connection->addr_text, &r->unparsed_uri, - &peer->peers->peers[peer->cur_peer].addr_port_text, + &peer->peers->peer[peer->cur_peer].name, + ctx->proxy->lcf->upstream->uri_separator, &ctx->proxy->lcf->upstream->uri); len -= p - buf; buf = p; @@ -835,8 +851,24 @@ u_char *ngx_http_proxy_log_error(void *d } +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, uintptr_t data) + u_char *buf, + ngx_http_log_op_t *op) { ngx_uint_t i; ngx_http_proxy_ctx_t *p; @@ -845,21 +877,10 @@ static u_char *ngx_http_proxy_log_proxy_ p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module); if (p == NULL) { - if (buf == NULL) { - return (u_char *) 1; - } - *buf = '-'; return buf + 1; } - - if (buf == NULL) { - /* find the request line length */ - return (u_char *) (uintptr_t) (p->states.nelts * /* STUB */ 100); - } - - i = 0; state = p->states.elts; @@ -935,6 +956,8 @@ static u_char *ngx_http_proxy_log_proxy_ } +#if 0 + static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r, u_char *buf, uintptr_t data) { @@ -1014,23 +1037,23 @@ static u_char *ngx_http_proxy_log_reason } } +#endif -static ngx_int_t ngx_http_proxy_pre_conf(ngx_conf_t *cf) + +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->op = NULL; - - op = ngx_http_log_fmt_ops; + op->run = NULL; - for (op = ngx_http_log_fmt_ops; op->op; op++) { + for (op = ngx_http_log_fmt_ops; op->run; op++) { if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->op; + op = (ngx_http_log_op_name_t *) op->run; } } - op->op = (ngx_http_log_op_pt) ngx_http_proxy_log_fmt_ops; + op->run = (ngx_http_log_op_run_pt) ngx_http_proxy_log_fmt_ops; return NGX_OK; } @@ -1044,24 +1067,19 @@ static void *ngx_http_proxy_create_loc_c ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)), 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->busy_lock = NULL; - - */ + /* + * 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->busy_lock = NULL; + */ conf->connect_timeout = NGX_CONF_UNSET_MSEC; conf->send_timeout = NGX_CONF_UNSET_MSEC; @@ -1210,11 +1228,15 @@ static char *ngx_http_proxy_merge_loc_co 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, - "cache", 1, 2, 0, cf->pool); + 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, - "temp", 1, 2, 0, cf->pool); + NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0, + ngx_garbage_collector_temp_handler, cf); ngx_conf_merge_value(conf->cache, prev->cache, 0); @@ -1256,24 +1278,23 @@ static char *ngx_http_proxy_merge_loc_co } - 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_uint_t i, len; - char *err; - u_char *host; - in_addr_t addr; - ngx_str_t *value; - struct hostent *h; - ngx_http_core_loc_conf_t *clcf; - + 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; - if (ngx_strncasecmp(value[1].data, "http://", 7) != 0) { + 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; } @@ -1284,121 +1305,52 @@ static char *ngx_http_proxy_set_pass(ngx return NGX_CONF_ERROR; } - lcf->upstream->url.len = value[1].len; - if (!(lcf->upstream->url.data = ngx_palloc(cf->pool, value[1].len + 1))) { - return NGX_CONF_ERROR; - } - - ngx_cpystrn(lcf->upstream->url.data, value[1].data, value[1].len + 1); - - value[1].data += 7; - value[1].len -= 7; + if (ngx_strncasecmp(url->data + 7, "unix:", 5) == 0) { - err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream); +#if (NGX_HAVE_UNIX_DOMAIN) - if (err) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, err); - return NGX_CONF_ERROR; - } - - if (!(host = ngx_palloc(cf->pool, lcf->upstream->host.len + 1))) { - return NGX_CONF_ERROR; - } + ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); - ngx_cpystrn(host, lcf->upstream->host.data, lcf->upstream->host.len + 1); - - /* AF_INET only */ - - addr = inet_addr((char *) host); - - if (addr == INADDR_NONE) { - h = gethostbyname((char *) host); + unix_upstream.name = *url; + unix_upstream.url.len = url->len - 7; + unix_upstream.url.data = url->data + 7; + unix_upstream.uri_part = 1; - if (h == NULL || h->h_addr_list[0] == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "host %s not found", host); - return NGX_CONF_ERROR; - } - - for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } - - /* MP: ngx_shared_palloc() */ - - lcf->peers = ngx_pcalloc(cf->pool, - sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1)); - - if (lcf->peers == NULL) { + if (!(lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream))) { return NGX_CONF_ERROR; } - lcf->peers->number = i; - - /* STUB */ - lcf->peers->max_fails = 1; - lcf->peers->fail_timeout = 60; - - for (i = 0; h->h_addr_list[i] != NULL; i++) { - lcf->peers->peers[i].host.data = host; - lcf->peers->peers[i].host.len = lcf->upstream->host.len; - lcf->peers->peers[i].addr = *(in_addr_t *)(h->h_addr_list[i]); - lcf->peers->peers[i].port = lcf->upstream->port; - - len = INET_ADDRSTRLEN - 1 + 1 + lcf->upstream->port_text.len; + 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; - lcf->peers->peers[i].addr_port_text.data = - ngx_palloc(cf->pool, len); - if (lcf->peers->peers[i].addr_port_text.data == 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; - len = ngx_inet_ntop(AF_INET, - &lcf->peers->peers[i].addr, - lcf->peers->peers[i].addr_port_text.data, - len); - - lcf->peers->peers[i].addr_port_text.data[len++] = ':'; - - ngx_memcpy(lcf->peers->peers[i].addr_port_text.data + len, - lcf->upstream->port_text.data, - lcf->upstream->port_text.len); - - lcf->peers->peers[i].addr_port_text.len = - len + lcf->upstream->port_text.len; - } +#endif } else { + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); - /* MP: ngx_shared_palloc() */ + 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; - if (!(lcf->peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)))) { + if (!(lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream))) { return NGX_CONF_ERROR; } - lcf->peers->number = 1; - - lcf->peers->peers[0].host.data = host; - lcf->peers->peers[0].host.len = lcf->upstream->host.len; - lcf->peers->peers[0].addr = addr; - lcf->peers->peers[0].port = lcf->upstream->port; - - len = lcf->upstream->host.len + 1 + lcf->upstream->port_text.len; - - lcf->peers->peers[0].addr_port_text.len = len; - - lcf->peers->peers[0].addr_port_text.data = ngx_palloc(cf->pool, len); - if (lcf->peers->peers[0].addr_port_text.data == NULL) { - return NGX_CONF_ERROR; - } - - len = lcf->upstream->host.len; - - ngx_memcpy(lcf->peers->peers[0].addr_port_text.data, - lcf->upstream->host.data, len); - - lcf->peers->peers[0].addr_port_text.data[len++] = ':'; - - ngx_memcpy(lcf->peers->peers[0].addr_port_text.data + len, - lcf->upstream->port_text.data, - lcf->upstream->port_text.len); + 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 = ""; } clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); @@ -1410,93 +1362,7 @@ static char *ngx_http_proxy_set_pass(ngx clcf->auto_redirect = 1; } - return NULL; -} - - -static char *ngx_http_proxy_parse_upstream(ngx_str_t *url, - ngx_http_proxy_upstream_conf_t *u) -{ - size_t i; - - if (url->data[0] == ':' || url->data[0] == '/') { - return "invalid upstream URL"; - } - - u->host.data = url->data; - u->host_header.data = url->data; - - for (i = 1; i < url->len; i++) { - if (url->data[i] == ':') { - u->port_text.data = &url->data[i] + 1; - u->host.len = i; - } - - if (url->data[i] == '/') { - u->uri.data = &url->data[i]; - u->uri.len = url->len - i; - u->host_header.len = i; - - if (u->host.len == 0) { - u->host.len = i; - } - - if (u->port_text.data == NULL) { - u->default_port = 1; - u->port = htons(80); - u->port_text.len = 2; - u->port_text.data = (u_char *) "80"; - return NULL; - } - - u->port_text.len = &url->data[i] - u->port_text.data; - - if (u->port_text.len > 0) { - u->port = (in_port_t) ngx_atoi(u->port_text.data, - u->port_text.len); - if (u->port > 0) { - - if (u->port == 80) { - u->default_port = 1; - } - - u->port = htons(u->port); - return NULL; - } - } - - return "invalid port in upstream URL"; - } - } - - if (u->host.len == 0) { - u->host.len = i; - } - - u->host_header.len = i; - - u->uri.data = (u_char *) "/"; - u->uri.len = 1; - - if (u->port_text.data == NULL) { - u->default_port = 1; - u->port = htons(80); - u->port_text.len = 2; - u->port_text.data = (u_char *) "80"; - return NULL; - } - - u->port_text.len = &url->data[i] - u->port_text.data; - - if (u->port_text.len > 0) { - u->port = (in_port_t) ngx_atoi(u->port_text.data, u->port_text.len); - if (u->port > 0) { - u->port = htons(u->port); - return NULL; - } - } - - return "invalid port in upstream URL"; + 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 --- a/src/http/modules/proxy/ngx_http_proxy_handler.h +++ b/src/http/modules/proxy/ngx_http_proxy_handler.h @@ -47,6 +47,8 @@ typedef struct { ngx_str_t port_text; ngx_str_t *location; + char *uri_separator; + in_port_t port; unsigned default_port:1; @@ -131,7 +133,11 @@ typedef struct { 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; diff --git a/src/http/modules/proxy/ngx_http_proxy_header.c b/src/http/modules/proxy/ngx_http_proxy_header.c --- a/src/http/modules/proxy/ngx_http_proxy_header.c +++ b/src/http/modules/proxy/ngx_http_proxy_header.c @@ -26,12 +26,7 @@ int ngx_http_proxy_copy_header(ngx_http_ part = &headers_in->headers.part; h = part->elts; -#if 0 - h = headers_in->headers.elts; - for (i = 0; i < headers_in->headers.nelts; i++) { -#endif - - for (i = 0 ; /* void */; i++) { + for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { @@ -113,10 +108,12 @@ int ngx_http_proxy_copy_header(ngx_http_ 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; @@ -169,7 +166,8 @@ static int ngx_http_proxy_rewrite_locati return NGX_ERROR; } - if (uc->url.len > loc->value.len + if (p->lcf->preserve_host + || uc->url.len > loc->value.len || ngx_rstrncmp(loc->value.data, uc->url.data, uc->url.len) != 0) { diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c --- a/src/http/modules/proxy/ngx_http_proxy_upstream.c +++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c @@ -14,7 +14,7 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p); -static void ngx_http_proxy_init_upstream(void *data); +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); @@ -53,9 +53,7 @@ static char connection_close_header[] = int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p) { int rc; - ngx_temp_file_t *tf; ngx_http_request_t *r; - ngx_http_request_body_t *rb; ngx_http_proxy_upstream_t *u; r = p->request; @@ -75,36 +73,7 @@ int ngx_http_proxy_request_upstream(ngx_ u->method = r->method; - if (!(rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - r->request_body = rb; - - if (r->headers_in.content_length_n <= 0) { - ngx_http_proxy_init_upstream(p); - return NGX_DONE; - } - - if (!(tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - tf->file.fd = NGX_INVALID_FILE; - tf->file.log = r->connection->log; - tf->path = p->lcf->temp_path; - tf->pool = r->pool; - tf->warn = "a client request body is buffered to a temporary file"; - /* tf->persistent = 0; */ - - rb->handler = ngx_http_proxy_init_upstream; - rb->data = p; - /* rb->bufs = NULL; */ - /* rb->buf = NULL; */ - /* rb->rest = 0; */ - - rb->temp_file = tf; - - rc = ngx_http_read_client_request_body(r); + rc = ngx_http_read_client_request_body(r, ngx_http_proxy_init_upstream); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; @@ -428,17 +397,16 @@ static ngx_chain_t *ngx_http_proxy_creat } -static void ngx_http_proxy_init_upstream(void *data) +static void ngx_http_proxy_init_upstream(ngx_http_request_t *r) { - ngx_http_proxy_ctx_t *p = data; ngx_chain_t *cl; - ngx_http_request_t *r; + 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; - r = p->request; + 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", @@ -502,7 +470,7 @@ static void ngx_http_proxy_init_upstream output->pool = r->pool; output->bufs.num = 1; output->tag = (ngx_buf_tag_t) &ngx_http_proxy_module; - output->output_filter = (ngx_output_chain_filter_pt) ngx_chain_writer; + output->output_filter = ngx_chain_writer; if (!(writer = ngx_palloc(r->pool, sizeof(ngx_chain_writer_ctx_t)))) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -700,7 +668,7 @@ static void ngx_http_proxy_connect(ngx_h } p->state->peer = - &p->upstream->peer.peers->peers[p->upstream->peer.cur_peer].addr_port_text; + &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); @@ -733,7 +701,7 @@ static void ngx_http_proxy_connect(ngx_h } if (r->request_body->buf) { - if (r->request_body->temp_file->file.fd != NGX_INVALID_FILE) { + if (r->request_body->temp_file) { if (!(output->free = ngx_alloc_chain_link(r->pool))) { ngx_http_proxy_finalize_request(p, @@ -1347,6 +1315,7 @@ static void ngx_http_proxy_send_response } 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; 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 @@ -13,6 +13,7 @@ #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; @@ -22,6 +23,7 @@ typedef struct ngx_http_in_addr_s ngx_h /* STUB */ #include +#include #include #include #include @@ -33,8 +35,8 @@ typedef struct ngx_http_in_addr_s ngx_h #endif -typedef struct { - u_int connection; +struct ngx_http_log_ctx_s { + ngx_uint_t connection; /* * we declare "action" as "char *" because the actions are usually @@ -45,18 +47,23 @@ typedef struct { char *action; ngx_str_t *client; ngx_http_request_t *request; -} ngx_http_log_ctx_t; +}; #define ngx_http_get_module_ctx(r, module) r->ctx[module.ctx_index] #define ngx_http_get_module_err_ctx(r, module) \ (r->err_ctx ? r->err_ctx[module.ctx_index] : r->ctx[module.ctx_index]) +/* STUB */ #define ngx_http_create_ctx(r, cx, module, size, error) \ do { \ ngx_test_null(cx, ngx_pcalloc(r->pool, size), error); \ r->ctx[module.ctx_index] = cx; \ } while (0) +/**/ + +#define ngx_http_set_ctx(r, c, module) \ + r->ctx[module.ctx_index] = c; #define ngx_http_delete_ctx(r, module) \ r->ctx[module.ctx_index] = NULL; @@ -80,7 +87,8 @@ void ngx_http_close_request(ngx_http_req void ngx_http_close_connection(ngx_connection_t *c); -ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r); +ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, + ngx_http_client_body_handler_pt post_handler); ngx_int_t ngx_http_send_header(ngx_http_request_t *r); ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, int error); 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 @@ -205,6 +205,13 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, client_body_timeout), NULL }, + { ngx_string("client_body_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_core_loc_conf_t, client_body_temp_path), + (void *) ngx_garbage_collector_temp_handler }, + { ngx_string("sendfile"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -1288,15 +1295,11 @@ static void *ngx_http_core_create_srv_co ngx_test_null(cscf, ngx_pcalloc(cf->pool, sizeof(ngx_http_core_srv_conf_t)), NGX_CONF_ERROR); - /* - - set by ngx_pcalloc(): - - conf->client_large_buffers.num = 0; - - */ - + * + * set by ngx_pcalloc(): + * conf->client_large_buffers.num = 0; + */ ngx_init_array(cscf->locations, cf->pool, 5, sizeof(void *), NGX_CONF_ERROR); @@ -1398,22 +1401,22 @@ static void *ngx_http_core_create_loc_co ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)), NGX_CONF_ERROR); - /* set by ngx_pcalloc(): - - lcf->root.len = 0; - lcf->root.data = NULL; - lcf->types = NULL; - lcf->default_type.len = 0; - lcf->default_type.data = NULL; - lcf->err_log = NULL; - lcf->error_pages = NULL; - - lcf->regex = NULL; - lcf->exact_match = 0; - lcf->auto_redirect = 0; - lcf->alias = 0; - - */ + /* + * set by ngx_pcalloc(): + * + * lcf->root.len = 0; + * lcf->root.data = NULL; + * lcf->types = NULL; + * lcf->default_type.len = 0; + * lcf->default_type.data = NULL; + * lcf->err_log = NULL; + * lcf->error_pages = NULL; + * lcf->client_body_path = NULL; + * lcf->regex = NULL; + * lcf->exact_match = 0; + * lcf->auto_redirect = 0; + * lcf->alias = 0; + */ lcf->client_max_body_size = NGX_CONF_UNSET_SIZE; lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE; @@ -1526,6 +1529,11 @@ static char *ngx_http_core_merge_loc_con ngx_conf_merge_msec_value(conf->lingering_timeout, prev->lingering_timeout, 5000); + ngx_conf_merge_path_value(conf->client_body_temp_path, + prev->client_body_temp_path, + NGX_HTTP_CLIENT_TEMP_PATH, 0, 0, 0, + ngx_garbage_collector_temp_handler, cf); + ngx_conf_merge_value(conf->reset_timedout_connection, prev->reset_timedout_connection, 0); ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1); @@ -1746,7 +1754,7 @@ static char *ngx_set_error_page(ngx_conf if (overwrite == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%V\"", value[i]); + "invalid value \"%V\"", &value[i]); return NGX_CONF_ERROR; } 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 @@ -199,6 +199,8 @@ struct ngx_http_core_loc_conf_s { ngx_array_t *error_pages; /* error_page */ + ngx_path_t *client_body_temp_path; /* client_body_temp_path */ + ngx_http_cache_hash_t *open_files; ngx_log_t *err_log; diff --git a/src/http/ngx_http_log_handler.c b/src/http/ngx_http_log_handler.c --- a/src/http/ngx_http_log_handler.c +++ b/src/http/ngx_http_log_handler.c @@ -11,40 +11,64 @@ static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, - uintptr_t data); -static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); + +static size_t ngx_http_log_request_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); + +static ngx_int_t ngx_http_log_header_in_compile(ngx_http_log_op_t *op, + ngx_str_t *value); +static size_t ngx_http_log_header_in_getlen(ngx_http_request_t *r, + uintptr_t data); static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); +static size_t ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, + u_char *buf, + ngx_http_log_op_t *op); + +static ngx_int_t ngx_http_log_header_out_compile(ngx_http_log_op_t *op, + ngx_str_t *value); +static size_t ngx_http_log_header_out_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static size_t ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, + u_char *buf, + ngx_http_log_op_t *op); + static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, - u_char *buf, uintptr_t data); + u_char *buf, + ngx_http_log_op_t *op); static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, u_char *buf, - uintptr_t data); -static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, - u_char *buf, uintptr_t data); -static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, - uintptr_t data); -static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); -static ngx_int_t ngx_http_log_pre_conf(ngx_conf_t *cf); +static ngx_table_elt_t *ngx_http_log_unknown_header(ngx_list_t *headers, + ngx_str_t *value); + +static ngx_int_t ngx_http_log_set_formats(ngx_conf_t *cf); static void *ngx_http_log_create_main_conf(ngx_conf_t *cf); static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, @@ -78,7 +102,7 @@ static ngx_command_t ngx_http_log_comma ngx_http_module_t ngx_http_log_module_ctx = { - ngx_http_log_pre_conf, /* pre conf */ + ngx_http_log_set_formats, /* pre conf */ ngx_http_log_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ @@ -110,28 +134,38 @@ static ngx_str_t ngx_http_combined_fmt = ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = { - { ngx_string("addr"), INET_ADDRSTRLEN - 1, ngx_http_log_addr }, - { ngx_string("conn"), NGX_INT32_LEN, ngx_http_log_connection }, - { ngx_string("pipe"), 1, ngx_http_log_pipe }, + { ngx_string("addr"), INET_ADDRSTRLEN - 1, NULL, NULL, ngx_http_log_addr }, + { ngx_string("conn"), NGX_INT32_LEN, NULL, NULL, ngx_http_log_connection }, + { ngx_string("pipe"), 1, NULL, NULL, ngx_http_log_pipe }, { ngx_string("time"), sizeof("28/Sep/1970:12:00:00") - 1, - ngx_http_log_time }, - { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec }, - { ngx_string("request"), 0, ngx_http_log_request }, - { ngx_string("status"), 3, ngx_http_log_status }, - { ngx_string("length"), NGX_OFF_T_LEN, ngx_http_log_length }, - { ngx_string("apache_length"), NGX_OFF_T_LEN, ngx_http_log_apache_length }, + NULL, NULL, ngx_http_log_time }, + { ngx_string("msec"), NGX_TIME_T_LEN + 4, NULL, NULL, ngx_http_log_msec }, + { ngx_string("status"), 3, NULL, NULL, ngx_http_log_status }, + { ngx_string("length"), NGX_OFF_T_LEN, NULL, NULL, ngx_http_log_length }, + { ngx_string("apache_length"), NGX_OFF_T_LEN, + NULL, NULL, ngx_http_log_apache_length }, { ngx_string("request_length"), NGX_SIZE_T_LEN, - ngx_http_log_request_length }, - { ngx_string("i"), NGX_HTTP_LOG_ARG, ngx_http_log_header_in }, - { ngx_string("o"), NGX_HTTP_LOG_ARG, ngx_http_log_header_out }, - { ngx_null_string, 0, NULL } + NULL, NULL, ngx_http_log_request_length }, + + { ngx_string("request"), 0, NULL, + ngx_http_log_request_getlen, + ngx_http_log_request }, + + { ngx_string("i"), 0, ngx_http_log_header_in_compile, + ngx_http_log_header_in_getlen, + ngx_http_log_header_in }, + + { ngx_string("o"), 0, ngx_http_log_header_out_compile, + ngx_http_log_header_out_getlen, + ngx_http_log_header_out }, + + { ngx_null_string, 0, NULL, NULL, NULL } }; ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) { ngx_uint_t i, l; - uintptr_t data; u_char *line, *p; size_t len; ngx_http_log_t *log; @@ -157,7 +191,7 @@ ngx_int_t ngx_http_log_handler(ngx_http_ op = log[l].ops->elts; for (i = 0; i < log[l].ops->nelts; i++) { if (op[i].len == 0) { - len += (size_t) op[i].op(r, NULL, op[i].data); + len += op[i].getlen(r, op[i].data); } else { len += op[i].len; @@ -177,20 +211,7 @@ ngx_int_t ngx_http_log_handler(ngx_http_ p = line; for (i = 0; i < log[l].ops->nelts; i++) { - if (op[i].op == NGX_HTTP_LOG_COPY_SHORT) { - len = op[i].len; - data = op[i].data; - while (len--) { - *p++ = (char) (data & 0xff); - data >>= 8; - } - - } else if (op[i].op == NGX_HTTP_LOG_COPY_LONG) { - p = ngx_cpymem(p, (void *) op[i].data, op[i].len); - - } else { - p = op[i].op(r, p, op[i].data); - } + p = op[i].run(r, p, &op[i]); } #if (NGX_WIN32) @@ -206,8 +227,33 @@ ngx_int_t ngx_http_log_handler(ngx_http_ } +static u_char *ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + size_t len; + uintptr_t data; + + len = op->len; + data = op->data; + + while (len--) { + *buf++ = (u_char) (data & 0xff); + data >>= 8; + } + + return buf; +} + + +static u_char *ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + return ngx_cpymem(buf, (u_char *) op->data, op->len); +} + + static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_cpymem(buf, r->connection->addr_text.data, r->connection->addr_text.len); @@ -215,14 +261,14 @@ static u_char *ngx_http_log_addr(ngx_htt static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_sprintf(buf, "%ui", r->connection->number); } static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { if (r->pipeline) { *buf = 'p'; @@ -235,7 +281,7 @@ static u_char *ngx_http_log_pipe(ngx_htt static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_cpymem(buf, ngx_cached_http_log_time.data, ngx_cached_http_log_time.len); @@ -243,7 +289,7 @@ static u_char *ngx_http_log_time(ngx_htt static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { struct timeval tv; @@ -253,20 +299,22 @@ static u_char *ngx_http_log_msec(ngx_htt } -static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, - uintptr_t data) +static size_t ngx_http_log_request_getlen(ngx_http_request_t *r, + uintptr_t data) { - if (buf == NULL) { - /* find the request line length */ - return (u_char *) r->request_line.len; - } + return r->request_line.len; +} + +static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ return ngx_cpymem(buf, r->request_line.data, r->request_line.len); } static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_sprintf(buf, "%ui", r->err_status ? r->err_status : r->headers_out.status); @@ -274,95 +322,320 @@ static u_char *ngx_http_log_status(ngx_h static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_sprintf(buf, "%O", r->connection->sent); } static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_sprintf(buf, "%O", r->connection->sent - r->header_size); } static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_sprintf(buf, "%z", r->request_length); } +static ngx_int_t ngx_http_log_header_in_compile(ngx_http_log_op_t *op, + ngx_str_t *value) +{ + ngx_uint_t i; + + op->len = 0; + + for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) { + + if (ngx_http_headers_in[i].name.len != value->len) { + continue; + } + + if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, value->data, + value->len) == 0) + { + op->getlen = ngx_http_log_header_in_getlen; + op->run = ngx_http_log_header_in; + op->data = ngx_http_headers_in[i].offset; + + return NGX_OK; + } + } + + op->getlen = ngx_http_log_unknown_header_in_getlen; + op->run = ngx_http_log_unknown_header_in; + op->data = (uintptr_t) value; + + return NGX_OK; +} + + +static size_t ngx_http_log_header_in_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + ngx_table_elt_t *h; + + h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); + + if (h) { + return h->value.len; + } + + return 1; +} + + static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { - ngx_uint_t i; - ngx_str_t *s; - ngx_table_elt_t *h; - ngx_http_log_op_t *op; + ngx_table_elt_t *h; + + h = *(ngx_table_elt_t **) ((char *) &r->headers_in + op->data); + + if (h) { + return ngx_cpymem(buf, h->value.data, h->value.len); + } + + *buf = '-'; + + return buf + 1; +} + + +static size_t ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + ngx_table_elt_t *h; + + h = ngx_http_log_unknown_header(&r->headers_in.headers, (ngx_str_t *) data); + + if (h) { + return h->value.len; + } + + return 1; +} + + +static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, + u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_table_elt_t *h; + + h = ngx_http_log_unknown_header(&r->headers_in.headers, + (ngx_str_t *) op->data); + + if (h) { + return ngx_cpymem(buf, h->value.data, h->value.len); + } + + *buf = '-'; + + return buf + 1; +} + + +static ngx_int_t ngx_http_log_header_out_compile(ngx_http_log_op_t *op, + ngx_str_t *value) +{ + ngx_uint_t i; + + op->len = 0; + + for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) { + + if (ngx_http_headers_out[i].name.len != value->len) { + continue; + } - if (r) { - h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); + if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, value->data, + value->len) == 0) + { + op->getlen = ngx_http_log_header_out_getlen; + op->run = ngx_http_log_header_out; + op->data = ngx_http_headers_out[i].offset; + + return NGX_OK; + } + } + + if (value->len == sizeof("Connection") - 1 + && ngx_strncasecmp(value->data, "Connection", value->len) == 0) + { + op->len = sizeof("keep-alive") - 1; + op->getlen = NULL; + op->run = ngx_http_log_connection_header_out; + op->data = 0; + return NGX_OK; + } - if (h == NULL) { + if (value->len == sizeof("Transfer-Encoding") - 1 + && ngx_strncasecmp(value->data, "Transfer-Encoding", value->len) == 0) + { + op->len = sizeof("chunked") - 1; + op->getlen = NULL; + op->run = ngx_http_log_transfer_encoding_header_out; + op->data = 0; + return NGX_OK; + } + + op->getlen = ngx_http_log_unknown_header_out_getlen; + op->run = ngx_http_log_unknown_header_out; + op->data = (uintptr_t) value; + + return NGX_OK; +} + + +static size_t ngx_http_log_header_out_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + ngx_table_elt_t *h; + + h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data); + + if (h) { + return h->value.len; + } + + /* + * No header pointer was found. + * However, some headers: "Date", "Server", "Content-Length", + * and "Last-Modified" have a special handling in the header filter + * but we do not set up their pointers in the filter because + * they are too seldom needed to be logged. + */ - /* no header */ + if (data == offsetof(ngx_http_headers_out_t, date)) { + return ngx_cached_http_time.len; + } + + if (data == offsetof(ngx_http_headers_out_t, server)) { + return (sizeof(NGINX_VER) - 1); + } + + if (data == offsetof(ngx_http_headers_out_t, content_length)) { + if (r->headers_out.content_length_n == -1) { + return 1; + } + + return NGX_OFF_T_LEN; + } + + if (data == offsetof(ngx_http_headers_out_t, last_modified)) { + if (r->headers_out.last_modified_time == -1) { + return 1; + } + + return sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; + } + + return 1; +} + - if (buf) { - *buf = '-'; - } +static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_table_elt_t *h; + + h = *(ngx_table_elt_t **) ((char *) &r->headers_out + op->data); + + if (h) { + return ngx_cpymem(buf, h->value.data, h->value.len); + } + + /* + * No header pointer was found. + * However, some headers: "Date", "Server", "Content-Length", + * and "Last-Modified" have a special handling in the header filter + * but we do not set up their pointers in the filter because + * they are too seldom needed to be logged. + */ + + if (op->data == offsetof(ngx_http_headers_out_t, date)) { + return ngx_cpymem(buf, ngx_cached_http_time.data, + ngx_cached_http_time.len); + } + + if (op->data == offsetof(ngx_http_headers_out_t, server)) { + return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1); + } + + if (op->data == offsetof(ngx_http_headers_out_t, content_length)) { + if (r->headers_out.content_length_n == -1) { + *buf = '-'; return buf + 1; } - if (buf == NULL) { - /* find the header length */ - return (u_char *) h->value.len; + return ngx_sprintf(buf, "%O", r->headers_out.content_length_n); + } + + if (op->data == offsetof(ngx_http_headers_out_t, last_modified)) { + if (r->headers_out.last_modified_time == -1) { + *buf = '-'; + + return buf + 1; } + return ngx_http_time(buf, r->headers_out.last_modified_time); + } + + *buf = '-'; + + return buf + 1; +} + + +static size_t ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + ngx_table_elt_t *h; + + h = ngx_http_log_unknown_header(&r->headers_out.headers, + (ngx_str_t *) data); + + if (h) { + return h->value.len; + } + + return 1; +} + + +static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, + u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_table_elt_t *h; + + h = ngx_http_log_unknown_header(&r->headers_out.headers, + (ngx_str_t *) op->data); + + if (h) { return ngx_cpymem(buf, h->value.data, h->value.len); } - /* find an offset while a format string compilation */ - - op = (ngx_http_log_op_t *) buf; - s = (ngx_str_t *) data; - - op->len = 0; - - for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) { - if (ngx_http_headers_in[i].name.len != s->len) { - continue; - } + *buf = '-'; - if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, s->data, s->len) - == 0) - { - op->op = ngx_http_log_header_in; - op->data = ngx_http_headers_in[i].offset; - return NULL; - } - } - - op->op = ngx_http_log_unknown_header_in; - op->data = (uintptr_t) s; - - return NULL; + return buf + 1; } -static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, - u_char *buf, uintptr_t data) +static ngx_table_elt_t *ngx_http_log_unknown_header(ngx_list_t *headers, + ngx_str_t *value) { ngx_uint_t i; - ngx_str_t *s; ngx_list_part_t *part; ngx_table_elt_t *h; - s = (ngx_str_t *) data; - - part = &r->headers_in.headers.part; + part = &headers->part; h = part->elts; for (i = 0; /* void */; i++) { @@ -377,172 +650,23 @@ static u_char *ngx_http_log_unknown_head i = 0; } - if (h[i].key.len != s->len) { + if (h[i].key.len != value->len) { continue; } - if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) { - if (buf == NULL) { - /* find the header length */ - return (u_char *) h[i].value.len; - } - - return ngx_cpymem(buf, h[i].value.data, h[i].value.len); + if (ngx_strncasecmp(h[i].key.data, value->data, value->len) == 0) { + return &h[i]; } } - /* no header */ - - if (buf) { - *buf = '-'; - } - - return buf + 1; -} - - -static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, - uintptr_t data) -{ - ngx_uint_t i; - ngx_str_t *s; - ngx_table_elt_t *h; - ngx_http_log_op_t *op; - - if (r) { - - /* run-time execution */ - - if (r->http_version < NGX_HTTP_VERSION_10) { - if (buf) { - *buf = '-'; - } - - return buf + 1; - } - - h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data); - - if (h == NULL) { - - /* - * No header pointer was found. - * However, some headers: "Date", "Server", "Content-Length", - * and "Last-Modified" have a special handling in the header filter - * but we do not set up their pointers in the filter because - * they are too seldom needed to be logged. - */ - - if (data == offsetof(ngx_http_headers_out_t, date)) { - if (buf == NULL) { - return (u_char *) ngx_cached_http_time.len; - } - return ngx_cpymem(buf, ngx_cached_http_time.data, - ngx_cached_http_time.len); - } - - if (data == offsetof(ngx_http_headers_out_t, server)) { - if (buf == NULL) { - return (u_char *) (sizeof(NGINX_VER) - 1); - } - return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1); - } - - if (data == offsetof(ngx_http_headers_out_t, content_length)) { - if (r->headers_out.content_length_n == -1) { - if (buf) { - *buf = '-'; - } - return buf + 1; - } - - if (buf == NULL) { - return (u_char *) NGX_OFF_T_LEN; - } - return ngx_sprintf(buf, "%O", r->headers_out.content_length_n); - } - - if (data == offsetof(ngx_http_headers_out_t, last_modified)) { - if (r->headers_out.last_modified_time == -1) { - if (buf) { - *buf = '-'; - } - return buf + 1; - } - - if (buf == NULL) { - return (u_char *) - sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; - } - return ngx_http_time(buf, r->headers_out.last_modified_time); - } - - if (buf) { - *buf = '-'; - } - - return buf + 1; - } - - if (buf == NULL) { - /* find the header length */ - return (u_char *) h->value.len; - } - - return ngx_cpymem(buf, h->value.data, h->value.len); - } - - /* find an offset while a format string compilation */ - - op = (ngx_http_log_op_t *) buf; - s = (ngx_str_t *) data; - - op->len = 0; - - for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) { - if (ngx_http_headers_out[i].name.len != s->len) { - continue; - } - - if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, s->data, s->len) - == 0) - { - op->op = ngx_http_log_header_out; - op->data = ngx_http_headers_out[i].offset; - return NULL; - } - } - - if (s->len == sizeof("Connection") - 1 - && ngx_strncasecmp(s->data, "Connection", s->len) == 0) - { - op->op = ngx_http_log_connection_header_out; - op->data = (uintptr_t) NULL; - return NULL; - } - - if (s->len == sizeof("Transfer-Encoding") - 1 - && ngx_strncasecmp(s->data, "Transfer-Encoding", s->len) == 0) { - op->op = ngx_http_log_transfer_encoding_header_out; - op->data = (uintptr_t) NULL; - return NULL; - } - - op->op = ngx_http_log_unknown_header_out; - op->data = (uintptr_t) s; - return NULL; } static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, - u_char *buf, uintptr_t data) + u_char *buf, + ngx_http_log_op_t *op) { - if (buf == NULL) { - return (u_char *) ((r->keepalive) ? sizeof("keep-alive") - 1: - sizeof("close") - 1); - } - if (r->keepalive) { return ngx_cpymem(buf, "keep-alive", sizeof("keep-alive") - 1); @@ -554,12 +678,8 @@ static u_char *ngx_http_log_connection_h static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { - if (buf == NULL) { - return (u_char *) ((r->chunked) ? sizeof("chunked") - 1 : 1); - } - if (r->chunked) { return ngx_cpymem(buf, "chunked", sizeof("chunked") - 1); } @@ -570,62 +690,12 @@ static u_char *ngx_http_log_transfer_enc } -static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, - u_char *buf, - uintptr_t data) -{ - ngx_uint_t i; - ngx_str_t *s; - ngx_list_part_t *part; - ngx_table_elt_t *h; - - s = (ngx_str_t *) data; - - part = &r->headers_out.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; - } - - if (h[i].key.len != s->len) { - continue; - } - - if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) { - if (buf == NULL) { - /* find the header length */ - return (u_char *) h[i].value.len; - } - - return ngx_cpymem(buf, h[i].value.data, h[i].value.len); - } - } - - /* no header */ - - if (buf) { - *buf = '-'; - } - - return buf + 1; -} - - -static ngx_int_t ngx_http_log_pre_conf(ngx_conf_t *cf) +static ngx_int_t ngx_http_log_set_formats(ngx_conf_t *cf) { ngx_http_log_op_name_t *op; for (op = ngx_http_log_fmt_ops; op->name.len; op++) { /* void */ } - op->op = NULL; + op->run = NULL; return NGX_OK; } @@ -889,15 +959,15 @@ static char *ngx_http_log_set_format(ngx break; } - for (name = ngx_http_log_fmt_ops; name->op; name++) { + for (name = ngx_http_log_fmt_ops; name->run; name++) { if (name->name.len == 0) { - name = (ngx_http_log_op_name_t *) name->op; + name = (ngx_http_log_op_name_t *) name->run; } if (name->name.len == fname_len && ngx_strncmp(name->name.data, fname, fname_len) == 0) { - if (name->len != NGX_HTTP_LOG_ARG) { + if (name->compile == NULL) { if (arg.len) { fname[fname_len] = '\0'; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -907,7 +977,8 @@ static char *ngx_http_log_set_format(ngx } op->len = name->len; - op->op = name->op; + op->getlen = name->getlen; + op->run = name->run; op->data = 0; break; @@ -926,7 +997,9 @@ static char *ngx_http_log_set_format(ngx } *a = arg; - name->op(NULL, (u_char *) op, (uintptr_t) a); + if (name->compile(op, a) == NGX_ERROR) { + return NGX_CONF_ERROR; + } break; } @@ -949,9 +1022,10 @@ static char *ngx_http_log_set_format(ngx if (len) { op->len = len; + op->getlen = NULL; if (len <= sizeof(uintptr_t)) { - op->op = NGX_HTTP_LOG_COPY_SHORT; + op->run = ngx_http_log_copy_short; op->data = 0; while (len--) { @@ -960,7 +1034,7 @@ static char *ngx_http_log_set_format(ngx } } else { - op->op = NGX_HTTP_LOG_COPY_LONG; + op->run = ngx_http_log_copy_long; if (!(p = ngx_palloc(cf->pool, len))) { return NGX_CONF_ERROR; diff --git a/src/http/ngx_http_log_handler.h b/src/http/ngx_http_log_handler.h --- a/src/http/ngx_http_log_handler.h +++ b/src/http/ngx_http_log_handler.h @@ -13,49 +13,54 @@ #include -typedef u_char *(*ngx_http_log_op_pt) (ngx_http_request_t *r, u_char *buf, - uintptr_t data); +typedef struct ngx_http_log_op_s ngx_http_log_op_t; + +typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); + +typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r, + uintptr_t data); -#define NGX_HTTP_LOG_COPY_SHORT (ngx_http_log_op_pt) 0 -#define NGX_HTTP_LOG_COPY_LONG (ngx_http_log_op_pt) -1 +typedef ngx_int_t (*ngx_http_log_op_compile_pt) (ngx_http_log_op_t *op, + ngx_str_t *value); -#define NGX_HTTP_LOG_ARG (u_int) -1 +struct ngx_http_log_op_s { + size_t len; + ngx_http_log_op_getlen_pt getlen; + ngx_http_log_op_run_pt run; + uintptr_t data; +}; typedef struct { - size_t len; - ngx_http_log_op_pt op; - uintptr_t data; -} ngx_http_log_op_t; - - -typedef struct { - ngx_str_t name; - ngx_array_t *ops; /* array of ngx_http_log_op_t */ + ngx_str_t name; + ngx_array_t *ops; /* array of ngx_http_log_op_t */ } ngx_http_log_fmt_t; typedef struct { - ngx_str_t name; - size_t len; - ngx_http_log_op_pt op; + ngx_str_t name; + size_t len; + ngx_http_log_op_compile_pt compile; + ngx_http_log_op_getlen_pt getlen; + ngx_http_log_op_run_pt run; } ngx_http_log_op_name_t; typedef struct { - ngx_array_t formats; /* array of ngx_http_log_fmt_t */ + ngx_array_t formats; /* array of ngx_http_log_fmt_t */ } ngx_http_log_main_conf_t; typedef struct { - ngx_open_file_t *file; - ngx_array_t *ops; /* array of ngx_http_log_op_t */ + ngx_open_file_t *file; + ngx_array_t *ops; /* array of ngx_http_log_op_t */ } ngx_http_log_t; typedef struct { - ngx_array_t *logs; /* array of ngx_http_log_t */ - ngx_uint_t off; /* unsigned off:1 */ + ngx_array_t *logs; /* array of ngx_http_log_t */ + ngx_uint_t off; /* unsigned off:1 */ } ngx_http_log_loc_conf_t; 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 @@ -34,15 +34,13 @@ ngx_int_t ngx_http_parse_request_line(ng sw_major_digit, sw_first_minor_digit, sw_minor_digit, - sw_almost_done, - sw_done + sw_almost_done } state; state = r->state; - p = b->pos; - while (p < b->last && state < sw_done) { - ch = *p++; + for (p = b->pos; p < b->last; p++) { + ch = *p; /* gcc 2.95.2 and msvc 6.0 compile this switch as an jump table */ @@ -50,7 +48,7 @@ ngx_int_t ngx_http_parse_request_line(ng /* HTTP methods: GET, HEAD, POST */ case sw_start: - r->request_start = p - 1; + r->request_start = p; if (ch == CR || ch == LF) { break; @@ -65,19 +63,19 @@ ngx_int_t ngx_http_parse_request_line(ng case sw_method: if (ch == ' ') { - r->method_end = p - 1; + r->method_end = p; m = r->request_start; - if (r->method_end - m == 3) { + if (p - m == 3) { if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') { r->method = NGX_HTTP_GET; } - } else if (r->method_end - m == 4) { + } else if (p - m == 4) { if (m[0] == 'P' && m[1] == 'O' - && m[2] == 'T' && m[3] == 'T') + && m[2] == 'S' && m[3] == 'T') { r->method = NGX_HTTP_POST; @@ -113,14 +111,14 @@ ngx_int_t ngx_http_parse_request_line(ng case sw_spaces_before_uri: switch (ch) { case '/': - r->uri_start = p - 1; + r->uri_start = p; state = sw_after_slash_in_uri; break; case ' ': break; default: if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { - r->schema_start = p - 1; + r->schema_start = p; state = sw_schema; break; } @@ -131,7 +129,7 @@ ngx_int_t ngx_http_parse_request_line(ng case sw_schema: switch (ch) { case ':': - r->schema_end = p - 1; + r->schema_end = p; state = sw_schema_slash; break; default: @@ -155,7 +153,7 @@ ngx_int_t ngx_http_parse_request_line(ng case sw_schema_slash_slash: switch (ch) { case '/': - r->host_start = p - 1; + r->host_start = p; state = sw_host; break; default: @@ -166,12 +164,12 @@ ngx_int_t ngx_http_parse_request_line(ng case sw_host: switch (ch) { case ':': - r->host_end = p - 1; + r->host_end = p; state = sw_port; break; case '/': - r->host_end = p - 1; - r->uri_start = p - 1; + r->host_end = p; + r->uri_start = p; state = sw_after_slash_in_uri; break; default: @@ -187,8 +185,8 @@ ngx_int_t ngx_http_parse_request_line(ng case sw_port: switch (ch) { case '/': - r->port_end = p - 1; - r->uri_start = p - 1; + r->port_end = p; + r->uri_start = p; state = sw_after_slash_in_uri; break; default: @@ -203,17 +201,16 @@ ngx_int_t ngx_http_parse_request_line(ng case sw_after_slash_in_uri: switch (ch) { case CR: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; state = sw_almost_done; break; case LF: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; - state = sw_done; - break; + goto done; case ' ': - r->uri_end = p - 1; + r->uri_end = p; state = sw_http_09; break; case '.': @@ -233,7 +230,7 @@ ngx_int_t ngx_http_parse_request_line(ng r->complex_uri = 1; break; case '?': - r->args_start = p; + r->args_start = p + 1; state = sw_uri; break; default: @@ -246,21 +243,20 @@ ngx_int_t ngx_http_parse_request_line(ng case sw_check_uri: switch (ch) { case CR: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; state = sw_almost_done; break; case LF: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; - state = sw_done; - break; + goto done; case ' ': - r->uri_end = p - 1; + r->uri_end = p; state = sw_http_09; break; case '.': - r->uri_ext = p; + r->uri_ext = p + 1; break; #if (NGX_WIN32) case '\\': @@ -277,7 +273,7 @@ ngx_int_t ngx_http_parse_request_line(ng state = sw_uri; break; case '?': - r->args_start = p; + r->args_start = p + 1; state = sw_uri; break; } @@ -287,17 +283,16 @@ ngx_int_t ngx_http_parse_request_line(ng case sw_uri: switch (ch) { case CR: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; state = sw_almost_done; break; case LF: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; - state = sw_done; - break; + goto done; case ' ': - r->uri_end = p - 1; + r->uri_end = p; state = sw_http_09; break; } @@ -314,9 +309,9 @@ ngx_int_t ngx_http_parse_request_line(ng break; case LF: r->http_minor = 9; - state = sw_done; - break; + goto done; case 'H': + r->http_protocol.data = p; state = sw_http_H; break; default: @@ -406,8 +401,7 @@ ngx_int_t ngx_http_parse_request_line(ng } if (ch == LF) { - state = sw_done; - break; + goto done; } if (ch < '0' || ch > '9') { @@ -419,42 +413,38 @@ ngx_int_t ngx_http_parse_request_line(ng /* end of request line */ case sw_almost_done: - r->request_end = p - 2; + r->request_end = p - 1; switch (ch) { case LF: - state = sw_done; - break; + goto done; default: return NGX_HTTP_PARSE_INVALID_REQUEST; } break; - - /* suppress warning */ - case sw_done: - break; } } b->pos = p; + r->state = state; - if (state == sw_done) { - if (r->request_end == NULL) { - r->request_end = p - 1; - } + return NGX_AGAIN; - r->http_version = r->http_major * 1000 + r->http_minor; - r->state = sw_start; +done: + + b->pos = p + 1; - if (r->http_version == 9 && r->method != NGX_HTTP_GET) { - return NGX_HTTP_PARSE_INVALID_09_METHOD; - } + if (r->request_end == NULL) { + r->request_end = p; + } - return NGX_OK; + r->http_version = r->http_major * 1000 + r->http_minor; + r->state = sw_start; - } else { - r->state = state; - return NGX_AGAIN; + if (r->http_version == 9 && r->method != NGX_HTTP_GET) { + return NGX_HTTP_PARSE_INVALID_09_METHOD; } + + return NGX_OK; } @@ -469,16 +459,13 @@ ngx_int_t ngx_http_parse_header_line(ngx sw_space_after_value, sw_almost_done, sw_header_almost_done, - sw_ignore_line, - sw_done, - sw_header_done + sw_ignore_line } state; state = r->state; - p = b->pos; - while (p < b->last && state < sw_done) { - ch = *p++; + for (p = b->pos; p < b->last; p++) { + ch = *p; switch (state) { @@ -486,16 +473,15 @@ ngx_int_t ngx_http_parse_header_line(ngx case sw_start: switch (ch) { case CR: - r->header_end = p - 1; + r->header_end = p; state = sw_header_almost_done; break; case LF: - r->header_end = p - 1; - state = sw_header_done; - break; + r->header_end = p; + goto header_done; default: state = sw_name; - r->header_name_start = p - 1; + r->header_name_start = p; c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'z') { @@ -523,7 +509,7 @@ ngx_int_t ngx_http_parse_header_line(ngx } if (ch == ':') { - r->header_name_end = p - 1; + r->header_name_end = p; state = sw_space_before_value; break; } @@ -539,7 +525,7 @@ ngx_int_t ngx_http_parse_header_line(ngx /* IIS may send the duplicate "HTTP/1.1 ..." lines */ if (ch == '/' && r->proxy - && p - r->header_start == 5 + && p - r->header_start == 4 && ngx_strncmp(r->header_start, "HTTP", 4) == 0) { state = sw_ignore_line; @@ -554,15 +540,14 @@ ngx_int_t ngx_http_parse_header_line(ngx case ' ': break; case CR: - r->header_start = r->header_end = p - 1; + r->header_start = r->header_end = p; state = sw_almost_done; break; case LF: - r->header_start = r->header_end = p - 1; - state = sw_done; - break; + r->header_start = r->header_end = p; + goto done; default: - r->header_start = p - 1; + r->header_start = p; state = sw_value; break; } @@ -572,17 +557,16 @@ ngx_int_t ngx_http_parse_header_line(ngx case sw_value: switch (ch) { case ' ': - r->header_end = p - 1; + r->header_end = p; state = sw_space_after_value; break; case CR: - r->header_end = p - 1; + r->header_end = p; state = sw_almost_done; break; case LF: - r->header_end = p - 1; - state = sw_done; - break; + r->header_end = p; + goto done; } break; @@ -595,8 +579,7 @@ ngx_int_t ngx_http_parse_header_line(ngx state = sw_almost_done; break; case LF: - state = sw_done; - break; + goto done; default: state = sw_value; break; @@ -618,8 +601,7 @@ ngx_int_t ngx_http_parse_header_line(ngx case sw_almost_done: switch (ch) { case LF: - state = sw_done; - break; + goto done; default: return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -629,34 +611,32 @@ ngx_int_t ngx_http_parse_header_line(ngx case sw_header_almost_done: switch (ch) { case LF: - state = sw_header_done; - break; + goto header_done; default: return NGX_HTTP_PARSE_INVALID_HEADER; } break; - - /* suppress warning */ - case sw_done: - case sw_header_done: - break; } } b->pos = p; + r->state = state; - if (state == sw_done) { - r->state = sw_start; - return NGX_OK; + return NGX_AGAIN; + +done: + + b->pos = p + 1; + r->state = sw_start; - } else if (state == sw_header_done) { - r->state = sw_start; - return NGX_HTTP_PARSE_HEADER_DONE; + return NGX_OK; + +header_done: - } else { - r->state = state; - return NGX_AGAIN; - } + b->pos = p + 1; + r->state = sw_start; + + return NGX_HTTP_PARSE_HEADER_DONE; } @@ -677,8 +657,10 @@ ngx_int_t ngx_http_parse_complex_uri(ngx sw_quoted_second } state, quoted_state; +#if (NGX_SUPPRESS_WARN) decoded = '\0'; quoted_state = sw_usual; +#endif state = sw_usual; p = r->uri_start; @@ -688,10 +670,10 @@ ngx_int_t ngx_http_parse_complex_uri(ngx ch = *p++; - while (p <= r->uri_end && r->args_start == NULL) { + while (p <= r->uri_end) { /* - * we use "ch = *p++" inside the cycle but this operation is safe + * we use "ch = *p++" inside the cycle, but this operation is safe, * because after the URI there is always at least one charcter: * the line feed */ @@ -731,7 +713,7 @@ ngx_int_t ngx_http_parse_complex_uri(ngx break; case '?': r->args_start = p; - break; + goto done; case ':': state = sw_colon; *u++ = ch; @@ -766,6 +748,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; default: state = sw_usual; *u++ = ch; @@ -794,6 +779,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; default: state = sw_usual; *u++ = ch; @@ -818,6 +806,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; default: state = sw_usual; *u++ = ch; @@ -844,6 +835,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; default: state = sw_usual; *u++ = ch; @@ -872,6 +866,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; #if (NGX_WIN32) case '.': state = sw_dot_dot_dot; @@ -953,11 +950,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'f') { ch = (u_char) ((decoded << 4) + c - 'a' + 10); - if (ch == '%') { - state = sw_usual; + if (ch == '?') { *u++ = ch; ch = *p++; - break; } state = quoted_state; break; @@ -967,6 +962,8 @@ ngx_int_t ngx_http_parse_complex_uri(ngx } } +done: + r->uri.len = u - r->uri.data; r->uri.data[r->uri.len] = '\0'; diff --git a/src/http/ngx_http_parse_time.c b/src/http/ngx_http_parse_time.c --- a/src/http/ngx_http_parse_time.c +++ b/src/http/ngx_http_parse_time.c @@ -216,10 +216,6 @@ time_t ngx_http_parse_time(u_char *value + (*(p + 2) - '0') * 10 + *(p + 3) - '0'; } -#if 0 - printf("%d.%d.%d %d:%d:%d\n", day, month + 1, year, hour, min, sec); -#endif - if (hour > 23 || min > 59 || sec > 59) { return NGX_ERROR; } @@ -239,7 +235,7 @@ time_t ngx_http_parse_time(u_char *value /* * shift new year to March 1 and start months from 1 (not 0), - * it's needed for Gauss's formula + * it is needed for Gauss's formula */ if (--month <= 0) { @@ -247,41 +243,16 @@ time_t ngx_http_parse_time(u_char *value year -= 1; } - /* Gauss's formula for Grigorian days from 1 March 1 BC */ + /* Gauss's formula for Grigorian days from 1 March 1 BC */ return (365 * year + year / 4 - year / 100 + year / 400 + 367 * month / 12 - 31 + day - /* - * 719527 days were between March 1, 1 BC and March 1, 1970, - * 31 and 28 days in January and February 1970 - */ + /* + * 719527 days were between March 1, 1 BC and March 1, 1970, + * 31 and 28 days in January and February 1970 + */ - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec; } - -#if 0 -char zero[] = "Sun, 01 Jan 1970 08:49:30"; -char one[] = "Sunday, 11-Dec-02 08:49:30"; -char two[] = "Sun Mar 1 08:49:37 2000"; -char thr[] = "Sun Dec 11 08:49:37 2002"; - -main() -{ - int rc; - - rc = ngx_http_parse_time(zero, sizeof(zero) - 1); - printf("rc: %d\n", rc); - - rc = ngx_http_parse_time(one, sizeof(one) - 1); - printf("rc: %d\n", rc); - - rc = ngx_http_parse_time(two, sizeof(two) - 1); - printf("rc: %d\n", rc); - - rc = ngx_http_parse_time(thr, sizeof(thr) - 1); - printf("rc: %d\n", rc); -} - -#endif 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 @@ -63,6 +63,8 @@ ngx_http_header_t ngx_http_headers_in[] { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer) }, { ngx_string("Content-Length"), offsetof(ngx_http_headers_in_t, content_length) }, + { ngx_string("Content-Type"), + offsetof(ngx_http_headers_in_t, content_type) }, { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range) }, #if 0 @@ -86,7 +88,7 @@ ngx_http_header_t ngx_http_headers_in[] { 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) }, #endif - + { ngx_null_string, 0 } }; @@ -175,7 +177,7 @@ static void ngx_http_init_request(ngx_ev { ngx_uint_t i; socklen_t len; - struct sockaddr_in addr_in; + struct sockaddr_in sin; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_in_port_t *in_port; @@ -283,21 +285,19 @@ static void ngx_http_init_request(ngx_ev r->in_addr = ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr; - } else { + } else #endif + { len = sizeof(struct sockaddr_in); - if (getsockname(c->fd, (struct sockaddr *) &addr_in, &len) == -1) { + if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { ngx_connection_error(c, ngx_socket_errno, "getsockname() failed"); ngx_http_close_connection(c); return; } - r->in_addr = addr_in.sin_addr.s_addr; - -#if (NGX_WIN32) + r->in_addr = sin.sin_addr.s_addr; } -#endif /* the last in_port->addrs address is "*" */ @@ -573,6 +573,11 @@ static void ngx_http_process_request_lin } + if (r->http_protocol.data) { + r->http_protocol.len = r->request_end - r->http_protocol.data; + } + + if (r->uri_ext) { if (r->args_start) { r->exten.len = r->args_start - 1 - r->uri_ext; @@ -2173,6 +2178,8 @@ void ngx_ssl_close_handler(ngx_event_t * void ngx_http_close_connection(ngx_connection_t *c) { + ngx_pool_t *pool; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "close http connection: %d", c->fd); @@ -2192,7 +2199,11 @@ void ngx_http_close_connection(ngx_conne (*ngx_stat_active)--; #endif + pool = c->pool; + ngx_close_connection(c); + + ngx_destroy_pool(c->pool); } 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 @@ -133,6 +133,7 @@ typedef struct { ngx_table_elt_t *user_agent; ngx_table_elt_t *referer; ngx_table_elt_t *content_length; + ngx_table_elt_t *content_type; ngx_table_elt_t *range; @@ -201,13 +202,14 @@ typedef struct { } ngx_http_headers_out_t; +typedef void (*ngx_http_client_body_handler_pt)(ngx_http_request_t *r); + typedef struct { - ngx_temp_file_t *temp_file; - ngx_chain_t *bufs; - ngx_buf_t *buf; - size_t rest; - void (*handler) (void *data); - void *data; + ngx_temp_file_t *temp_file; + ngx_chain_t *bufs; + ngx_buf_t *buf; + size_t rest; + ngx_http_client_body_handler_pt post_handler; } ngx_http_request_body_t; @@ -256,6 +258,8 @@ struct ngx_http_request_s { ngx_http_cache_t *cache; + ngx_http_upstream_t *upstream; + ngx_file_t file; ngx_pool_t *pool; @@ -280,6 +284,7 @@ struct ngx_http_request_s { ngx_str_t unparsed_uri; ngx_str_t method_name; + ngx_str_t http_protocol; ngx_http_request_t *main; 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 @@ -11,31 +11,67 @@ 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); +static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r, + ngx_connection_t *c); +/* + * on completion ngx_http_read_client_request_body() adds to + * r->request_body->bufs one or two bufs: + * *) one memory buf that was preread in r->header_in; + * *) one memory or file buf that contains the rest of the body + */ -ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r) +ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, + ngx_http_client_body_handler_pt post_handler) + { ssize_t size; ngx_buf_t *b; ngx_chain_t *cl; + ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; + if (!(rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->request_body = rb; + + if (r->headers_in.content_length_n <= 0) { + post_handler(r); + return NGX_OK; + } + + rb->post_handler = post_handler; + + /* + * set by ngx_pcalloc(): + * + * rb->bufs = NULL; + * rb->buf = NULL; + * rb->rest = 0; + */ + size = r->header_in->last - r->header_in->pos; if (size) { /* there is the pre-read part of the request body */ - ngx_test_null(b, ngx_calloc_buf(r->pool), - NGX_HTTP_INTERNAL_SERVER_ERROR); + if (!(b = ngx_calloc_buf(r->pool))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } b->temporary = 1; b->start = b->pos = r->header_in->pos; b->end = b->last = r->header_in->last; - ngx_alloc_link_and_set_buf(r->request_body->bufs, b, r->pool, - NGX_HTTP_INTERNAL_SERVER_ERROR); + if (!(rb->bufs = ngx_alloc_chain_link(r->pool))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rb->bufs->buf = b; + rb->bufs->next = NULL; if (size >= r->headers_in.content_length_n) { @@ -44,7 +80,7 @@ ngx_int_t ngx_http_read_client_request_b r->header_in->pos += r->headers_in.content_length_n; r->request_length += r->headers_in.content_length_n; - r->request_body->handler(r->request_body->data); + post_handler(r); return NGX_OK; } @@ -56,35 +92,39 @@ ngx_int_t ngx_http_read_client_request_b clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - r->request_body->rest = r->headers_in.content_length_n - size; + rb->rest = r->headers_in.content_length_n - size; - if (r->request_body->rest - < clcf->client_body_buffer_size + if (rb->rest < clcf->client_body_buffer_size + (clcf->client_body_buffer_size >> 2)) { - size = r->request_body->rest; + size = rb->rest; } else { size = clcf->client_body_buffer_size; } - ngx_test_null(r->request_body->buf, ngx_create_temp_buf(r->pool, size), - NGX_HTTP_INTERNAL_SERVER_ERROR); + if (!(rb->buf = ngx_create_temp_buf(r->pool, size))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - ngx_alloc_link_and_set_buf(cl, r->request_body->buf, r->pool, - NGX_HTTP_INTERNAL_SERVER_ERROR); + if (!(cl = ngx_alloc_chain_link(r->pool))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - if (r->request_body->bufs) { - r->request_body->bufs->next = cl; + cl->buf = rb->buf; + cl->next = NULL; + + if (rb->bufs) { + rb->bufs->next = cl; } else { - r->request_body->bufs = cl; + rb->bufs = cl; } r->connection->read->event_handler = ngx_http_read_client_request_body_handler; - return ngx_http_do_read_client_request_body(r); + return ngx_http_do_read_client_request_body(r, r->connection); } @@ -102,7 +142,7 @@ static void ngx_http_read_client_request return; } - rc = ngx_http_do_read_client_request_body(r); + rc = ngx_http_do_read_client_request_body(r, c); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { ngx_http_finalize_request(r, rc); @@ -110,24 +150,45 @@ static void ngx_http_read_client_request } -static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r) +static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r, + ngx_connection_t *c) { size_t size; ssize_t n; ngx_buf_t *b; - ngx_connection_t *c; + ngx_temp_file_t *tf; + 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, "http read client request body"); for ( ;; ) { - if (r->request_body->buf->last == r->request_body->buf->end) { - n = ngx_write_chain_to_temp_file(r->request_body->temp_file, - r->request_body->bufs->next ? r->request_body->bufs->next: - r->request_body->bufs); + if (rb->buf->last == rb->buf->end) { + + if (rb->temp_file == NULL) { + if (!(tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) { + return NGX_ERROR; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + tf->file.fd = NGX_INVALID_FILE; + tf->file.log = r->connection->log; + tf->path = clcf->client_body_temp_path; + tf->pool = r->pool; + tf->warn = "a client request body is buffered " + "to a temporary file"; + + rb->temp_file = tf; + + } + + n = ngx_write_chain_to_temp_file(rb->temp_file, + rb->bufs->next ? rb->bufs->next: + rb->bufs); /* TODO: n == 0 or not complete and level event */ @@ -135,19 +196,19 @@ static ngx_int_t ngx_http_do_read_client return NGX_HTTP_INTERNAL_SERVER_ERROR; } - r->request_body->temp_file->offset += n; + rb->temp_file->offset += n; - r->request_body->buf->pos = r->request_body->buf->start; - r->request_body->buf->last = r->request_body->buf->start; + rb->buf->pos = rb->buf->start; + rb->buf->last = rb->buf->start; } - size = r->request_body->buf->end - r->request_body->buf->last; + size = rb->buf->end - rb->buf->last; - if (size > r->request_body->rest) { - size = r->request_body->rest; + if (size > rb->rest) { + size = rb->rest; } - n = c->recv(c, r->request_body->buf->last, size); + n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body recv %z", n); @@ -173,33 +234,33 @@ static ngx_int_t ngx_http_do_read_client return NGX_HTTP_BAD_REQUEST; } - r->request_body->buf->last += n; - r->request_body->rest -= n; + rb->buf->last += n; + rb->rest -= n; r->request_length += n; - if (r->request_body->rest == 0) { + if (rb->rest == 0) { break; } - if (r->request_body->buf->last < r->request_body->buf->end) { + if (rb->buf->last < rb->buf->end) { break; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http client request body rest %uz", - r->request_body->rest); + "http client request body rest %uz", rb->rest); - if (r->request_body->rest) { + if (rb->rest) { return NGX_AGAIN; } - if (r->request_body->temp_file->file.fd != NGX_INVALID_FILE) { + if (rb->temp_file) { /* save the last part */ - n = ngx_write_chain_to_temp_file(r->request_body->temp_file, - r->request_body->bufs->next ? r->request_body->bufs->next: - r->request_body->bufs); + + n = ngx_write_chain_to_temp_file(rb->temp_file, + rb->bufs->next ? rb->bufs->next: + rb->bufs); /* TODO: n == 0 or not complete and level event */ @@ -213,18 +274,18 @@ static ngx_int_t ngx_http_do_read_client b->in_file = 1; b->file_pos = 0; - b->file_last = r->request_body->temp_file->file.offset; - b->file = &r->request_body->temp_file->file; + b->file_last = rb->temp_file->file.offset; + b->file = &rb->temp_file->file; - if (r->request_body->bufs->next) { - r->request_body->bufs->next->buf = b; + if (rb->bufs->next) { + rb->bufs->next->buf = b; } else { - r->request_body->bufs->buf = b; + rb->bufs->buf = b; } } - r->request_body->handler(r->request_body->data); + rb->post_handler(r); return NGX_OK; } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_upstream.c @@ -0,0 +1,1204 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +static void ngx_http_upstream_check_broken_connection(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, + ngx_http_upstream_t *u); +static void ngx_http_upstream_send_request(ngx_http_request_t *r, + ngx_http_upstream_t *u); +static void ngx_http_upstream_send_request_handler(ngx_event_t *wev); +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_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, + ngx_http_upstream_t *u, + ngx_uint_t ft_type); +static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, + ngx_http_upstream_t *u, + ngx_int_t rc); + +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 ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf); + + +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 */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_upstream_module = { + NGX_MODULE, + &ngx_http_upstream_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_log_op_name_t ngx_http_upstream_log_fmt_ops[] = { + { ngx_string("upstream_status"), 0, NULL, + ngx_http_upstream_log_status_getlen, + ngx_http_upstream_log_status }, + { ngx_null_string, 0, NULL, NULL, NULL } +}; + + +char *ngx_http_upstream_header_errors[] = { + "upstream sent invalid header", + "upstream sent too long header line" +}; + + +void ngx_http_upstream_init(ngx_http_request_t *r) +{ + ngx_connection_t *c; + ngx_http_upstream_t *u; + + c = r->connection; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http init upstream, client timer: %d", c->read->timer_set); + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + c->read->event_handler = ngx_http_upstream_check_broken_connection; + + if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { + + c->write->event_handler = ngx_http_upstream_check_broken_connection; + + if (!c->write->active) { + if (ngx_add_event(c->write, NGX_WRITE_EVENT, + NGX_CLEAR_EVENT) == NGX_ERROR) + { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + } + + u = r->upstream; + + u->method = r->method; + + if (u->create_request(r) == NGX_ERROR) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->peer.log = r->connection->log; + u->saved_ctx = r->connection->log->data; + u->saved_handler = r->connection->log->handler; + r->connection->log->data = u->log_ctx; + r->connection->log->handler = u->log_handler; + + u->output.sendfile = r->connection->sendfile; + u->output.pool = r->pool; + u->output.bufs.num = 1; + u->output.output_filter = ngx_chain_writer; + u->output.filter_ctx = &u->writer; + + u->writer.pool = r->pool; + + if (ngx_array_init(&u->states, r->pool, u->peer.peers->number, + sizeof(ngx_http_upstream_state_t)) == NGX_ERROR) + { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + if (!(u->state = ngx_push_array(&u->states))) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); + + ngx_http_upstream_connect(r, u); +} + + +static void ngx_http_upstream_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_upstream_t *u; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http upstream check client, write event:%d", ev->write); + +#if (NGX_HAVE_KQUEUE) + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + + if (!ev->pending_eof) { + return; + } + + ev->eof = 1; + + if (ev->kq_errno) { + ev->error = 1; + } + + c = ev->data; + r = c->data; + u = r->upstream; + + if (!u->cachable && u->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_upstream_finalize_request(r, u, + 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 (u->peer.connection == NULL) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + + return; + } + +#endif + + c = ev->data; + + 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; + } + + r = c->data; + u = r->upstream; + + if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) { + if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + + if (n > 0) { + return; + } + + ev->eof = 1; + + if (n == -1) { + if (err == NGX_EAGAIN) { + return; + } + + ev->error = 1; + + } else { + /* n == 0 */ + err = 0; + } + + if (!u->cachable && u->peer.connection) { + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "client closed prematurely connection, " + "so upstream connection is closed too"); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "client closed prematurely connection"); + + if (u->peer.connection == NULL) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } +} + + +static void ngx_http_upstream_connect(ngx_http_request_t *r, + ngx_http_upstream_t *u) +{ + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_log_ctx_t *ctx; + + ctx = r->connection->log->data; + ctx->action = "connecting to upstream"; + + r->connection->single_connection = 0; + + rc = ngx_event_connect_peer(&u->peer); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream connect: %i", rc); + + if (rc == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->state->peer = &u->peer.peers->peer[u->peer.cur_peer].name; + + if (rc == NGX_CONNECT_ERROR) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + return; + } + + 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->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 */ + + u->writer.out = NULL; + u->writer.last = &u->writer.out; + u->writer.connection = c; + u->writer.limit = 0; + + if (u->request_sent) { + ngx_http_upstream_reinit(r, u); + } + + if (r->request_body->buf) { + if (r->request_body->temp_file) { + + if (!(u->output.free = ngx_alloc_chain_link(r->pool))) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->output.free->buf = r->request_body->buf; + u->output.free->next = NULL; + u->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 = u->output.tag; + + } else { + r->request_body->buf->pos = r->request_body->buf->start; + } + } + + u->request_sent = 0; + + if (rc == NGX_AGAIN) { + ngx_add_timer(c->write, u->conf->connect_timeout); + return; + } + + /* rc == NGX_OK */ + + ngx_http_upstream_send_request(r, u); +} + + +static void 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; + } + + /* reinit the request chain */ + + for (cl = r->request_body->bufs; cl; cl = cl->next) { + cl->buf->pos = cl->buf->start; + cl->buf->file_pos = 0; + } + + /* reinit the ngx_output_chain() context */ + + u->output.buf = NULL; + u->output.in = NULL; + u->output.free = NULL; + u->output.busy = NULL; + + /* reinit u->header_in buffer */ + +#if 0 + if (u->cache) { + u->header_in.pos = u->header_in.start + u->cache->ctx.header_size; + u->header_in.last = u->header_in.pos; + + } else { + u->header_in.pos = u->header_in.start; + 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 */ + + if (!(u->state = ngx_push_array(&u->states))) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); + + u->status = 0; + u->status_count = 0; +} + + +static void ngx_http_upstream_send_request(ngx_http_request_t *r, + ngx_http_upstream_t *u) +{ + int rc; + ngx_connection_t *c; + ngx_http_log_ctx_t *ctx; + + c = u->peer.connection; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream send request"); + +#if (NGX_HAVE_KQUEUE) + + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) + && !u->request_sent + && c->write->pending_eof) + { + ngx_log_error(NGX_LOG_ERR, c->log, c->write->kq_errno, + "connect() failed"); + + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + return; + } + +#endif + + ctx = c->log->data; + ctx->action = "sending request to upstream"; + + rc = ngx_output_chain(&u->output, + u->request_sent ? NULL : r->request_body->bufs); + + u->request_sent = 1; + + if (rc == NGX_ERROR) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + return; + } + + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + if (rc == NGX_AGAIN) { + ngx_add_timer(c->write, u->conf->send_timeout); + + if (ngx_handle_write_event(c->write, u->conf->send_lowat) == NGX_ERROR) + { + ngx_http_upstream_finalize_request(r, u, + 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_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; + return; + } + + ngx_add_timer(c->read, u->conf->read_timeout); + +#if 1 + if (c->read->ready) { + + /* post aio operation */ + + /* + * TODO comment + * although we can post aio operation just in the end + * of ngx_http_upstream_connect() CHECK IT !!! + * it's better to do here because we postpone header buffer allocation + */ + + ngx_http_upstream_process_header(c->read); + return; + } +#endif + + c->write->event_handler = ngx_http_upstream_dummy_handler; + + if (ngx_handle_level_write_event(c->write) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } +} + + +static void ngx_http_upstream_send_request_handler(ngx_event_t *wev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_log_ctx_t *ctx; + ngx_http_upstream_t *u; + + c = wev->data; + r = c->data; + u = r->upstream; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, + "http upstream send request handler"); + + if (wev->timedout) { + ctx = c->log->data; + ctx->action = "sending request to upstream"; + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT); + return; + } + + if (r->connection->write->eof && (!u->cachable || !u->request_sent)) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_http_upstream_send_request(r, u); +} + + +static void ngx_http_upstream_process_header(ngx_event_t *rev) +{ + ssize_t n; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_log_ctx_t *ctx; + ngx_http_upstream_t *u; + + c = rev->data; + r = c->data; + u = r->upstream; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "http upstream process handler"); + + ctx = c->log->data; + ctx->action = "reading response header from upstream"; + + if (rev->timedout) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT); + return; + } + + if (u->header_in.start == NULL) { + u->header_in.start = ngx_palloc(r->pool, u->conf->header_buffer_size); + if (u->header_in.start == NULL) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->header_in.pos = u->header_in.start; + u->header_in.last = u->header_in.start; + u->header_in.end = u->header_in.last + u->conf->header_buffer_size; + u->header_in.temporary = 1; + + u->header_in.tag = u->output.tag; + +#if 0 + if (u->cache) { + u->header_in.pos += u->cache->ctx.header_size; + u->header_in.last = u->header_in.pos; + } +#endif + } + + n = ngx_recv(u->peer.connection, u->header_in.last, + u->header_in.end - u->header_in.last); + + if (n == NGX_AGAIN) { +#if 0 + ngx_add_timer(rev, u->read_timeout); +#endif + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + 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_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + return; + } + + if (n == NGX_HTTP_INTERNAL_SERVER_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->header_in.last += n; + +#if 0 + u->valid_header_in = 0; + + u->peer.cached = 0; +#endif + + rc = u->process_header(r); + + if (rc == NGX_AGAIN) { +#if 0 + ngx_add_timer(rev, u->read_timeout); +#endif + + if (u->header_in.last == u->header_in.end) { + ngx_log_error(NGX_LOG_ERR, rev->log, 0, + "upstream sent too big header"); + + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER); + return; + } + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + return; + } + + if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER); + return; + } + + if (rc == NGX_ERROR || rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + /* rc == NGX_OK */ + + ngx_http_upstream_send_response(r, u); +} + + +static void ngx_http_upstream_send_response(ngx_http_request_t *r, + ngx_http_upstream_t *u) +{ + ngx_event_pipe_t *p; + ngx_http_core_loc_conf_t *clcf; + + + if (u->send_header(r) == NGX_HTTP_INTERNAL_SERVER_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->header_sent = 1; + + /* TODO: preallocate event_pipe bufs, look "Content-Length" */ + +#if 0 + + if (u->cache && u->cache->ctx.file.fd != NGX_INVALID_FILE) { + if (ngx_close_file(u->cache->ctx.file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + u->cache->ctx.file.name.data); + } + } + + if (u->cachable) { + header = (ngx_http_cache_header_t *) u->header_in->start; + + header->expires = u->cache->ctx.expires; + header->last_modified = u->cache->ctx.last_modified; + header->date = u->cache->ctx.date; + header->length = r->headers_out.content_length_n; + u->cache->ctx.length = r->headers_out.content_length_n; + + header->key_len = u->cache->ctx.key0.len; + ngx_memcpy(&header->key, u->cache->ctx.key0.data, header->key_len); + header->key[header->key_len] = LF; + } + +#endif + + p = &u->pipe; + + p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter; + p->output_ctx = r; + p->tag = u->output.tag; + p->bufs = u->conf->bufs; + p->busy_size = u->conf->busy_buffers_size; + p->upstream = u->peer.connection; + p->downstream = r->connection; + p->pool = r->pool; + p->log = r->connection->log; + + p->cachable = u->cachable; + + if (!(p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + p->temp_file->file.fd = NGX_INVALID_FILE; + p->temp_file->file.log = r->connection->log; + p->temp_file->path = u->conf->temp_path; + p->temp_file->pool = r->pool; + + if (u->cachable) { + p->temp_file->persistent = 1; + } else { + p->temp_file->warn = "an upstream response is buffered " + "to a temporary file"; + } + + p->max_temp_file_size = u->conf->max_temp_file_size; + p->temp_file_write_size = u->conf->temp_file_write_size; + + if (!(p->preread_bufs = ngx_alloc_chain_link(r->pool))) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + p->preread_bufs->buf = &u->header_in; + p->preread_bufs->next = NULL; + u->header_in.recycled = 1; + + p->preread_size = u->header_in.last - u->header_in.pos; + + if (u->cachable) { + p->buf_to_file = ngx_calloc_buf(r->pool); + if (p->buf_to_file == NULL) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + p->buf_to_file->pos = u->header_in.start; + p->buf_to_file->last = u->header_in.pos; + p->buf_to_file->temporary = 1; + } + + if (ngx_event_flags & NGX_USE_AIO_EVENT) { + /* the posted aio operation may currupt a shadow buffer */ + p->single_buf = 1; + } + + /* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */ + p->free_bufs = 1; + + /* + * event_pipe would do u->header_in.last += p->preread_size + * as though these bytes were read + */ + u->header_in.last = u->header_in.pos; + + if (u->conf->cyclic_temp_file) { + + /* + * we need to disable the use of sendfile() if we use cyclic temp file + * because the writing a new data may interfere with sendfile() + * that uses the same kernel file pages (at least on FreeBSD) + */ + + p->cyclic_temp_file = 1; + r->connection->sendfile = 0; + + } else { + p->cyclic_temp_file = 0; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + p->read_timeout = u->conf->read_timeout; + 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; + + ngx_http_upstream_process_body(u->peer.connection->read); +} + + +static void ngx_http_upstream_process_body(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_log_ctx_t *ctx; + ngx_http_upstream_t *u; + ngx_event_pipe_t *p; + + c = ev->data; + r = c->data; + u = r->upstream; + + ctx = ev->log->data; + + if (ev->write) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http proxy process downstream"); + ctx->action = "sending to client"; + + } else { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http proxy process upstream"); + ctx->action = "reading upstream body"; + } + + p = &u->pipe; + + if (ev->timedout) { + if (ev->write) { + p->downstream_error = 1; + ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, + "client timed out"); + + } else { + p->upstream_error = 1; + ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, + "upstream timed out"); + } + + } else { + if (ngx_event_pipe(p, ev->write) == NGX_ABORT) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + } + + if (u->peer.connection) { + +#if (NGX_HTTP_FILE_CACHE) + + if (p->upstream_done && u->cachable) { + if (ngx_http_cache_update(r) == NGX_ERROR) { + ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + } else if (p->upstream_eof && u->cachable) { + + /* TODO: check length & update cache */ + + if (ngx_http_cache_update(r) == NGX_ERROR) { + ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + } + +#endif + + if (p->upstream_done || p->upstream_eof || p->upstream_error) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http proxy upstream exit: %p", p->out); +#if 0 + ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); +#endif + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + } + + if (p->downstream_error) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http proxy downstream error"); + + if (!u->cachable && u->peer.connection) { + ngx_http_upstream_finalize_request(r, u, 0); + } + } +} + + +static void ngx_http_upstream_dummy_handler(ngx_event_t *wev) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, + "http upstream dummy handler"); +} + + +static void ngx_http_upstream_next(ngx_http_request_t *r, + ngx_http_upstream_t *u, + ngx_uint_t ft_type) +{ + ngx_uint_t status; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http next upstream, %xD", ft_type); + +#if 0 + ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); +#endif + + if (ft_type != NGX_HTTP_UPSTREAM_FT_HTTP_404) { + ngx_event_connect_peer_failed(&u->peer); + } + + if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT, + "upstream timed out"); + } + + if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) { + status = 0; + + } else { + switch(ft_type) { + + case NGX_HTTP_UPSTREAM_FT_TIMEOUT: + status = NGX_HTTP_GATEWAY_TIME_OUT; + break; + + case NGX_HTTP_UPSTREAM_FT_HTTP_500: + status = NGX_HTTP_INTERNAL_SERVER_ERROR; + break; + + case NGX_HTTP_UPSTREAM_FT_HTTP_404: + status = NGX_HTTP_NOT_FOUND; + break; + + /* + * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING + * never reach here + */ + + default: + status = NGX_HTTP_BAD_GATEWAY; + } + } + + if (r->connection->write->eof) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + + if (status) { + u->state->status = status; + + if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) + { + +#if (NGX_HTTP_CACHE) + + if (u->stale && (u->conf->use_stale & ft_type)) { + ngx_http_upstream_finalize_request(r, u, + ngx_http_proxy_send_cached_response(r)); + return; + } + +#endif + + ngx_http_upstream_finalize_request(r, u, status); + return; + } + } + + if (u->peer.connection) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "close http upstream connection: %d", + u->peer.connection->fd); + + ngx_close_connection(u->peer.connection); + } + +#if 0 + if (u->conf->busy_lock && !u->busy_locked) { + ngx_http_upstream_busy_lock(p); + return; + } +#endif + + ngx_http_upstream_connect(r, u); +} + + +static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, + ngx_http_upstream_t *u, + ngx_int_t rc) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "finalize http upstream request"); + + u->finalize_request(r, rc); + + if (u->peer.connection) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "close http upstream connection: %d", + u->peer.connection->fd); + + ngx_close_connection(u->peer.connection); + } + + if (u->header_sent + && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) + { + rc = 0; + } + + if (u->saved_ctx) { + r->connection->log->data = u->saved_ctx; + r->connection->log->handler = u->saved_handler; + } + + if (u->pipe.temp_file->file.fd) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream temp fd: %d", + u->pipe.temp_file->file.fd); + } + +#if 0 + if (u->cache) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy cache fd: %d", + u->cache->ctx.file.fd); + } +#endif + + if (u->pipe.temp_file->file.fd) { + r->file.fd = u->pipe.temp_file->file.fd; + +#if 0 + } else if (u->cache) { + r->file.fd = u->cache->ctx.file.fd; +#endif + } + + if (rc == 0 && r->main == NULL) { + rc = ngx_http_send_last(r); + } + + ngx_http_finalize_request(r, rc); +} + + +static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + if (r->upstream) { + return r->upstream->states.nelts * (3 + 2); + } + + return 1; +} + + +static u_char *ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_uint_t i; + ngx_http_upstream_t *u; + ngx_http_upstream_state_t *state; + + u = r->upstream; + + if (u == NULL) { + *buf = '-'; + return buf + 1; + } + + i = 0; + state = u->states.elts; + + for ( ;; ) { + if (state[i].status == 0) { + *buf++ = '-'; + + } else { + buf = ngx_sprintf(buf, "%ui", state[i].status); + } + + if (++i == u->states.nelts) { + return buf; + } + + *buf++ = ','; + *buf++ = ' '; + } +} + + +u_char *ngx_http_upstream_log_error(void *data, u_char *buf, size_t len) +{ + ngx_http_log_ctx_t *ctx = data; + + u_char *p; + ngx_int_t escape; + ngx_str_t uri; + ngx_http_request_t *r; + ngx_http_upstream_t *u; + ngx_peer_connection_t *peer; + + r = ctx->request; + u = r->upstream; + peer = &u->peer; + + p = ngx_snprintf(buf, len, + " while %s, client: %V, URL: %V, upstream: %V%V%s%V", + ctx->action, + &r->connection->addr_text, + &r->unparsed_uri, + &u->schema, + &peer->peers->peer[peer->cur_peer].name, + peer->peers->peer[peer->cur_peer].uri_separator, + &u->uri); + len -= p - buf; + buf = p; + + if (r->quoted_uri) { + escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location->len, + r->uri.len - u->location->len, + NGX_ESCAPE_URI); + } else { + escape = 0; + } + + if (escape) { + if (len >= r->uri.len - u->location->len + escape) { + + ngx_escape_uri(buf, r->uri.data + u->location->len, + r->uri.len - u->location->len, NGX_ESCAPE_URI); + + buf += r->uri.len - u->location->len + escape; + + if (r->args.len == 0) { + return buf; + } + + len -= r->uri.len - u->location->len + escape; + + return ngx_snprintf(buf, len, "?%V", &r->args); + } + + p = ngx_palloc(r->pool, r->uri.len - u->location->len + escape); + if (p == NULL) { + return buf; + } + + ngx_escape_uri(p, r->uri.data + u->location->len, + r->uri.len - u->location->len, NGX_ESCAPE_URI); + + uri.len = r->uri.len - u->location->len + escape; + uri.data = p; + + } else { + uri.len = r->uri.len - u->location->len; + uri.data = r->uri.data + u->location->len; + + } + + return ngx_snprintf(buf, len, "%V%s%V", + &uri, r->args.len ? "?" : "", &r->args); +} + + +static ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf) +{ + ngx_http_log_op_name_t *op; + + for (op = ngx_http_upstream_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_upstream_log_fmt_ops; + + return NGX_OK; +} diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_upstream.h @@ -0,0 +1,122 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_HTTP_UPSTREAM_H_INCLUDED_ +#define _NGX_HTTP_UPSTREAM_H_INCLUDED_ + + +#include +#include +#include +#include +#include +#include + + +#define NGX_HTTP_UPSTREAM_FT_ERROR 0x02 +#define NGX_HTTP_UPSTREAM_FT_TIMEOUT 0x04 +#define NGX_HTTP_UPSTREAM_FT_INVALID_HEADER 0x08 +#define NGX_HTTP_UPSTREAM_FT_HTTP_500 0x10 +#define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x20 +#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x40 +#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x80 + + +#define NGX_HTTP_UPSTREAM_INVALID_HEADER 40 + + +typedef struct { + time_t bl_time; + ngx_uint_t bl_state; + + ngx_uint_t status; + time_t time; + + 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; + + 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_bufs_t bufs; + + ngx_flag_t x_powered_by; + ngx_flag_t cyclic_temp_file; + + ngx_path_t *temp_path; +} ngx_http_upstream_conf_t; + + +typedef struct ngx_http_upstream_s ngx_http_upstream_t; + +struct ngx_http_upstream_s { + ngx_http_request_t *request; + + ngx_peer_connection_t peer; + + ngx_event_pipe_t pipe; + + ngx_output_chain_ctx_t output; + ngx_chain_writer_ctx_t writer; + + ngx_http_upstream_conf_t *conf; + + 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_str_t schema; + ngx_str_t uri; + ngx_str_t *location; + + ngx_http_log_ctx_t *log_ctx; + ngx_log_handler_pt log_handler; + ngx_http_log_ctx_t *saved_ctx; + ngx_log_handler_pt saved_handler; + + /* 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_upstream_state_t *state; + ngx_array_t states; /* of ngx_http_upstream_state_t */ + + unsigned cachable: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(void *data, u_char *buf, size_t len); + + +extern char *ngx_http_upstream_header_errors[]; + + +#endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */ diff --git a/src/http/ngx_http_write_filter.c b/src/http/ngx_http_write_filter.c --- a/src/http/ngx_http_write_filter.c +++ b/src/http/ngx_http_write_filter.c @@ -69,8 +69,19 @@ ngx_int_t ngx_http_write_filter(ngx_http for (cl = ctx->out; cl; cl = cl->next) { ll = &cl->next; + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, + "write old buf t:%d f:%d %p, pos %p, size: %z " + "file: %O, size: %z", + cl->buf->temporary, cl->buf->in_file, + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + #if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "zero size buf in writer"); ngx_debug_point(); } #endif @@ -97,8 +108,19 @@ ngx_int_t ngx_http_write_filter(ngx_http *ll = cl; ll = &cl->next; + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, + "write new buf t:%d f:%d %p, pos %p, size: %z " + "file: %O, size: %z", + cl->buf->temporary, cl->buf->in_file, + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + #if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "zero size buf in writer"); ngx_debug_point(); } #endif 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 @@ -37,6 +37,7 @@ #include /* TCP_NODELAY, TCP_NOPUSH */ #include #include +#include #include /* setproctitle() before 4.1 */ #include diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -10,16 +10,16 @@ /* - * Although FreeBSD sendfile() allows to pass a header and a trailer + * Although FreeBSD sendfile() allows to pass a header and a trailer, * it can not send a header with a part of the file in one packet until - * FreeBSD 5.3. Besides over the fast ethernet connection sendfile() + * FreeBSD 5.3. Besides, over the fast ethernet connection sendfile() * may send the partially filled packets, i.e. the 8 file pages may be sent * as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet, * and then again the 11 full 1460-bytes packets. * - * So we use the TCP_NOPUSH option (similar to Linux's TCP_CORK) - * to postpone the sending - it not only sends a header and the first part - * of the file in one packet but also sends the file pages in the full packets. + * Threfore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK) + * to postpone the sending - it not only sends a header and the first part of + * the file in one packet, but also sends the file pages in the full packets. * * But until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush a pending * data that less than MSS so that data may be sent with 5 second delay. @@ -220,7 +220,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( err = ngx_errno; /* - * there is a tiny chance to be interrupted, however + * there is a tiny chance to be interrupted, however, * we continue a processing without the TCP_NOPUSH */ @@ -249,7 +249,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771 */ - if (ngx_freebsd_sendfile_nbytes_bug == 0) { + if (!ngx_freebsd_sendfile_nbytes_bug) { header_size = 0; } @@ -282,7 +282,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( if (rc == 0 && sent == 0) { /* - * rc and sent are equals to zero when someone has truncated + * rc and sent equal to zero when someone has truncated * the file, so the offset became beyond the end of the file */ @@ -370,8 +370,8 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( if (eagain) { /* - * sendfile() can return EAGAIN even if it has sent - * a whole file part but the successive sendfile() call would + * sendfile() may return EAGAIN, even if it has sent a whole file + * part, it indicates that the successive sendfile() call would * return EAGAIN right away and would not send anything. * We use it as a hint. */ 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 @@ -42,6 +42,7 @@ #include /* TCP_NODELAY, TCP_CORK */ #include #include +#include #include /* tzset() */ #include /* memalign() */ diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -11,9 +11,10 @@ /* * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit - * offsets only and the including breaks the compiling - * if off_t is 64 bit wide. So we use own sendfile() definition where offset - * parameter is int32_t and use sendfile() for the file parts below 2G only. + * offsets only, and the including breaks the compiling, + * if off_t is 64 bit wide. So we use own sendfile() definition, where offset + * parameter is int32_t, and use sendfile() for the file parts below 2G only, + * see src/os/unix/ngx_linux_config.h * * Linux 2.4.21 has a new sendfile64() syscall #239. */ @@ -85,6 +86,14 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng continue; } +#if 1 + if (!ngx_buf_in_memory(cl->buf) && !cl->buf->in_file) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "zero size buf in sendfile"); + ngx_debug_point(); + } +#endif + if (!ngx_buf_in_memory_only(cl->buf)) { break; } @@ -118,7 +127,6 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng && cl && cl->buf->in_file) { - /* the TCP_CORK and TCP_NODELAY are mutually exclusive */ if (c->tcp_nodelay) { @@ -131,7 +139,7 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng err = ngx_errno; /* - * there is a tiny chance to be interrupted, however + * there is a tiny chance to be interrupted, however, * we continue a processing with the TCP_NODELAY * and without the TCP_CORK */ @@ -157,7 +165,7 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng err = ngx_errno; /* - * there is a tiny chance to be interrupted, however + * there is a tiny chance to be interrupted, however, * we continue a processing without the TCP_CORK */ 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 @@ -57,6 +57,7 @@ #include /* TCP_NODELAY */ #include #include +#include #if (NGX_HAVE_LIMITS_H) #include /* IOV_MAX */ 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 @@ -1113,7 +1113,7 @@ static void ngx_garbage_collector_cycle( for (i = 0; i < cycle->pathes.nelts; i++) { ctx.path = path[i]; ctx.log = cycle->log; - ctx.handler = path[i]->gc_handler; + ctx.handler = path[i]->cleaner; ngx_collect_garbage(&ctx, &path[i]->name, 0); } 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 @@ -41,6 +41,7 @@ #include /* TCP_NODELAY */ #include #include +#include #include #include /* IOV_MAX */