# HG changeset patch # User Igor Sysoev # Date 1317758400 -14400 # Node ID d3cf6c6b0043ae7240f9f64389598f778760fc55 # Parent 6c19b251b92674710573c472e8aba406fa72da50 nginx 1.1.5 *) Feature: the "uwsgi_buffering" and "scgi_buffering" directives. Thanks to Peter Smit. *) Bugfix: non-cacheable responses might be cached if "proxy_cache_bypass" directive was used. Thanks to John Ferlito. *) Bugfix: in HTTP/1.1 support in the ngx_http_proxy_module. *) Bugfix: cached responses with an empty body were returned incorrectly; the bug had appeared in 0.8.31. *) Bugfix: 201 responses of the ngx_http_dav_module were incorrect; the bug had appeared in 0.8.32. *) Bugfix: in the "return" directive. *) Bugfix: the "ssl_session_cache builtin" directive caused segmentation fault; the bug had appeared in 1.1.1. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,27 @@ +Changes with nginx 1.1.5 05 Oct 2011 + + *) Feature: the "uwsgi_buffering" and "scgi_buffering" directives. + Thanks to Peter Smit. + + *) Bugfix: non-cacheable responses might be cached if + "proxy_cache_bypass" directive was used. + Thanks to John Ferlito. + + *) Bugfix: in HTTP/1.1 support in the ngx_http_proxy_module. + + *) Bugfix: cached responses with an empty body were returned + incorrectly; the bug had appeared in 0.8.31. + + *) Bugfix: 201 responses of the ngx_http_dav_module were incorrect; the + bug had appeared in 0.8.32. + + *) Bugfix: in the "return" directive. + + *) Bugfix: the "ssl_session_cache builtin" directive caused segmentation + fault; the bug had appeared in 1.1.1. + + Changes with nginx 1.1.4 20 Sep 2011 *) Feature: the ngx_http_upstream_keepalive module. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,28 @@ +Изменения в nginx 1.1.5 05.10.2011 + + *) Добавление: директивы uwsgi_buffering и scgi_buffering. + Спасибо Peter Smit. + + *) Исправление: при использовании proxy_cache_bypass могли быть + закэшированы некэшируемые ответы. + Спасибо John Ferlito. + + *) Исправление: в модуле ngx_http_proxy_module при работе с бэкендами по + HTTP/1.1. + + *) Исправление: закэшированные ответы с пустым телом возвращались + некорректно; ошибка появилась в 0.8.31. + + *) Исправление: ответы с кодом 201 модуля ngx_http_dav_module были + некорректны; ошибка появилась в 0.8.32. + + *) Исправление: в директиве return. + + *) Исправление: при использовании директивы "ssl_session_cache builtin" + происходил segmentation fault; ошибка появилась в 1.1.1. + + Изменения в nginx 1.1.4 20.09.2011 *) Добавление: модуль ngx_http_upstream_keepalive. diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1001004 -#define NGINX_VERSION "1.1.4" +#define nginx_version 1001005 +#define NGINX_VERSION "1.1.5" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" 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 @@ -111,19 +111,12 @@ static ngx_str_t ngx_http_gif_type = ng static ngx_int_t ngx_http_empty_gif_handler(ngx_http_request_t *r) { - ngx_int_t rc; ngx_http_complex_value_t cv; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } - rc = ngx_http_discard_request_body(r); - - if (rc != NGX_OK) { - return rc; - } - ngx_memzero(&cv, sizeof(ngx_http_complex_value_t)); cv.value.len = sizeof(ngx_empty_gif); diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -187,14 +187,14 @@ typedef struct { + ( ((u_char *) (p))[7]) ) #define ngx_mp4_set_64value(p, n) \ - ((u_char *) (p))[0] = (u_char) ((n) >> 56); \ - ((u_char *) (p))[1] = (u_char) ((n) >> 48); \ - ((u_char *) (p))[2] = (u_char) ((n) >> 40); \ - ((u_char *) (p))[3] = (u_char) ((n) >> 32); \ - ((u_char *) (p))[4] = (u_char) ((n) >> 24); \ - ((u_char *) (p))[5] = (u_char) ((n) >> 16); \ - ((u_char *) (p))[6] = (u_char) ((n) >> 8); \ - ((u_char *) (p))[7] = (u_char) (n) + ((u_char *) (p))[0] = (u_char) ((uint64_t) (n) >> 56); \ + ((u_char *) (p))[1] = (u_char) ((uint64_t) (n) >> 48); \ + ((u_char *) (p))[2] = (u_char) ((uint64_t) (n) >> 40); \ + ((u_char *) (p))[3] = (u_char) ((uint64_t) (n) >> 32); \ + ((u_char *) (p))[4] = (u_char) ( (n) >> 24); \ + ((u_char *) (p))[5] = (u_char) ( (n) >> 16); \ + ((u_char *) (p))[6] = (u_char) ( (n) >> 8); \ + ((u_char *) (p))[7] = (u_char) (n) #define ngx_mp4_last_trak(mp4) \ &((ngx_http_mp4_trak_t *) mp4->trak.elts)[mp4->trak.nelts - 1] @@ -499,9 +499,16 @@ ngx_http_mp4_handler(ngx_http_request_t if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) { - start = ngx_atofp(value.data, value.len, 3); - - if (start != NGX_ERROR) { + /* + * A Flash player may send start value with a lot of digits + * after dot so strtod() is used instead of atofp(). NaNs and + * infinities become negative numbers after (int) conversion. + */ + + ngx_set_errno(0); + start = (int) (strtod((char *) value.data, NULL) * 1000); + + if (ngx_errno == 0 && start >= 0) { r->allow_ranges = 0; mp4 = ngx_pcalloc(r->pool, sizeof(ngx_http_mp4_file_t)); @@ -1066,7 +1073,7 @@ ngx_http_mp4_update_mdat_atom(ngx_http_m atom_header = mp4->mdat_atom_header; - if (atom_data_size > 0xffffffff) { + if ((uint64_t) atom_data_size > 0xffffffff) { atom_size = 1; atom_header_size = sizeof(ngx_mp4_atom_header64_t); ngx_mp4_set_64value(atom_header + sizeof(ngx_mp4_atom_header_t), 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 @@ -1559,7 +1559,7 @@ ngx_http_proxy_copy_filter(ngx_event_pip r = p->input_ctx; p->upstream_done = 1; - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "upstream sent too many data"); } @@ -1647,6 +1647,8 @@ ngx_http_proxy_parse_chunked(ngx_http_re state = sw_trailer; break; case ';': + case ' ': + case '\t': state = sw_last_chunk_extension; break; default: @@ -1664,6 +1666,8 @@ ngx_http_proxy_parse_chunked(ngx_http_re state = sw_chunk_data; break; case ';': + case ' ': + case '\t': state = sw_chunk_extension; break; default: @@ -1813,9 +1817,6 @@ done: invalid: - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "upstream sent invalid chunked response"); - return NGX_ERROR; } @@ -1929,7 +1930,7 @@ ngx_http_proxy_chunked_filter(ngx_event_ /* invalid response */ - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid chunked response"); return NGX_ERROR; @@ -2085,7 +2086,7 @@ ngx_http_proxy_non_buffered_chunked_filt /* invalid response */ - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid chunked response"); return NGX_ERROR; diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -167,8 +167,8 @@ ngx_http_rewrite_handler(ngx_http_reques code(e); } - if (e->status == NGX_DECLINED) { - return NGX_DECLINED; + if (e->status < NGX_HTTP_BAD_REQUEST) { + return e->status; } if (r->err_status == 0) { diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -96,6 +96,13 @@ static ngx_command_t ngx_http_scgi_comma offsetof(ngx_http_scgi_loc_conf_t, upstream.store_access), NULL }, + { ngx_string("scgi_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_scgi_loc_conf_t, upstream.buffering), + NULL }, + { ngx_string("scgi_ignore_client_abort"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -412,7 +419,7 @@ ngx_http_scgi_handler(ngx_http_request_t u->abort_request = ngx_http_scgi_abort_request; u->finalize_request = ngx_http_scgi_finalize_request; - u->buffering = 1; + u->buffering = scf->upstream.buffering; u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); if (u->pipe == NULL) { @@ -1038,6 +1045,8 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t /* "scgi_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; + conf->upstream.change_buffering = 1; + ngx_str_set(&conf->upstream.module, "scgi"); return conf; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -616,6 +616,8 @@ ngx_http_ssl_session_cache(ngx_conf_t *c return NGX_CONF_ERROR; } + sscf->shm_zone->init = ngx_ssl_session_cache_init; + continue; } @@ -626,8 +628,6 @@ ngx_http_ssl_session_cache(ngx_conf_t *c sscf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; } - sscf->shm_zone->init = ngx_ssl_session_cache_init; - return NGX_CONF_OK; invalid: diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -123,6 +123,13 @@ static ngx_command_t ngx_http_uwsgi_comm offsetof(ngx_http_uwsgi_loc_conf_t, upstream.store_access), NULL }, + { ngx_string("uwsgi_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_uwsgi_loc_conf_t, upstream.buffering), + NULL }, + { ngx_string("uwsgi_ignore_client_abort"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -445,7 +452,7 @@ ngx_http_uwsgi_handler(ngx_http_request_ u->abort_request = ngx_http_uwsgi_abort_request; u->finalize_request = ngx_http_uwsgi_finalize_request; - u->buffering = 1; + u->buffering = uwcf->upstream.buffering; u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); if (u->pipe == NULL) { @@ -1091,6 +1098,8 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_ /* "uwsgi_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; + conf->upstream.change_buffering = 1; + ngx_str_set(&conf->upstream.module, "uwsgi"); return conf; diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -48,7 +48,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.1.4'; +our $VERSION = '1.1.5'; require XSLoader; XSLoader::load('nginx', $VERSION); 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 @@ -1281,7 +1281,7 @@ ngx_http_add_addresses(ngx_conf_t *cf, n if (addr[i].opt.set) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "a duplicate listen options for %s", addr[i].opt.addr); + "duplicate listen options for %s", addr[i].opt.addr); return NGX_ERROR; } @@ -1747,10 +1747,12 @@ ngx_http_add_listening(ngx_conf_t *cf, n #if (NGX_WIN32) { - ngx_iocp_conf_t *iocpcf; - - iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); - if (iocpcf->acceptex_read) { + ngx_iocp_conf_t *iocpcf = NULL; + + if (ngx_get_conf(cf->cycle->conf_ctx, ngx_events_module)) { + iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); + } + if (iocpcf && iocpcf->acceptex_read) { ls->post_accept_buffer_size = cscf->client_header_buffer_size; } } 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 @@ -1784,13 +1784,12 @@ ngx_http_send_response(ngx_http_request_ ngx_buf_t *b; ngx_chain_t out; + if (ngx_http_discard_request_body(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + r->headers_out.status = status; - if (status == NGX_HTTP_NO_CONTENT) { - r->header_only = 1; - return ngx_http_send_header(r); - } - if (ngx_http_complex_value(r, cv, &val) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -853,6 +853,10 @@ ngx_http_cache_send(ngx_http_request_t * ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache send: %s", c->file.name.data); + if (r != r->main && c->length - c->body_start == 0) { + return ngx_http_send_header(r); + } + /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); @@ -865,8 +869,6 @@ ngx_http_cache_send(ngx_http_request_t * return NGX_HTTP_INTERNAL_SERVER_ERROR; } - r->header_only = (c->length - c->body_start) == 0; - rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { @@ -876,7 +878,7 @@ ngx_http_cache_send(ngx_http_request_t * b->file_pos = c->body_start; b->file_last = c->length; - b->in_file = 1; + b->in_file = (c->length - c->body_start) ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 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 @@ -421,7 +421,6 @@ ngx_http_special_response_handler(ngx_ht if (error == NGX_HTTP_CREATED) { /* 201 */ err = 0; - r->header_only = 1; } else if (error == NGX_HTTP_NO_CONTENT) { /* 204 */ @@ -636,7 +635,7 @@ ngx_http_send_special_response(ngx_http_ r->headers_out.content_type_lowcase = NULL; } else { - r->headers_out.content_length_n = -1; + r->headers_out.content_length_n = 0; } if (r->headers_out.content_length) { @@ -654,7 +653,7 @@ ngx_http_send_special_response(ngx_http_ } if (ngx_http_error_pages[err].len == 0) { - return NGX_OK; + return ngx_http_send_special(r, NGX_HTTP_LAST); } b = ngx_calloc_buf(r->pool); 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 @@ -683,6 +683,8 @@ ngx_http_upstream_cache(ngx_http_request return NGX_DECLINED; } + u->cacheable = 1; + switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) { case NGX_ERROR: @@ -696,8 +698,6 @@ ngx_http_upstream_cache(ngx_http_request break; } - u->cacheable = 1; - c = r->cache; c->min_uses = u->conf->cache_min_uses; @@ -2181,8 +2181,6 @@ ngx_http_upstream_send_response(ngx_http ngx_http_upstream_finalize_request(r, u, 0); return; } - - u->cacheable = 1; } break; @@ -2927,6 +2925,7 @@ ngx_http_upstream_next(ngx_http_request_ } ngx_close_connection(u->peer.connection); + u->peer.connection = NULL; } #if 0 @@ -3071,7 +3070,12 @@ ngx_http_upstream_finalize_request(ngx_h r->connection->log->action = "sending to client"; - if (rc == 0) { + if (rc == 0 +#if (NGX_HTTP_CACHE) + && !r->cached +#endif + ) + { rc = ngx_http_send_special(r, NGX_HTTP_LAST); } @@ -4329,6 +4333,10 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng continue; } + if (flags & NGX_HTTP_UPSTREAM_CREATE) { + uscfp[i]->flags = flags; + } + return uscfp[i]; } diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -464,6 +464,8 @@ ngx_mail_ssl_session_cache(ngx_conf_t *c return NGX_CONF_ERROR; } + scf->shm_zone->init = ngx_ssl_session_cache_init; + continue; } @@ -474,8 +476,6 @@ ngx_mail_ssl_session_cache(ngx_conf_t *c scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; } - scf->shm_zone->init = ngx_ssl_session_cache_init; - return NGX_CONF_OK; invalid: