# HG changeset patch # User Igor Sysoev # Date 1131557155 0 # Node ID 58475592100cb792c125101b6d2d898f5adada30 # Parent ae8920455206a388e26fb53f932683305a3b9e53 nginx-0.3.8-RELEASE import *) Security: nginx now checks URI got from a backend in "X-Accel-Redirect" header line or in SSI file for the "/../" paths and zeroes. *) Change: nginx now does not treat the empty user name in the "Authorization" header line as valid one. *) Feature: the "ssl_session_timeout" directives of the ngx_http_ssl_module and ngx_imap_ssl_module. *) Feature: the "auth_http_header" directive of the ngx_imap_auth_http_module. *) Feature: the "add_header" directive. *) Feature: the ngx_http_realip_module. *) Feature: the new variables to use in the "log_format" directive: $bytes_sent, $apache_bytes_sent, $status, $time_gmt, $uri, $request_time, $request_length, $upstream_status, $upstream_response_time, $gzip_ratio, $uid_got, $uid_set, $connection, $pipe, and $msec. The parameters in the "%name" form will be canceled soon. *) Change: now the false variable values in the "if" directive are the empty string "" and string starting with "0". *) Bugfix: while using proxied or FastCGI-server nginx may leave connections and temporary files with client requests in open state. *) Bugfix: the worker processes did not flush the buffered logs on graceful exit. *) Bugfix: if the request URI was changes by the "rewrite" directive and the request was proxied in location given by regular expression, then the incorrect request was transferred to backend; the bug had appeared in 0.2.6. *) Bugfix: the "expires" directive did not remove the previous "Expires" header. *) Bugfix: nginx may stop to accept requests if the "rtsig" method and several worker processes were used. *) Bugfix: the "\"" and "\'" escape symbols were incorrectly handled in SSI commands. *) Bugfix: if the response was ended just after the SSI command and gzipping was used, then the response did not transferred complete or did not transferred at all. diff --git a/auto/cc/bcc b/auto/cc/bcc --- a/auto/cc/bcc +++ b/auto/cc/bcc @@ -63,5 +63,9 @@ ngx_binout="-e" ngx_objext="obj" ngx_binext=".exe" +ngx_long_start='@&&| + ' +ngx_long_end='|' + ngx_regex_dirsep='\\' ngx_dirsep="\\" diff --git a/auto/cc/conf b/auto/cc/conf --- a/auto/cc/conf +++ b/auto/cc/conf @@ -11,6 +11,9 @@ ngx_binout="-o " ngx_objext="o" ngx_binext= +ngx_long_start= +ngx_long_end= + ngx_regex_dirsep="\/" ngx_dirsep='/' @@ -22,6 +25,9 @@ ngx_tab=' \ ' ngx_spacer= +ngx_long_regex_cont=$ngx_regex_cont +ngx_long_cont=$ngx_cont + . auto/cc/name if test -n "$CFLAGS"; then diff --git a/auto/cc/icc b/auto/cc/icc --- a/auto/cc/icc +++ b/auto/cc/icc @@ -38,6 +38,7 @@ CFLAGS="$CFLAGS $IPO" CORE_LINK="$CORE_LINK $IPO" CORE_LINK="$CORE_LINK -opt_report_file=$NGX_OBJS/opt_report_file" + case $CPU in pentium) # optimize for Pentium and Athlon @@ -104,7 +105,7 @@ CFLAGS="$CFLAGS -wd1418" CFLAGS="$CFLAGS -wd1419" case "$NGX_ICC_VER" in - 8.* | 9.*) + 9.*) # "cc" clobber ignored, warnings for Liunx's htons() CFLAGS="$CFLAGS -wd1469" # explicit conversion of a 64-bit integral type to a smaller @@ -119,6 +120,15 @@ case "$NGX_ICC_VER" in CFLAGS="$CFLAGS -wd1595" ;; + 8.*) + # "cc" clobber ignored, warnings for Liunx's htons() + CFLAGS="$CFLAGS -wd1469" + + # STUB + # non-POD class type passed through ellipsis, Linux only ? + CFLAGS="$CFLAGS -wd1595" + ;; + *) ;; esac diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -114,5 +114,13 @@ ngx_binout="-Fe" ngx_objext="obj" ngx_binext=".exe" +ngx_long_start='@<< + ' +ngx_long_end='<<' +ngx_long_regex_cont=' \ + ' +ngx_long_cont=' + ' + #ngx_regex_dirsep='\\' #ngx_dirsep="\\" diff --git a/auto/make b/auto/make --- a/auto/make +++ b/auto/make @@ -26,7 +26,9 @@ if [ "$CC" = wcl386 ]; then echo MAKE = wmake >> $NGX_MAKEFILE ngx_regex_cont=' ' + ngx_long_regex_cont=' ' ngx_cont=' ' + ngx_long_cont=' ' ngx_tab=' ' fi @@ -170,22 +172,22 @@ ngx_deps=`echo $ngx_all_objs $ngx_module -e "s/\//$ngx_regex_dirsep/g"` ngx_objs=`echo $ngx_all_objs $ngx_modules_obj \ - | sed -e "s/ *\([^ ][^ ]*\)/$ngx_regex_cont\1/g" \ + | sed -e "s/ *\([^ ][^ ]*\)/$ngx_long_regex_cont\1/g" \ -e "s/\//$ngx_regex_dirsep/g"` ngx_libs=${CORE_LIBS:+`echo $NGX_LD_OPT $CORE_LIBS \ - | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_regex_cont/"`} + | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`} ngx_link=${CORE_LINK:+`echo $CORE_LINK \ - | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_regex_cont/"`} + | sed -e "s/\//$ngx_regex_dirsep/g" -e "s/^/$ngx_long_regex_cont/"`} cat << END >> $NGX_MAKEFILE $NGX_OBJS${ngx_dirsep}nginx${ngx_binext}: $ngx_deps$ngx_spacer - \$(LINK) ${ngx_binout}$NGX_OBJS${ngx_dirsep}nginx$ngx_cont$ngx_objs$ngx_libs$ngx_link + \$(LINK) ${ngx_long_start}${ngx_binout}$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link $ngx_rcc - +${ngx_long_end} END diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -139,6 +139,12 @@ if [ $HTTP_ACCESS = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_ACCESS_SRCS" fi +if [ $HTTP_REALIP = YES ]; then + have=NGX_HTTP_REALIP . auto/have + HTTP_MODULES="$HTTP_MODULES $HTTP_REALIP_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_REALIP_SRCS" +fi + if [ $HTTP_STATUS = YES ]; then have=NGX_HTTP_STATUS . auto/have HTTP_MODULES="$HTTP_MODULES $HTTP_STATUS_MODULE" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -50,6 +50,7 @@ HTTP_GZIP=YES HTTP_SSL=NO HTTP_SSI=YES HTTP_POSTPONE=NO +HTTP_REALIP=NO HTTP_ACCESS=YES HTTP_AUTH_BASIC=YES HTTP_USERID=YES @@ -125,6 +126,7 @@ do --http-fastcgi-temp-path=*) NGX_HTTP_FASTCGI_TEMP_PATH="$value" ;; --with-http_ssl_module) HTTP_SSL=YES ;; + --with-http_realip_module) HTTP_REALIP=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; --without-http_ssi_module) HTTP_SSI=NO ;; diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -310,6 +310,10 @@ HTTP_USERID_FILTER_MODULE=ngx_http_useri HTTP_USERID_SRCS=src/http/modules/ngx_http_userid_filter_module.c +HTTP_REALIP_MODULE=ngx_http_realip_module +HTTP_REALIP_SRCS=src/http/modules/ngx_http_realip_module.c + + HTTP_ACCESS_MODULE=ngx_http_access_module HTTP_ACCESS_SRCS=src/http/modules/ngx_http_access_module.c diff --git a/conf/nginx.conf b/conf/nginx.conf --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -1,13 +1,13 @@ #user nobody; -worker_processes 3; +worker_processes 1; #error_log logs/error.log; #pid logs/nginx.pid; events { - connections 1024; + worker_connections 1024; } @@ -25,7 +25,7 @@ http { server { listen 80; - charset koi8-r; + #charset koi8-r; #access_log logs/access.log; diff --git a/docs/xml/change_log_conf.xml b/docs/xml/change_log_conf.xml --- a/docs/xml/change_log_conf.xml +++ b/docs/xml/change_log_conf.xml @@ -15,6 +15,7 @@ Исправление Добавление Изменение + Безопасность Изменение @@ -25,6 +26,7 @@ Bugfix Feature Change + Security Workaround Jan diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -9,6 +9,181 @@ nginx changelog + + + + +nginx теперь проверят URI, полученные от бэкенда в строке "X-Accel-Redirect" +в заголовке ответа, или в SSI файле на наличие путей "/../" и нулей. + + +nginx now checks URI got from a backend in "X-Accel-Redirect" header line +or in SSI file for the "/../" paths and zeroes. + + + + + +nginx теперь не воспринимает пустое имя как правильное +в строке "Authorization" в заголовке запроса. + + +nginx now does not treat the empty user name in the "Authorization" header +line as valid one. + + + + + +директива ssl_session_timeout модулей +ngx_http_ssl_module и ngx_imap_ssl_module. + + +the "ssl_session_timeout" directives +of the ngx_http_ssl_module and ngx_imap_ssl_module. + + + + + +директива auth_http_header модуля ngx_imap_auth_http_module. + + +the "auth_http_header" directive of the ngx_imap_auth_http_module. + + + + + +директива add_header. + + +the "add_header" directive. + + + + + +модуль ngx_http_realip_module. + + +the ngx_http_realip_module. +directives. + + + + + +новые переменные для использования в директиве log_format: +$bytes_sent, $apache_bytes_sent, $status, $time_gmt, +$uri, $request_time, $request_length, +$upstream_status, $upstream_response_time, +$gzip_ratio, +$uid_got, $uid_set, +$connection, $pipe и $msec. +Параметры в виде "%name" скоро будут упразднены. + + +the new variables to use in the "log_format" directive: +$bytes_sent, $apache_bytes_sent, $status, $time_gmt, +$uri, $request_time, $request_length, +$upstream_status, $upstream_response_time, +$gzip_ratio, +$uid_got, $uid_set, +$connection, $pipe, and $msec. +The parameters in the "%name" form will be canceled soon. + + + + + +в директиве "if" ложными значениями переменных теперь являются +пустая строка "" и строки, начинающиеся на "0". + + +now the false variable values in the "if" directive are the empty string "" +and string starting with "0". + + + + + +при работает с проксированными или FastCGI-серверами nginx мог оставлять +открытыми соединения и временные файлы с запросами клиентов. + + +while using proxied or FastCGI-server nginx may leave connections +and temporary files with client requests in open state. + + + + + +рабочие процессы не сбрасывал буферизированные логи при плавном выходе. + + +the worker processes did not flush the buffered logs on graceful exit. + + + + + +если URI запроса изменялось с помощью rewrite, а затем запрос проксировался +в location, заданном регулярным выражением, то бэкенду передавался +неверный запрос; +ошибка появилась в 0.2.6. + + +if the request URI was changes by the "rewrite" directive and the request +was proxied in location given by regular expression, then the incorrect +request was transferred to backend; +bug appeared in 0.2.6. + + + + + +директива expires не удаляла уже установленную строку заголовка "Expires". + + +the "expires" directive did not remove the previous "Expires" header. + + + + + +при использовании метода rtsig и нескольких рабочих процессах nginx +мог перестать принимать запросы. + + +nginx may stop to accept requests if the "rtsig" method and several worker +processes were used. + + + + + +в SSI командах неверно обрабатывались строки "\"" и "\'". + + +the "\"" and "\'" escape symbols were incorrectly handled in SSI commands. + + + + + +если ответ заканчивался сразу же после SSI команды, то при использовании +сжатия ответ передавался не до конца или не передавался вообще. + + +if the response was ended just after the SSI command and gzipping was used, +then the response did not transferred complete or did not transferred at all. + + + + + + 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.3.7" +#define NGINX_VER "nginx/0.3.8" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" 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 @@ -82,7 +82,7 @@ struct ngx_command_s { void *post; }; -#define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL } +#define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL } struct ngx_open_file_s { 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 @@ -190,7 +190,9 @@ ngx_vsnprintf(u_char *buf, size_t max, c case 'V': s = va_arg(args, ngx_str_t *); - len = (buf + s->len < last) ? s->len : (size_t) (last - buf); + len = s->len & 0xffff; + len = (buf + len < last) ? len : (size_t) (last - buf); + buf = ngx_cpymem(buf, s->data, len); fmt++; 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 @@ -46,7 +46,7 @@ typedef struct { #define ngx_strncmp(s1, s2, n) strncmp((const char *) s1, (const char *) s2, n) -/* msvc and icc compile strcmp() to inline loop */ +/* msvc and icc7 compile strcmp() to inline loop */ #define ngx_strcmp(s1, s2) strcmp((const char *) s1, (const char *) s2) @@ -55,20 +55,55 @@ typedef struct { /* - * msvc and icc compile memset() to the inline "rep stos" + * msvc and icc7 compile memset() to the inline "rep stos" * while ZeroMemory() and bzero() are the calls. - * icc may also inline several mov's of a zeroed register for small blocks. + * icc7 may also inline several mov's of a zeroed register for small blocks. */ #define ngx_memzero(buf, n) (void) memset(buf, 0, n) #define ngx_memset(buf, c, n) (void) memset(buf, c, n) -/* msvc and icc compile memcpy() to the inline "rep movs" */ +/* + * gcc3, msvc, and icc7 compile memcpy() to the inline "rep movs". + * gcc3 compiles memcpy(d, s, 4) to the inline "mov"es. + * icc8 compile memcpy(d, s, 4) to the inline "mov"es or XMM moves. + */ #define ngx_memcpy(dst, src, n) (void) memcpy(dst, src, n) #define ngx_cpymem(dst, src, n) ((u_char *) memcpy(dst, src, n)) + (n) -/* msvc and icc compile memcmp() to the inline loop */ +#if ( __INTEL_COMPILER >= 800 ) + +/* + * the simple inline cycle copies the variable length strings up to 16 + * bytes faster than icc8 autodetecting _intel_fast_memcpy() + */ + +static ngx_inline u_char * +ngx_copy(u_char *dst, u_char *src, size_t len) +{ + if (len < 17) { + + while (len) { + *dst++ = *src++; + len--; + } + + return dst; + + } else { + return ngx_cpymem(dst, src, len); + } +} + +#else + +#define ngx_copy ngx_cpymem + +#endif + + +/* msvc and icc7 compile memcmp() to the inline loop */ #define ngx_memcmp memcmp diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c --- a/src/event/modules/ngx_rtsig_module.c +++ b/src/event/modules/ngx_rtsig_module.c @@ -288,7 +288,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy ngx_int_t instance; ngx_err_t err; siginfo_t si; - ngx_event_t *rev, *wev; + ngx_event_t *rev, *wev, **queue; struct timespec ts, *tp; struct sigaction sa; ngx_connection_t *c; @@ -381,15 +381,32 @@ ngx_rtsig_process_events(ngx_cycle_t *cy } if ((si.si_band & (POLLIN|POLLHUP|POLLERR)) && rev->active) { + rev->ready = 1; - rev->handler(rev); + + if (flags & NGX_POST_EVENTS) { + queue = (ngx_event_t **) (rev->accept ? + &ngx_posted_accept_events : &ngx_posted_events); + + ngx_locked_post_event(rev, queue); + + } else { + rev->handler(rev); + } } wev = c->write; if ((si.si_band & (POLLOUT|POLLHUP|POLLERR)) && wev->active) { + wev->ready = 1; - wev->handler(wev); + + if (flags & NGX_POST_EVENTS) { + ngx_locked_post_event(wev, &ngx_posted_events); + + } else { + wev->handler(wev); + } } return NGX_OK; diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -48,6 +48,7 @@ ngx_atomic_t *ngx_connection_cou ngx_atomic_t *ngx_accept_mutex_ptr; +ngx_atomic_t *ngx_accept_mutex_last_owner; ngx_atomic_t *ngx_accept_mutex; ngx_uint_t ngx_accept_mutex_held; ngx_msec_t ngx_accept_mutex_delay; @@ -249,10 +250,6 @@ ngx_process_events_and_timers(ngx_cycle_ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "timer delta: %M", delta); - if (delta) { - ngx_event_expire_timers(); - } - if (ngx_posted_accept_events) { ngx_event_process_posted(cycle, &ngx_posted_accept_events); } @@ -261,6 +258,10 @@ ngx_process_events_and_timers(ngx_cycle_ *ngx_accept_mutex = 0; } + if (delta) { + ngx_event_expire_timers(); + } + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "posted events %p", ngx_posted_events); @@ -470,6 +471,7 @@ ngx_event_module_init(ngx_cycle_t *cycle /* TODO: adjust cache line size, 128 is P4 cache line size */ size = 128 /* ngx_accept_mutex */ + + 128 /* ngx_accept_mutex_last_owner */ + 128; /* ngx_connection_counter */ #if (NGX_STAT_STUB) @@ -489,16 +491,17 @@ ngx_event_module_init(ngx_cycle_t *cycle } ngx_accept_mutex_ptr = (ngx_atomic_t *) shared; - ngx_connection_counter = (ngx_atomic_t *) (shared + 128); + ngx_accept_mutex_last_owner = (ngx_atomic_t *) (shared + 1 * 128); + ngx_connection_counter = (ngx_atomic_t *) (shared + 2 * 128); #if (NGX_STAT_STUB) - ngx_stat_accepted = (ngx_atomic_t *) (shared + 2 * 128); - ngx_stat_handled = (ngx_atomic_t *) (shared + 3 * 128); - ngx_stat_requests = (ngx_atomic_t *) (shared + 4 * 128); - ngx_stat_active = (ngx_atomic_t *) (shared + 5 * 128); - ngx_stat_reading = (ngx_atomic_t *) (shared + 6 * 128); - ngx_stat_writing = (ngx_atomic_t *) (shared + 7 * 128); + ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * 128); + ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * 128); + ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * 128); + ngx_stat_active = (ngx_atomic_t *) (shared + 6 * 128); + ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * 128); + ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * 128); #endif @@ -1082,10 +1085,10 @@ ngx_event_init_conf(ngx_cycle_t *cycle, #endif #if (NGX_HAVE_RTSIG) ngx_uint_t rtsig; + ngx_core_conf_t *ccf; #endif ngx_int_t i, connections; ngx_module_t *module; - ngx_core_conf_t *ccf; ngx_event_module_t *event_module; connections = NGX_CONF_UNSET_UINT; @@ -1189,8 +1192,6 @@ ngx_event_init_conf(ngx_cycle_t *cycle, return NGX_CONF_OK; } -#endif - if (ecf->accept_mutex) { return NGX_CONF_OK; } @@ -1205,6 +1206,12 @@ ngx_event_init_conf(ngx_cycle_t *cycle, "the \"rtsig\" method requires \"accept_mutex\" to be on"); return NGX_CONF_ERROR; + +#else + + return NGX_CONF_OK; + +#endif } diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -438,6 +438,7 @@ typedef struct { extern ngx_atomic_t *ngx_connection_counter; extern ngx_atomic_t *ngx_accept_mutex_ptr; +extern ngx_atomic_t *ngx_accept_mutex_last_owner; extern ngx_atomic_t *ngx_accept_mutex; extern ngx_uint_t ngx_accept_mutex_held; extern ngx_msec_t ngx_accept_mutex_delay; @@ -474,8 +475,6 @@ extern ngx_module_t ngx_event_ void ngx_event_accept(ngx_event_t *ev); ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle); -ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle); -ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len); 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 @@ -13,6 +13,8 @@ #define NGX_SOCKLEN 512 +static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); +static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle); static void ngx_close_accepted_connection(ngx_connection_t *c); @@ -262,15 +264,20 @@ ngx_trylock_accept_mutex(ngx_cycle_t *cy ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "accept mutex locked"); - if (!ngx_accept_mutex_held) { - if (ngx_enable_accept_events(cycle) == NGX_ERROR) { - *ngx_accept_mutex = 0; - return NGX_ERROR; - } + if (ngx_accept_mutex_held + && (!(ngx_event_flags & NGX_USE_RTSIG_EVENT) + || *ngx_accept_mutex_last_owner == (ngx_atomic_t) ngx_pid)) + { + return NGX_OK; + } - ngx_accept_mutex_held = 1; + if (ngx_enable_accept_events(cycle) == NGX_ERROR) { + *ngx_accept_mutex = 0; + return NGX_ERROR; } + ngx_accept_mutex_held = 1; + return NGX_OK; } @@ -286,7 +293,7 @@ ngx_trylock_accept_mutex(ngx_cycle_t *cy } -ngx_int_t +static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle) { ngx_uint_t i; @@ -299,10 +306,17 @@ ngx_enable_accept_events(ngx_cycle_t *cy c = ls[i].connection; if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { + + if (ngx_accept_mutex_held) { + c->read->disabled = 1; + } + if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } + *ngx_accept_mutex_last_owner = ngx_pid; + } else { if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; @@ -314,7 +328,7 @@ ngx_enable_accept_events(ngx_cycle_t *cy } -ngx_int_t +static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle) { ngx_uint_t i; diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -14,7 +14,7 @@ typedef struct { in_addr_t mask; in_addr_t addr; - unsigned deny; + ngx_uint_t deny; /* unsigned deny:1; */ } ngx_http_access_rule_t; @@ -106,7 +106,7 @@ ngx_http_access_handler(ngx_http_request for (i = 0; i < alcf->rules->nelts; i++) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "%08XD %08XD %08XD", + "access: %08XD %08XD %08XD", sin->sin_addr.s_addr, rule[i].mask, rule[i].addr); if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) { diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -17,6 +17,7 @@ typedef struct { ngx_str_t index; + ngx_array_t *flushes; ngx_array_t *params_len; ngx_array_t *params; ngx_array_t *params_source; @@ -111,9 +112,8 @@ static ngx_int_t ngx_http_fastcgi_add_va static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); -static ngx_http_variable_value_t * - ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, - uintptr_t data); +static ngx_int_t ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -410,6 +410,9 @@ ngx_http_fastcgi_create_request(ngx_http if (flcf->params_len) { ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); + ngx_http_script_flush_no_cachable_variables(r, flcf->flushes); + le.flushed = 1; + le.ip = flcf->params_len->elts; le.request = r; @@ -507,6 +510,7 @@ ngx_http_fastcgi_create_request(ngx_http e.ip = flcf->params->elts; e.pos = b->last; e.request = r; + e.flushed = 1; le.ip = flcf->params_len->elts; @@ -597,8 +601,8 @@ ngx_http_fastcgi_create_request(ngx_http *b->last++ = ch; } - b->last = ngx_cpymem(b->last, header[i].value.data, - header[i].value.len); + b->last = ngx_copy(b->last, header[i].value.data, + header[i].value.len); } } @@ -1634,9 +1638,10 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf } if (conf->params_source == NULL) { - conf->params_source = prev->params_source; + conf->flushes = prev->flushes; conf->params_len = prev->params_len; conf->params = prev->params; + conf->params_source = prev->params_source; if (conf->params_source == NULL) { return NGX_CONF_OK; @@ -1647,7 +1652,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf if (conf->params_len == NULL) { return NGX_CONF_ERROR; } - + conf->params = ngx_array_create(cf->pool, 512, 1); if (conf->params == NULL) { return NGX_CONF_ERROR; @@ -1729,6 +1734,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf sc.cf = cf; sc.source = &src[i].value; + sc.flushes = &conf->flushes; sc.lengths = &conf->params_len; sc.values = &conf->params; @@ -1764,38 +1770,36 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf } -static ngx_http_variable_value_t * -ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { u_char *p; - ngx_http_variable_value_t *vv; ngx_http_fastcgi_loc_conf_t *flcf; - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } - - vv->value = 0; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); if (r->uri.data[r->uri.len - 1] != '/') { - vv->text = r->uri; - return vv; + v->len = r->uri.len; + v->data = r->uri.data; + return NGX_OK; } - vv->text.len = r->uri.len + flcf->index.len; + v->len = r->uri.len + flcf->index.len; - vv->text.data = ngx_palloc(r->pool, vv->text.len); - if (vv->text.data == NULL) { - return NULL; + v->data = ngx_palloc(r->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; } - p = ngx_cpymem(vv->text.data, r->uri.data, r->uri.len); + p = ngx_copy(v->data, r->uri.data, r->uri.len); ngx_memcpy(p, flcf->index.data, flcf->index.len); - return vv; + return NGX_OK; } @@ -1860,7 +1864,7 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng clcf->handler = ngx_http_fastcgi_handler; - lcf->upstream.location = &clcf->name; + lcf->upstream.location = clcf->name; if (clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -65,31 +65,34 @@ ngx_module_t ngx_http_geo_module = { static ngx_http_variable_value_t ngx_http_geo_null_value = - { 0, ngx_string("0") }; + ngx_http_variable(""); /* AF_INET only */ -static ngx_http_variable_value_t * -ngx_http_geo_variable(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_geo_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) { ngx_radix_tree_t *tree = (ngx_radix_tree_t *) data; struct sockaddr_in *sin; - ngx_http_variable_value_t *var; + ngx_http_variable_value_t *vv; sin = (struct sockaddr_in *) r->connection->sockaddr; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http geo started"); - var = (ngx_http_variable_value_t *) + vv = (ngx_http_variable_value_t *) ngx_radix32tree_find(tree, ntohl(sin->sin_addr.s_addr)); + *v = *vv; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http geo: %V %V", &r->connection->addr_text, &var->text); + "http geo: %V %V", &r->connection->addr_text, v); - return var; + return NGX_OK; } @@ -182,7 +185,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c static char * ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { - ngx_int_t rc, n; + ngx_int_t rc; ngx_str_t *value, file; ngx_uint_t i; ngx_inet_cidr_t cidrin; @@ -226,30 +229,18 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command cidrin.mask = ntohl(cidrin.mask); } - n = ngx_atoi(value[1].data, value[1].len); - var = NULL; v = geo->values.elts; - if (n == NGX_ERROR) { - for (i = 0; i < geo->values.nelts; i++) { - if (v[i]->text.len != value[1].len) { - continue; - } - - if (ngx_strncmp(value[1].data, v[i]->text.data, value[1].len) == 0) - { - var = v[i]; - break; - } + for (i = 0; i < geo->values.nelts; i++) { + if ((size_t) v[i]->len != value[1].len) { + continue; } - } else { - for (i = 0; i < geo->values.nelts; i++) { - if (v[i]->value == (ngx_uint_t) n) { - var = v[i]; - break; - } + if (ngx_strncmp(value[1].data, v[i]->data, value[1].len) == 0) + { + var = v[i]; + break; } } @@ -259,13 +250,15 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command return NGX_CONF_ERROR; } - var->text.len = value[1].len; - var->text.data = ngx_pstrdup(geo->pool, &value[1]); - if (var->text.data == NULL) { + var->len = value[1].len; + var->data = ngx_pstrdup(geo->pool, &value[1]); + if (var->data == NULL) { return NGX_CONF_ERROR; } - var->value = (n == NGX_ERROR) ? 0 : n; + var->valid = 1; + var->no_cachable = 0; + var->not_found = 0; v = ngx_array_push(&geo->values); if (v == NULL) { @@ -294,7 +287,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "duplicate parameter \"%V\", value: \"%V\", " "old value: \"%V\"", - &value[0], &var->text, &old->text); + &value[0], var, old); rc = ngx_radix32tree_delete(geo->tree, cidrin.addr, cidrin.mask); diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -79,7 +79,9 @@ static void ngx_http_gzip_error(ngx_http static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); -static ngx_int_t ngx_http_gzip_add_log_formats(ngx_conf_t *cf); +static ngx_int_t ngx_http_gzip_add_variables(ngx_conf_t *cf); +static ngx_int_t ngx_http_gzip_ratio_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_gzip_filter_init(ngx_cycle_t *cycle); static void *ngx_http_gzip_create_conf(ngx_conf_t *cf); @@ -199,7 +201,7 @@ static ngx_command_t ngx_http_gzip_filt static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { - ngx_http_gzip_add_log_formats, /* preconfiguration */ + ngx_http_gzip_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -256,6 +258,7 @@ struct gztrailer { #endif +static ngx_str_t ngx_http_gzip_ratio = ngx_string("gzip_ratio"); static ngx_str_t ngx_http_gzip_no_cache = ngx_string("no-cache"); static ngx_str_t ngx_http_gzip_no_store = ngx_string("no-store"); static ngx_str_t ngx_http_gzip_private = ngx_string("private"); @@ -956,10 +959,18 @@ ngx_http_gzip_error(ngx_http_gzip_ctx_t static ngx_int_t -ngx_http_gzip_add_log_formats(ngx_conf_t *cf) +ngx_http_gzip_add_variables(ngx_conf_t *cf) { + ngx_http_variable_t *var; ngx_http_log_op_name_t *op; + var = ngx_http_add_variable(cf, &ngx_http_gzip_ratio, 0); + if (var == NULL) { + return NGX_ERROR; + } + + var->handler = ngx_http_gzip_ratio_variable; + for (op = ngx_http_gzip_log_fmt_ops; op->name.len; op++) { /* void */ } op->run = NULL; @@ -976,6 +987,50 @@ ngx_http_gzip_add_log_formats(ngx_conf_t static ngx_int_t +ngx_http_gzip_ratio_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_uint_t zint, zfrac; + ngx_http_gzip_ctx_t *ctx; + + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + + ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); + + if (ctx == NULL || ctx->zout == 0) { + v->not_found = 1; + return NGX_OK; + } + + v->data = ngx_palloc(r->pool, NGX_INT32_LEN + 3); + if (v->data == NULL) { + return NGX_ERROR; + } + + zint = (ngx_uint_t) (ctx->zin / ctx->zout); + zfrac = (ngx_uint_t) ((ctx->zin * 100 / ctx->zout) % 100); + + if ((ctx->zin * 1000 / ctx->zout) % 10 > 4) { + + /* the rounding, e.g., 2.125 to 2.13 */ + + zfrac++; + + if (zfrac > 99) { + zint++; + zfrac = 0; + } + } + + v->len = ngx_sprintf(v->data, "%ui.%02ui", zint, zfrac) - v->data; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_gzip_filter_init(ngx_cycle_t *cycle) { ngx_http_next_header_filter = ngx_http_top_header_filter; diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -10,7 +10,9 @@ typedef struct { - time_t expires; + time_t expires; + ngx_str_t cache_control; + ngx_array_t *headers; } ngx_http_headers_conf_t; @@ -22,20 +24,31 @@ typedef struct { static ngx_int_t ngx_http_headers_filter_init(ngx_cycle_t *cycle); static void *ngx_http_headers_create_conf(ngx_conf_t *cf); static char *ngx_http_headers_merge_conf(ngx_conf_t *cf, - void *parent, void *child); + void *parent, void *child); static char *ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_command_t ngx_http_headers_filter_commands[] = { { ngx_string("expires"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, ngx_http_headers_expires, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL}, + { ngx_string("add_header"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE2, + ngx_http_headers_add, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + ngx_null_command }; @@ -79,7 +92,7 @@ ngx_http_headers_filter(ngx_http_request { size_t len; ngx_uint_t i; - ngx_table_elt_t *expires, *cc, **ccp; + ngx_table_elt_t *expires, *cc, **ccp, *h, *out; ngx_http_headers_conf_t *conf; if ((r->headers_out.status != NGX_HTTP_OK @@ -117,7 +130,8 @@ ngx_http_headers_filter(ngx_http_request if (ccp == NULL) { if (ngx_array_init(&r->headers_out.cache_control, r->pool, - 1, sizeof(ngx_table_elt_t *)) != NGX_OK) + 1, sizeof(ngx_table_elt_t *)) + != NGX_OK) { return NGX_ERROR; } @@ -188,6 +202,50 @@ ngx_http_headers_filter(ngx_http_request } } + if (conf->cache_control.len) { + + ccp = r->headers_out.cache_control.elts; + + if (ccp == NULL) { + + if (ngx_array_init(&r->headers_out.cache_control, r->pool, + 1, sizeof(ngx_table_elt_t *)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + ccp = ngx_array_push(&r->headers_out.cache_control); + if (ccp == NULL) { + return NGX_ERROR; + } + + cc = ngx_list_push(&r->headers_out.headers); + if (cc == NULL) { + return NGX_ERROR; + } + + cc->hash = 1; + cc->key.len = sizeof("Cache-Control") - 1; + cc->key.data = (u_char *) "Cache-Control"; + cc->value = conf->cache_control; + + *ccp = cc; + } + + if (conf->headers) { + h = conf->headers->elts; + for (i = 0; i < conf->headers->nelts; i++) { + out = ngx_list_push(&r->headers_out.headers); + if (out == NULL) { + return NGX_ERROR; + } + + *out = h[i]; + } + } + return ngx_http_next_header_filter(r); } @@ -207,11 +265,19 @@ ngx_http_headers_create_conf(ngx_conf_t { ngx_http_headers_conf_t *conf; - conf = ngx_palloc(cf->pool, sizeof(ngx_http_headers_conf_t)); + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_headers_conf_t)); if (conf == NULL) { return NGX_CONF_ERROR; } + /* + * set by ngx_pcalloc(): + * + * conf->cache_control.len = 0; + * conf->cache_control.data = NULL; + * conf->headers = NULL; + */ + conf->expires = NGX_HTTP_EXPIRES_UNSET; return conf; @@ -229,6 +295,14 @@ ngx_http_headers_merge_conf(ngx_conf_t * NGX_HTTP_EXPIRES_OFF : prev->expires; } + if (conf->cache_control.data == NULL) { + conf->cache_control = prev->cache_control; + } + + if (conf->headers == NULL) { + conf->headers = prev->headers; + } + return NGX_CONF_OK; } @@ -287,3 +361,38 @@ ngx_http_headers_expires(ngx_conf_t *cf, return NGX_CONF_OK; } + + +static char * +ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_headers_conf_t *hcf = conf; + + ngx_str_t *value; + ngx_table_elt_t *h; + + value = cf->args->elts; + + if (ngx_strcasecmp(value[1].data, "cache-control") == 0) { + hcf->cache_control = value[2]; + return NGX_CONF_OK; + } + + if (hcf->headers == NULL) { + hcf->headers = ngx_array_create(cf->pool, 1, sizeof(ngx_table_elt_t)); + if (hcf->headers == NULL) { + return NGX_CONF_ERROR; + } + } + + h = ngx_array_push(hcf->headers); + if (h == NULL) { + return NGX_CONF_ERROR; + } + + h->hash = 1; + h->key = value[1]; + h->value = value[2]; + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c @@ -180,6 +180,7 @@ ngx_http_index_handler(ngx_http_request_ e.ip = index[i].lengths->elts; e.request = r; + e.flushed = 1; /* 1 byte for terminating '\0' */ @@ -298,7 +299,7 @@ ngx_http_index_handler(ngx_http_request_ return NGX_HTTP_INTERNAL_SERVER_ERROR; } - last = ngx_cpymem(uri.data, r->uri.data, r->uri.len); + last = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(last, ctx->index.data, ctx->index.len - 1); } @@ -476,7 +477,7 @@ ngx_http_index_set_index(ngx_conf_t *cf, ilcf->max_index_len = index->name.len; } - /* include the terminating '\0' to the length to use ngx_memcpy() */ + /* include the terminating '\0' to the length to use ngx_copy() */ index->name.len++; continue; diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -10,6 +10,35 @@ #include + +typedef struct { + ngx_str_t name; + ngx_array_t *ops; /* array of ngx_http_log_op_t */ +} ngx_http_log_fmt_t; + +typedef struct { + ngx_array_t formats; /* array of ngx_http_log_fmt_t */ + ngx_uint_t combined_used; /* unsigned combined_used:1 */ +} 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_http_log_t; + +typedef struct { + ngx_array_t *logs; /* array of ngx_http_log_t */ + ngx_uint_t off; /* unsigned off:1 */ +} ngx_http_log_loc_conf_t; + + +typedef struct { + ngx_str_t name; + size_t len; + ngx_http_log_op_run_pt run; +} ngx_http_log_var_t; + + static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, @@ -24,10 +53,10 @@ static u_char *ngx_http_log_request_time ngx_http_log_op_t *op); static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); -static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf, +static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); -static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); +static u_char *ngx_http_log_apache_bytes_sent(ngx_http_request_t *r, + u_char *buf, ngx_http_log_op_t *op); static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); @@ -83,7 +112,9 @@ static char *ngx_http_log_set_log(ngx_co void *conf); static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static ngx_int_t ngx_http_log_init(ngx_cycle_t *cycle); +static char *ngx_http_log_compile_format(ngx_conf_t *cf, + ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s); +static ngx_int_t ngx_http_log_init(ngx_conf_t *cf); static ngx_command_t ngx_http_log_commands[] = { @@ -108,7 +139,7 @@ static ngx_command_t ngx_http_log_comma ngx_http_module_t ngx_http_log_module_ctx = { ngx_http_log_set_formats, /* preconfiguration */ - NULL, /* postconfiguration */ + ngx_http_log_init, /* postconfiguration */ ngx_http_log_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ @@ -127,7 +158,7 @@ ngx_module_t ngx_http_log_module = { ngx_http_log_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ - ngx_http_log_init, /* init module */ + NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ @@ -137,21 +168,34 @@ ngx_module_t ngx_http_log_module = { }; -static ngx_str_t http_access_log = ngx_string(NGX_HTTP_LOG_PATH); +static ngx_str_t http_access_log = ngx_string(NGX_HTTP_LOG_PATH); + + +static ngx_str_t ngx_http_combined_fmt = + ngx_string("$remote_addr - $remote_user [$time_gmt] " + "\"$request\" $status $apache_bytes_sent " + "\"$http_referer\" \"$http_user_agent\""); -static ngx_str_t ngx_http_combined_fmt = -#if 0 - ngx_string("$remote_addr - $remote_user [%time] " - "\"$request\" %status %apache_length " - "\"$http_referer\" \"$http_user_agent\""); -#endif - ngx_string("%addr - - [%time] " - "\"%request\" %status %apache_length " - "\"%{referer}i\" \"%{user-agent}i\""); +static ngx_http_log_var_t ngx_http_log_vars[] = { + { ngx_string("connection"), NGX_ATOMIC_T_LEN, ngx_http_log_connection }, + { ngx_string("pipe"), 1, ngx_http_log_pipe }, + { ngx_string("time_gmt"), sizeof("28/Sep/1970:12:00:00 +0600") - 1, + ngx_http_log_time }, + { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec }, + { ngx_string("request_time"), NGX_TIME_T_LEN, ngx_http_log_request_time }, + { ngx_string("status"), 3, ngx_http_log_status }, + { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent }, + { ngx_string("apache_bytes_sent"), NGX_OFF_T_LEN, + ngx_http_log_apache_bytes_sent }, + { ngx_string("request_length"), NGX_SIZE_T_LEN, + ngx_http_log_request_length }, + + { ngx_null_string, 0, NULL } +}; -ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = { +ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = { { ngx_string("addr"), INET_ADDRSTRLEN - 1, NULL, NULL, ngx_http_log_addr }, { ngx_string("conn"), NGX_ATOMIC_T_LEN, NULL, NULL, ngx_http_log_connection }, @@ -162,9 +206,10 @@ ngx_http_log_op_name_t ngx_http_log_fmt_ { ngx_string("request_time"), NGX_TIME_T_LEN, NULL, NULL, ngx_http_log_request_time }, { 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("length"), NGX_OFF_T_LEN, + NULL, NULL, ngx_http_log_bytes_sent }, { ngx_string("apache_length"), NGX_OFF_T_LEN, - NULL, NULL, ngx_http_log_apache_length }, + NULL, NULL, ngx_http_log_apache_bytes_sent }, { ngx_string("request_length"), NGX_SIZE_T_LEN, NULL, NULL, ngx_http_log_request_length }, @@ -376,14 +421,15 @@ ngx_http_log_status(ngx_http_request_t * static u_char * -ngx_http_log_length(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) +ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf, + 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, +ngx_http_log_apache_bytes_sent(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) { off_t length; @@ -792,14 +838,11 @@ ngx_http_log_variable_getlen(ngx_http_re value = ngx_http_get_indexed_variable(r, data); - if (value == NULL - || value == NGX_HTTP_VAR_NOT_FOUND - || value->text.len == 0) - { + if (value == NULL || value->not_found) { return 1; } - return value->text.len; + return value->len; } @@ -810,15 +853,12 @@ ngx_http_log_variable(ngx_http_request_t value = ngx_http_get_indexed_variable(r, op->data); - if (value == NULL - || value == NGX_HTTP_VAR_NOT_FOUND - || value->text.len == 0) - { + if (value == NULL || value->not_found) { *buf = '-'; return buf + 1; } - return ngx_cpymem(buf, value->text.data, value->text.len); + return ngx_cpymem(buf, value->data, value->len); } @@ -839,8 +879,7 @@ ngx_http_log_create_main_conf(ngx_conf_t { ngx_http_log_main_conf_t *conf; - char *rc; - ngx_str_t *value; + ngx_http_log_fmt_t *fmt; conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t)); if (conf == NULL) { @@ -848,38 +887,21 @@ ngx_http_log_create_main_conf(ngx_conf_t } if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t)) - == NGX_ERROR) + != NGX_OK) { return NGX_CONF_ERROR; } - cf->args->nelts = 0; - - value = ngx_array_push(cf->args); - if (value == NULL) { + fmt = ngx_array_push(&conf->formats); + if (fmt == NULL) { return NGX_CONF_ERROR; } - value->len = 0; - value->data = NULL; - - value = ngx_array_push(cf->args); - if (value == NULL) { - return NGX_CONF_ERROR; - } + fmt->name.len = sizeof("combined") - 1; + fmt->name.data = (u_char *) "combined"; - value->len = sizeof("combined") - 1; - value->data = (u_char *) "combined"; - - value = ngx_array_push(cf->args); - if (value == NULL) { - return NGX_CONF_ERROR; - } - - *value = ngx_http_combined_fmt; - - rc = ngx_http_log_set_format(cf, NULL, conf); - if (rc != NGX_CONF_OK) { + fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t)); + if (fmt->ops == NULL) { return NGX_CONF_ERROR; } @@ -947,6 +969,7 @@ ngx_http_log_merge_loc_conf(ngx_conf_t * /* the default "combined" format */ log->ops = fmt[0].ops; + lmcf->combined_used = 1; } } @@ -997,6 +1020,7 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx } else { name.len = sizeof("combined") - 1; name.data = (u_char *) "combined"; + lmcf->combined_used = 1; } fmt = lmcf->formats.elts; @@ -1058,20 +1082,16 @@ ngx_http_log_set_format(ngx_conf_t *cf, { ngx_http_log_main_conf_t *lmcf = conf; - u_char *data, *p, *fname, ch; - size_t i, len, fname_len; - ngx_str_t *value, var, arg, *a; - ngx_uint_t s, f, bracket; - ngx_http_log_op_t *op; - ngx_http_log_fmt_t *fmt; - ngx_http_log_op_name_t *name; + ngx_str_t *value; + ngx_uint_t i; + ngx_http_log_fmt_t *fmt; value = cf->args->elts; fmt = lmcf->formats.elts; - for (f = 0; f < lmcf->formats.nelts; f++) { - if (fmt[f].name.len == value[1].len - && ngx_strcmp(fmt->name.data, value[1].data) == 0) + for (i = 0; i < lmcf->formats.nelts; i++) { + if (fmt[i].name.len == value[1].len + && ngx_strcmp(fmt[i].name.data, value[1].data) == 0) { return "duplicate \"log_format\" name"; } @@ -1084,20 +1104,38 @@ ngx_http_log_set_format(ngx_conf_t *cf, fmt->name = value[1]; - fmt->ops = ngx_array_create(cf->pool, 20, sizeof(ngx_http_log_op_t)); + fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t)); if (fmt->ops == NULL) { return NGX_CONF_ERROR; } - arg.data = NULL; + return ngx_http_log_compile_format(cf, fmt->ops, cf->args, 2); +} + - for (s = 2; s < cf->args->nelts; s++) { +static char * +ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops, + ngx_array_t *args, ngx_uint_t s) +{ + u_char *data, *p, *fname, *arg_data, ch; + size_t i, len, fname_len, arg_len; + ngx_str_t *value, var, *a; + ngx_uint_t bracket; + ngx_http_log_op_t *op; + ngx_http_log_var_t *v; + ngx_http_log_op_name_t *name; + static ngx_uint_t warn; + + value = args->elts; + arg_data = NULL; + + for ( /* void */ ; s < args->nelts; s++) { i = 0; while (i < value[s].len) { - op = ngx_array_push(fmt->ops); + op = ngx_array_push(ops); if (op == NULL) { return NGX_CONF_ERROR; } @@ -1114,22 +1152,29 @@ ngx_http_log_set_format(ngx_conf_t *cf, if (value[s].data[i] == '{') { i++; - arg.data = &value[s].data[i]; + arg_data = &value[s].data[i]; while (i < value[s].len && value[s].data[i] != '}') { i++; } - arg.len = &value[s].data[i] - arg.data; + arg_len = &value[s].data[i] - arg_data; - if (i == value[s].len || arg.len == 0) { + if (i == value[s].len || arg_len == 0) { goto invalid; } i++; } else { - arg.len = 0; + arg_len = 0; + } + + if (warn == 0) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "the parameters in the \"%%name\" form are deprecated, " + "use the \"$variable\" instead"); + warn = 1; } fname = &value[s].data[i]; @@ -1156,7 +1201,7 @@ ngx_http_log_set_format(ngx_conf_t *cf, && ngx_strncmp(name->name.data, fname, fname_len) == 0) { if (name->compile == NULL) { - if (arg.len) { + if (arg_len) { fname[fname_len] = '\0'; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%s\" must not have argument", @@ -1172,7 +1217,7 @@ ngx_http_log_set_format(ngx_conf_t *cf, break; } - if (arg.len == 0) { + if (arg_len == 0) { fname[fname_len] = '\0'; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"%s\" requires argument", @@ -1185,7 +1230,9 @@ ngx_http_log_set_format(ngx_conf_t *cf, return NGX_CONF_ERROR; } - *a = arg; + a->len = arg_len; + a->data = arg_data; + if (name->compile(cf, op, a) == NGX_ERROR) { return NGX_CONF_ERROR; } @@ -1198,6 +1245,8 @@ ngx_http_log_set_format(ngx_conf_t *cf, goto invalid; } + continue; + } else if (value[s].data[i] == '$') { if (++i == value[s].len) { @@ -1249,47 +1298,64 @@ ngx_http_log_set_format(ngx_conf_t *cf, goto invalid; } + for (v = ngx_http_log_vars; v->name.len; v++) { + + if (v->name.len == var.len + && ngx_strncmp(v->name.data, var.data, var.len) == 0) + { + op->len = v->len; + op->getlen = NULL; + op->run = v->run; + op->data = 0; + + goto found; + } + } + if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) { return NGX_CONF_ERROR; } - } else { - i++; + found: + + continue; + } + + i++; - while (i < value[s].len - && value[s].data[i] != '$' - && value[s].data[i] != '%') - { - i++; - } + while (i < value[s].len + && value[s].data[i] != '$' + && value[s].data[i] != '%') + { + i++; + } - len = &value[s].data[i] - data; + len = &value[s].data[i] - data; - if (len) { - - op->len = len; - op->getlen = NULL; + if (len) { - if (len <= sizeof(uintptr_t)) { - op->run = ngx_http_log_copy_short; - op->data = 0; + op->len = len; + op->getlen = NULL; - while (len--) { - op->data <<= 8; - op->data |= data[len]; - } + if (len <= sizeof(uintptr_t)) { + op->run = ngx_http_log_copy_short; + op->data = 0; - } else { - op->run = ngx_http_log_copy_long; + while (len--) { + op->data <<= 8; + op->data |= data[len]; + } + + } else { + op->run = ngx_http_log_copy_long; - p = ngx_palloc(cf->pool, len); - if (p == NULL) { - return NGX_CONF_ERROR; - } + p = ngx_palloc(cf->pool, len); + if (p == NULL) { + return NGX_CONF_ERROR; + } - ngx_memcpy(p, data, len); - op->data = (uintptr_t) p; - } + ngx_memcpy(p, data, len); + op->data = (uintptr_t) p; } } } @@ -1306,11 +1372,37 @@ invalid: static ngx_int_t -ngx_http_log_init(ngx_cycle_t *cycle) +ngx_http_log_init(ngx_conf_t *cf) { + ngx_str_t *value; + ngx_array_t a; + ngx_http_log_fmt_t *fmt; + ngx_http_log_main_conf_t *lmcf; ngx_http_core_main_conf_t *cmcf; - cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); + + if (lmcf->combined_used) { + if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) { + return NGX_ERROR; + } + + value = ngx_array_push(&a); + if (value == NULL) { + return NGX_ERROR; + } + + *value = ngx_http_combined_fmt; + fmt = lmcf->formats.elts; + + if (ngx_http_log_compile_format(cf, fmt->ops, &a, 0) + != NGX_CONF_OK) + { + return NGX_ERROR; + } + } + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); cmcf->log_handler = ngx_http_log_handler; diff --git a/src/http/modules/ngx_http_log_module.h b/src/http/modules/ngx_http_log_module.h --- a/src/http/modules/ngx_http_log_module.h +++ b/src/http/modules/ngx_http_log_module.h @@ -35,12 +35,6 @@ struct ngx_http_log_op_s { typedef struct { 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_compile_pt compile; ngx_http_log_op_getlen_pt getlen; @@ -48,23 +42,6 @@ typedef struct { } ngx_http_log_op_name_t; -typedef struct { - 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_http_log_t; - - -typedef struct { - ngx_array_t *logs; /* array of ngx_http_log_t */ - ngx_uint_t off; /* unsigned off:1 */ -} ngx_http_log_loc_conf_t; - - extern ngx_http_log_op_name_t ngx_http_log_fmt_ops[]; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -37,6 +37,7 @@ typedef struct { ngx_peers_t *peers; + ngx_array_t *flushes; ngx_array_t *headers_set_len; ngx_array_t *headers_set; ngx_hash_t *headers_set_hash; @@ -75,13 +76,13 @@ static void ngx_http_proxy_abort_request static void ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc); -static ngx_http_variable_value_t * - ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * +static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, - uintptr_t data); + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix); @@ -431,7 +432,7 @@ ngx_http_proxy_create_request(ngx_http_r escape = 0; - loc_len = r->valid_location ? u->conf->location->len : 0; + loc_len = r->valid_location ? u->conf->location.len : 0; if (u->conf->uri.len == 0 && r->valid_unparsed_uri) { len += r->unparsed_uri.len; @@ -447,8 +448,11 @@ ngx_http_proxy_create_request(ngx_http_r ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); + ngx_http_script_flush_no_cachable_variables(r, plcf->flushes); + le.ip = plcf->headers_set_len->elts; le.request = r; + le.flushed = 1; while (*(uintptr_t *) le.ip) { while (*(uintptr_t *) le.ip) { @@ -506,16 +510,16 @@ ngx_http_proxy_create_request(ngx_http_r /* the request line */ - b->last = ngx_cpymem(b->last, method.data, method.len); + b->last = ngx_copy(b->last, method.data, method.len); u->uri.data = b->last; if (u->conf->uri.len == 0 && r->valid_unparsed_uri) { - b->last = ngx_cpymem(b->last, r->unparsed_uri.data, - r->unparsed_uri.len); + b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len); + } else { if (r->valid_location) { - b->last = ngx_cpymem(b->last, u->conf->uri.data, u->conf->uri.len); + b->last = ngx_copy(b->last, u->conf->uri.data, u->conf->uri.len); } if (escape) { @@ -524,13 +528,13 @@ ngx_http_proxy_create_request(ngx_http_r b->last += r->uri.len - loc_len + escape; } else { - b->last = ngx_cpymem(b->last, r->uri.data + loc_len, - r->uri.len - loc_len); + b->last = ngx_copy(b->last, r->uri.data + loc_len, + r->uri.len - loc_len); } if (r->args.len > 0) { *b->last++ = '?'; - b->last = ngx_cpymem(b->last, r->args.data, r->args.len); + b->last = ngx_copy(b->last, r->args.data, r->args.len); } } @@ -543,6 +547,7 @@ ngx_http_proxy_create_request(ngx_http_r e.ip = plcf->headers_set->elts; e.pos = b->last; e.request = r; + e.flushed = 1; le.ip = plcf->headers_set_len->elts; @@ -600,13 +605,12 @@ ngx_http_proxy_create_request(ngx_http_r continue; } - b->last = ngx_cpymem(b->last, header[i].key.data, - header[i].key.len); + b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); *b->last++ = ':'; *b->last++ = ' '; - b->last = ngx_cpymem(b->last, header[i].value.data, - header[i].value.len); + b->last = ngx_copy(b->last, header[i].value.data, + header[i].value.len); *b->last++ = CR; *b->last++ = LF; @@ -735,6 +739,7 @@ ngx_http_proxy_process_status_line(ngx_h if (u->headers_in.status_line.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } + ngx_memcpy(u->headers_in.status_line.data, p->status_start, u->headers_in.status_line.len); @@ -1054,83 +1059,77 @@ ngx_http_proxy_finalize_request(ngx_http } -static ngx_http_variable_value_t * -ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_proxy_host_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_variable_value_t *vv; ngx_http_proxy_loc_conf_t *plcf; - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } - plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - vv->value = 0; - vv->text = plcf->host_header; + v->len = plcf->host_header.len; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = plcf->host_header.data; - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_proxy_port_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_variable_value_t *vv; ngx_http_proxy_loc_conf_t *plcf; - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } - plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); - vv->value = 0; - vv->text = plcf->port_text; + v->len = plcf->port_text.len; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = plcf->port_text.data; - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * +static ngx_int_t ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, - uintptr_t data) + + ngx_http_variable_value_t *v, uintptr_t data) { - u_char *p; - ngx_http_variable_value_t *vv; + u_char *p; - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } - - vv->value = 0; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; if (r->headers_in.x_forwarded_for == NULL) { - vv->text = r->connection->addr_text; - return vv; + v->len = r->connection->addr_text.len; + v->data = r->connection->addr_text.data; + return NGX_OK; } - vv->text.len = r->headers_in.x_forwarded_for->value.len - + sizeof(", ") - 1 + r->connection->addr_text.len; + v->len = r->headers_in.x_forwarded_for->value.len + + sizeof(", ") - 1 + r->connection->addr_text.len; - p = ngx_palloc(r->pool, vv->text.len); + p = ngx_palloc(r->pool, v->len); if (p == NULL) { - return NULL; + return NGX_ERROR; } - vv->text.data = p; + v->data = p; - p = ngx_cpymem(p, r->headers_in.x_forwarded_for->value.data, - r->headers_in.x_forwarded_for->value.len); + p = ngx_copy(p, r->headers_in.x_forwarded_for->value.data, + r->headers_in.x_forwarded_for->value.len); *p++ = ','; *p++ = ' '; ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len); - return vv; + return NGX_OK; } @@ -1186,11 +1185,9 @@ ngx_http_proxy_rewrite_redirect_text(ngx p = data; - if (prefix) { - p = ngx_cpymem(p, h->value.data, prefix); - } + p = ngx_copy(p, h->value.data, prefix); - p = ngx_cpymem(p, pr->replacement.text.data, pr->replacement.text.len); + p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len); ngx_memcpy(p, h->value.data + prefix + pr->redirect.len, h->value.len - pr->redirect.len - prefix); @@ -1235,9 +1232,7 @@ ngx_http_proxy_rewrite_redirect_vars(ngx p = data; - if (prefix) { - p = ngx_cpymem(p, h->value.data, prefix); - } + p = ngx_copy(p, h->value.data, prefix); e.ip = pr->replacement.vars.values; e.pos = p; @@ -1530,7 +1525,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t pr->handler = ngx_http_proxy_rewrite_redirect_text; pr->redirect = conf->upstream.url; - pr->replacement.text = *conf->upstream.location; + pr->replacement.text = conf->upstream.location; } } @@ -1540,10 +1535,11 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t } if (conf->headers_source == NULL) { - conf->headers_source = prev->headers_source; + conf->flushes = prev->flushes; conf->headers_set_len = prev->headers_set_len; conf->headers_set = prev->headers_set; conf->headers_set_hash = prev->headers_set_hash; + conf->headers_source = prev->headers_source; } if (conf->headers_set_hash) { @@ -1680,6 +1676,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t sc.cf = cf; sc.source = &src[i].value; + sc.flushes = &conf->flushes; sc.lengths = &conf->headers_set_len; sc.values = &conf->headers_set; @@ -1843,15 +1840,19 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ clcf->handler = ngx_http_proxy_handler; - plcf->upstream.location = &clcf->name; + plcf->upstream.location = clcf->name; #if (NGX_PCRE) - if (clcf->regex && plcf->upstream.uri.len) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"proxy_pass\" may not have URI part in " - "location given by regular expression"); - return NGX_CONF_ERROR; + if (clcf->regex) { + if (plcf->upstream.uri.len) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_pass\" may not have URI part in " + "location given by regular expression"); + return NGX_CONF_ERROR; + } + + plcf->upstream.location.len = 0; } #endif @@ -1911,7 +1912,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, pr->handler = ngx_http_proxy_rewrite_redirect_text; pr->redirect = plcf->upstream.url; - pr->replacement.text = *plcf->upstream.location; + pr->replacement.text = plcf->upstream.location; return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_realip_module.c @@ -0,0 +1,275 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +/* AF_INET only */ + +typedef struct { + in_addr_t mask; + in_addr_t addr; +} ngx_http_realip_from_t; + + +typedef struct { + ngx_array_t *from; /* array of ngx_http_realip_from_t */ + + ngx_uint_t xfwd; +} ngx_http_realip_loc_conf_t; + + +static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r); +static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_http_realip_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_http_realip_init(ngx_cycle_t *cycle); + + +static ngx_conf_enum_t ngx_http_realip_header[] = { + { ngx_string("X-Forwarded-For"), 1 }, + { ngx_string("X-Real-IP"), 0 }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_realip_commands[] = { + + { ngx_string("set_real_ip_from"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_realip_from, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("real_ip_header"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_realip_loc_conf_t, xfwd), + &ngx_http_realip_header }, + + ngx_null_command +}; + + + +ngx_http_module_t ngx_http_realip_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_realip_create_loc_conf, /* create location configuration */ + ngx_http_realip_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_realip_module = { + NGX_MODULE_V1, + &ngx_http_realip_module_ctx, /* module context */ + ngx_http_realip_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + ngx_http_realip_init, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_realip_handler(ngx_http_request_t *r) +{ + u_char *ip, *p; + size_t len; + ngx_uint_t i; + struct sockaddr_in *sin; + ngx_http_realip_from_t *from; + ngx_http_realip_loc_conf_t *rlcf; + + if (r->realip_set) { + return NGX_OK; + } + + rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module); + + if (rlcf->from == NULL) { + return NGX_OK; + } + + if (rlcf->xfwd == 0) { + if (r->headers_in.x_real_ip == NULL) { + return NGX_OK; + } + + len = r->headers_in.x_real_ip->value.len; + ip = r->headers_in.x_real_ip->value.data; + + } else { + if (r->headers_in.x_forwarded_for == NULL) { + return NGX_OK; + } + + len = r->headers_in.x_forwarded_for->value.len; + ip = r->headers_in.x_forwarded_for->value.data; + + for (p = ip + len; p > ip; p--) { + if (*p == ' ' || *p == ',') { + p++; + len -= p - ip; + ip = p; + break; + } + } + } + + /* AF_INET only */ + + sin = (struct sockaddr_in *) r->connection->sockaddr; + + from = rlcf->from->elts; + for (i = 0; i < rlcf->from->nelts; i++) { + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "realip: %08XD %08XD %08XD", + sin->sin_addr.s_addr, from[i].mask, from[i].addr); + + if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) { + + r->connection->addr_text.len = len; + r->connection->addr_text.data = ip; + + sin->sin_addr.s_addr = inet_addr((char *) ip); + + r->realip_set = 1; + + return NGX_OK; + } + } + + return NGX_OK; +} + + +static char * +ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_realip_loc_conf_t *rlcf = conf; + + ngx_str_t *value; + ngx_inet_cidr_t in_cidr; + ngx_http_realip_from_t *from; + + if (rlcf->from == NULL) { + rlcf->from = ngx_array_create(cf->pool, 2, + sizeof(ngx_http_realip_from_t)); + if (rlcf->from == NULL) { + return NGX_CONF_ERROR; + } + } + + from = ngx_array_push(rlcf->from); + if (from == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + from->addr = inet_addr((char *) value[1].data); + + if (from->addr != INADDR_NONE) { + from->mask = 0xffffffff; + + return NGX_CONF_OK; + } + + if (ngx_ptocidr(&value[1], &in_cidr) == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", + &value[1]); + return NGX_CONF_ERROR; + } + + from->mask = in_cidr.mask; + from->addr = in_cidr.addr; + + return NGX_CONF_OK; +} + + +static void * +ngx_http_realip_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_realip_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->from = NULL; + */ + + conf->xfwd = NGX_CONF_UNSET_UINT; + + return conf; +} + + +static char * +ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_realip_loc_conf_t *prev = parent; + ngx_http_realip_loc_conf_t *conf = child; + + if (conf->from == NULL) { + conf->from = prev->from; + } + + ngx_conf_merge_unsigned_value(conf->xfwd, prev->xfwd, 0); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_realip_init(ngx_cycle_t *cycle) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_realip_handler; + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_realip_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -142,7 +142,7 @@ ngx_module_t ngx_http_rewrite_module = static ngx_http_variable_value_t ngx_http_rewrite_null_value = - { 0, ngx_string("") }; + ngx_http_variable(""); static ngx_int_t @@ -214,9 +214,8 @@ ngx_http_rewrite_invalid_referer_code(ng e->ip += sizeof(uintptr_t); if (cf->referers == NULL) { - e->sp->value = 0; - e->sp->text.len = 0; - e->sp->text.data = (u_char *) ""; + e->sp->data = (u_char *) ""; + e->sp->len = 0; e->sp++; return; @@ -224,17 +223,15 @@ ngx_http_rewrite_invalid_referer_code(ng if (r->headers_in.referer == NULL) { if (cf->no_referer) { - e->sp->value = 0; - e->sp->text.len = 0; - e->sp->text.data = (u_char *) ""; + e->sp->data = (u_char *) ""; + e->sp->len = 0; e->sp++; return; } else { - e->sp->value = 1; - e->sp->text.len = 1; - e->sp->text.data = (u_char *) "1"; + e->sp->data = (u_char *) "1"; + e->sp->len = 1; e->sp++; return; @@ -248,17 +245,15 @@ ngx_http_rewrite_invalid_referer_code(ng || (ngx_strncasecmp(ref, "http://", 7) != 0)) { if (cf->blocked_referer) { - e->sp->value = 0; - e->sp->text.len = 0; - e->sp->text.data = (u_char *) "0"; + e->sp->data = (u_char *) ""; + e->sp->len = 0; e->sp++; return; } else { - e->sp->value = 1; - e->sp->text.len = 1; - e->sp->text.data = (u_char *) "1"; + e->sp->data = (u_char *) "1"; + e->sp->len = 1; e->sp++; return; @@ -288,9 +283,8 @@ ngx_http_rewrite_invalid_referer_code(ng if (ngx_strncmp(&ref[n], refs[i].name.data, refs[i].name.len) == 0) { - e->sp->value = 0; - e->sp->text.len = 0; - e->sp->text.data = (u_char *) ""; + e->sp->data = (u_char *) ""; + e->sp->len = 0; e->sp++; return; @@ -300,9 +294,8 @@ ngx_http_rewrite_invalid_referer_code(ng } else { if (ngx_strncasecmp(refs[i].name.data, ref, refs[i].name.len) == 0) { - e->sp->value = 0; - e->sp->text.len = 0; - e->sp->text.data = (u_char *) ""; + e->sp->data = (u_char *) ""; + e->sp->len = 0; e->sp++; return; @@ -310,15 +303,15 @@ ngx_http_rewrite_invalid_referer_code(ng } } - e->sp->value = 1; - e->sp->text.len = 1; - e->sp->text.data = (u_char *) "1"; + e->sp->data = (u_char *) "1"; + e->sp->len = 1; e->sp++; } -static ngx_http_variable_value_t * -ngx_http_rewrite_var(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) { ngx_http_variable_t *var; ngx_http_core_main_conf_t *cmcf; @@ -336,7 +329,9 @@ ngx_http_rewrite_var(ngx_http_request_t ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "using uninitialized \"%V\" variable", &var[data].name); - return &ngx_http_rewrite_null_value; + *v = ngx_http_rewrite_null_value; + + return NGX_OK; } @@ -411,6 +406,13 @@ ngx_http_rewrite_init(ngx_cycle_t *cycle cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); + h = ngx_array_push(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_rewrite_handler; + h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); if (h == NULL) { return NGX_ERROR; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -144,8 +144,8 @@ static ngx_int_t ngx_http_ssi_else(ngx_h static ngx_int_t ngx_http_ssi_endif(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); -static ngx_http_variable_value_t * - ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt); +static ngx_int_t ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t gmt); static char *ngx_http_ssi_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -562,6 +562,8 @@ ngx_http_ssi_body_filter(ngx_http_reques } + b = NULL; + if (rc == NGX_OK) { for (cmd = ngx_http_ssi_commands; cmd->handler; cmd++) { @@ -1200,10 +1202,12 @@ ngx_http_ssi_parse(ngx_http_request_t *r } if (ch == '"' && state == ssi_double_quoted_value_state) { + ctx->param->value.data[ctx->param->value.len - 1] = ch; break; } if (ch == '\'' && state == ssi_quoted_value_state) { + ctx->param->value.data[ctx->param->value.len - 1] = ch; break; } @@ -1378,9 +1382,9 @@ static ngx_int_t ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t *text, ngx_uint_t flags) { - u_char ch, *p, **value, *data; - size_t *size, len, prefix; - ngx_str_t var, part, *val; + u_char ch, *p, **value, *data, *part_data; + size_t *size, len, prefix, part_len; + ngx_str_t var, *val; ngx_uint_t i, j, n, bracket; ngx_array_t lengths, values; ngx_http_variable_value_t *vv; @@ -1408,7 +1412,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re return NGX_ERROR; } - p = ngx_cpymem(data, r->uri.data, prefix); + p = ngx_copy(data, r->uri.data, prefix); ngx_memcpy(p, text->data, text->len); text->len = len; @@ -1498,20 +1502,22 @@ ngx_http_ssi_evaluate_string(ngx_http_re return NGX_ERROR; } - if (vv == NGX_HTTP_VAR_NOT_FOUND) { + if (vv->not_found) { continue; } - part = vv->text; + part_data = vv->data; + part_len = vv->len; } else { - part = *val; + part_data = val->data; + part_len = val->len; } } else { - part.data = &text->data[i]; - - for (p = part.data; i < text->len; i++) { + part_data = &text->data[i]; + + for (p = part_data; i < text->len; i++) { ch = text->data[i]; if (ch == '$') { @@ -1527,24 +1533,24 @@ ngx_http_ssi_evaluate_string(ngx_http_re *p++ = ch; } - part.len = p - part.data; + part_len = p - part_data; } - len += part.len; + len += part_len; size = ngx_array_push(&lengths); if (size == NULL) { return NGX_ERROR; } - *size = part.len; + *size = part_len; value = ngx_array_push(&values); if (value == NULL) { return NGX_ERROR; } - *value = part.data; + *value = part_data; } prefix = 0; @@ -1577,12 +1583,10 @@ ngx_http_ssi_evaluate_string(ngx_http_re text->len = len; text->data = p; - if (prefix) { - p = ngx_cpymem(p, r->uri.data, prefix); - } + p = ngx_copy(p, r->uri.data, prefix); for (i = 0; i < values.nelts; i++) { - p = ngx_cpymem(p, value[i], size[i]); + p = ngx_copy(p, value[i], size[i]); } return NGX_OK; @@ -1601,7 +1605,7 @@ ngx_http_ssi_include(ngx_http_request_t ngx_str_t **params) { ngx_str_t *uri, *file, args; - ngx_uint_t i; + ngx_uint_t flags; uri = params[NGX_HTTP_SSI_INCLUDE_VIRTUAL]; file = params[NGX_HTTP_SSI_INCLUDE_FILE]; @@ -1631,20 +1635,16 @@ ngx_http_ssi_include(ngx_http_request_t args.len = 0; args.data = NULL; - - if (params[NGX_HTTP_SSI_INCLUDE_VIRTUAL]) { - for (i = 0; i < uri->len; i++) { - if (uri->data[i] == '?') { - args.len = uri->len - i - 1; - args.data = &uri->data[i + 1]; - uri->len -= args.len + 1; - - break; - } - } + flags = 0; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "ssi include: \"%V\"", uri); + + if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { + return NGX_HTTP_SSI_ERROR; } - if (ngx_http_subrequest(r, uri, &args) != NGX_OK) { + if (ngx_http_subrequest(r, uri, &args, flags) != NGX_OK) { return NGX_HTTP_SSI_ERROR; } @@ -1658,7 +1658,7 @@ ngx_http_ssi_echo(ngx_http_request_t *r, { ngx_uint_t i; ngx_buf_t *b; - ngx_str_t *var, *value; + ngx_str_t *var, *value, text; ngx_chain_t *cl; ngx_http_variable_value_t *vv; @@ -1677,8 +1677,10 @@ ngx_http_ssi_echo(ngx_http_request_t *r, return NGX_HTTP_SSI_ERROR; } - if (vv != NGX_HTTP_VAR_NOT_FOUND) { - value = &vv->text; + if (!vv->not_found) { + text.data = vv->data; + text.len = vv->len; + value = &text; } } @@ -1817,7 +1819,8 @@ ngx_http_ssi_if(ngx_http_request_t *r, n if ((*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') - || *p == '$' || *p == '{' || *p == '}' || *p == '_') + || *p == '$' || *p == '{' || *p == '}' || *p == '_' + || *p == '"' || *p == '\'') { continue; } @@ -1971,19 +1974,18 @@ ngx_http_ssi_endif(ngx_http_request_t *r } -static ngx_http_variable_value_t * -ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt) +static ngx_int_t +ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t gmt) { - ngx_http_ssi_ctx_t *ctx; - ngx_http_variable_value_t *vv; - ngx_time_t *tp; - struct tm tm; - char buf[NGX_HTTP_SSI_DATE_LEN]; - - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } + ngx_http_ssi_ctx_t *ctx; + ngx_time_t *tp; + struct tm tm; + char buf[NGX_HTTP_SSI_DATE_LEN]; + + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; tp = ngx_timeofday(); @@ -1992,16 +1994,14 @@ ngx_http_ssi_date_gmt_local_variable(ngx if (ctx->timefmt.len == sizeof("%s") - 1 && ctx->timefmt.data[0] == '%' && ctx->timefmt.data[1] == 's') { - vv->value = tp->sec + (gmt ? 0 : tp->gmtoff); - - vv->text.data = ngx_palloc(r->pool, NGX_TIME_T_LEN); - if (vv->text.data == NULL) { - return NULL; + v->data = ngx_palloc(r->pool, NGX_TIME_T_LEN); + if (v->data == NULL) { + return NGX_ERROR; } - vv->text.len = ngx_sprintf(vv->text.data, "%T", vv->value) - - vv->text.data; - return vv; + v->len = ngx_sprintf(v->data, "%T", tp->sec + (gmt ? 0 : tp->gmtoff)) + - v->data; + return NGX_OK; } if (gmt) { @@ -2010,22 +2010,20 @@ ngx_http_ssi_date_gmt_local_variable(ngx ngx_libc_localtime(tp->sec, &tm); } - vv->value = tp->sec + (gmt ? 0 : tp->gmtoff); - - vv->text.len = strftime(buf, NGX_HTTP_SSI_DATE_LEN, - (char *) ctx->timefmt.data, &tm); - if (vv->text.len == 0) { - return NULL; + v->len = strftime(buf, NGX_HTTP_SSI_DATE_LEN, + (char *) ctx->timefmt.data, &tm); + if (v->len == 0) { + return NGX_ERROR; } - vv->text.data = ngx_palloc(r->pool, vv->text.len); - if (vv->text.data == NULL) { - return NULL; + v->data = ngx_palloc(r->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; } - ngx_memcpy(vv->text.data, buf, vv->text.len); - - return vv; + ngx_memcpy(v->data, buf, v->len); + + return NGX_OK; } 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,6 +8,7 @@ #include #include + #define NGX_DEFLAUT_CERTIFICATE "cert.pem" #define NGX_DEFLAUT_CERTIFICATE_KEY "cert.pem" #define NGX_DEFLAUT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" @@ -84,6 +85,13 @@ static ngx_command_t ngx_http_ssl_comma ngx_http_ssl_nosupported, 0, 0, ngx_http_ssl_openssl097 }, #endif + { ngx_string("ssl_session_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_sec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, session_timeout), + NULL }, + ngx_null_command }; @@ -146,6 +154,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t */ scf->enable = NGX_CONF_UNSET; + scf->session_timeout = NGX_CONF_UNSET; scf->prefer_server_ciphers = NGX_CONF_UNSET; return scf; @@ -166,6 +175,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * return NGX_CONF_OK; } + ngx_conf_merge_value(conf->session_timeout, + prev->session_timeout, 300); + ngx_conf_merge_value(conf->prefer_server_ciphers, prev->prefer_server_ciphers, 0); @@ -229,6 +241,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * SSL_CTX_set_session_id_context(conf->ssl.ctx, ngx_http_session_id_ctx, sizeof(ngx_http_session_id_ctx) - 1); + SSL_CTX_set_timeout(conf->ssl.ctx, conf->session_timeout); + return NGX_CONF_OK; } 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 @@ -22,6 +22,8 @@ typedef struct { ngx_uint_t protocols; + time_t session_timeout; + ngx_str_t certificate; ngx_str_t certificate_key; @@ -29,14 +31,6 @@ typedef struct { } ngx_http_ssl_srv_conf_t; -ngx_int_t ngx_http_ssl_read(ngx_http_request_t *r, u_char *buf, size_t size); -ngx_int_t ngx_http_ssl_shutdown(ngx_http_request_t *r); -ngx_chain_t *ngx_http_ssl_write(ngx_connection_t *c, ngx_chain_t *in, - off_t limit); - -void ngx_http_ssl_close_connection(SSL *ssl, ngx_log_t *log); - - extern ngx_module_t ngx_http_ssl_module; diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -195,7 +195,7 @@ ngx_http_static_handler(ngx_http_request return NGX_HTTP_INTERNAL_SERVER_ERROR; } - last = ngx_cpymem(location, r->uri.data, r->uri.len); + last = ngx_copy(location, r->uri.data, r->uri.len); } *last = '/'; diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -55,7 +55,10 @@ static size_t ngx_http_userid_log_uid_se static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, 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_add_variables(ngx_conf_t *cf); +static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle); static void *ngx_http_userid_create_conf(ngx_conf_t *cf); static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, @@ -158,7 +161,7 @@ static ngx_command_t ngx_http_userid_co ngx_http_module_t ngx_http_userid_filter_module_ctx = { - ngx_http_userid_add_log_formats, /* preconfiguration */ + ngx_http_userid_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -199,6 +202,10 @@ static ngx_http_log_op_name_t ngx_http_u }; +static ngx_str_t ngx_http_userid_got = ngx_string("uid_got"); +static ngx_str_t ngx_http_userid_set = ngx_string("uid_set"); + + static ngx_int_t ngx_http_userid_filter(ngx_http_request_t *r) { @@ -387,7 +394,7 @@ ngx_http_userid_set_uid(ngx_http_request return NGX_ERROR; } - p = ngx_cpymem(cookie, conf->name.data, conf->name.len); + p = ngx_copy(cookie, conf->name.data, conf->name.len); *p++ = '='; if (ctx->uid_got[3] == 0) { @@ -417,11 +424,9 @@ ngx_http_userid_set_uid(ngx_http_request p = ngx_http_cookie_time(p, ngx_time() + conf->expires); } - if (conf->domain.len) { - p = ngx_cpymem(p, conf->domain.data, conf->domain.len); - } + p = ngx_copy(p, conf->domain.data, conf->domain.len); - p = ngx_cpymem(p, conf->path.data, conf->path.len); + p = ngx_copy(p, conf->path.data, conf->path.len); set_cookie = ngx_list_push(&r->headers_out.headers); if (set_cookie == NULL) { @@ -489,7 +494,7 @@ ngx_http_userid_log_uid_got(ngx_http_req conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - buf = ngx_cpymem(buf, conf->name.data, conf->name.len); + buf = ngx_copy(buf, conf->name.data, conf->name.len); *buf++ = '='; @@ -533,7 +538,7 @@ ngx_http_userid_log_uid_set(ngx_http_req conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - buf = ngx_cpymem(buf, conf->name.data, conf->name.len); + buf = ngx_copy(buf, conf->name.data, conf->name.len); *buf++ = '='; @@ -544,10 +549,28 @@ ngx_http_userid_log_uid_set(ngx_http_req static ngx_int_t -ngx_http_userid_add_log_formats(ngx_conf_t *cf) +ngx_http_userid_add_variables(ngx_conf_t *cf) { + ngx_http_variable_t *var; ngx_http_log_op_name_t *op; + var = ngx_http_add_variable(cf, &ngx_http_userid_got, 0); + if (var == NULL) { + return NGX_ERROR; + } + + var->handler = ngx_http_userid_variable; + var->data = offsetof(ngx_http_userid_ctx_t, uid_got); + + var = ngx_http_add_variable(cf, &ngx_http_userid_set, 0); + if (var == NULL) { + return NGX_ERROR; + } + + var->handler = ngx_http_userid_variable; + var->data = offsetof(ngx_http_userid_ctx_t, uid_set); + + for (op = ngx_http_userid_log_fmt_ops; op->name.len; op++) { /* void */ } op->run = NULL; @@ -564,6 +587,42 @@ ngx_http_userid_add_log_formats(ngx_conf static ngx_int_t +ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + uint32_t *uid; + ngx_http_userid_ctx_t *ctx; + ngx_http_userid_conf_t *conf; + + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + + ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); + + uid = (uint32_t *) ((char *) ctx + data); + + if (ctx == NULL || uid[3] == 0) { + v->not_found = 1; + return NGX_OK; + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); + + v->len = conf->name.len + sizeof("=00001111222233334444555566667777") - 1; + v->data = ngx_palloc(r->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(v->data, "%V=%08XD%08XD%08XD%08XD", + &conf->name, uid[0], uid[1], uid[2], uid[3]); + + return NGX_OK; +} + + +static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle) { ngx_http_next_header_filter = ngx_http_top_header_filter; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -277,19 +277,31 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* init lists of the handlers */ - if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) != NGX_OK) + if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) { return NGX_CONF_ERROR; } - cmcf->phases[NGX_HTTP_REWRITE_PHASE].type = NGX_OK; + cmcf->phases[NGX_HTTP_POST_READ_PHASE].type = NGX_OK; + + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].type = NGX_OK; /* the special find config phase for a single handler */ if (ngx_array_init(&cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) != NGX_OK) + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) { return NGX_CONF_ERROR; } @@ -304,8 +316,19 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma *h = ngx_http_find_location_config; + if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + cmcf->phases[NGX_HTTP_REWRITE_PHASE].type = NGX_OK; + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) != NGX_OK) + cf->pool, 4, sizeof(ngx_http_handler_pt)) + != NGX_OK) { return NGX_CONF_ERROR; } @@ -314,7 +337,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, - cf->pool, 4, sizeof(ngx_http_handler_pt)) != NGX_OK) + cf->pool, 4, sizeof(ngx_http_handler_pt)) + != NGX_OK) { return NGX_CONF_ERROR; } @@ -353,6 +377,9 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } } + if (ngx_http_variables_init_vars(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } /* * http{}'s cf->ctx was needed while the configuration merging 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 @@ -62,6 +62,8 @@ void ngx_http_init_connection(ngx_connec ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b); ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r); +ngx_int_t ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, + ngx_str_t *args, ngx_uint_t *flags); ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b); ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, ngx_str_t *value); 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 @@ -22,7 +22,6 @@ static ngx_int_t ngx_http_core_find_loca ngx_array_t *locations, size_t len); static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf); -static ngx_int_t ngx_http_core_postconfiguration(ngx_conf_t *cf); static void *ngx_http_core_create_main_conf(ngx_conf_t *cf); static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf); static void *ngx_http_core_create_srv_conf(ngx_conf_t *cf); @@ -368,7 +367,7 @@ static ngx_command_t ngx_http_core_comm ngx_http_module_t ngx_http_core_module_ctx = { ngx_http_core_preconfiguration, /* preconfiguration */ - ngx_http_core_postconfiguration, /* postconfiguration */ + NULL, /* postconfiguration */ ngx_http_core_create_main_conf, /* create main configuration */ ngx_http_core_init_main_conf, /* init main configuration */ @@ -448,7 +447,8 @@ ngx_http_handler(ngx_http_request_t *r) r->uri_changed = 1; r->uri_changes = NGX_HTTP_MAX_REWRITE_CYCLES + 1; - r->phase = NGX_HTTP_REWRITE_PHASE; + r->phase = (r->main == r) ? NGX_HTTP_POST_READ_PHASE: + NGX_HTTP_SERVER_REWRITE_PHASE; r->phase_handler = 0; ngx_http_core_run_phases(r); @@ -991,7 +991,7 @@ ngx_http_map_uri_to_path(ngx_http_reques return NULL; } - last = ngx_cpymem(path->data, clcf->root.data, clcf->root.len); + last = ngx_copy(path->data, clcf->root.data, clcf->root.len); last = ngx_cpystrn(last, r->uri.data + alias, r->uri.len - alias + 1); return last; @@ -1054,7 +1054,7 @@ ngx_http_auth_basic_user(ngx_http_reques } } - if (len == auth.len) { + if (len == 0 || len == auth.len) { r->headers_in.user.data = (u_char *) ""; return NGX_DECLINED; } @@ -1070,7 +1070,7 @@ ngx_http_auth_basic_user(ngx_http_reques ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, - ngx_str_t *uri, ngx_str_t *args) + ngx_str_t *uri, ngx_str_t *args, ngx_uint_t flags) { ngx_http_request_t *sr; ngx_http_core_srv_conf_t *cscf; @@ -1116,9 +1116,21 @@ ngx_http_subrequest(ngx_http_request_t * sr->request_line = r->request_line; sr->uri = *uri; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http subrequest \"%V\"", uri); + if (args) { sr->args = *args; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http subrequest args \"%V\"", args); } + + if (flags & NGX_HTTP_ZERO_IN_URI) { + sr->zero_in_uri = 1; + } + sr->unparsed_uri = r->unparsed_uri; sr->method_name = r->method_name; sr->http_protocol = r->http_protocol; @@ -1167,9 +1179,6 @@ ngx_http_subrequest(ngx_http_request_t * sr->discard_body = r->discard_body; sr->main_filter_need_in_memory = r->main_filter_need_in_memory; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http subrequest \"%V\"", uri); - ngx_http_handler(sr); /* the request pool may be already destroyed */ @@ -1192,6 +1201,9 @@ ngx_http_internal_redirect(ngx_http_requ if (args) { r->args = *args; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "internal redirect args: \"%V\"", args); + } else { r->args.len = 0; r->args.data = NULL; @@ -1657,13 +1669,6 @@ ngx_http_core_preconfiguration(ngx_conf_ } -static ngx_int_t -ngx_http_core_postconfiguration(ngx_conf_t *cf) -{ - return ngx_http_variables_init_vars(cf); -} - - static void * ngx_http_core_create_main_conf(ngx_conf_t *cf) { 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 @@ -44,8 +44,10 @@ typedef struct { typedef enum { - NGX_HTTP_FIND_CONFIG_PHASE = 0, + NGX_HTTP_POST_READ_PHASE = 0, + NGX_HTTP_SERVER_REWRITE_PHASE, + NGX_HTTP_FIND_CONFIG_PHASE, NGX_HTTP_REWRITE_PHASE, NGX_HTTP_ACCESS_PHASE, @@ -260,7 +262,7 @@ u_char *ngx_http_map_uri_to_path(ngx_htt ngx_int_t ngx_http_auth_basic_user(ngx_http_request_t *r); ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, - ngx_str_t *uri, ngx_str_t *args); + ngx_str_t *uri, ngx_str_t *args, ngx_uint_t flags); ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args); diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -351,12 +351,12 @@ ngx_http_header_filter(ngx_http_request_ /* status line */ if (r->headers_out.status_line.len) { - b->last = ngx_cpymem(b->last, r->headers_out.status_line.data, - r->headers_out.status_line.len); + b->last = ngx_copy(b->last, r->headers_out.status_line.data, + r->headers_out.status_line.len); } else { - b->last = ngx_cpymem(b->last, ngx_http_status_lines[status].data, - ngx_http_status_lines[status].len); + b->last = ngx_copy(b->last, ngx_http_status_lines[status].data, + ngx_http_status_lines[status].len); } *b->last++ = CR; *b->last++ = LF; @@ -377,14 +377,14 @@ ngx_http_header_filter(ngx_http_request_ b->last = ngx_cpymem(b->last, "Content-Type: ", sizeof("Content-Type: ") - 1); p = b->last; - b->last = ngx_cpymem(b->last, r->headers_out.content_type.data, - r->headers_out.content_type.len); + b->last = ngx_copy(b->last, r->headers_out.content_type.data, + r->headers_out.content_type.len); if (r->headers_out.charset.len) { b->last = ngx_cpymem(b->last, "; charset=", sizeof("; charset=") - 1); - b->last = ngx_cpymem(b->last, r->headers_out.charset.data, - r->headers_out.charset.len); + b->last = ngx_copy(b->last, r->headers_out.charset.data, + r->headers_out.charset.len); /* update r->headers_out.content_type for possible logging */ @@ -428,28 +428,27 @@ ngx_http_header_filter(ngx_http_request_ #endif *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/'; - b->last = ngx_cpymem(b->last, r->server_name.data, - r->server_name.len); + b->last = ngx_copy(b->last, r->server_name.data, r->server_name.len); if (clcf->port_in_redirect) { #if (NGX_HTTP_SSL) if (r->connection->ssl) { if (r->port != 443) { - b->last = ngx_cpymem(b->last, r->port_text->data, - r->port_text->len); + b->last = ngx_copy(b->last, r->port_text->data, + r->port_text->len); } } else #endif { if (r->port != 80) { - b->last = ngx_cpymem(b->last, r->port_text->data, - r->port_text->len); + b->last = ngx_copy(b->last, r->port_text->data, + r->port_text->len); } } } - b->last = ngx_cpymem(b->last, r->headers_out.location->value.data, - r->headers_out.location->value.len); + b->last = ngx_copy(b->last, r->headers_out.location->value.data, + r->headers_out.location->value.len); /* update r->headers_out.location->value for possible logging */ @@ -497,11 +496,10 @@ ngx_http_header_filter(ngx_http_request_ continue; } - b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len); + b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); *b->last++ = ':' ; *b->last++ = ' ' ; - b->last = ngx_cpymem(b->last, header[i].value.data, - header[i].value.len); + b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); *b->last++ = CR; *b->last++ = LF; } 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 @@ -763,6 +763,7 @@ ngx_http_parse_complex_uri(ngx_http_requ "s:%d in:'%Xd:%c', out:'%c'", state, ch, ch, *u); switch (state) { + case sw_usual: switch(ch) { #if (NGX_WIN32) @@ -810,7 +811,6 @@ ngx_http_parse_complex_uri(ngx_http_requ switch(ch) { #if (NGX_WIN32) case '\\': - break; #endif case '/': break; @@ -837,7 +837,6 @@ ngx_http_parse_complex_uri(ngx_http_requ switch(ch) { #if (NGX_WIN32) case '\\': - /* fall through */ #endif case '/': state = sw_slash; @@ -866,7 +865,6 @@ ngx_http_parse_complex_uri(ngx_http_requ switch(ch) { #if (NGX_WIN32) case '\\': - /* fall through */ #endif case '/': state = sw_slash; @@ -923,6 +921,9 @@ ngx_http_parse_complex_uri(ngx_http_requ quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; default: state = sw_usual; *u++ = ch; @@ -1003,6 +1004,92 @@ done: ngx_int_t +ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri, + ngx_str_t *args, ngx_uint_t *flags) +{ + u_char ch, *p; + size_t len; + + len = uri->len; + p = uri->data; + + if (len == 0 || p[0] == '?') { + goto unsafe; + } + + if (p[0] == '.' && len == 3 && p[1] == '.' && (p[2] == '/' +#if (NGX_WIN32) + || p[2] == '\\' +#endif + )) + { + goto unsafe; + } + + for ( /* void */ ; len; len--) { + + ch = *p++; + + if (ch == '?') { + args->len = len - 1; + args->data = p; + uri->len -= len; + + return NGX_OK; + } + + if (ch == '\0') { + *flags |= NGX_HTTP_ZERO_IN_URI; + continue; + } + + if (ch != '/' +#if (NGX_WIN32) + && ch != '\\' +#endif + ) + { + continue; + } + + if (len > 2) { + + /* detect "/../" */ + + if (p[2] == '/') { + goto unsafe; + } + +#if (NGX_WIN32) + + if (p[2] == '\\') { + goto unsafe; + } + + if (len > 3) { + + /* detect "/.../" */ + + if (p[3] == '/' || p[3] == '\\') { + goto unsafe; + } + } +#endif + } + } + + return NGX_OK; + +unsafe: + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unsafe URI \"%V\" was detected", uri); + + return NGX_ERROR; +} + + +ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name, ngx_str_t *value) { @@ -1059,6 +1146,7 @@ ngx_http_parse_multi_header_lines(ngx_ar return i; skip: + while (start < end) { ch = *start++; if (ch == ';' || ch == ',') { 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 @@ -112,12 +112,18 @@ ngx_http_header_t ngx_http_headers_in[] { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive), ngx_http_process_header_line }, -#if (NGX_HTTP_PROXY) +#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP) { ngx_string("X-Forwarded-For"), offsetof(ngx_http_headers_in_t, x_forwarded_for), ngx_http_process_header_line }, #endif +#if (NGX_HTTP_REALIP) + { ngx_string("X-Real-IP"), + offsetof(ngx_http_headers_in_t, x_real_ip), + ngx_http_process_header_line }, +#endif + #if (NGX_HTTP_HEADERS) { ngx_string("Accept"), offsetof(ngx_http_headers_in_t, accept), ngx_http_process_header_line }, @@ -190,20 +196,21 @@ ngx_http_init_connection(ngx_connection_ static void ngx_http_init_request(ngx_event_t *rev) { - ngx_uint_t i; - socklen_t len; - struct sockaddr_in sin; - ngx_connection_t *c; - ngx_http_request_t *r; - ngx_http_in_port_t *in_port; - ngx_http_in_addr_t *in_addr; - ngx_http_log_ctx_t *ctx; - ngx_http_connection_t *hc; - ngx_http_server_name_t *server_name; - ngx_http_core_srv_conf_t *cscf; - ngx_http_core_loc_conf_t *clcf; + ngx_uint_t i; + socklen_t len; + struct sockaddr_in sin; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_in_port_t *in_port; + ngx_http_in_addr_t *in_addr; + ngx_http_log_ctx_t *ctx; + ngx_http_connection_t *hc; + ngx_http_server_name_t *server_name; + ngx_http_core_srv_conf_t *cscf; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_main_conf_t *cmcf; #if (NGX_HTTP_SSL) - ngx_http_ssl_srv_conf_t *sscf; + ngx_http_ssl_srv_conf_t *sscf; #endif #if (NGX_STAT_STUB) @@ -377,13 +384,21 @@ void ngx_http_init_request(ngx_event_t * return; } - r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); if (r->ctx == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts + * sizeof(ngx_http_variable_value_t)); + if (r->variables == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + c->single_connection = 1; r->connection = c; 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 @@ -40,6 +40,8 @@ #define NGX_HTTP_PARSE_HEADER_ERROR 13 #define NGX_HTTP_PARSE_INVALID_HEADER 13 +#define NGX_HTTP_ZERO_IN_URI 1 + #define NGX_HTTP_OK 200 #define NGX_HTTP_NO_CONTENT 204 @@ -150,10 +152,14 @@ typedef struct { ngx_table_elt_t *keep_alive; -#if (NGX_HTTP_PROXY) +#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP) ngx_table_elt_t *x_forwarded_for; #endif +#if (NGX_HTTP_REALIP) + ngx_table_elt_t *x_real_ip; +#endif + #if (NGX_HTTP_HEADERS) ngx_table_elt_t *accept; ngx_table_elt_t *accept_language; @@ -320,7 +326,7 @@ struct ngx_http_request_s { ngx_http_handler_pt content_handler; ngx_uint_t access_code; - ngx_http_variable_value_t **variables; + ngx_http_variable_value_t *variables; size_t limit_rate; @@ -366,6 +372,16 @@ struct ngx_http_request_s { unsigned bypass_cache:1; unsigned no_cache:1; +#if (NGX_HTTP_REALIP) + + /* + * instead of using the request context data in ngx_http_realip_module + * we use the single bit in the request structure + */ + unsigned realip_set:1; + +#endif + #if 0 unsigned cachable:1; #endif 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 @@ -220,14 +220,7 @@ ngx_http_do_read_client_request_body(ngx "http client request body recv %z", n); if (n == NGX_AGAIN) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(c->read, clcf->client_body_timeout); - - if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - return NGX_AGAIN; + break; } if (n == 0) { @@ -257,9 +250,20 @@ ngx_http_do_read_client_request_body(ngx "http client request body rest %uz", rb->rest); if (rb->rest) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(c->read, clcf->client_body_timeout); + + if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + return NGX_AGAIN; } + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + if (rb->temp_file) { /* save the last part */ diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -34,7 +34,7 @@ ngx_http_script_compile(ngx_http_script_ { u_char ch; size_t size; - ngx_int_t index; + ngx_int_t index, *p; ngx_str_t name; uintptr_t *code; ngx_uint_t i, n, bracket; @@ -42,6 +42,15 @@ ngx_http_script_compile(ngx_http_script_ ngx_http_script_copy_code_t *copy; ngx_http_script_copy_capture_code_t *copy_capture; + if (sc->flushes && *sc->flushes == NULL) { + n = sc->variables ? sc->variables : 1; + *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t)); + if (*sc->flushes == NULL) { + return NGX_ERROR; + } + } + + if (*sc->lengths == NULL) { n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) + sizeof(ngx_http_script_var_code_t)) @@ -167,6 +176,15 @@ ngx_http_script_compile(ngx_http_script_ return NGX_ERROR; } + if (sc->flushes) { + p = ngx_array_push(*sc->flushes); + if (p == NULL) { + return NGX_ERROR; + } + + *p = index; + } + var_code = ngx_http_script_add_code(*sc->lengths, sizeof(ngx_http_script_var_code_t), NULL); @@ -276,6 +294,24 @@ invalid_variable: } +void +ngx_http_script_flush_no_cachable_variables(ngx_http_request_t *r, + ngx_array_t *indices) +{ + ngx_uint_t n, *index; + + if (indices) { + index = indices->elts; + for (n = 0; n < indices->nelts; n++) { + if (r->variables[index[n]].no_cachable) { + r->variables[index[n]].valid = 0; + r->variables[index[n]].not_found = 0; + } + } + } +} + + void * ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size) { @@ -335,8 +371,8 @@ ngx_http_script_copy_code(ngx_http_scrip code = (ngx_http_script_copy_code_t *) e->ip; if (!e->skip) { - e->pos = ngx_cpymem(e->pos, e->ip + sizeof(ngx_http_script_copy_code_t), - code->len); + e->pos = ngx_copy(e->pos, e->ip + sizeof(ngx_http_script_copy_code_t), + code->len); } e->ip += sizeof(ngx_http_script_copy_code_t) @@ -359,10 +395,15 @@ ngx_http_script_copy_var_len_code(ngx_ht e->ip += sizeof(ngx_http_script_var_code_t); - value = ngx_http_get_indexed_variable(e->request, code->index); + if (e->flushed) { + value = ngx_http_get_indexed_variable(e->request, code->index); - if (value && value != NGX_HTTP_VAR_NOT_FOUND) { - return value->text.len; + } else { + value = ngx_http_get_flushed_variable(e->request, code->index); + } + + if (value && !value->not_found) { + return value->len; } return 0; @@ -380,10 +421,16 @@ ngx_http_script_copy_var_code(ngx_http_s e->ip += sizeof(ngx_http_script_var_code_t); if (!e->skip) { - value = ngx_http_get_indexed_variable(e->request, code->index); + + if (e->flushed) { + value = ngx_http_get_indexed_variable(e->request, code->index); - if (value && value != NGX_HTTP_VAR_NOT_FOUND) { - e->pos = ngx_cpymem(e->pos, value->text.data, value->text.len); + } else { + value = ngx_http_get_flushed_variable(e->request, code->index); + } + + if (value && !value->not_found) { + e->pos = ngx_copy(e->pos, value->data, value->len); if (e->log) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, @@ -440,9 +487,9 @@ ngx_http_script_copy_capture_code(ngx_ht e->captures[code->n + 1] - e->captures[code->n], NGX_ESCAPE_ARGS); } else { - e->pos = ngx_cpymem(e->pos, - &e->line.data[e->captures[code->n]], - e->captures[code->n + 1] - e->captures[code->n]); + e->pos = ngx_copy(e->pos, + &e->line.data[e->captures[code->n]], + e->captures[code->n + 1] - e->captures[code->n]); } } @@ -487,7 +534,8 @@ ngx_http_script_regex_start_code(ngx_htt e->line = r->uri; } else { e->sp--; - e->line = e->sp->text; + e->line.len = e->sp->len; + e->line.data = e->sp->data; } rc = ngx_regex_exec(code->regex, &e->line, e->captures, code->ncaptures); @@ -502,9 +550,8 @@ ngx_http_script_regex_start_code(ngx_htt e->ncaptures = 0; if (code->test) { - e->sp->value = 0; - e->sp->text.len = 0; - e->sp->text.data = (u_char *) ""; + e->sp->len = 0; + e->sp->data = (u_char *) ""; e->sp++; e->ip += sizeof(ngx_http_script_regex_code_t); @@ -533,9 +580,8 @@ ngx_http_script_regex_start_code(ngx_htt e->ncaptures = code->ncaptures; if (code->test) { - e->sp->value = 1; - e->sp->text.len = 1; - e->sp->text.data = (u_char *) "1"; + e->sp->len = 1; + e->sp->data = (u_char *) "1"; e->sp++; e->ip += sizeof(ngx_http_script_regex_code_t); @@ -634,7 +680,7 @@ ngx_http_script_regex_end_code(ngx_http_ if (code->add_args && r->args.len) { *e->pos++ = (u_char) (code->args ? '&' : '?'); - e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len); + e->pos = ngx_copy(e->pos, r->args.data, r->args.len); } e->buf.len = e->pos - e->buf.data; @@ -665,7 +711,7 @@ ngx_http_script_regex_end_code(ngx_http_ if (code->add_args && r->args.len) { *e->pos++ = '&'; - e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len); + e->pos = ngx_copy(e->pos, r->args.data, r->args.len); } r->args.len = e->pos - e->args; @@ -741,7 +787,7 @@ ngx_http_script_if_code(ngx_http_script_ e->sp--; - if (e->sp->value) { + if (e->sp->len && e->sp->data[0] != '0') { if (code->loc_conf) { e->request->loc_conf = code->loc_conf; ngx_http_update_location_config(e->request); @@ -794,8 +840,8 @@ ngx_http_script_complex_value_code(ngx_h e->pos = e->buf.data; - e->sp->value = 0; - e->sp->text = e->buf; + e->sp->data = e->buf.data; + e->sp->len = e->buf.len; e->sp++; } @@ -812,9 +858,8 @@ ngx_http_script_value_code(ngx_http_scri ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script value"); - e->sp->value = (ngx_uint_t) code->value; - e->sp->text.len = (size_t) code->text_len; - e->sp->text.data = (u_char *) code->text_data; + e->sp->len = code->text_len; + e->sp->data = (u_char *) code->text_data; e->sp++; } @@ -823,8 +868,6 @@ void ngx_http_script_set_var_code(ngx_http_script_engine_t *e) { ngx_http_request_t *r; - ngx_http_variable_value_t *value; - ngx_http_core_main_conf_t *cmcf; ngx_http_script_var_code_t *code; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, @@ -836,30 +879,13 @@ ngx_http_script_set_var_code(ngx_http_sc r = e->request; - if (r->variables == NULL) { - cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - - r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts - * sizeof(ngx_http_variable_value_t *)); - if (r->variables == NULL) { - e->ip = ngx_http_script_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } - } - - value = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (value == NULL) { - e->ip = ngx_http_script_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } - e->sp--; - *value = *e->sp; - - r->variables[code->index] = value; + r->variables[code->index].len = e->sp->len; + r->variables[code->index].valid = 1; + r->variables[code->index].no_cachable = 0; + r->variables[code->index].not_found = 0; + r->variables[code->index].data = e->sp->data; } @@ -876,20 +902,20 @@ ngx_http_script_var_code(ngx_http_script e->ip += sizeof(ngx_http_script_var_code_t); - value = ngx_http_get_indexed_variable(e->request, code->index); + value = ngx_http_get_flushed_variable(e->request, code->index); - if (value && value != NGX_HTTP_VAR_NOT_FOUND) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http script var: %ui, \"%V\"", value->value, &value->text); + if (value && !value->not_found) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script var: \"%V\"", value); + *e->sp = *value; e->sp++; return; } - e->sp->value = 0; - e->sp->text.len = 0; - e->sp->text.data = (u_char *) ""; + e->sp->data = (u_char *) ""; + e->sp->len = 0; e->sp++; } diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -14,46 +14,49 @@ typedef struct { - u_char *ip; - u_char *pos; - ngx_http_variable_value_t *sp; + u_char *ip; + u_char *pos; + ngx_http_variable_value_t *sp; - ngx_str_t buf; - ngx_str_t line; + ngx_str_t buf; + ngx_str_t line; /* the start of the rewritten arguments */ - u_char *args; - - unsigned skip:1; - unsigned quote:1; - unsigned log:1; + u_char *args; - int *captures; - ngx_uint_t ncaptures; + unsigned flushed:1; + unsigned skip:1; + unsigned quote:1; + unsigned log:1; - ngx_int_t status; - ngx_http_request_t *request; + int *captures; + ngx_uint_t ncaptures; + + ngx_int_t status; + ngx_http_request_t *request; } ngx_http_script_engine_t; typedef struct { - ngx_conf_t *cf; - ngx_str_t *source; - ngx_array_t **lengths; - ngx_array_t **values; + ngx_conf_t *cf; + ngx_str_t *source; - ngx_uint_t variables; - ngx_uint_t ncaptures; - ngx_uint_t size; + ngx_array_t **flushes; + ngx_array_t **lengths; + ngx_array_t **values; - void *main; + ngx_uint_t variables; + ngx_uint_t ncaptures; + ngx_uint_t size; + + void *main; - unsigned compile_args:1; - unsigned compile_null:1; - unsigned complete_lengths:1; - unsigned complete_values:1; + unsigned compile_args:1; + unsigned compile_null:1; + unsigned complete_lengths:1; + unsigned complete_values:1; - unsigned args:1; + unsigned args:1; } ngx_http_script_compile_t; @@ -149,6 +152,8 @@ typedef struct { ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value); ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc); +void ngx_http_script_flush_no_cachable_variables(ngx_http_request_t *r, + ngx_array_t *indices); void *ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size); diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -67,12 +67,20 @@ static size_t ngx_http_upstream_log_stat 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 size_t ngx_http_upstream_log_response_time_getlen(ngx_http_request_t *r, + uintptr_t data); static u_char *ngx_http_upstream_log_response_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); static u_char *ngx_http_upstream_log_error(ngx_http_request_t *r, u_char *buf, size_t len); -static ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf); + +static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf); +static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf); static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf); @@ -133,6 +141,12 @@ ngx_http_upstream_header_t ngx_http_ups ngx_http_upstream_copy_multi_header_lines, offsetof(ngx_http_headers_out_t, cache_control), 1 }, + { ngx_string("Expires"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, expires), + ngx_http_upstream_copy_header_line, + offsetof(ngx_http_headers_out_t, expires), 1 }, + { ngx_string("Connection"), ngx_http_upstream_ignore_header_line, 0, ngx_http_upstream_ignore_header_line, 0, 0 }, @@ -173,7 +187,7 @@ ngx_http_upstream_header_t ngx_http_ups ngx_http_module_t ngx_http_upstream_module_ctx = { - ngx_http_upstream_add_log_formats, /* preconfiguration */ + ngx_http_upstream_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ ngx_http_upstream_create_main_conf, /* create main configuration */ @@ -205,14 +219,27 @@ ngx_module_t ngx_http_upstream_module = 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_string("upstream_response_time"), NGX_TIME_T_LEN + 4, NULL, NULL, - ngx_http_upstream_log_response_time }, + ngx_http_upstream_log_status_getlen, + ngx_http_upstream_log_status }, + { ngx_string("upstream_response_time"), 0, NULL, + ngx_http_upstream_log_response_time_getlen, + ngx_http_upstream_log_response_time }, { ngx_null_string, 0, NULL, NULL, NULL } }; +static ngx_http_variable_t ngx_http_upstream_vars[] = { + + { ngx_string("upstream_status"), + ngx_http_upstream_status_variable, 0, 0, 0 }, + + { ngx_string("upstream_response_time"), + ngx_http_upstream_response_time_variable, 0, 0, 0 }, + + { ngx_null_string, NULL, 0, 0, 0 } +}; + + char *ngx_http_upstream_header_errors[] = { "upstream sent invalid header", "upstream sent too long header line" @@ -509,29 +536,27 @@ ngx_http_upstream_connect(ngx_http_reque } } - if (r->request_body) { - if (r->request_body->temp_file && r->main == r) { - - /* - * the r->request_body->buf can be reused for one request only, - * the subrequests should allocate their own temporay bufs - */ - - u->output.free = ngx_alloc_chain_link(r->pool); - if (u->output.free == NULL) { - 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; + if (r->request_body && r->request_body->temp_file && r->main == r) { + + /* + * the r->request_body->buf can be reused for one request only, + * the subrequests should allocate their own temporay bufs + */ + + u->output.free = ngx_alloc_chain_link(r->pool); + if (u->output.free == NULL) { + 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; } u->request_sent = 0; @@ -574,20 +599,19 @@ ngx_http_upstream_reinit(ngx_http_reques /* reinit the subrequest's ngx_output_chain() context */ - if (r->request_body) { - if (r->request_body->temp_file && r->main != r && u->output.buf) { - - u->output.free = ngx_alloc_chain_link(r->pool); - if (u->output.free == NULL) { - return NGX_ERROR; - } - - u->output.free->buf = u->output.buf; - u->output.free->next = NULL; - - u->output.buf->pos = u->output.buf->start; - u->output.buf->last = u->output.buf->start; + if (r->request_body && r->request_body->temp_file + && r->main != r && u->output.buf) + { + u->output.free = ngx_alloc_chain_link(r->pool); + if (u->output.free == NULL) { + return NGX_ERROR; } + + u->output.free->buf = u->output.buf; + u->output.free->next = NULL; + + u->output.buf->pos = u->output.buf->start; + u->output.buf->last = u->output.buf->start; } u->output.buf = NULL; @@ -690,7 +714,6 @@ ngx_http_upstream_send_request(ngx_http_ } c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; - return; } ngx_add_timer(c->read, u->conf->read_timeout); @@ -751,7 +774,8 @@ ngx_http_upstream_process_header(ngx_eve { ssize_t n; ngx_int_t rc; - ngx_uint_t i, key; + ngx_str_t *uri, args; + ngx_uint_t i, key, flags; ngx_list_part_t *part; ngx_table_elt_t *h; ngx_connection_t *c; @@ -982,9 +1006,21 @@ ngx_http_upstream_process_header(ngx_eve } } - ngx_http_internal_redirect(r, - &r->upstream->headers_in.x_accel_redirect->value, - NULL); + uri = &r->upstream->headers_in.x_accel_redirect->value; + args.len = 0; + args.data = NULL; + flags = 0; + + if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_NOT_FOUND); + return; + } + + if (flags & NGX_HTTP_ZERO_IN_URI) { + r->zero_in_uri = 1; + } + + ngx_http_internal_redirect(r, uri, &args); return; } @@ -1057,7 +1093,7 @@ ngx_http_upstream_send_response(ngx_http u->header_sent = 1; - if (r->request_body->temp_file) { + if (r->request_body && r->request_body->temp_file) { for (cl = r->pool->cleanup; cl; cl = cl->next) { if (cl->handler == ngx_pool_cleanup_file) { clf = cl->data; @@ -1586,7 +1622,7 @@ static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_table_elt_t *ho; + ngx_table_elt_t *ho, **ph; ho = ngx_list_push(&r->headers_out.headers); if (ho == NULL) { @@ -1595,6 +1631,11 @@ ngx_http_upstream_copy_header_line(ngx_h *ho = *h; + if (offset) { + ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset); + *ph = ho; + } + return NGX_OK; } @@ -1814,7 +1855,7 @@ ngx_http_upstream_log_status(ngx_http_re u = r->upstream; - if (u == NULL) { + if (u == NULL || u->states.nelts == 0) { *buf = '-'; return buf + 1; } @@ -1840,6 +1881,18 @@ ngx_http_upstream_log_status(ngx_http_re } +static size_t +ngx_http_upstream_log_response_time_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + if (r->upstream) { + return r->upstream->states.nelts * (NGX_TIME_T_LEN + 4 + 2); + } + + return 1; +} + + static u_char * ngx_http_upstream_log_response_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) @@ -1850,7 +1903,7 @@ ngx_http_upstream_log_response_time(ngx_ u = r->upstream; - if (u == NULL) { + if (u == NULL || u->states.nelts == 0) { *buf = '-'; return buf + 1; } @@ -1905,10 +1958,21 @@ ngx_http_upstream_log_error(ngx_http_req static ngx_int_t -ngx_http_upstream_add_log_formats(ngx_conf_t *cf) +ngx_http_upstream_add_variables(ngx_conf_t *cf) { + ngx_http_variable_t *var, *v; ngx_http_log_op_name_t *op; + for (v = ngx_http_upstream_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->handler = v->handler; + var->data = v->data; + } + for (op = ngx_http_upstream_log_fmt_ops; op->name.len; op++) { /* void */ } op->run = NULL; @@ -1924,6 +1988,118 @@ ngx_http_upstream_add_log_formats(ngx_co } +static ngx_int_t +ngx_http_upstream_status_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_http_upstream_t *u; + ngx_http_upstream_state_t *state; + + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + + u = r->upstream; + + if (u == NULL || u->states.nelts == 0) { + v->not_found = 1; + return NGX_OK; + } + + len = u->states.nelts * (3 + 2); + + p = ngx_palloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->data = p; + + i = 0; + state = u->states.elts; + + for ( ;; ) { + if (state[i].status == 0) { + *p++ = '-'; + + } else { + p = ngx_sprintf(p, "%ui", state[i].status); + } + + if (++i == u->states.nelts) { + break; + } + + *p++ = ','; + *p++ = ' '; + } + + v->len = p - v->data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_response_time_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_http_upstream_t *u; + ngx_http_upstream_state_t *state; + + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + + u = r->upstream; + + if (u == NULL || u->states.nelts == 0) { + v->not_found = 1; + return NGX_OK; + } + + len = u->states.nelts * (NGX_TIME_T_LEN + 4 + 2); + + p = ngx_palloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->data = p; + + i = 0; + state = u->states.elts; + + for ( ;; ) { + if (state[i].status == 0) { + *p++ = '-'; + + } else { + p = ngx_sprintf(p, "%d.%03d", + state[i].response_time / 1000, + state[i].response_time % 1000); + } + + if (++i == u->states.nelts) { + break; + } + + *p++ = ','; + *p++ = ' '; + } + + v->len = p - v->data; + + return NGX_OK; +} + + static void * ngx_http_upstream_create_main_conf(ngx_conf_t *cf) { diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -83,7 +83,7 @@ typedef struct { ngx_str_t schema; ngx_str_t uri; - ngx_str_t *location; + ngx_str_t location; ngx_str_t url; /* used in proxy_rewrite_location */ } ngx_http_upstream_conf_t; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -10,34 +10,32 @@ #include -static ngx_http_variable_value_t * - ngx_http_variable_request(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_headers(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_unknown_header(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_host(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_remote_port(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_server_addr(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_server_port(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_document_root(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_request_filename(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_request_method(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_remote_user(ngx_http_request_t *r, uintptr_t data); -static ngx_http_variable_value_t * - ngx_http_variable_sent(ngx_http_request_t *r, uintptr_t data); +static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_unknown_header(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_server_addr(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_request_filename(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_request_method(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_remote_user(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); /* @@ -95,8 +93,13 @@ static ngx_http_variable_t ngx_http_cor { ngx_string("request_uri"), ngx_http_variable_request, offsetof(ngx_http_request_t, unparsed_uri), 0, 0 }, + { ngx_string("uri"), ngx_http_variable_request, + offsetof(ngx_http_request_t, uri), + NGX_HTTP_VAR_NOCACHABLE, 0 }, + { ngx_string("document_uri"), ngx_http_variable_request, - offsetof(ngx_http_request_t, uri), 0, 0 }, + offsetof(ngx_http_request_t, uri), + NGX_HTTP_VAR_NOCACHABLE, 0 }, { ngx_string("request"), ngx_http_variable_request, offsetof(ngx_http_request_t, request_line), 0, 0 }, @@ -117,10 +120,6 @@ static ngx_http_variable_t ngx_http_cor { ngx_string("remote_user"), ngx_http_variable_remote_user, 0, 0, 0 }, - { ngx_string("sent"), ngx_http_variable_sent, 0, 0, 0 }, - - { ngx_string("apache_sent"), ngx_http_variable_sent, 1, 0, 0 }, - { ngx_null_string, NULL, 0, 0, 0 } }; @@ -233,7 +232,6 @@ ngx_http_variable_value_t * ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index) { ngx_http_variable_t *v; - ngx_http_variable_value_t *vv; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); @@ -244,27 +242,42 @@ ngx_http_get_indexed_variable(ngx_http_r return NULL; } - if (r->variables && r->variables[index]) { - return r->variables[index]; + if (r->variables[index].not_found || r->variables[index].valid) { + return &r->variables[index]; } v = cmcf->variables.elts; - vv = v[index].handler(r, v[index].data); + if (v[index].handler(r, &r->variables[index], v[index].data) == NGX_OK) { - if (r->variables == NULL) { - r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts - * sizeof(ngx_http_variable_value_t *)); - if (r->variables == NULL) { - return NULL; + if (v[index].flags & NGX_HTTP_VAR_NOCACHABLE) { + r->variables[index].no_cachable = 1; } + + return &r->variables[index]; } - if (!(v[index].flags & NGX_HTTP_VAR_NOCACHABLE)) { - r->variables[index] = vv; + return NULL; +} + + +ngx_http_variable_value_t * +ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_uint_t index) +{ + ngx_http_variable_value_t *v; + + v = &r->variables[index]; + + if (v->valid) { + if (!v->no_cachable) { + return v; + } + + v->valid = 0; + v->not_found = 0; } - return vv; + return ngx_http_get_indexed_variable(r, index); } @@ -273,6 +286,7 @@ ngx_http_get_variable(ngx_http_request_t { ngx_uint_t i, key; ngx_http_variable_t *v; + ngx_http_variable_value_t *vv; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); @@ -292,31 +306,15 @@ ngx_http_get_variable(ngx_http_request_t return ngx_http_get_indexed_variable(r, v[key].index); } else { - return v[key].handler(r, v[key].data); - } - } - if (ngx_strncmp(name->data, "http_", 5) == 0) { - return ngx_http_variable_unknown_header(r, (uintptr_t) name); - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unknown \"%V\" variable", name); + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - return NGX_HTTP_VAR_NOT_FOUND; -} - + if (vv && v[key].handler(r, vv, v[key].data) == NGX_OK) { + return vv; + } -static ngx_http_variable_value_t * -ngx_http_variable_request(ngx_http_request_t *r, uintptr_t data) -{ - ngx_str_t *s; - ngx_http_variable_value_t *vv; - - s = (ngx_str_t *) ((char *) r + data); - - if (s->data == NULL) { - return NGX_HTTP_VAR_NOT_FOUND; + return NULL; + } } vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); @@ -324,81 +322,117 @@ ngx_http_variable_request(ngx_http_reque return NULL; } - vv->value = 0; - vv->text = *s; - - return vv; -} - + if (ngx_strncmp(name->data, "http_", 5) == 0) { -static ngx_http_variable_value_t * -ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data) -{ - ngx_table_elt_t *h; - ngx_http_variable_value_t *vv; + if (ngx_http_variable_unknown_header(r, vv, (uintptr_t) name) == NGX_OK) + { + return vv; + } - h = *(ngx_table_elt_t **) ((char *) r + data); - - if (h == NULL) { - return NGX_HTTP_VAR_NOT_FOUND; - } - - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { return NULL; } - vv->value = 0; - vv->text = h->value; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unknown \"%V\" variable", name); + + vv->not_found = 1; return vv; } -static ngx_http_variable_value_t * -ngx_http_variable_headers(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + ngx_str_t *s; + + s = (ngx_str_t *) ((char *) r + data); + + if (s->data) { + v->len = s->len; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = s->data; + + } else { + v->not_found = 1; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) { - u_char *p; - ngx_uint_t i; - ngx_array_t *a; - ngx_table_elt_t **h; - ngx_http_variable_value_t *vv; + ngx_table_elt_t *h; + + h = *(ngx_table_elt_t **) ((char *) r + data); + + if (h) { + v->len = h->value.len; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = h->value.data; + + } else { + v->not_found = 1; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_variable_headers(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + size_t len; + u_char *p; + ngx_uint_t i; + ngx_array_t *a; + ngx_table_elt_t **h; a = (ngx_array_t *) ((char *) r + data); if (a->nelts == 0) { - return NGX_HTTP_VAR_NOT_FOUND; + v->not_found = 1; + return NGX_OK; } - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } - - vv->value = 0; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; h = a->elts; if (a->nelts == 1) { - vv->text = (*h)->value; - return vv; - } + v->len = (*h)->value.len; + v->data = (*h)->value.data; - vv->text.len = (size_t) - (ssize_t) (sizeof("; ") - 1); - - for (i = 0; i < a->nelts; i++) { - vv->text.len += h[i]->value.len + sizeof("; ") - 1; + return NGX_OK; } - vv->text.data = ngx_palloc(r->pool, vv->text.len); - if (vv->text.data == NULL) { - return NULL; + len = (size_t) - (ssize_t) (sizeof("; ") - 1); + + for (i = 0; i < a->nelts; i++) { + len += h[i]->value.len + sizeof("; ") - 1; } - p = vv->text.data; + p = ngx_palloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = len; + v->data = p; for (i = 0; /* void */ ; i++) { - p = ngx_cpymem(p, h[i]->value.data, h[i]->value.len); + p = ngx_copy(p, h[i]->value.data, h[i]->value.len); if (i == a->nelts - 1) { break; @@ -407,20 +441,20 @@ ngx_http_variable_headers(ngx_http_reque *p++ = ';'; *p++ = ' '; } - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_variable_unknown_header(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_unknown_header(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { ngx_str_t *var = (ngx_str_t *) data; - u_char ch; - ngx_uint_t i, n; - ngx_list_part_t *part; - ngx_table_elt_t *header; - ngx_http_variable_value_t *vv; + u_char ch; + ngx_uint_t i, n; + ngx_list_part_t *part; + ngx_table_elt_t *header; part = &r->headers_in.headers.part; header = part->elts; @@ -453,80 +487,72 @@ ngx_http_variable_unknown_header(ngx_htt } if (n + 5 == var->len) { - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } + v->len = header[i].value.len; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = header[i].value.data; - vv->value = 0; - vv->text = header[i].value; - return vv; + return NGX_OK; } } - return NGX_HTTP_VAR_NOT_FOUND; + v->not_found = 1; + + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_variable_host(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) { - ngx_http_variable_value_t *vv; + if (r->headers_in.host) { + v->len = r->headers_in.host_name_len; + v->data = r->headers_in.host->value.data; - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; + } else { + v->len = r->server_name.len; + v->data = r->server_name.data; } - vv->value = 0; - - if (r->headers_in.host) { - vv->text.len = r->headers_in.host_name_len; - vv->text.data = r->headers_in.host->value.data; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; - } else { - vv->text = r->server_name; - } - - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_remote_addr(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_variable_value_t *vv; + v->len = r->connection->addr_text.len; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = r->connection->addr_text.data; - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } - - vv->value = 0; - vv->text = r->connection->addr_text; - - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_variable_remote_port(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_remote_port(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - ngx_uint_t port; - struct sockaddr_in *sin; - ngx_http_variable_value_t *vv; + ngx_uint_t port; + struct sockaddr_in *sin; - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } + v->len = 0; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; - vv->value = 0; - vv->text.len = 0; - - vv->text.data = ngx_palloc(r->pool, sizeof("65535") - 1); - if (vv->text.data == NULL) { - return NULL; + v->data = ngx_palloc(r->pool, sizeof("65535") - 1); + if (v->data == NULL) { + return NGX_ERROR; } /* AF_INET only */ @@ -537,34 +563,25 @@ ngx_http_variable_remote_port(ngx_http_r port = ntohs(sin->sin_port); if (port > 0 && port < 65536) { - vv->value = port; - vv->text.len = ngx_sprintf(vv->text.data, "%ui", port) - - vv->text.data; + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; } } - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_variable_server_addr(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_server_addr(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - socklen_t len; - ngx_connection_t *c; - struct sockaddr_in sin; - ngx_http_variable_value_t *vv; + socklen_t len; + ngx_connection_t *c; + struct sockaddr_in sin; - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } - - vv->value = 0; - - vv->text.data = ngx_palloc(r->pool, INET_ADDRSTRLEN); - if (vv->text.data == NULL) { - return NULL; + v->data = ngx_palloc(r->pool, INET_ADDRSTRLEN); + if (v->data == NULL) { + return NGX_ERROR; } c = r->connection; @@ -574,168 +591,126 @@ ngx_http_variable_server_addr(ngx_http_r if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, "getsockname() failed"); - return NULL; + return NGX_ERROR; } r->in_addr = sin.sin_addr.s_addr; } - vv->text.len = ngx_inet_ntop(c->listening->family, &r->in_addr, - vv->text.data, INET_ADDRSTRLEN); + v->len = ngx_inet_ntop(c->listening->family, &r->in_addr, + v->data, INET_ADDRSTRLEN); + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_variable_server_port(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_server_port(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_variable_value_t *vv; + v->len = r->port_text->len - 1; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = r->port_text->data + 1; - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } - - vv->value = r->port; - vv->text.len = r->port_text->len - 1; - vv->text.data = r->port_text->data + 1; - - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_variable_document_root(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_document_root(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_core_loc_conf_t *clcf; - ngx_http_variable_value_t *vv; - - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } + ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - vv->value = 0; - vv->text = clcf->root; + v->len = clcf->root.len; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = clcf->root.data; - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_variable_request_filename(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_request_filename(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_variable_value_t *vv; + ngx_str_t path; - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } - - vv->value = 0; - - if (ngx_http_map_uri_to_path(r, &vv->text, 0) == NULL) { - return NULL; + if (ngx_http_map_uri_to_path(r, &path, 0) == NULL) { + return NGX_ERROR; } /* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */ - vv->text.len--; + v->len = path.len - 1; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = path.data; - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_variable_request_method(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_request_method(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - ngx_http_variable_value_t *vv; + if (r->method_name.data) { + if (r->upstream && r->upstream->method.len) { + v->len = r->upstream->method.len; + v->data = r->upstream->method.data; - if (r->method_name.data == NULL) { - return NGX_HTTP_VAR_NOT_FOUND; + } else { + v->len = r->method_name.len; + v->data = r->method_name.data; + } + + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + + } else { + v->not_found = 1; } - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } - - vv->value = 0; - - if (r->upstream && r->upstream->method.len) { - vv->text = r->upstream->method; - - } else { - vv->text = r->method_name; - } - - return vv; + return NGX_OK; } -static ngx_http_variable_value_t * -ngx_http_variable_remote_user(ngx_http_request_t *r, uintptr_t data) +static ngx_int_t +ngx_http_variable_remote_user(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { - ngx_int_t rc; - ngx_http_variable_value_t *vv; + ngx_int_t rc; rc = ngx_http_auth_basic_user(r); if (rc == NGX_DECLINED) { - return NGX_HTTP_VAR_NOT_FOUND; + v->not_found = 1; + return NGX_OK; } if (rc == NGX_ERROR) { - return NULL; - } - - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; + return NGX_ERROR; } - vv->value = 0; - vv->text = r->headers_in.user; - - return vv; -} - - -static ngx_http_variable_value_t * -ngx_http_variable_sent(ngx_http_request_t *r, uintptr_t data) -{ - off_t sent; - u_char *p; - ngx_http_variable_value_t *vv; - - vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); - if (vv == NULL) { - return NULL; - } + v->len = r->headers_in.user.len; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = r->headers_in.user.data; - sent = r->connection->sent; - - if (data) { - sent -= r->header_size; - - if (sent < 0) { - sent = 0; - } - } - - p = ngx_palloc(r->pool, NGX_OFF_T_LEN); - if (p == NULL) { - return NULL; - } - - vv->value = 0; - vv->text.len = ngx_sprintf(p, "%O", sent) - p; - vv->text.data = p; - - return vv; + return NGX_OK; } diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -14,18 +14,22 @@ #include -#define NGX_HTTP_VAR_NOT_FOUND (ngx_http_variable_value_t *) -1 - +typedef struct { + unsigned len:29; -typedef struct { - ngx_uint_t value; - ngx_str_t text; + unsigned valid:1; + unsigned no_cachable:1; + unsigned not_found:1; + + u_char *data; } ngx_http_variable_value_t; +#define ngx_http_variable(v) { sizeof(v) - 1, 1, 0, 0, (u_char *) v } + typedef struct ngx_http_variable_s ngx_http_variable_t; -typedef ngx_http_variable_value_t * - (*ngx_http_get_variable_pt) (ngx_http_request_t *r, uintptr_t data); +typedef ngx_int_t (*ngx_http_get_variable_pt) (ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); #define NGX_HTTP_VAR_CHANGABLE 1 @@ -34,11 +38,11 @@ typedef ngx_http_variable_value_t * struct ngx_http_variable_s { - ngx_str_t name; /* must be first to build the hash */ - ngx_http_get_variable_pt handler; - uintptr_t data; - ngx_uint_t flags; - ngx_uint_t index; + ngx_str_t name; /* must be first to build the hash */ + ngx_http_get_variable_pt handler; + uintptr_t data; + ngx_uint_t flags; + ngx_uint_t index; }; @@ -47,9 +51,15 @@ ngx_http_variable_t *ngx_http_add_variab ngx_int_t ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name); ngx_http_variable_value_t *ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index); +ngx_http_variable_value_t *ngx_http_get_flushed_variable(ngx_http_request_t *r, + ngx_uint_t index); + ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name); +#define ngx_http_clear_variable(r, index) r->variables0[index].text.data = NULL; + + ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf); ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf); diff --git a/src/imap/ngx_imap_auth_http_module.c b/src/imap/ngx_imap_auth_http_module.c --- a/src/imap/ngx_imap_auth_http_module.c +++ b/src/imap/ngx_imap_auth_http_module.c @@ -18,6 +18,9 @@ typedef struct { ngx_str_t host_header; ngx_str_t uri; + ngx_str_t header; + + ngx_array_t *headers; } ngx_imap_auth_http_conf_t; @@ -70,6 +73,8 @@ static void *ngx_imap_auth_http_create_c static char *ngx_imap_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child); static char *ngx_imap_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_imap_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_command_t ngx_imap_auth_http_commands[] = { @@ -88,6 +93,13 @@ static ngx_command_t ngx_imap_auth_http offsetof(ngx_imap_auth_http_conf_t, timeout), NULL }, + { ngx_string("auth_http_header"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE2, + ngx_imap_auth_http_header, + NGX_IMAP_SRV_CONF_OFFSET, + 0, + NULL }, + ngx_null_command }; @@ -991,12 +1003,12 @@ ngx_imap_auth_http_create_request(ngx_im } b->last = ngx_cpymem(b->last, "GET ", sizeof("GET ") - 1); - b->last = ngx_cpymem(b->last, ahcf->uri.data, ahcf->uri.len); + b->last = ngx_copy(b->last, ahcf->uri.data, ahcf->uri.len); b->last = ngx_cpymem(b->last, " HTTP/1.0" CRLF, sizeof(" HTTP/1.0" CRLF) - 1); b->last = ngx_cpymem(b->last, "Host: ", sizeof("Host: ") - 1); - b->last = ngx_cpymem(b->last, ahcf->host_header.data, + b->last = ngx_copy(b->last, ahcf->host_header.data, ahcf->host_header.len); *b->last++ = CR; *b->last++ = LF; @@ -1004,11 +1016,11 @@ ngx_imap_auth_http_create_request(ngx_im sizeof("Auth-Method: plain" CRLF) - 1); b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1); - b->last = ngx_cpymem(b->last, s->login.data, s->login.len); + b->last = ngx_copy(b->last, s->login.data, s->login.len); *b->last++ = CR; *b->last++ = LF; b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1); - b->last = ngx_cpymem(b->last, s->passwd.data, s->passwd.len); + b->last = ngx_copy(b->last, s->passwd.data, s->passwd.len); *b->last++ = CR; *b->last++ = LF; b->last = ngx_cpymem(b->last, "Auth-Protocol: ", @@ -1021,10 +1033,14 @@ ngx_imap_auth_http_create_request(ngx_im s->login_attempt); b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1); - b->last = ngx_cpymem(b->last, s->connection->addr_text.data, + b->last = ngx_copy(b->last, s->connection->addr_text.data, s->connection->addr_text.len); *b->last++ = CR; *b->last++ = LF; + if (ahcf->header.len) { + b->last = ngx_copy(b->last, ahcf->header.data, ahcf->header.len); + } + /* add "\r\n" at the header end */ *b->last++ = CR; *b->last++ = LF; @@ -1065,6 +1081,11 @@ ngx_imap_auth_http_merge_conf(ngx_conf_t ngx_imap_auth_http_conf_t *prev = parent; ngx_imap_auth_http_conf_t *conf = child; + u_char *p; + size_t len; + ngx_uint_t i; + ngx_table_elt_t *header; + if (conf->peers == NULL) { conf->peers = prev->peers; conf->host_header = prev->host_header; @@ -1073,6 +1094,34 @@ ngx_imap_auth_http_merge_conf(ngx_conf_t ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); + if (conf->headers == NULL) { + conf->headers = prev->headers; + conf->header = prev->header; + } + + if (conf->headers && conf->header.len == 0) { + len = 0; + header = conf->headers->elts; + for (i = 0; i < conf->headers->nelts; i++) { + len += header[i].key.len + 2 + header[i].value.len + 2; + } + + p = ngx_palloc(cf->pool, len); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + conf->header.len = len; + conf->header.data = p; + + for (i = 0; i < conf->headers->nelts; i++) { + p = ngx_cpymem(p, header[i].key.data, header[i].key.len); + *p++ = ':'; *p++ = ' '; + p = ngx_cpymem(p, header[i].value.data, header[i].value.len); + *p++ = CR; *p++ = LF; + } + } + return NGX_CONF_OK; } @@ -1087,7 +1136,7 @@ ngx_imap_auth_http(ngx_conf_t *cf, ngx_c #if (NGX_HAVE_UNIX_DOMAIN) ngx_unix_domain_upstream_t unix_upstream; #endif - + value = cf->args->elts; url = &value[1]; @@ -1143,3 +1192,32 @@ ngx_imap_auth_http(ngx_conf_t *cf, ngx_c return NGX_CONF_OK; } + + +static char * +ngx_imap_auth_http_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_imap_auth_http_conf_t *ahcf = conf; + + ngx_str_t *value; + ngx_table_elt_t *header; + + if (ahcf->headers == NULL) { + ahcf->headers = ngx_array_create(cf->pool, 1, sizeof(ngx_table_elt_t)); + if (ahcf->headers == NULL) { + return NGX_CONF_ERROR; + } + } + + header = ngx_array_push(ahcf->headers); + if (header == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + header->key = value[1]; + header->value = value[2]; + + return NGX_CONF_OK; +} diff --git a/src/imap/ngx_imap_ssl_module.c b/src/imap/ngx_imap_ssl_module.c --- a/src/imap/ngx_imap_ssl_module.c +++ b/src/imap/ngx_imap_ssl_module.c @@ -83,6 +83,12 @@ static ngx_command_t ngx_imap_ssl_comma ngx_imap_ssl_nosupported, 0, 0, ngx_imap_ssl_openssl097 }, #endif + { ngx_string("ssl_session_timeout"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_sec_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_ssl_conf_t, session_timeout), + NULL }, ngx_null_command }; @@ -140,6 +146,7 @@ ngx_imap_ssl_create_conf(ngx_conf_t *cf) */ scf->enable = NGX_CONF_UNSET; + scf->session_timeout = NGX_CONF_UNSET; scf->prefer_server_ciphers = NGX_CONF_UNSET; return scf; @@ -160,6 +167,9 @@ ngx_imap_ssl_merge_conf(ngx_conf_t *cf, return NGX_CONF_OK; } + ngx_conf_merge_value(conf->session_timeout, + prev->session_timeout, 300); + ngx_conf_merge_value(conf->prefer_server_ciphers, prev->prefer_server_ciphers, 0); @@ -225,6 +235,8 @@ ngx_imap_ssl_merge_conf(ngx_conf_t *cf, SSL_CTX_set_session_id_context(conf->ssl.ctx, ngx_imap_session_id_ctx, sizeof(ngx_imap_session_id_ctx) - 1); + SSL_CTX_set_timeout(conf->ssl.ctx, conf->session_timeout); + return NGX_CONF_OK; } diff --git a/src/imap/ngx_imap_ssl_module.h b/src/imap/ngx_imap_ssl_module.h --- a/src/imap/ngx_imap_ssl_module.h +++ b/src/imap/ngx_imap_ssl_module.h @@ -22,6 +22,8 @@ typedef struct { ngx_uint_t protocols; + time_t session_timeout; + ngx_str_t certificate; ngx_str_t certificate_key; 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 @@ -15,9 +15,10 @@ static void ngx_start_worker_processes(n static void ngx_start_garbage_collector(ngx_cycle_t *cycle, ngx_int_t type); static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo); static ngx_uint_t ngx_reap_childs(ngx_cycle_t *cycle); -static void ngx_master_exit(ngx_cycle_t *cycle); +static void ngx_master_process_exit(ngx_cycle_t *cycle); static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data); static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority); +static void ngx_worker_process_exit(ngx_cycle_t *cycle); static void ngx_channel_handler(ngx_event_t *ev); #if (NGX_THREADS) static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle); @@ -156,7 +157,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy } if (!live && (ngx_terminate || ngx_quit)) { - ngx_master_exit(cycle); + ngx_master_process_exit(cycle); } if (ngx_terminate) { @@ -283,7 +284,7 @@ ngx_single_process_cycle(ngx_cycle_t *cy } } - ngx_master_exit(cycle); + ngx_master_process_exit(cycle); } if (ngx_reconfigure) { @@ -628,7 +629,7 @@ ngx_reap_childs(ngx_cycle_t *cycle) static void -ngx_master_exit(ngx_cycle_t *cycle) +ngx_master_process_exit(ngx_cycle_t *cycle) { ngx_uint_t i; @@ -658,8 +659,6 @@ ngx_master_exit(ngx_cycle_t *cycle) static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { - ngx_uint_t i; - ngx_connection_t *c; #if (NGX_THREADS) ngx_int_t n; ngx_err_t err; @@ -717,26 +716,7 @@ ngx_worker_process_cycle(ngx_cycle_t *cy { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); - -#if (NGX_THREADS) - ngx_terminate = 1; - - ngx_wakeup_worker_threads(cycle); -#endif - - if (ngx_debug_quit) { - ngx_debug_point(); - } - - /* - * we do not destroy cycle->pool here because a signal handler - * that uses cycle->log can be called at this point - */ - -#if 0 - ngx_destroy_pool(cycle->pool); -#endif - exit(0); + ngx_worker_process_exit(cycle); } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); @@ -746,41 +726,7 @@ ngx_worker_process_cycle(ngx_cycle_t *cy if (ngx_terminate) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); -#if (NGX_THREADS) - ngx_wakeup_worker_threads(cycle); -#endif - - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->exit_process) { - ngx_modules[i]->exit_process(cycle); - } - } - - c = cycle->connections; - for (i = 0; i < cycle->connection_n; i++) { - if (c[i].fd != -1 - && c[i].read - && !c[i].read->accept - && !c[i].read->channel) - { - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "open socket #%d left in %ui connection, " - "aborting", - c[i].fd, i); - ngx_abort(); - } - } - - /* - * we do not destroy cycle->pool here because a signal handler - * that uses cycle->log can be called at this point - */ - -#if 0 - ngx_destroy_pool(cycle->pool); -#endif - - exit(0); + ngx_worker_process_exit(cycle); } if (ngx_quit) { @@ -957,6 +903,56 @@ ngx_worker_process_init(ngx_cycle_t *cyc static void +ngx_worker_process_exit(ngx_cycle_t *cycle) +{ + ngx_uint_t i; + ngx_connection_t *c; + +#if (NGX_THREADS) + ngx_terminate = 1; + + ngx_wakeup_worker_threads(cycle); +#endif + + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->exit_process) { + ngx_modules[i]->exit_process(cycle); + } + } + + c = cycle->connections; + for (i = 0; i < cycle->connection_n; i++) { + if (c[i].fd != -1 + && c[i].read + && !c[i].read->accept + && !c[i].read->channel) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "open socket #%d left in %ui connection, " + "aborting", + c[i].fd, i); + ngx_abort(); + } + } + + if (ngx_debug_quit) { + ngx_debug_point(); + } + + /* + * we do not destroy cycle->pool here because a signal handler + * that uses cycle->log can be called at this point + */ + +#if 0 + ngx_destroy_pool(cycle->pool); +#endif + + exit(0); +} + + +static void ngx_channel_handler(ngx_event_t *ev) { ngx_int_t n;