diff options
author | Igor Sysoev <igor@sysoev.ru> | 2005-11-26 10:11:11 +0000 |
---|---|---|
committer | Igor Sysoev <igor@sysoev.ru> | 2005-11-26 10:11:11 +0000 |
commit | c31a9bb5e336b15f48c875e1f448f71d68f3feb9 (patch) | |
tree | 31ae2b332d1b263c858bab6ee4c21778403f181d /src | |
parent | 99d9a4b4c547800d582a96871416797fb446b02b (diff) | |
download | nginx-release-0.3.12.tar.gz nginx-release-0.3.12.zip |
nginx-0.3.12-RELEASE importrelease-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; the bug had 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;
the bug had 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.
Diffstat (limited to 'src')
41 files changed, 1359 insertions, 270 deletions
diff --git a/src/core/nginx.h b/src/core/nginx.h index 95d93ccb2..44b15f9f2 100644 --- 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 index b7f597d39..31d990315 100644 --- 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_chain_t **chain, ngx_chain_t *in) } +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 index 471ab190c..625db2a93 100644 --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -132,6 +132,7 @@ ngx_int_t ngx_chain_writer(void *ctx, ngx_chain_t *in); ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); +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 index acec1308f..d89fa7f32 100644 --- 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 *filename) 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_command_t *cmd, void *conf) 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 index 2ef595d59..e1859f852 100644 --- 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 index 3b51e9622..96569b893 100644 --- 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 index d44e300ca..ee68fc1c2 100644 --- 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 index d1e7bbdc5..a1f9d59cd 100644 --- 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 *log) 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 index b8b169244..30590ee9e 100644 --- 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 index d866ffd48..e47666751 100644 --- 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 event, u_int flags) } 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 event, u_int flags) 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_t *c) 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_t *c, u_int flags) 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 index a347e1c3d..672eac2ba 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -48,7 +48,6 @@ ngx_atomic_t *ngx_connection_counter = &connection_counter; 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_t *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, ngx_command_t *cmd, void *conf) 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 index 215463578..be943ae4d 100644 --- 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 index fb43af432..afb1a1f3b 100644 --- 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 *cycle) 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 *cycle) 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 index 9970ed328..779ec1867 100644 --- 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_pipe_t *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_pipe_t *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_pipe_t *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 index b129a9874..cf855575c 100644 --- 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_conf_t *cf, void *parent, void *child) 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 *post, void *data) { 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 index 5c9a415c7..c7af1214c 100644 --- 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_commands[] = { static u_char ngx_empty_gif[] = { - '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 */ - - /* 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 */ - - /* 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 */ + '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 */ + + /* 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 */ + + /* 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 */ 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 index 5d2c153e2..125b8e023 100644 --- 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_uint_t header; + 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_http_fastcgi_ctx_t; @@ -151,6 +151,10 @@ static ngx_str_t ngx_http_fastcgi_script_name = 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,13 +203,20 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_lowat), &ngx_http_fastcgi_lowat_post }, - { ngx_string("fastcgi_header_buffer_size"), + { 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.header_buffer_size), + 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.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, ngx_conf_set_flag_slot, @@ -371,8 +382,13 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r) 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_request_t *r) 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_request_t *r) 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_request_t *r) } 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_request_t *r) 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_request_t *r) /* 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_request_t *r) 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_request_t *r) } 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_conf_t *cf) * 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_t *cf, void *parent, void *child) 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_t *cf, void *parent, void *child) 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_t *cf, void *parent, void *child) } - 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 index 3bcf73ac9..9436e5983 100644 --- 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_string(NGX_HTTP_LOG_PATH); 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_command_t *cmd, void *conf) 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 index 000000000..6217dd109 --- /dev/null +++ b/src/http/modules/ngx_http_memcached_module.c @@ -0,0 +1,616 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +#include <ngx_http.h> + + +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 index f1581e9e7..8278d34e4 100644 --- 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(ngx_conf_t *cf, void *post, void *data); static ngx_conf_post_t ngx_http_proxy_lowat_post = { ngx_http_proxy_lowat_check }; +static ngx_conf_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_commands[] = { 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,13 +212,20 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body), NULL }, - { ngx_string("proxy_header_buffer_size"), + { 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.header_buffer_size), + 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.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, ngx_conf_set_msec_slot, @@ -333,6 +351,7 @@ static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF; static ngx_table_elt_t ngx_http_proxy_headers[] = { { 0, ngx_string("Host"), ngx_string("$proxy_host") }, { 0, ngx_string("Connection"), ngx_string("close") }, + { 0, ngx_string("Keep-Alive"), ngx_string("") }, { 0, ngx_null_string, ngx_null_string } }; @@ -395,7 +414,15 @@ ngx_http_proxy_handler(ngx_http_request_t *r) 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_http_request_t *r, ngx_http_proxy_ctx_t *p) 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_http_request_t *r, ngx_http_proxy_ctx_t *p) } } - 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_request_t *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_t *cf) * 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_t *cf) * 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 *cf, void *parent, void *child) 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 *cf, void *parent, void *child) 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 *cf, void *parent, void *child) } - 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 index 05e2c9376..7b21eae25 100644 --- 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_request_t *r) || 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 index 8732423fd..210bbf6f3 100644 --- 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 index 74cd010a0..808d945ac 100644 --- 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_t *r) 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 index bfb7c6b13..023899870 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -326,8 +326,18 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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_command_t *cmd, void *conf) 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 index 8e5ae5740..ddcd1be44 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -76,7 +76,11 @@ void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc); void ngx_http_empty_handler(ngx_event_t *wev); void ngx_http_request_empty_handler(ngx_http_request_t *r); -ngx_int_t ngx_http_send_last(ngx_http_request_t *r); +#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 index 5fd53179d..474338933 100644 --- 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_request_t *r) 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 *r, } 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 index 1be3b38f3..e9c994dd1 100644 --- 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 index a73c788b6..f6950566d 100644 --- 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 *rev) 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_t *rev) 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_t *rev) 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_request_t *r) 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_request_t *r) 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 *rev) #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_request_t *r) 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 *r, ngx_int_t error) 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 index da12b58d6..7b0e7f0da 100644 --- 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 index d115fddc3..b8d698f71 100644 --- 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[] = +"<html>" CRLF +"<head><title>411 Length Required</title></head>" CRLF +"<body bgcolor=\"white\">" CRLF +"<center><h1>411 Length Required</h1></center>" CRLF +; + + static char error_413_page[] = "<html>" CRLF "<head><title>413 Request Entity Too Large</title></head>" 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 index 62f5d9eae..37e979a9d 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -6,7 +6,6 @@ #include <ngx_config.h> #include <ngx_core.h> -#include <ngx_event_connect.h> #include <ngx_http.h> @@ -24,6 +23,12 @@ static void ngx_http_upstream_send_request_handler(ngx_event_t *wev); static void ngx_http_upstream_process_header(ngx_event_t *rev); static void ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u); +static void + ngx_http_upstream_process_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_request_t *r, ngx_http_upstream_t *u) 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_event_t *rev) 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->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->header_in.tag = u->output.tag; + 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_event_t *rev) #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_event_t *rev) 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_event_t *rev) 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_event_t *rev) && 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_event_t *rev) 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_request_t *r, ngx_http_upstream_t *u) 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_request_t *r, ngx_http_upstream_t *u) } } + 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_request_t *r, ngx_http_upstream_t *u) } 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_request_t *r, ngx_http_upstream_t *u) #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_request_t *r, ngx_http_upstream_t *u) 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; + u->buffer.recycled = 1; - p->preread_size = u->header_in.last - u->header_in.pos; + 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_request_t *r, ngx_http_upstream_t *u) 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_request_t *r, ngx_http_upstream_t *u) 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_request_t *r, ngx_http_upstream_t *u) 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_request_t *r, ngx_http_upstream_t *u) 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_t *ev) 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_http_request_t *r, 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_http_request_t *r, 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 index ad4c1d4cb..203265970 100644 --- 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 index f00619d60..3969d7ef0 100644 --- 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 *cf) 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 index 721335ed2..662b3347b 100644 --- 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_connection_t *c, ngx_chain_t *in, off_t limit) 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 index 9de4cd5ec..0e99cb413 100644 --- 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_chain_t *chain) 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 index e96ca7898..6f01ab3ec 100644 --- 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 *c, u_char *buf, size_t size) 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 *c, u_char *buf, size_t size) } return 0; - - } else { - return NGX_AGAIN; } } } diff --git a/src/os/unix/ngx_send.c b/src/os/unix/ngx_send.c index 167f2eca3..0c3f959da 100644 --- 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 *c, u_char *buf, size_t size) #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 index 84a4c8476..a668b95e1 100644 --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -48,6 +48,8 @@ #include <inttypes.h> #include <crypt.h> +#define NGX_ALIGNMENT _MAX_ALIGNMENT + #include <ngx_auto_config.h> diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c index f95c2cad8..09e08e108 100644 --- 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, ngx_chain_t *in, off_t limit) #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/win32/ngx_atomic.h b/src/os/win32/ngx_atomic.h index 1e3334548..8003b740f 100644 --- a/src/os/win32/ngx_atomic.h +++ b/src/os/win32/ngx_atomic.h @@ -25,7 +25,8 @@ typedef volatile ngx_atomic_uint_t ngx_atomic_t; /* the new SDK headers */ #define ngx_atomic_cmp_set(lock, old, set) \ - (InterlockedCompareExchange((long *) lock, set, old) == old) + ((ngx_atomic_uint_t) InterlockedCompareExchange((long *) lock, set, old) \ + == old) #else diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h index 9658c1225..f2c7a0665 100644 --- a/src/os/win32/ngx_win32_config.h +++ b/src/os/win32/ngx_win32_config.h @@ -126,12 +126,14 @@ typedef int sig_atomic_t; #define NGX_SIZE_T_LEN sizeof("-2147483648") - 1 +#define NGX_MAX_SIZE_T_VALUE 2147483647 #define NGX_TIME_T_LEN sizeof("-2147483648") - 1 #define NGX_TIME_T_SIZE 4 #define NGX_OFF_T_LEN sizeof("-9223372036854775807") - 1 #define NGX_MAX_OFF_T_VALUE 9223372036854775807 #define NGX_SIG_ATOMIC_T_SIZE 4 + #define NGX_HAVE_LITTLE_ENDIAN 1 #define NGX_HAVE_NONALIGNED 1 |