# HG changeset patch # User Igor Sysoev # Date 1132952400 -10800 # Node ID 82d695e3d662a63e5a63decf903cd621f7564d50 # Parent a27c77ef3ad8a3bbc47e6852f7490afe7be4e92f nginx 0.3.12 *) Security: if nginx was built with the ngx_http_realip_module and the "satisfy_any on" directive was used, then access and authorization directives did not work. The ngx_http_realip_module was not built and is not built by default. *) Change: the "$time_gmt" variable name was changed to "$time_local". *) Change: the "proxy_header_buffer_size" and "fastcgi_header_buffer_size" directives was renamed to the "proxy_buffer_size" and "fastcgi_buffer_size" directives. *) Feature: the ngx_http_memcached_module. *) Feature: the "proxy_buffering" directive. *) Bugfix: the changes in accept mutex handling when the "rtsig" method was used; bug appeared in 0.3.0. *) Bugfix: if the client sent the "Transfer-Encoding: chunked" header line, then nginx returns the 411 error. *) Bugfix: if the "auth_basic" directive was inherited from the http level, then the realm in the "WWW-Authenticate" header line was without the "Basic realm" text. *) Bugfix: if the "combined" format was explicitly specified in the "access_log" directive, then the empty lines was written to the log; bug appeared in 0.3.8. *) Bugfix: nginx did not run on the sparc platform under any OS except Solaris. *) Bugfix: now it is not necessary to place space between the quoted string and closing bracket in the "if" directive. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,46 @@ + +Changes with nginx 0.3.12 26 Nov 2005 + + *) Security: if nginx was built with the ngx_http_realip_module and the + "satisfy_any on" directive was used, then access and authorization + directives did not work. The ngx_http_realip_module was not built + and is not built by default. + + *) Change: the "$time_gmt" variable name was changed to "$time_local". + + *) Change: the "proxy_header_buffer_size" and + "fastcgi_header_buffer_size" directives was renamed to the + "proxy_buffer_size" and "fastcgi_buffer_size" directives. + + *) Feature: the ngx_http_memcached_module. + + *) Feature: the "proxy_buffering" directive. + + *) Bugfix: the changes in accept mutex handling when the "rtsig" method + was used; bug appeared in 0.3.0. + + *) Bugfix: if the client sent the "Transfer-Encoding: chunked" header + line, then nginx returns the 411 error. + + *) Bugfix: if the "auth_basic" directive was inherited from the http + level, then the realm in the "WWW-Authenticate" header line was + without the "Basic realm" text. + + *) Bugfix: if the "combined" format was explicitly specified in the + "access_log" directive, then the empty lines was written to the log; + bug appeared in 0.3.8. + + *) Bugfix: nginx did not run on the sparc platform under any OS except + Solaris. + + *) Bugfix: now it is not necessary to place space between the quoted + string and closing bracket in the "if" directive. + Changes with nginx 0.3.11 15 Nov 2005 - *) Bugfix: nginx did not pass while proxying the client request headers - and body; bug appeared in 0.3.10. + *) Bugfix: nginx did not pass the client request headers and body while + proxying; bug appeared in 0.3.10. Changes with nginx 0.3.10 15 Nov 2005 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,41 @@ + +Изменения в nginx 0.3.12 26.11.2005 + + *) Безопасность: если nginx был собран с модулем + ngx_http_realip_module, то при использовании директивы "satisfy_any + on" директивы доступа и аутентификации не работали. Модуль + ngx_http_realip_module не собирался и не собирается по умолчанию. + + *) Изменение: имя переменной "$time_gmt" изменено на "$time_local". + + *) Изменение: директивы proxy_header_buffer_size и + fastcgi_header_buffer_size переименованы соответственно в + proxy_buffer_size и fastcgi_buffer_size. + + *) Добавление: модуль ngx_http_memcached_module. + + *) Добавление: директива proxy_buffering. + + *) Исправление: изменение в работе с accept mutex при использовании + метода rtsig; ошибка появилась в 0.3.0. + + *) Исправление: если клиент передал строку "Transfer-Encoding: chunked" + в заголоовке запроса, то nginx теперь выдаёт ошибку 411. + + *) Исправление: при наследовании директивы auth_basic с уровня http в + строке "WWW-Authenticate" заголовка ответа выводился realm без + текста "Basic realm". + + *) Исправление: если в директиве access_log был явно указан формат + combined, то в лог записывались пустые строки; ошибка появилась в + 0.3.8. + + *) Исправление: nginx не работал на платформе sparc под любыми OS, + кроме Solaris. + + *) Исправление: в директиве if теперь не нужно разделять пробелом + строку в кавычках и закрывающую скобку. + Изменения в nginx 0.3.11 15.11.2005 diff --git a/auto/cc/gcc b/auto/cc/gcc --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -34,9 +34,9 @@ if [ $ngx_found = yes ]; then fi -case "$NGX_PLATFORM" in +case "$NGX_MACHINE" in - *:sun4u) + sun4u | sparc ) # "-mcpu=v9" enables the "casa" assembler instruction CFLAGS="$CFLAGS -mcpu=v9" ;; @@ -80,6 +80,13 @@ case $CPU in CPU_OPT="-march=opteron" ;; + sparc32) + # build 32-bit UltraSparc binary + CPU_OPT="-m32" + CORE_LINK="$CORE_LINK -m32" + CC_AUX_FLAGS="$CC_AUX_FLAGS -m32" + ;; + sparc64) # build 64-bit UltraSparc binary CPU_OPT="-m64" diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -194,6 +194,11 @@ if [ $HTTP_FASTCGI = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_FASTCGI_SRCS" fi +if [ $HTTP_MEMCACHED = YES ]; then + HTTP_MODULES="$HTTP_MODULES $HTTP_MEMCACHED_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_MEMCACHED_SRCS" +fi + if [ $HTTP_EMPTY_GIF = YES ]; then HTTP_MODULES="$HTTP_MODULES $HTTP_EMPTY_GIF_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_EMPTY_GIF_SRCS" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -61,6 +61,7 @@ HTTP_REFERER=YES HTTP_REWRITE=YES HTTP_PROXY=YES HTTP_FASTCGI=YES +HTTP_MEMCACHED=YES HTTP_EMPTY_GIF=YES # STUB @@ -138,11 +139,12 @@ do --without-http_autoindex_module) HTTP_AUTOINDEX=NO ;; --without-http_status_module) HTTP_STATUS=NO ;; --without-http_geo_module) HTTP_GEO=NO ;; - --without-http_referer) HTTP_REFERER=NO ;; + --without-http_referer_module) HTTP_REFERER=NO ;; --without-http_rewrite_module) HTTP_REWRITE=NO ;; --without-http_proxy_module) HTTP_PROXY=NO ;; --without-http_fastcgi_module) HTTP_FASTCGI=NO ;; - --without-http_epmty_gif_module) HTTP_EMPTY_GIF=NO ;; + --without-http_memcached_module) HTTP_MEMCACHED=NO ;; + --without-http_empty_gif_module) HTTP_EMPTY_GIF=NO ;; # STUB --with-http_stub_status_module) HTTP_STUB_STATUS=YES ;; @@ -213,6 +215,7 @@ cat << END --without-poll_module disable poll module --with-http_ssl_module enable ngx_http_ssl_module + --with-http_realip_module enable ngx_http_realip_module --without-http_charset_module disable ngx_http_charset_module --without-http_gzip_module disable ngx_http_gzip_module --without-http_ssi_module disable ngx_http_ssi_module @@ -221,9 +224,12 @@ cat << END --without-http_auth_basic_module disable ngx_http_auth_basic_module --without-http_autoindex_module disable ngx_http_autoindex_module --without-http_geo_module disable ngx_http_geo_module + --without-http_referer_module disable ngx_http_referer_module --without-http_rewrite_module disable ngx_http_rewrite_module --without-http_proxy_module disable ngx_http_proxy_module --without-http_fastcgi_module disable ngx_http_fastcgi_module + --without-http_memcached_module disable ngx_http_memcached_module + --without-http_empty_gif_module disable ngx_http_empty_gif_module --http-log-path=PATH set path to the http access log --http-client-body-temp-path=PATH set path to the http client request body diff --git a/auto/os/conf b/auto/os/conf --- a/auto/os/conf +++ b/auto/os/conf @@ -63,4 +63,8 @@ case "$NGX_MACHINE" in have=NGX_HAVE_NONALIGNED . auto/have ;; + sun4u | ia64 ) + have=NGX_ALIGNMENT value=16 . auto/define + ;; + esac diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -355,6 +355,10 @@ HTTP_FASTCGI_MODULE=ngx_http_fastcgi_mod HTTP_FASTCGI_SRCS=src/http/modules/ngx_http_fastcgi_module.c +HTTP_MEMCACHED_MODULE=ngx_http_memcached_module +HTTP_MEMCACHED_SRCS=src/http/modules/ngx_http_memcached_module.c + + HTTP_EMPTY_GIF_MODULE=ngx_http_empty_gif_module HTTP_EMPTY_GIF_SRCS=src/http/modules/ngx_http_empty_gif_module.c 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.11" +#define NGINX_VER "nginx/0.3.12" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c --- a/src/core/ngx_buf.c +++ b/src/core/ngx_buf.c @@ -151,6 +151,34 @@ ngx_chain_add_copy(ngx_pool_t *pool, ngx } +ngx_chain_t * +ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free) +{ + ngx_chain_t *cl; + + if (*free) { + cl = *free; + *free = cl->next; + cl->next = NULL; + return cl; + } + + cl = ngx_alloc_chain_link(p); + if (cl == NULL) { + return NULL; + } + + cl->buf = ngx_calloc_buf(p); + if (cl->buf == NULL) { + return NULL; + } + + cl->next = NULL; + + return cl; +} + + void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy, ngx_chain_t **out, ngx_buf_tag_t tag) diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -132,6 +132,7 @@ ngx_int_t ngx_chain_writer(void *ctx, ng ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); +ngx_chain_t *ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free); void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy, ngx_chain_t **out, ngx_buf_tag_t tag); diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -77,8 +77,8 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN); if (fd == NGX_INVALID_FILE) { - ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, - ngx_open_file_n " \"%s\" failed", filename->data); + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + ngx_open_file_n " \"%s\" failed", filename->data); return NGX_CONF_ERROR; } @@ -451,12 +451,18 @@ ngx_conf_read_token(ngx_conf_t *cf) return NGX_CONF_BLOCK_START; } - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "unexpected \"%c\" in %s:%ui", - ch, cf->conf_file->file.name.data, - cf->conf_file->line); + if (ch == ')') { + last_space = 1; + need_space = 0; - return NGX_ERROR; + } else { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "unexpected \"%c\" in %s:%ui", + ch, cf->conf_file->file.name.data, + cf->conf_file->line); + + return NGX_ERROR; + } } if (last_space) { @@ -1167,6 +1173,20 @@ ngx_conf_unsupported(ngx_conf_t *cf, ngx char * +ngx_conf_deprecated(ngx_conf_t *cf, void *post, void *data) +{ + ngx_conf_deprecated_t *d = post; + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "the \"%s\" directive is deprecated, " + "use the \"%s\" directive instead", + d->old_name, d->new_name); + + return NGX_CONF_OK; +} + + +char * ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data) { ngx_conf_num_bounds_t *bounds = post; 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 @@ -189,6 +189,13 @@ typedef struct { typedef struct { ngx_conf_post_handler_pt post_handler; + char *old_name; + char *new_name; +} ngx_conf_deprecated_t; + + +typedef struct { + ngx_conf_post_handler_pt post_handler; ngx_int_t low; ngx_int_t high; } ngx_conf_num_bounds_t; @@ -208,6 +215,8 @@ typedef struct { } ngx_conf_bitmask_t; + +char * ngx_conf_deprecated(ngx_conf_t *cf, void *post, void *data); char *ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data); diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -76,32 +76,30 @@ #if 1 /* STUB: autoconf */ -typedef int ngx_int_t; -typedef u_int ngx_uint_t; -typedef int ngx_flag_t; -#define NGX_INT_T_LEN sizeof("-2147483648") - 1 +typedef int ngx_int_t; +typedef u_int ngx_uint_t; +typedef int ngx_flag_t; +#define NGX_INT_T_LEN sizeof("-2147483648") - 1 #else -typedef long ngx_int_t; -typedef u_long ngx_uint_t; -typedef long ngx_flag_t; -#define NGX_INT_T_LEN sizeof("-9223372036854775808") - 1 +typedef long ngx_int_t; +typedef u_long ngx_uint_t; +typedef long ngx_flag_t; +#define NGX_INT_T_LEN sizeof("-9223372036854775808") - 1 #endif -#define NGX_INT32_LEN sizeof("-2147483648") - 1 -#define NGX_INT64_LEN sizeof("-9223372036854775808") - 1 +#define NGX_INT32_LEN sizeof("-2147483648") - 1 +#define NGX_INT64_LEN sizeof("-9223372036854775808") - 1 -#if (NGX_SOLARIS) -#define NGX_ALIGN (_MAX_ALIGNMENT - 1) -#else -/* TODO: auto_conf */ -#define NGX_ALIGN (sizeof(unsigned long) - 1) /* platform word */ +#ifndef NGX_ALIGNMENT +#define NGX_ALIGNMENT sizeof(unsigned long) /* platform word */ #endif -#define ngx_align(p) (u_char *) (((uintptr_t) p + NGX_ALIGN) & ~NGX_ALIGN) +#define ngx_align(p) (u_char *) (((uintptr_t) p + (NGX_ALIGNMENT - 1)) \ + & ~(NGX_ALIGNMENT - 1)) #define ngx_abort abort @@ -109,7 +107,7 @@ typedef long ngx_flag_t; /* TODO: auto_conf: ngx_inline inline __inline __inline__ */ #ifndef ngx_inline -#define ngx_inline inline +#define ngx_inline inline #endif #define NGX_ACCEPT_THRESHOLD 100 diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -12,8 +12,8 @@ /* * ngx_sock_ntop() and ngx_inet_ntop() may be implemented as - * "ngx_sprintf(text, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3])", - * however, they were implemented long before the ngx_sprintf() appeared + * "ngx_sprintf(text, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3])", however, + * they had been implemented long before the ngx_sprintf() had appeared * and they are faster by 1.5-2.5 times, so it is worth to keep them. * * By the way, the implementation using ngx_sprintf() is faster by 2.5-3 times diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -20,9 +20,10 @@ ngx_create_pool(size_t size, ngx_log_t * p->last = (u_char *) p + sizeof(ngx_pool_t); p->end = (u_char *) p + size; + p->current = p; + p->chain = NULL; p->next = NULL; p->large = NULL; - p->chain = NULL; p->cleanup = NULL; p->log = log; @@ -91,7 +92,7 @@ ngx_palloc(ngx_pool_t *pool, size_t size && size <= (size_t) (pool->end - (u_char *) pool) - (size_t) ngx_align(sizeof(ngx_pool_t))) { - for (p = pool, n = pool->next; /* void */; p = n, n = n->next) { + for (p = pool->current; /* void */ ; p = p->next) { m = ngx_align(p->last); if ((size_t) (p->end - m) >= size) { @@ -100,7 +101,11 @@ ngx_palloc(ngx_pool_t *pool, size_t size return m; } - if (n == NULL) { + if ((size_t) (p->end - m) < NGX_ALIGNMENT) { + p->current = p->next; + } + + if (p->next == NULL) { break; } } @@ -112,6 +117,10 @@ ngx_palloc(ngx_pool_t *pool, size_t size return NULL; } + if (p->current == NULL) { + p->current = n; + } + p->next = n; m = ngx_align(n->last); n->last = m + size; diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h --- a/src/core/ngx_palloc.h +++ b/src/core/ngx_palloc.h @@ -44,6 +44,7 @@ struct ngx_pool_large_s { struct ngx_pool_s { u_char *last; u_char *end; + ngx_pool_t *current; ngx_chain_t *chain; ngx_pool_t *next; ngx_pool_large_t *large; diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -241,7 +241,7 @@ ngx_epoll_add_event(ngx_event_t *ev, int } ee.events = events | flags; - ee.data.u64 = (uintptr_t) c | ev->instance; + ee.data.ptr = (void *) ((uintptr_t) c | ev->instance); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0, "epoll add event: fd:%d op:%d ev:%08XD", @@ -296,7 +296,7 @@ ngx_epoll_del_event(ngx_event_t *ev, int if (e->active) { op = EPOLL_CTL_MOD; ee.events = prev | flags; - ee.data.u64 = (uintptr_t) c | ev->instance; + ee.data.ptr = (void *) ((uintptr_t) c | ev->instance); } else { op = EPOLL_CTL_DEL; @@ -326,7 +326,7 @@ ngx_epoll_add_connection(ngx_connection_ struct epoll_event ee; ee.events = EPOLLIN|EPOLLOUT|EPOLLET; - ee.data.u64 = (uintptr_t) c | c->read->instance; + ee.data.ptr = (void *) ((uintptr_t) c | c->read->instance); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "epoll add connection: fd:%d ev:%08XD", c->fd, ee.events); @@ -367,7 +367,7 @@ ngx_epoll_del_connection(ngx_connection_ op = EPOLL_CTL_DEL; ee.events = 0; - ee.data.u64 = 0; + ee.data.ptr = NULL; if (epoll_ctl(ep, op, c->fd, &ee) == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, 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,7 +48,6 @@ 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; @@ -255,7 +254,7 @@ ngx_process_events_and_timers(ngx_cycle_ } if (ngx_accept_mutex_held) { - *ngx_accept_mutex = 0; + (void) ngx_atomic_cmp_set(ngx_accept_mutex, ngx_pid, 0); } if (delta) { @@ -471,7 +470,6 @@ 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) @@ -491,17 +489,16 @@ ngx_event_module_init(ngx_cycle_t *cycle } ngx_accept_mutex_ptr = (ngx_atomic_t *) shared; - ngx_accept_mutex_last_owner = (ngx_atomic_t *) (shared + 1 * 128); - ngx_connection_counter = (ngx_atomic_t *) (shared + 2 * 128); + ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * 128); #if (NGX_STAT_STUB) - 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); + 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); #endif @@ -919,6 +916,12 @@ ngx_event_connections(ngx_conf_t *cf, ng return "is duplicate" ; } + if (ngx_strcmp(cmd->name.data, "connections") == 0) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "the \"connections\" directive is deprecated, " + "use the \"worker_connections\" directive instead"); + } + value = cf->args->elts; ecf->connections = ngx_atoi(value[1].data, value[1].len); if (ecf->connections == (ngx_uint_t) NGX_ERROR) { 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,7 +438,6 @@ 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; 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 @@ -265,9 +265,7 @@ 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 - && (!(ngx_event_flags & NGX_USE_RTSIG_EVENT) - || *ngx_accept_mutex_last_owner == (ngx_atomic_t) ngx_pid)) + if (ngx_accept_mutex_held && !(ngx_event_flags & NGX_USE_RTSIG_EVENT)) { return NGX_OK; } @@ -308,16 +306,10 @@ ngx_enable_accept_events(ngx_cycle_t *cy 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; diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -122,6 +122,8 @@ ngx_event_pipe_read_upstream(ngx_event_p } else { +#if (NGX_HAVE_KQUEUE) + /* * kqueue notifies about the end of file or a pending error. * This test allows not to allocate a buf on these conditions @@ -129,14 +131,15 @@ ngx_event_pipe_read_upstream(ngx_event_p */ if (p->upstream->read->available == 0 - && p->upstream->read->pending_eof) + && p->upstream->read->pending_eof + /* FreeBSD 5.x-6.x may erroneously report ETIMEDOUT */ + && p->upstream->read->kq_errno != NGX_ETIMEDOUT) { p->upstream->read->ready = 0; p->upstream->read->eof = 0; p->upstream_eof = 1; p->read = 1; -#if (NGX_HAVE_KQUEUE) if (p->upstream->read->kq_errno) { p->upstream->read->error = 1; p->upstream_error = 1; @@ -144,12 +147,13 @@ ngx_event_pipe_read_upstream(ngx_event_p ngx_log_error(NGX_LOG_ERR, p->log, p->upstream->read->kq_errno, - "readv() failed"); + "kevent() reported that upstream " + "closed connection"); } -#endif break; } +#endif if (p->free_raw_bufs) { diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -332,32 +332,10 @@ ngx_http_auth_basic_merge_loc_conf(ngx_c ngx_http_auth_basic_loc_conf_t *prev = parent; ngx_http_auth_basic_loc_conf_t *conf = child; - size_t len; - u_char *realm, *p; - - if (conf->realm.data) { - if (conf->realm.len) { - len = sizeof("Basic realm=\"") - 1 + conf->realm.len + 1; - - realm = ngx_palloc(cf->pool, len); - if (realm == NULL) { - return NGX_CONF_ERROR; - } - - p = ngx_cpymem(realm, "Basic realm=\"", - sizeof("Basic realm=\"") - 1); - p = ngx_cpymem(p, conf->realm.data, conf->realm.len); - *p = '"'; - - conf->realm.len = len; - conf->realm.data = realm; - } - - } else { + if (conf->realm.data == NULL) { conf->realm = prev->realm; } - if (conf->user_file.data) { if (ngx_conf_full_name(cf->cycle, &conf->user_file) != NGX_OK) { return NGX_CONF_ERROR; @@ -395,10 +373,27 @@ ngx_http_auth_basic(ngx_conf_t *cf, void { ngx_str_t *realm = data; + size_t len; + u_char *basic, *p; + if (ngx_strcmp(realm->data, "off") == 0) { realm->len = 0; realm->data = (u_char *) ""; } + len = sizeof("Basic realm=\"") - 1 + realm->len + 1; + + basic = ngx_palloc(cf->pool, len); + if (basic == NULL) { + return NGX_CONF_ERROR; + } + + p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1); + p = ngx_cpymem(p, realm->data, realm->len); + *p = '"'; + + realm->len = len; + realm->data = basic; + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_empty_gif_module.c b/src/http/modules/ngx_http_empty_gif_module.c --- a/src/http/modules/ngx_http_empty_gif_module.c +++ b/src/http/modules/ngx_http_empty_gif_module.c @@ -28,49 +28,49 @@ static ngx_command_t ngx_http_empty_gif static u_char ngx_empty_gif[] = { - 'G', 'I', 'F', '8', '9', 'a', /* header */ + 'G', 'I', 'F', '8', '9', 'a', /* header */ - /* logical screen descriptor */ - 0x01, 0x00, /* logical screen width */ - 0x01, 0x00, /* logical screen height */ - 0x80, /* global 1-bit color table */ - 0x01, /* background color #1 */ - 0x00, /* no aspect ratio */ + /* logical screen descriptor */ + 0x01, 0x00, /* logical screen width */ + 0x01, 0x00, /* logical screen height */ + 0x80, /* global 1-bit color table */ + 0x01, /* background color #1 */ + 0x00, /* no aspect ratio */ - /* global color table */ - 0x00, 0x00, 0x00, /* #0: black */ - 0xff, 0xff, 0xff, /* #1: white */ + /* global color table */ + 0x00, 0x00, 0x00, /* #0: black */ + 0xff, 0xff, 0xff, /* #1: white */ - /* graphic control extension */ - 0x21, /* extension introducer */ - 0xf9, /* graphic control label */ - 0x04, /* block size */ - 0x01, /* transparent color is given, */ - /* no disposal specified, */ - /* user input is not expected */ - 0x00, 0x00, /* delay time */ - 0x01, /* transparent color #1 */ - 0x00, /* block terminator */ + /* graphic control extension */ + 0x21, /* extension introducer */ + 0xf9, /* graphic control label */ + 0x04, /* block size */ + 0x01, /* transparent color is given, */ + /* no disposal specified, */ + /* user input is not expected */ + 0x00, 0x00, /* delay time */ + 0x01, /* transparent color #1 */ + 0x00, /* block terminator */ - /* image descriptor */ - 0x2c, /* image separator */ - 0x00, 0x00, /* image left position */ - 0x00, 0x00, /* image top position */ - 0x01, 0x00, /* image width */ - 0x01, 0x00, /* image height */ - 0x00, /* no local color table, no interlaced */ + /* image descriptor */ + 0x2c, /* image separator */ + 0x00, 0x00, /* image left position */ + 0x00, 0x00, /* image top position */ + 0x01, 0x00, /* image width */ + 0x01, 0x00, /* image height */ + 0x00, /* no local color table, no interlaced */ - /* table based image data */ - 0x02, /* LZW minimum code size, */ - /* must be at least 2-bit */ - 0x02, /* block size */ + /* table based image data */ + 0x02, /* LZW minimum code size, */ + /* must be at least 2-bit */ + 0x02, /* block size */ 0x4c, 0x01, /* compressed bytes 01_001_100, 0000000_1 */ - /* 100: clear code */ - /* 001: 1 */ - /* 101: end of information code */ - 0x00, /* block terminator */ + /* 100: clear code */ + /* 001: 1 */ + /* 101: end of information code */ + 0x00, /* block terminator */ - 0x3B /* trailer */ + 0x3B /* trailer */ }; 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 @@ -11,16 +11,16 @@ typedef struct { - ngx_http_upstream_conf_t upstream; + ngx_http_upstream_conf_t upstream; - ngx_peers_t *peers; + ngx_peers_t *peers; - ngx_str_t index; + ngx_str_t index; - ngx_array_t *flushes; - ngx_array_t *params_len; - ngx_array_t *params; - ngx_array_t *params_source; + ngx_array_t *flushes; + ngx_array_t *params_len; + ngx_array_t *params; + ngx_array_t *params_source; } ngx_http_fastcgi_loc_conf_t; @@ -39,14 +39,14 @@ typedef enum { typedef struct { - ngx_http_fastcgi_state_e state; - u_char *pos; - u_char *last; - ngx_uint_t type; - size_t length; - size_t padding; + ngx_http_fastcgi_state_e state; + u_char *pos; + u_char *last; + ngx_uint_t type; + size_t length; + size_t padding; - ngx_uint_t header; + ngx_uint_t header; } ngx_http_fastcgi_ctx_t; @@ -151,6 +151,10 @@ static ngx_str_t ngx_http_fastcgi_scrip static ngx_conf_post_t ngx_http_fastcgi_lowat_post = { ngx_http_fastcgi_lowat_check }; +static ngx_conf_deprecated_t ngx_conf_deprecated_fastcgi_header_buffer_size = { + ngx_conf_deprecated, "fastcgi_header_buffer_size", "fastcgi_buffer_size" +}; + static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, @@ -199,12 +203,19 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_lowat), &ngx_http_fastcgi_lowat_post }, + { ngx_string("fastcgi_buffer_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffer_size), + NULL }, + { ngx_string("fastcgi_header_buffer_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.header_buffer_size), - NULL }, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffer_size), + &ngx_conf_deprecated_fastcgi_header_buffer_size }, { ngx_string("fastcgi_pass_request_headers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, @@ -371,8 +382,13 @@ ngx_http_fastcgi_handler(ngx_http_reques u->abort_request = ngx_http_fastcgi_abort_request; u->finalize_request = ngx_http_fastcgi_finalize_request; - u->pipe.input_filter = ngx_http_fastcgi_input_filter; - u->pipe.input_ctx = r; + u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); + if (u->pipe == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + u->pipe->input_filter = ngx_http_fastcgi_input_filter; + u->pipe->input_ctx = r; r->upstream = u; @@ -799,13 +815,13 @@ ngx_http_fastcgi_process_header(ngx_http if (f->state < ngx_http_fastcgi_st_data) { - f->pos = u->header_in.pos; - f->last = u->header_in.last; + f->pos = u->buffer.pos; + f->last = u->buffer.last; rc = ngx_http_fastcgi_process_record(r, f); - u->header_in.pos = f->pos; - u->header_in.last = f->last; + u->buffer.pos = f->pos; + u->buffer.last = f->last; if (rc == NGX_AGAIN) { return NGX_AGAIN; @@ -835,22 +851,22 @@ ngx_http_fastcgi_process_header(ngx_http if (f->state == ngx_http_fastcgi_st_padding) { - if (u->header_in.pos + f->padding < u->header_in.last) { + if (u->buffer.pos + f->padding < u->buffer.last) { f->state = ngx_http_fastcgi_st_version; - u->header_in.pos += f->padding; + u->buffer.pos += f->padding; continue; } - if (u->header_in.pos + f->padding == u->header_in.last) { + if (u->buffer.pos + f->padding == u->buffer.last) { f->state = ngx_http_fastcgi_st_version; - u->header_in.pos = u->header_in.last; + u->buffer.pos = u->buffer.last; return NGX_AGAIN; } - f->padding -= u->header_in.last - u->header_in.pos; - u->header_in.pos = u->header_in.last; + f->padding -= u->buffer.last - u->buffer.pos; + u->buffer.pos = u->buffer.last; return NGX_AGAIN; } @@ -868,18 +884,18 @@ ngx_http_fastcgi_process_header(ngx_http } if (f->length) { - line.data = u->header_in.pos; + line.data = u->buffer.pos; - if (u->header_in.pos + f->length <= u->header_in.last) { + if (u->buffer.pos + f->length <= u->buffer.last) { line.len = f->length; - u->header_in.pos += f->length; + u->buffer.pos += f->length; f->length = 0; f->state = ngx_http_fastcgi_st_padding; } else { - line.len = u->header_in.last - u->header_in.pos; - f->length -= u->header_in.last - u->header_in.pos; - u->header_in.pos = u->header_in.last; + line.len = u->buffer.last - u->buffer.pos; + f->length -= u->buffer.last - u->buffer.pos; + u->buffer.pos = u->buffer.last; } while (line.data[line.len - 1] == LF @@ -893,7 +909,7 @@ ngx_http_fastcgi_process_header(ngx_http ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "FastCGI sent in stderr: \"%V\"", &line); - if (u->header_in.pos == u->header_in.last) { + if (u->buffer.pos == u->buffer.last) { return NGX_AGAIN; } @@ -907,17 +923,17 @@ ngx_http_fastcgi_process_header(ngx_http /* f->type == NGX_HTTP_FASTCGI_STDOUT */ - start = u->header_in.pos; + start = u->buffer.pos; - if (u->header_in.pos + f->length < u->header_in.last) { + if (u->buffer.pos + f->length < u->buffer.last) { /* - * set u->header_in.last to the end of the FastCGI record data + * set u->buffer.last to the end of the FastCGI record data * for ngx_http_parse_header_line() */ - last = u->header_in.last; - u->header_in.last = u->header_in.pos + f->length; + last = u->buffer.last; + u->buffer.last = u->buffer.pos + f->length; } else { last = NULL; @@ -927,7 +943,7 @@ ngx_http_fastcgi_process_header(ngx_http for ( ;; ) { - rc = ngx_http_parse_header_line(r, &u->header_in); + rc = ngx_http_parse_header_line(r, &u->buffer); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fastcgi parser: %d", rc); @@ -1024,13 +1040,13 @@ ngx_http_fastcgi_process_header(ngx_http } if (last) { - u->header_in.last = last; + u->buffer.last = last; } - f->length -= u->header_in.pos - start; + f->length -= u->buffer.pos - start; if (rc == NGX_AGAIN) { - if (u->header_in.pos == u->header_in.last) { + if (u->buffer.pos == u->buffer.last) { return NGX_AGAIN; } @@ -1439,12 +1455,14 @@ ngx_http_fastcgi_create_loc_conf(ngx_con * conf->index.data = NULL; */ + conf->upstream.buffering = NGX_CONF_UNSET; + conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; - conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE; + conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; @@ -1485,6 +1503,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf ngx_http_script_compile_t sc; ngx_http_script_copy_code_t *copy; + ngx_conf_merge_value(conf->upstream.buffering, + prev->upstream.buffering, 1); + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -1497,8 +1518,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf ngx_conf_merge_size_value(conf->upstream.send_lowat, prev->upstream.send_lowat, 0); - ngx_conf_merge_size_value(conf->upstream.header_buffer_size, - prev->upstream.header_buffer_size, + ngx_conf_merge_size_value(conf->upstream.buffer_size, + prev->upstream.buffer_size, (size_t) ngx_pagesize); @@ -1512,7 +1533,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf } - size = conf->upstream.header_buffer_size; + size = conf->upstream.buffer_size; if (size < conf->upstream.bufs.size) { size = conf->upstream.bufs.size; } 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 @@ -172,7 +172,7 @@ static ngx_str_t http_access_log = ngx_ static ngx_str_t ngx_http_combined_fmt = - ngx_string("$remote_addr - $remote_user [$time_gmt] " + ngx_string("$remote_addr - $remote_user [$time_local] " "\"$request\" $status $body_bytes_sent " "\"$http_referer\" \"$http_user_agent\""); @@ -180,7 +180,7 @@ static ngx_str_t ngx_http_combined_fmt 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_string("time_local"), 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 }, @@ -1019,6 +1019,11 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx if (cf->args->nelts >= 3) { name = value[2]; + + if (ngx_strcmp(name.data, "combined") == 0) { + lmcf->combined_used = 1; + } + } else { name.len = sizeof("combined") - 1; name.data = (u_char *) "combined"; @@ -1384,6 +1389,7 @@ ngx_http_log_init(ngx_conf_t *cf) { ngx_str_t *value; ngx_array_t a; + ngx_http_handler_pt *h; ngx_http_log_fmt_t *fmt; ngx_http_log_main_conf_t *lmcf; ngx_http_core_main_conf_t *cmcf; @@ -1412,7 +1418,12 @@ ngx_http_log_init(ngx_conf_t *cf) cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - cmcf->log_handler = ngx_http_log_handler; + h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_log_handler; return NGX_OK; } diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_memcached_module.c @@ -0,0 +1,616 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +typedef struct { + ngx_http_upstream_conf_t upstream; + ngx_peers_t *peers; +} ngx_http_memcached_loc_conf_t; + + +typedef struct { + size_t rest; + ngx_http_request_t *request; +} ngx_http_memcached_ctx_t; + + +static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r); +static ngx_int_t ngx_http_memcached_reinit_request(ngx_http_request_t *r); +static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r); +static ngx_int_t ngx_http_memcached_filter_init(void *data); +static ngx_int_t ngx_http_memcached_filter(void *data, ssize_t bytes); +static void ngx_http_memcached_abort_request(ngx_http_request_t *r); +static void ngx_http_memcached_finalize_request(ngx_http_request_t *r, + ngx_int_t rc); + +static void *ngx_http_memcached_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + +static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_conf_bitmask_t ngx_http_memcached_next_upstream_masks[] = { + { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, + { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, + { ngx_string("invalid_response"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("not_found"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_memcached_commands[] = { + + { ngx_string("memcached_pass"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_memcached_pass, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("memcached_connect_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.connect_timeout), + NULL }, + + { ngx_string("memcached_send_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.send_timeout), + NULL }, + + { ngx_string("memcached_buffer_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.buffer_size), + NULL }, + + { ngx_string("memcached_read_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.read_timeout), + NULL }, + + { ngx_string("memcached_next_upstream"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream), + &ngx_http_memcached_next_upstream_masks }, + + { ngx_string("memcached_upstream_max_fails"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.max_fails), + NULL }, + + { ngx_string("memcached_upstream_fail_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_sec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.fail_timeout), + NULL }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_memcached_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_memcached_create_loc_conf, /* create location configration */ + ngx_http_memcached_merge_loc_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_memcached_module = { + NGX_MODULE_V1, + &ngx_http_memcached_module_ctx, /* module context */ + ngx_http_memcached_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +#define NGX_HTTP_MEMCACHED_END (sizeof(ngx_http_memcached_end) - 1) +static u_char ngx_http_memcached_end[] = CRLF "END" CRLF; + + +static ngx_int_t +ngx_http_memcached_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_upstream_t *u; + ngx_http_memcached_ctx_t *ctx; + ngx_http_memcached_loc_conf_t *mlcf; + + if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { + return NGX_HTTP_NOT_ALLOWED; + } + + rc = ngx_http_discard_body(r); + + if (rc != NGX_OK && rc != NGX_AGAIN) { + return rc; + } + + if (ngx_http_set_content_type(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); + + u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); + if (u == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + u->peer.log = r->connection->log; + u->peer.log_error = NGX_ERROR_ERR; + u->peer.peers = mlcf->peers; + u->peer.tries = mlcf->peers->number; +#if (NGX_THREADS) + u->peer.lock = &r->connection->lock; +#endif + + u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module; + + u->conf = &mlcf->upstream; + + u->create_request = ngx_http_memcached_create_request; + u->reinit_request = ngx_http_memcached_reinit_request; + u->process_header = ngx_http_memcached_process_header; + u->abort_request = ngx_http_memcached_abort_request; + u->finalize_request = ngx_http_memcached_finalize_request; + + r->upstream = u; + + ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t)); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ctx->rest = NGX_HTTP_MEMCACHED_END; + ctx->request = r; + + u->input_filter_init = ngx_http_memcached_filter_init; + u->input_filter = ngx_http_memcached_filter; + u->input_filter_ctx = ctx; + + ngx_http_upstream_init(r); + + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_memcached_create_request(ngx_http_request_t *r) +{ + size_t len; + ngx_buf_t *b; + ngx_chain_t *cl; + + len = sizeof("get ") - 1 + r->uri.len + sizeof(" " CRLF) - 1; + if (r->args.len) { + len += 1+ r->args.len; + } + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NGX_ERROR; + } + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + + r->upstream->request_bufs = cl; + + *b->last++ = 'g'; *b->last++ = 'e'; *b->last++ = 't'; *b->last++ = ' '; + + b->last = ngx_copy(b->last, r->uri.data, r->uri.len); + + if (r->args.len) { + *b->last++ = '?'; + b->last = ngx_copy(b->last, r->args.data, r->args.len); + } + +#if (NGX_DEBUG) + { + ngx_str_t s; + + s.len = b->last - b->pos; + s.data = b->pos; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http memcached request: \"%V\"", &s); + } +#endif + + *b->last++ = ' '; *b->last++ = CR; *b->last++ = LF; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_memcached_reinit_request(ngx_http_request_t *r) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_memcached_process_header(ngx_http_request_t *r) +{ + u_char *p, *len; + ngx_str_t line; + ngx_http_upstream_t *u; + + u = r->upstream; + + for (p = u->buffer.pos; p < u->buffer.last; p++) { + if (*p == LF) { + goto found; + } + } + + return NGX_AGAIN; + +found: + + *p = '\0'; + + line.len = p - u->buffer.pos - 1; + line.data = u->buffer.pos; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "memcached: \"%V\"", &line); + + p = u->buffer.pos; + + if (ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) { + + p += sizeof("VALUE ") - 1; + + if (ngx_strncmp(p, r->uri.data, r->uri.len) != 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "memcached sent invalid key in response \"%V\" " + "for key \"%V\"", + &line, &r->uri); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + p += r->uri.len; + + if (*p++ != ' ') { + goto no_valid; + } + + /* skip flags */ + + while (*p) { + if (*p++ == ' ') { + goto length; + } + } + + goto no_valid; + + length: + + len = p; + + while (*p && *p++ != CR) { /* void */ } + + r->headers_out.content_length_n = ngx_atoof(len, p - len - 1); + if (r->headers_out.content_length_n == -1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "memcached sent invalid length in response \"%V\" " + "for key \"%V\"", + &line, &r->uri); + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + u->headers_in.status_n = 200; + u->buffer.pos = p + 1; + + return NGX_OK; + } + + if (ngx_strcmp(p, "END\x0d") == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "key: \"%V\" was not found by memcached", &r->uri); + + u->headers_in.status_n = 404; + + return NGX_OK; + } + +no_valid: + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "memcached sent invalid response: \"%V\"", &line); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; +} + + +static ngx_int_t +ngx_http_memcached_filter_init(void *data) +{ + ngx_http_memcached_ctx_t *ctx = data; + + ngx_http_upstream_t *u; + + u = ctx->request->upstream; + + u->length += NGX_HTTP_MEMCACHED_END; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_memcached_filter(void *data, ssize_t bytes) +{ + ngx_http_memcached_ctx_t *ctx = data; + + u_char *last; + ngx_buf_t *b; + ngx_chain_t *cl, **ll; + ngx_http_upstream_t *u; + + u = ctx->request->upstream; + b = &u->buffer; + + if (u->length == ctx->rest) { + + if (ngx_strncmp(b->last, + ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END + - ctx->rest, + bytes) != 0) + { + ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, + "memcached sent invalid trailer"); + } + + u->length -= bytes; + ctx->rest -= bytes; + + return NGX_OK; + } + + for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { + ll = &cl->next; + } + + cl = ngx_chain_get_free_buf(ctx->request->pool, &u->free_bufs); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf->flush = 1; + cl->buf->memory = 1; + + *ll = cl; + + cl->buf->pos = b->last; + b->last += bytes; + cl->buf->last = b->last; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, + "memcached filter bytes:%z size:%z length:%z rest:%z", + bytes, b->last - b->pos, u->length, ctx->rest); + + if (b->last - b->pos <= (ssize_t) (u->length - NGX_HTTP_MEMCACHED_END)) { + u->length -= bytes; + return NGX_OK; + } + + + last = b->pos + u->length - NGX_HTTP_MEMCACHED_END; + + if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) { + ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, + "memcached sent invalid trailer"); + } + + ctx->rest = u->length - (b->last - b->pos); + b->last = last; + cl->buf->last = last; + u->length = ctx->rest; + + return NGX_OK; +} + + +static void +ngx_http_memcached_abort_request(ngx_http_request_t *r) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "abort http memcached request"); + return; +} + + +static void +ngx_http_memcached_finalize_request(ngx_http_request_t *r, ngx_int_t rc) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "finalize http memcached request"); + return; +} + + +static void * +ngx_http_memcached_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_memcached_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->upstream.bufs.num = 0; + * conf->upstream.next_upstream = 0; + * conf->upstream.temp_path = NULL; + * conf->upstream.schema = { 0, NULL }; + * conf->upstream.uri = { 0, NULL }; + * conf->upstream.location = NULL; + * + * conf->peers = NULL; + */ + + conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + + conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; + + conf->upstream.max_fails = NGX_CONF_UNSET_UINT; + conf->upstream.fail_timeout = NGX_CONF_UNSET; + + /* "fastcgi_cyclic_temp_file" is disabled */ + conf->upstream.cyclic_temp_file = 0; + + /* the hardcoded values */ + conf->upstream.send_lowat = 0; + conf->upstream.bufs.num = 0; + conf->upstream.busy_buffers_size = 0; + conf->upstream.max_temp_file_size = 0; + conf->upstream.temp_file_write_size = 0; + conf->upstream.pass_x_powered_by = 0; + conf->upstream.redirect_errors = 1; + conf->upstream.redirect_404 = 1; + conf->upstream.pass_server = 1; + conf->upstream.pass_date = 1; + conf->upstream.pass_request_headers = 0; + conf->upstream.pass_request_body = 0; + + return conf; +} + + +static char * +ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_memcached_loc_conf_t *prev = parent; + ngx_http_memcached_loc_conf_t *conf = child; + + ngx_uint_t i; + + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, + prev->upstream.connect_timeout, 60000); + + ngx_conf_merge_msec_value(conf->upstream.send_timeout, + prev->upstream.send_timeout, 60000); + + ngx_conf_merge_msec_value(conf->upstream.read_timeout, + prev->upstream.read_timeout, 60000); + + ngx_conf_merge_size_value(conf->upstream.buffer_size, + prev->upstream.buffer_size, + (size_t) ngx_pagesize); + + ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, + prev->upstream.next_upstream, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_UPSTREAM_FT_ERROR + |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); + + ngx_conf_merge_unsigned_value(conf->upstream.max_fails, + prev->upstream.max_fails, 1); + + ngx_conf_merge_sec_value(conf->upstream.fail_timeout, + prev->upstream.fail_timeout, 10); + + if (conf->peers && conf->peers->number > 1) { + for (i = 0; i < conf->peers->number; i++) { + conf->peers->peer[i].weight = 1; + conf->peers->peer[i].max_fails = conf->upstream.max_fails; + conf->peers->peer[i].fail_timeout = conf->upstream.fail_timeout; + } + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_memcached_loc_conf_t *lcf = conf; + + ngx_str_t *value; + ngx_inet_upstream_t inet_upstream; + ngx_http_core_loc_conf_t *clcf; + + if (lcf->upstream.schema.len) { + return "is duplicate"; + } + + value = cf->args->elts; + + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + + inet_upstream.name = value[1]; + inet_upstream.url = value[1]; + + lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); + if (lcf->peers == NULL) { + return NGX_CONF_ERROR; + } + + lcf->upstream.schema.len = sizeof("memcached://") - 1; + lcf->upstream.schema.data = (u_char *) "memcached://"; + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + clcf->handler = ngx_http_memcached_handler; + + lcf->upstream.location = clcf->name; + + if (clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + + return NGX_CONF_OK; +} 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 @@ -111,6 +111,10 @@ static char *ngx_http_proxy_lowat_check( static ngx_conf_post_t ngx_http_proxy_lowat_post = { ngx_http_proxy_lowat_check }; +static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_header_buffer_size = { + ngx_conf_deprecated, "proxy_header_buffer_size", "proxy_buffer_size" +}; + static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, @@ -138,6 +142,13 @@ static ngx_command_t ngx_http_proxy_com 0, NULL }, + { ngx_string("proxy_buffering"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering), + NULL }, + { ngx_string("proxy_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -201,12 +212,19 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body), NULL }, + { ngx_string("proxy_buffer_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size), + NULL }, + { ngx_string("proxy_header_buffer_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, upstream.header_buffer_size), - NULL }, + offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size), + &ngx_conf_deprecated_proxy_header_buffer_size }, { ngx_string("proxy_read_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, @@ -333,6 +351,7 @@ static char ngx_http_proxy_version[] = static ngx_table_elt_t ngx_http_proxy_headers[] = { { 0, ngx_string("Host"), ngx_string("$proxy_host") }, { 0, ngx_string("Connection"), ngx_string("close") }, + { 0, ngx_string("Keep-Alive"), ngx_string("") }, { 0, ngx_null_string, ngx_null_string } }; @@ -395,7 +414,15 @@ ngx_http_proxy_handler(ngx_http_request_ u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; } - u->pipe.input_filter = ngx_event_pipe_copy_input_filter; + if (plcf->upstream.buffering) { + + u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); + if (u->pipe == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + u->pipe->input_filter = ngx_event_pipe_copy_input_filter; + } u->accel = 1; @@ -828,7 +855,7 @@ ngx_http_proxy_parse_status_line(ngx_htt state = r->state; - for (pos = u->header_in.pos; pos < u->header_in.last; pos++) { + for (pos = u->buffer.pos; pos < u->buffer.last; pos++) { ch = *pos; switch (state) { @@ -986,14 +1013,14 @@ ngx_http_proxy_parse_status_line(ngx_htt } } - u->header_in.pos = pos; + u->buffer.pos = pos; r->state = state; return NGX_AGAIN; done: - u->header_in.pos = pos + 1; + u->buffer.pos = pos + 1; if (p->status_end == NULL) { p->status_end = pos; @@ -1019,7 +1046,7 @@ ngx_http_proxy_process_header(ngx_http_r for ( ;; ) { - rc = ngx_http_parse_header_line(r, &r->upstream->header_in); + rc = ngx_http_parse_header_line(r, &r->upstream->buffer); if (rc == NGX_OK) { @@ -1359,7 +1386,6 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ * set by ngx_pcalloc(): * * conf->upstream.bufs.num = 0; - * conf->upstream.path = NULL; * conf->upstream.next_upstream = 0; * conf->upstream.temp_path = NULL; * conf->upstream.schema = { 0, NULL }; @@ -1377,12 +1403,14 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ * conf->rewrite_locations = NULL; */ + conf->upstream.buffering = NGX_CONF_UNSET; + conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; - conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE; + conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; @@ -1426,6 +1454,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t ngx_http_script_compile_t sc; ngx_http_script_copy_code_t *copy; + ngx_conf_merge_value(conf->upstream.buffering, + prev->upstream.buffering, 1); + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -1438,8 +1469,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t ngx_conf_merge_size_value(conf->upstream.send_lowat, prev->upstream.send_lowat, 0); - ngx_conf_merge_size_value(conf->upstream.header_buffer_size, - prev->upstream.header_buffer_size, + ngx_conf_merge_size_value(conf->upstream.buffer_size, + prev->upstream.buffer_size, (size_t) ngx_pagesize); ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, @@ -1452,7 +1483,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t } - size = conf->upstream.header_buffer_size; + size = conf->upstream.buffer_size; if (size < conf->upstream.bufs.size) { size = conf->upstream.bufs.size; } diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -136,7 +136,7 @@ ngx_http_range_header_filter(ngx_http_re || r->headers_out.status != NGX_HTTP_OK || r->main != r || r->headers_out.content_length_n == -1 - || !r->filter_allow_ranges) + || !r->allow_ranges) { return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -264,7 +264,7 @@ ngx_http_realip_init(ngx_cycle_t *cycle) *h = ngx_http_realip_handler; - h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); + h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); if (h == NULL) { return NGX_ERROR; } 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 @@ -256,7 +256,7 @@ ngx_http_static_handler(ngx_http_request return NGX_HTTP_INTERNAL_SERVER_ERROR; } - r->filter_allow_ranges = 1; + r->allow_ranges = 1; rc = ngx_http_send_header(r); 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 @@ -326,8 +326,18 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma cmcf->phases[NGX_HTTP_REWRITE_PHASE].type = NGX_OK; + if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + cmcf->phases[NGX_HTTP_PREACCESS_PHASE].type = NGX_OK; + + if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers, - cf->pool, 4, sizeof(ngx_http_handler_pt)) + cf->pool, 2, sizeof(ngx_http_handler_pt)) != NGX_OK) { return NGX_CONF_ERROR; @@ -346,6 +356,16 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma cmcf->phases[NGX_HTTP_CONTENT_PHASE].type = NGX_OK; + if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers, + cf->pool, 1, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + cmcf->phases[NGX_HTTP_LOG_PHASE].type = NGX_OK; + + cmcf->headers_in_hash.max_size = 100; cmcf->headers_in_hash.bucket_limit = 1; cmcf->headers_in_hash.bucket_size = sizeof(ngx_http_header_t); 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 @@ -76,7 +76,11 @@ void ngx_http_finalize_request(ngx_http_ void ngx_http_empty_handler(ngx_event_t *wev); void ngx_http_request_empty_handler(ngx_http_request_t *r); -ngx_int_t ngx_http_send_last(ngx_http_request_t *r); +#define NGX_HTTP_LAST 1 +#define NGX_HTTP_FLUSH 2 + +ngx_int_t ngx_http_send_special(ngx_http_request_t *r, ngx_uint_t flags); + u_char * ngx_http_log_error_info(ngx_http_request_t *r, u_char *buf, size_t len); diff --git a/src/http/ngx_http_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 @@ -476,7 +476,7 @@ ngx_http_core_run_phases(ngx_http_reques cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - for (/* void */; r->phase < NGX_HTTP_LAST_PHASE; r->phase++) { + for (/* void */; r->phase < NGX_HTTP_LOG_PHASE; r->phase++) { if (r->phase == NGX_HTTP_REWRITE_PHASE + 1 && r->uri_changed) { @@ -1098,7 +1098,8 @@ ngx_http_subrequest(ngx_http_request_t * } if (ngx_list_init(&sr->headers_out.headers, r->pool, 20, - sizeof(ngx_table_elt_t)) == NGX_ERROR) + sizeof(ngx_table_elt_t)) + == NGX_ERROR) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -50,10 +50,12 @@ typedef enum { NGX_HTTP_FIND_CONFIG_PHASE, NGX_HTTP_REWRITE_PHASE, + NGX_HTTP_PREACCESS_PHASE, + NGX_HTTP_ACCESS_PHASE, NGX_HTTP_CONTENT_PHASE, - NGX_HTTP_LAST_PHASE + NGX_HTTP_LOG_PHASE } ngx_http_phases; @@ -66,8 +68,7 @@ typedef struct { typedef struct { ngx_array_t servers; /* ngx_http_core_srv_conf_t */ - ngx_http_phase_t phases[NGX_HTTP_LAST_PHASE]; - ngx_http_handler_pt log_handler; + ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1]; ngx_hash_t headers_in_hash; ngx_hash_t variables_hash; @@ -84,8 +85,8 @@ typedef struct { typedef struct { /* - * array of the ngx_http_core_loc_conf_t, - * used in the translation handler and in the merge phase + * array of the ngx_http_core_loc_conf_t *, + * used in the ngx_http_core_find_location() and in the merge phase */ ngx_array_t locations; @@ -287,7 +288,7 @@ extern ngx_uint_t ngx_http_max_module; \ #define ngx_http_clear_accept_ranges(r) \ \ - r->filter_allow_ranges = 0; \ + r->allow_ranges = 0; \ if (r->headers_out.accept_ranges) { \ r->headers_out.accept_ranges->hash = 0 ; \ r->headers_out.accept_ranges = NULL; \ 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 @@ -95,6 +95,10 @@ ngx_http_header_t ngx_http_headers_in[] { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range), ngx_http_process_header_line }, + { ngx_string("Transfer-Encoding"), + offsetof(ngx_http_headers_in_t, transfer_encoding), + ngx_http_process_header_line }, + #if (NGX_HTTP_GZIP) { ngx_string("Accept-Encoding"), offsetof(ngx_http_headers_in_t, accept_encoding), @@ -377,7 +381,8 @@ void ngx_http_init_request(ngx_event_t * if (ngx_list_init(&r->headers_out.headers, r->pool, 20, - sizeof(ngx_table_elt_t)) == NGX_ERROR) + sizeof(ngx_table_elt_t)) + == NGX_ERROR) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -660,7 +665,8 @@ ngx_http_process_request_line(ngx_event_ if (ngx_list_init(&r->headers_in.headers, r->pool, 20, - sizeof(ngx_table_elt_t)) == NGX_ERROR) + sizeof(ngx_table_elt_t)) + == NGX_ERROR) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -668,7 +674,8 @@ ngx_http_process_request_line(ngx_event_ if (ngx_array_init(&r->headers_in.cookies, r->pool, 2, - sizeof(ngx_table_elt_t *)) == NGX_ERROR) + sizeof(ngx_table_elt_t *)) + == NGX_ERROR) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -1213,7 +1220,7 @@ ngx_http_process_request_header(ngx_http if (r->headers_in.content_length_n == NGX_ERROR) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent invalid \"Content-Length\" header"); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + ngx_http_finalize_request(r, NGX_HTTP_LENGTH_REQUIRED); return NGX_ERROR; } } @@ -1221,7 +1228,16 @@ ngx_http_process_request_header(ngx_http if (r->method == NGX_HTTP_POST && r->headers_in.content_length_n == -1) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "client sent POST method without \"Content-Length\" header"); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + ngx_http_finalize_request(r, NGX_HTTP_LENGTH_REQUIRED); + return NGX_ERROR; + } + + if (r->headers_in.transfer_encoding + && ngx_strstr(r->headers_in.transfer_encoding->value.data, "chunked")) + { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent \"Transfer-Encoding: chunked\" header"); + ngx_http_finalize_request(r, NGX_HTTP_LENGTH_REQUIRED); return NGX_ERROR; } @@ -2095,7 +2111,10 @@ ngx_http_keepalive_handler(ngx_event_t * #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { - if (rev->pending_eof) { + if (rev->pending_eof + /* FreeBSD 5.x-6.x may erroneously report ETIMEDOUT */ + && rev->kq_errno != NGX_ETIMEDOUT) + { c->log->handler = NULL; ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno, "kevent() reported that client %V closed " @@ -2312,7 +2331,7 @@ ngx_http_request_empty_handler(ngx_http_ ngx_int_t -ngx_http_send_last(ngx_http_request_t *r) +ngx_http_send_special(ngx_http_request_t *r, ngx_uint_t flags) { ngx_buf_t *b; ngx_chain_t out; @@ -2322,7 +2341,14 @@ ngx_http_send_last(ngx_http_request_t *r return NGX_ERROR; } - b->last_buf = 1; + if (flags & NGX_HTTP_LAST) { + b->last_buf = 1; + } + + if (flags & NGX_HTTP_FLUSH) { + b->flush = 1; + } + out.buf = b; out.next = NULL; @@ -2354,8 +2380,10 @@ void ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error) { ngx_log_t *log; + ngx_uint_t i, n; struct linger linger; ngx_http_log_ctx_t *ctx; + ngx_http_handler_pt *log_handler; ngx_http_core_loc_conf_t *clcf; ngx_http_core_main_conf_t *cmcf; @@ -2386,8 +2414,10 @@ ngx_http_request_done(ngx_http_request_t cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - if (cmcf->log_handler) { - cmcf->log_handler(r); + log_handler = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.elts; + n = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.nelts; + for (i = 0; i < n; i++) { + log_handler[i](r); } if (r->connection->timedout) { 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 @@ -58,6 +58,7 @@ #define NGX_HTTP_NOT_FOUND 404 #define NGX_HTTP_NOT_ALLOWED 405 #define NGX_HTTP_REQUEST_TIME_OUT 408 +#define NGX_HTTP_LENGTH_REQUIRED 411 #define NGX_HTTP_REQUEST_ENTITY_TOO_LARGE 413 #define NGX_HTTP_REQUEST_URI_TOO_LARGE 414 #define NGX_HTTP_RANGE_NOT_SATISFIABLE 416 @@ -143,6 +144,8 @@ typedef struct { ngx_table_elt_t *range; + ngx_table_elt_t *transfer_encoding; + #if (NGX_HTTP_GZIP) ngx_table_elt_t *accept_encoding; ngx_table_elt_t *via; @@ -400,7 +403,7 @@ struct ngx_http_request_s { unsigned main_filter_need_in_memory:1; unsigned filter_need_in_memory:1; unsigned filter_need_temporary:1; - unsigned filter_allow_ranges:1; + unsigned allow_ranges:1; #if (NGX_STAT_STUB) unsigned stat_reading:1; diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -115,6 +115,14 @@ static char error_410_page[] = ; +static char error_411_page[] = +"" CRLF +"411 Length Required" CRLF +"" CRLF +"

411 Length Required

" CRLF +; + + static char error_413_page[] = "" CRLF "413 Request Entity Too Large" CRLF @@ -213,7 +221,7 @@ static ngx_str_t error_pages[] = { ngx_string(error_408_page), ngx_null_string, /* 409 */ ngx_string(error_410_page), - ngx_null_string, /* 411 */ + ngx_string(error_411_page), ngx_null_string, /* 412 */ ngx_string(error_413_page), ngx_string(error_414_page), diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -6,7 +6,6 @@ #include #include -#include #include @@ -24,6 +23,12 @@ static void ngx_http_upstream_send_reque static void ngx_http_upstream_process_header(ngx_event_t *rev); static void ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u); +static void + ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r); +static void ngx_http_upstream_process_non_buffered_body(ngx_event_t *ev); +static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data); +static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data, + ssize_t bytes); static void ngx_http_upstream_process_downstream(ngx_http_request_t *r); static void ngx_http_upstream_process_body(ngx_event_t *ev); static void ngx_http_upstream_dummy_handler(ngx_event_t *wev); @@ -699,21 +704,21 @@ ngx_http_upstream_reinit(ngx_http_reques u->output.in = NULL; u->output.busy = NULL; - /* reinit u->header_in buffer */ + /* reinit u->buffer */ #if 0 if (u->cache) { - u->header_in.pos = u->header_in.start + u->cache->ctx.header_size; - u->header_in.last = u->header_in.pos; + u->buffer.pos = u->buffer.start + u->cache->ctx.header_size; + u->buffer.last = u->buffer.pos; } else { - u->header_in.pos = u->header_in.start; - u->header_in.last = u->header_in.start; + u->buffer.pos = u->buffer.start; + u->buffer.last = u->buffer.start; } #else - u->header_in.pos = u->header_in.start; - u->header_in.last = u->header_in.start; + u->buffer.pos = u->buffer.start; + u->buffer.last = u->buffer.start; #endif @@ -881,23 +886,24 @@ ngx_http_upstream_process_header(ngx_eve return; } - if (u->header_in.start == NULL) { - u->header_in.start = ngx_palloc(r->pool, u->conf->header_buffer_size); - if (u->header_in.start == NULL) { + if (u->buffer.start == NULL) { + u->buffer.start = ngx_palloc(r->pool, u->conf->buffer_size); + if (u->buffer.start == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } - u->header_in.pos = u->header_in.start; - u->header_in.last = u->header_in.start; - u->header_in.end = u->header_in.start + u->conf->header_buffer_size; - u->header_in.temporary = 1; - - u->header_in.tag = u->output.tag; + u->buffer.pos = u->buffer.start; + u->buffer.last = u->buffer.start; + u->buffer.end = u->buffer.start + u->conf->buffer_size; + u->buffer.temporary = 1; + + u->buffer.tag = u->output.tag; if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 8, - sizeof(ngx_table_elt_t)) == NGX_ERROR) + sizeof(ngx_table_elt_t)) + != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -906,14 +912,14 @@ ngx_http_upstream_process_header(ngx_eve #if 0 if (u->cache) { - u->header_in.pos += u->cache->ctx.header_size; - u->header_in.last = u->header_in.pos; + u->buffer.pos += u->cache->ctx.header_size; + u->buffer.last = u->buffer.pos; } #endif } - n = u->peer.connection->recv(u->peer.connection, u->header_in.last, - u->header_in.end - u->header_in.last); + n = u->peer.connection->recv(u->peer.connection, u->buffer.last, + u->buffer.end - u->buffer.last); if (n == NGX_AGAIN) { #if 0 @@ -939,7 +945,7 @@ ngx_http_upstream_process_header(ngx_eve return; } - u->header_in.last += n; + u->buffer.last += n; #if 0 u->valid_header_in = 0; @@ -954,7 +960,7 @@ ngx_http_upstream_process_header(ngx_eve ngx_add_timer(rev, u->read_timeout); #endif - if (u->header_in.pos == u->header_in.end) { + if (u->buffer.pos == u->buffer.end) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "upstream sent too big header"); @@ -1020,6 +1026,13 @@ ngx_http_upstream_process_header(ngx_eve && u->conf->redirect_errors && r->err_ctx == NULL) { + if (u->headers_in.status_n == NGX_HTTP_NOT_FOUND + && u->conf->redirect_404) + { + ngx_http_upstream_finalize_request(r, u, 404); + return; + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->error_pages) { @@ -1112,6 +1125,7 @@ ngx_http_upstream_process_header(ngx_eve static void ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) { + ssize_t size; ngx_int_t rc; ngx_uint_t i, key; ngx_list_part_t *part; @@ -1165,6 +1179,13 @@ ngx_http_upstream_send_response(ngx_http r->headers_out.status = u->headers_in.status_n; r->headers_out.status_line = u->headers_in.status_line; + if (r->headers_out.content_length_n != -1) { + u->length = (size_t) r->headers_out.content_length_n; + + } else { + u->length = NGX_MAX_SIZE_T_VALUE; + } + rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK) { @@ -1188,6 +1209,53 @@ ngx_http_upstream_send_response(ngx_http } } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (u->pipe == NULL) { + + if (u->input_filter == NULL) { + u->input_filter_init = ngx_http_upstream_non_buffered_filter_init; + u->input_filter = ngx_http_upstream_non_buffered_filter; + u->input_filter_ctx = r; + } + + u->peer.connection->read->handler = + ngx_http_upstream_process_non_buffered_body; + r->write_event_handler = + ngx_http_upstream_process_non_buffered_downstream; + + r->limit_rate = 0; + + if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + size = u->buffer.last - u->buffer.pos; + + if (size) { + u->buffer.last = u->buffer.pos; + + if (u->input_filter(u->input_filter_ctx, size) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + ngx_http_upstream_process_non_buffered_body(r->connection->write); + + } else { + u->buffer.pos = u->buffer.start; + u->buffer.last = u->buffer.start; + + if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + } + + return; + } + /* TODO: preallocate event_pipe bufs, look "Content-Length" */ #if 0 @@ -1201,7 +1269,7 @@ ngx_http_upstream_send_response(ngx_http } if (u->cachable) { - header = (ngx_http_cache_header_t *) u->header_in->start; + header = (ngx_http_cache_header_t *) u->buffer->start; header->expires = u->cache->ctx.expires; header->last_modified = u->cache->ctx.last_modified; @@ -1216,7 +1284,7 @@ ngx_http_upstream_send_response(ngx_http #endif - p = &u->pipe; + p = u->pipe; p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter; p->output_ctx = r; @@ -1256,11 +1324,11 @@ ngx_http_upstream_send_response(ngx_http ngx_http_upstream_finalize_request(r, u, 0); return; } - p->preread_bufs->buf = &u->header_in; + p->preread_bufs->buf = &u->buffer; p->preread_bufs->next = NULL; - u->header_in.recycled = 1; - - p->preread_size = u->header_in.last - u->header_in.pos; + u->buffer.recycled = 1; + + p->preread_size = u->buffer.last - u->buffer.pos; if (u->cachable) { p->buf_to_file = ngx_calloc_buf(r->pool); @@ -1268,8 +1336,8 @@ ngx_http_upstream_send_response(ngx_http ngx_http_upstream_finalize_request(r, u, 0); return; } - p->buf_to_file->pos = u->header_in.start; - p->buf_to_file->last = u->header_in.pos; + p->buf_to_file->pos = u->buffer.start; + p->buf_to_file->last = u->buffer.pos; p->buf_to_file->temporary = 1; } @@ -1282,10 +1350,10 @@ ngx_http_upstream_send_response(ngx_http p->free_bufs = 1; /* - * event_pipe would do u->header_in.last += p->preread_size + * event_pipe would do u->buffer.last += p->preread_size * as though these bytes were read */ - u->header_in.last = u->header_in.pos; + u->buffer.last = u->buffer.pos; if (u->conf->cyclic_temp_file) { @@ -1302,8 +1370,6 @@ ngx_http_upstream_send_response(ngx_http p->cyclic_temp_file = 0; } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - p->read_timeout = u->conf->read_timeout; p->send_timeout = clcf->send_timeout; p->send_lowat = clcf->send_lowat; @@ -1316,6 +1382,191 @@ ngx_http_upstream_send_response(ngx_http static void +ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r) +{ + ngx_http_upstream_process_non_buffered_body(r->connection->write); +} + + +static void +ngx_http_upstream_process_non_buffered_body(ngx_event_t *ev) +{ + size_t size; + ssize_t n; + ngx_buf_t *b; + ngx_uint_t do_write; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_upstream_t *u; + ngx_http_core_loc_conf_t *clcf; + + c = ev->data; + + if (ev->write) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream process non buffered downstream"); + c->log->action = "sending to client"; + + } else { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream process non buffered upstream"); + c->log->action = "reading upstream"; + } + + if (ev->timedout) { + if (ev->write) { + c->timedout = 1; + ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, + "client timed out"); + } else { + ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, + "upstream timed out"); + } + } + + r = c->data; + u = r->upstream; + + b = &u->buffer; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + do_write = ev->write; + + for ( ;; ) { + + if (do_write) { + + if (u->out_bufs || u->busy_bufs) { + if (ngx_http_output_filter(r, u->out_bufs) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + ngx_chain_update_chains(&u->free_bufs, &u->busy_bufs, + &u->out_bufs, u->output.tag); + } + + if (u->busy_bufs == NULL) { + + if (u->length == 0 + || u->peer.connection->read->eof + || u->peer.connection->read->error) + { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + b->pos = b->start; + b->last = b->start; + } + } + + size = b->end - b->last; + + if (size > u->length) { + size = u->length; + } + + if (size && u->peer.connection->read->ready) { + n = u->peer.connection->recv(u->peer.connection, b->last, size); + + if (n == NGX_AGAIN) { + break; + } + + if (n > 0) { + if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + } + + do_write = 1; + + continue; + } + + break; + } + + if (ngx_handle_write_event(r->connection->write, clcf->send_lowat) + == NGX_ERROR) + { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (r->connection->write->active) { + ngx_add_timer(r->connection->write, clcf->send_timeout); + + } else if (r->connection->write->timer_set) { + ngx_del_timer(r->connection->write); + } + + if (ngx_handle_read_event(u->peer.connection->read, 0) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (u->peer.connection->read->active) { + ngx_add_timer(u->peer.connection->read, u->conf->read_timeout); + + } else if (r->connection->read->timer_set) { + ngx_del_timer(r->connection->read); + } +} + + +static ngx_int_t +ngx_http_upstream_non_buffered_filter_init(void *data) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes) +{ + ngx_http_request_t *r = data; + + ngx_buf_t *b; + ngx_chain_t *cl, **ll; + ngx_http_upstream_t *u; + + u = r->upstream; + + for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { + ll = &cl->next; + } + + cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs); + if (cl == NULL) { + return NGX_ERROR; + } + + *ll = cl; + + cl->buf->flush = 1; + cl->buf->memory = 1; + + b = &u->buffer; + + cl->buf->pos = b->last; + b->last += bytes; + cl->buf->last = b->last; + + if (u->length == NGX_MAX_SIZE_T_VALUE) { + return NGX_OK; + } + + u->length -= bytes; + + return NGX_OK; +} + + +static void ngx_http_upstream_process_downstream(ngx_http_request_t *r) { ngx_http_upstream_process_body(r->connection->write); @@ -1345,7 +1596,7 @@ ngx_http_upstream_process_body(ngx_event c->log->action = "reading upstream"; } - p = &u->pipe; + p = u->pipe; if (ev->timedout) { if (ev->write) { @@ -1614,10 +1865,10 @@ ngx_http_upstream_finalize_request(ngx_h rc = 0; } - if (u->pipe.temp_file) { + if (u->pipe && u->pipe->temp_file) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream temp fd: %d", - u->pipe.temp_file->file.fd); + u->pipe->temp_file->file.fd); } #if 0 @@ -1637,7 +1888,7 @@ ngx_http_upstream_finalize_request(ngx_h r->connection->log->action = "sending to client"; if (rc == 0 && r->main == r) { - rc = ngx_http_send_last(r); + rc = ngx_http_send_special(r, NGX_HTTP_LAST); } ngx_http_finalize_request(r, rc); 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 @@ -51,7 +51,7 @@ typedef struct { ngx_msec_t timeout; size_t send_lowat; - size_t header_buffer_size; + size_t buffer_size; size_t busy_buffers_size; size_t max_temp_file_size; @@ -68,6 +68,7 @@ typedef struct { ngx_bufs_t bufs; + ngx_flag_t buffering; ngx_flag_t pass_request_headers; ngx_flag_t pass_request_body; @@ -86,6 +87,8 @@ typedef struct { ngx_str_t location; ngx_str_t url; /* used in proxy_rewrite_location */ + ngx_uint_t redirect_404; /* unsigned redirect_404:1; */ + #if (NGX_HTTP_SSL) ngx_ssl_t *ssl; #endif @@ -139,7 +142,7 @@ typedef struct { struct ngx_http_upstream_s { ngx_peer_connection_t peer; - ngx_event_pipe_t pipe; + ngx_event_pipe_t *pipe; ngx_chain_t *request_bufs; @@ -150,7 +153,16 @@ struct ngx_http_upstream_s { ngx_http_upstream_headers_in_t headers_in; - ngx_buf_t header_in; + ngx_buf_t buffer; + size_t length; + + ngx_chain_t *out_bufs; + ngx_chain_t *busy_bufs; + ngx_chain_t *free_bufs; + + ngx_int_t (*input_filter_init)(void *data); + ngx_int_t (*input_filter)(void *data, ssize_t bytes); + void *input_filter_ctx; ngx_int_t (*create_request)(ngx_http_request_t *r); ngx_int_t (*reinit_request)(ngx_http_request_t *r); 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 @@ -851,7 +851,8 @@ ngx_http_variables_init_vars(ngx_conf_t cmcf->variables_hash.name = "http variables"; if (ngx_hash_init(&cmcf->variables_hash, cf->pool, - cmcf->all_variables.elts, cmcf->all_variables.nelts) != NGX_OK) + cmcf->all_variables.elts, cmcf->all_variables.nelts) + != NGX_OK) { return NGX_ERROR; } diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -58,7 +58,7 @@ ngx_freebsd_sendfile_chain(ngx_connectio if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof - /* FreeBSD 6.0 may erroneously report ETIMEDOUT */ + /* FreeBSD 5.x-6.x may erroneously report ETIMEDOUT */ && wev->kq_errno != NGX_ETIMEDOUT) { (void) ngx_connection_error(c, wev->kq_errno, diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -32,23 +32,26 @@ ngx_readv_chain(ngx_connection_t *c, ngx rev->pending_eof, rev->available, rev->kq_errno); if (rev->available == 0) { - if (rev->pending_eof) { + + if (!rev->pending_eof) { + return NGX_AGAIN; + } + + /* FreeBSD 5.x-6.x may erroneously report ETIMEDOUT */ + if (rev->kq_errno != NGX_ETIMEDOUT) { + rev->ready = 0; rev->eof = 1; - ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno, - "kevent() reported about an closed connection"); - if (rev->kq_errno) { rev->error = 1; ngx_set_socket_errno(rev->kq_errno); - return NGX_ERROR; + + return ngx_connection_error(c, rev->kq_errno, + "kevent() reported about an closed connection"); } return 0; - - } else { - return NGX_AGAIN; } } } diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -25,7 +25,14 @@ ssize_t ngx_unix_recv(ngx_connection_t * rev->pending_eof, rev->available, rev->kq_errno); if (rev->available == 0) { - if (rev->pending_eof) { + + if (!rev->pending_eof) { + return NGX_AGAIN; + } + + /* FreeBSD 5.x-6.x may erroneously report ETIMEDOUT */ + if (rev->kq_errno != NGX_ETIMEDOUT) { + rev->ready = 0; rev->eof = 1; @@ -38,9 +45,6 @@ ssize_t ngx_unix_recv(ngx_connection_t * } return 0; - - } else { - return NGX_AGAIN; } } } diff --git a/src/os/unix/ngx_send.c b/src/os/unix/ngx_send.c --- a/src/os/unix/ngx_send.c +++ b/src/os/unix/ngx_send.c @@ -19,7 +19,11 @@ ssize_t ngx_unix_send(ngx_connection_t * #if (NGX_HAVE_KQUEUE) - if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) + && wev->pending_eof + /* FreeBSD 5.x-6.x may erroneously report ETIMEDOUT */ + && wev->kq_errno != NGX_ETIMEDOUT) + { (void) ngx_connection_error(c, wev->kq_errno, "kevent() reported about an closed connection"); wev->error = 1; diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -48,6 +48,8 @@ #include #include +#define NGX_ALIGNMENT _MAX_ALIGNMENT + #include diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c --- a/src/os/unix/ngx_writev_chain.c +++ b/src/os/unix/ngx_writev_chain.c @@ -33,7 +33,11 @@ ngx_writev_chain(ngx_connection_t *c, ng #if (NGX_HAVE_KQUEUE) - if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) + && wev->pending_eof + /* FreeBSD 5.x-6.x may erroneously report ETIMEDOUT */ + && wev->kq_errno != NGX_ETIMEDOUT) + { (void) ngx_connection_error(c, wev->kq_errno, "kevent() reported about an closed connection"); wev->error = 1;