summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornginx <nginx@nginx.org>2014-10-28 15:18:24 +0000
committerJon Kolb <kolbyjack@gmail.com>2014-10-28 15:18:24 +0000
commit9a11306bd73c32aeea6f1d6587215dd8054559bb (patch)
tree435740e737335f93914d879f202d6f24521417a5
parent4aeefe1f3cef9d863cc04f7ee3fe2c730e6cfdf1 (diff)
downloadnginx-9a11306bd73c32aeea6f1d6587215dd8054559bb.tar.gz
Changes with nginx 1.7.7 28 Oct 2014v1.7.7
*) Change: now nginx takes into account the "Vary" header line in a backend response while caching. *) Feature: the "proxy_force_ranges", "fastcgi_force_ranges", "scgi_force_ranges", and "uwsgi_force_ranges" directives. *) Feature: the "proxy_limit_rate", "fastcgi_limit_rate", "scgi_limit_rate", and "uwsgi_limit_rate" directives. *) Feature: the "Vary" parameter of the "proxy_ignore_headers", "fastcgi_ignore_headers", "scgi_ignore_headers", and "uwsgi_ignore_headers" directives. *) Bugfix: the last part of a response received from a backend with unbufferred proxy might not be sent to a client if "gzip" or "gunzip" directives were used. *) Bugfix: in the "proxy_cache_revalidate" directive. Thanks to Piotr Sikora. *) Bugfix: in error handling. Thanks to Yichun Zhang and Daniil Bondarev. *) Bugfix: in the "proxy_next_upstream_tries" and "proxy_next_upstream_timeout" directives. Thanks to Feng Gu. *) Bugfix: nginx/Windows could not be built with MinGW-w64 gcc. Thanks to Kouhei Sutou.
-rw-r--r--CHANGES33
-rw-r--r--CHANGES.ru32
-rw-r--r--src/core/nginx.h4
-rw-r--r--src/core/ngx_hash.c2
-rw-r--r--src/event/ngx_event_openssl.c17
-rw-r--r--src/event/ngx_event_openssl.h2
-rw-r--r--src/event/ngx_event_pipe.c41
-rw-r--r--src/event/ngx_event_pipe.h3
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c22
-rw-r--r--src/http/modules/ngx_http_gunzip_filter_module.c10
-rw-r--r--src/http/modules/ngx_http_gzip_filter_module.c10
-rw-r--r--src/http/modules/ngx_http_proxy_module.c22
-rw-r--r--src/http/modules/ngx_http_scgi_module.c22
-rw-r--r--src/http/modules/ngx_http_uwsgi_module.c22
-rw-r--r--src/http/ngx_http_cache.h11
-rw-r--r--src/http/ngx_http_file_cache.c282
-rw-r--r--src/http/ngx_http_request.c5
-rw-r--r--src/http/ngx_http_upstream.c116
-rw-r--r--src/http/ngx_http_upstream.h4
-rw-r--r--src/http/ngx_http_write_filter_module.c4
-rw-r--r--src/os/unix/ngx_aio_read_chain.c2
-rw-r--r--src/os/unix/ngx_darwin_sendfile_chain.c1
-rw-r--r--src/os/unix/ngx_freebsd_sendfile_chain.c1
-rw-r--r--src/os/unix/ngx_linux_sendfile_chain.c1
-rw-r--r--src/os/unix/ngx_os.h7
-rw-r--r--src/os/unix/ngx_readv_chain.c20
-rw-r--r--src/os/unix/ngx_solaris_sendfilev_chain.c1
-rw-r--r--src/os/unix/ngx_writev_chain.c1
28 files changed, 662 insertions, 36 deletions
diff --git a/CHANGES b/CHANGES
index ddfb80014..b94ba2fe3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,37 @@
+Changes with nginx 1.7.7 28 Oct 2014
+
+ *) Change: now nginx takes into account the "Vary" header line in a
+ backend response while caching.
+
+ *) Feature: the "proxy_force_ranges", "fastcgi_force_ranges",
+ "scgi_force_ranges", and "uwsgi_force_ranges" directives.
+
+ *) Feature: the "proxy_limit_rate", "fastcgi_limit_rate",
+ "scgi_limit_rate", and "uwsgi_limit_rate" directives.
+
+ *) Feature: the "Vary" parameter of the "proxy_ignore_headers",
+ "fastcgi_ignore_headers", "scgi_ignore_headers", and
+ "uwsgi_ignore_headers" directives.
+
+ *) Bugfix: the last part of a response received from a backend with
+ unbufferred proxy might not be sent to a client if "gzip" or "gunzip"
+ directives were used.
+
+ *) Bugfix: in the "proxy_cache_revalidate" directive.
+ Thanks to Piotr Sikora.
+
+ *) Bugfix: in error handling.
+ Thanks to Yichun Zhang and Daniil Bondarev.
+
+ *) Bugfix: in the "proxy_next_upstream_tries" and
+ "proxy_next_upstream_timeout" directives.
+ Thanks to Feng Gu.
+
+ *) Bugfix: nginx/Windows could not be built with MinGW-w64 gcc.
+ Thanks to Kouhei Sutou.
+
+
Changes with nginx 1.7.6 30 Sep 2014
*) Change: the deprecated "limit_zone" directive is not supported
diff --git a/CHANGES.ru b/CHANGES.ru
index 4eff3ccf9..988651ef7 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,36 @@
+Изменения в nginx 1.7.7 28.10.2014
+
+ *) Изменение: теперь nginx учитывает при кэшировании строку "Vary" в
+ заголовке ответа бэкенда.
+
+ *) Добавление: директивы proxy_force_ranges, fastcgi_force_ranges,
+ scgi_force_ranges и uwsgi_force_ranges.
+
+ *) Добавление: директивы proxy_limit_rate, fastcgi_limit_rate,
+ scgi_limit_rate и uwsgi_limit_rate.
+
+ *) Добавление: параметр Vary директив proxy_ignore_headers,
+ fastcgi_ignore_headers, scgi_ignore_headers и uwsgi_ignore_headers.
+
+ *) Исправление: последняя часть ответа, полученного от бэкенда при
+ небуферизированном проксировании, могла не отправляться клиенту, если
+ использовались директивы gzip или gunzip.
+
+ *) Исправление: в директиве proxy_cache_revalidate.
+ Спасибо Piotr Sikora.
+
+ *) Исправление: в обработке ошибок.
+ Спасибо Yichun Zhang и Даниилу Бондареву.
+
+ *) Исправление: в директивах proxy_next_upstream_tries и
+ proxy_next_upstream_timeout.
+ Спасибо Feng Gu.
+
+ *) Исправление: nginx/Windows не собирался с MinGW-w64 gcc.
+ Спасибо Kouhei Sutou.
+
+
Изменения в nginx 1.7.6 30.09.2014
*) Изменение: устаревшая директива limit_zone больше не поддерживается.
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 3030b44b4..2d923fb85 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1007006
-#define NGINX_VERSION "1.7.6"
+#define nginx_version 1007007
+#define NGINX_VERSION "1.7.7"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c
index c7bfed709..65ad83947 100644
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -312,6 +312,8 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
continue;
}
+ size--;
+
ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0,
"could not build optimal %s, you should increase "
"either %s_max_size: %i or %s_bucket_size: %i; "
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 975a8e001..f34565277 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -1185,10 +1185,10 @@ ngx_ssl_handshake_handler(ngx_event_t *ev)
ssize_t
-ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl)
+ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit)
{
u_char *last;
- ssize_t n, bytes;
+ ssize_t n, bytes, size;
ngx_buf_t *b;
bytes = 0;
@@ -1197,8 +1197,19 @@ ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl)
last = b->last;
for ( ;; ) {
+ size = b->end - last;
- n = ngx_ssl_recv(c, last, b->end - last);
+ if (limit) {
+ if (bytes >= limit) {
+ return bytes;
+ }
+
+ if (bytes + size > limit) {
+ size = (ssize_t) (limit - bytes);
+ }
+ }
+
+ n = ngx_ssl_recv(c, last, size);
if (n > 0) {
last += n;
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 408694035..08eff6445 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -194,7 +194,7 @@ ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool,
ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size);
ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size);
-ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl);
+ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit);
ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
void ngx_ssl_free_buffer(ngx_connection_t *c);
diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c
index 64fb07bde..62663d5a4 100644
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -66,11 +66,13 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
return NGX_ABORT;
}
- if (rev->active && !rev->ready) {
- ngx_add_timer(rev, p->read_timeout);
+ if (!rev->delayed) {
+ if (rev->active && !rev->ready) {
+ ngx_add_timer(rev, p->read_timeout);
- } else if (rev->timer_set) {
- ngx_del_timer(rev);
+ } else if (rev->timer_set) {
+ ngx_del_timer(rev);
+ }
}
}
@@ -99,9 +101,11 @@ ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
static ngx_int_t
ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
{
+ off_t limit;
ssize_t n, size;
ngx_int_t rc;
ngx_buf_t *b;
+ ngx_msec_t delay;
ngx_chain_t *chain, *cl, *ln;
if (p->upstream_eof || p->upstream_error || p->upstream_done) {
@@ -169,6 +173,25 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
}
#endif
+ if (p->limit_rate) {
+ if (p->upstream->read->delayed) {
+ break;
+ }
+
+ limit = (off_t) p->limit_rate * (ngx_time() - p->start_sec + 1)
+ - p->read_length;
+
+ if (limit <= 0) {
+ p->upstream->read->delayed = 1;
+ delay = (ngx_msec_t) (- limit * 1000 / p->limit_rate + 1);
+ ngx_add_timer(p->upstream->read, delay);
+ break;
+ }
+
+ } else {
+ limit = 0;
+ }
+
if (p->free_raw_bufs) {
/* use the free bufs if they exist */
@@ -270,7 +293,7 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
break;
}
- n = p->upstream->recv_chain(p->upstream, chain);
+ n = p->upstream->recv_chain(p->upstream, chain, limit);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe recv chain: %z", n);
@@ -301,6 +324,8 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
}
}
+ delay = p->limit_rate ? (ngx_msec_t) n * 1000 / p->limit_rate : 0;
+
p->read_length += n;
cl = chain;
p->free_raw_bufs = NULL;
@@ -337,6 +362,12 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
ln->next = p->free_raw_bufs;
p->free_raw_bufs = cl;
}
+
+ if (delay > 0) {
+ p->upstream->read->delayed = 1;
+ ngx_add_timer(p->upstream->read, delay);
+ break;
+ }
}
#if (NGX_DEBUG)
diff --git a/src/event/ngx_event_pipe.h b/src/event/ngx_event_pipe.h
index f24e6d148..451fc4c05 100644
--- a/src/event/ngx_event_pipe.h
+++ b/src/event/ngx_event_pipe.h
@@ -80,6 +80,9 @@ struct ngx_event_pipe_s {
size_t preread_size;
ngx_buf_t *buf_to_file;
+ size_t limit_rate;
+ time_t start_sec;
+
ngx_temp_file_t *temp_file;
/* STUB */ int num;
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index a49c93ca2..b7f7ea14a 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -326,6 +326,20 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size_conf),
NULL },
+ { ngx_string("fastcgi_force_ranges"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_fastcgi_loc_conf_t, upstream.force_ranges),
+ NULL },
+
+ { ngx_string("fastcgi_limit_rate"),
+ 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.limit_rate),
+ NULL },
+
#if (NGX_HTTP_CACHE)
{ ngx_string("fastcgi_cache"),
@@ -2332,6 +2346,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
+ conf->upstream.force_ranges = NGX_CONF_UNSET;
conf->upstream.local = NGX_CONF_UNSET_PTR;
@@ -2342,6 +2357,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+ conf->upstream.limit_rate = 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;
@@ -2413,6 +2429,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.ignore_client_abort,
prev->upstream.ignore_client_abort, 0);
+ ngx_conf_merge_value(conf->upstream.force_ranges,
+ prev->upstream.force_ranges, 0);
+
ngx_conf_merge_ptr_value(conf->upstream.local,
prev->upstream.local, NULL);
@@ -2435,6 +2454,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
+ ngx_conf_merge_size_value(conf->upstream.limit_rate,
+ prev->upstream.limit_rate, 0);
+
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
8, ngx_pagesize);
diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c
index 70ec0aace..c1341f562 100644
--- a/src/http/modules/ngx_http_gunzip_filter_module.c
+++ b/src/http/modules/ngx_http_gunzip_filter_module.c
@@ -175,6 +175,7 @@ static ngx_int_t
ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
int rc;
+ ngx_uint_t flush;
ngx_chain_t *cl;
ngx_http_gunzip_ctx_t *ctx;
@@ -199,7 +200,7 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
}
- if (ctx->nomem || in == NULL) {
+ if (ctx->nomem) {
/* flush busy buffers */
@@ -212,6 +213,10 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl,
(ngx_buf_tag_t) &ngx_http_gunzip_filter_module);
ctx->nomem = 0;
+ flush = 0;
+
+ } else {
+ flush = ctx->busy ? 1 : 0;
}
for ( ;; ) {
@@ -258,7 +263,7 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
/* rc == NGX_AGAIN */
}
- if (ctx->out == NULL) {
+ if (ctx->out == NULL && !flush) {
return ctx->busy ? NGX_AGAIN : NGX_OK;
}
@@ -276,6 +281,7 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
"gunzip out: %p", ctx->out);
ctx->nomem = 0;
+ flush = 0;
if (ctx->done) {
return rc;
diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c
index c57a4a3c7..f941e6397 100644
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -316,6 +316,7 @@ static ngx_int_t
ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
int rc;
+ ngx_uint_t flush;
ngx_chain_t *cl;
ngx_http_gzip_ctx_t *ctx;
@@ -372,7 +373,7 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
r->connection->buffered |= NGX_HTTP_GZIP_BUFFERED;
}
- if (ctx->nomem || in == NULL) {
+ if (ctx->nomem) {
/* flush busy buffers */
@@ -385,6 +386,10 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl,
(ngx_buf_tag_t) &ngx_http_gzip_filter_module);
ctx->nomem = 0;
+ flush = 0;
+
+ } else {
+ flush = ctx->busy ? 1 : 0;
}
for ( ;; ) {
@@ -432,7 +437,7 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
/* rc == NGX_AGAIN */
}
- if (ctx->out == NULL) {
+ if (ctx->out == NULL && !flush) {
ngx_http_gzip_filter_free_copy_buf(r, ctx);
return ctx->busy ? NGX_AGAIN : NGX_OK;
@@ -457,6 +462,7 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
ctx->last_out = &ctx->out;
ctx->nomem = 0;
+ flush = 0;
if (ctx->done) {
return rc;
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index c8a80ef48..ea4109c77 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -389,6 +389,20 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
NULL },
+ { ngx_string("proxy_force_ranges"),
+ 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.force_ranges),
+ NULL },
+
+ { ngx_string("proxy_limit_rate"),
+ 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.limit_rate),
+ NULL },
+
#if (NGX_HTTP_CACHE)
{ ngx_string("proxy_cache"),
@@ -2472,6 +2486,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
+ conf->upstream.force_ranges = NGX_CONF_UNSET;
conf->upstream.local = NGX_CONF_UNSET_PTR;
@@ -2482,6 +2497,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+ conf->upstream.limit_rate = 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;
@@ -2568,6 +2584,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.ignore_client_abort,
prev->upstream.ignore_client_abort, 0);
+ ngx_conf_merge_value(conf->upstream.force_ranges,
+ prev->upstream.force_ranges, 0);
+
ngx_conf_merge_ptr_value(conf->upstream.local,
prev->upstream.local, NULL);
@@ -2590,6 +2609,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
+ ngx_conf_merge_size_value(conf->upstream.limit_rate,
+ prev->upstream.limit_rate, 0);
+
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
8, ngx_pagesize);
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index 313f3b3ad..71dcd34f9 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -183,6 +183,20 @@ static ngx_command_t ngx_http_scgi_commands[] = {
offsetof(ngx_http_scgi_loc_conf_t, upstream.busy_buffers_size_conf),
NULL },
+ { ngx_string("scgi_force_ranges"),
+ 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.force_ranges),
+ NULL },
+
+ { ngx_string("scgi_limit_rate"),
+ 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_scgi_loc_conf_t, upstream.limit_rate),
+ NULL },
+
#if (NGX_HTTP_CACHE)
{ ngx_string("scgi_cache"),
@@ -1091,6 +1105,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
+ conf->upstream.force_ranges = NGX_CONF_UNSET;
conf->upstream.local = NGX_CONF_UNSET_PTR;
@@ -1101,6 +1116,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+ conf->upstream.limit_rate = 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;
@@ -1167,6 +1183,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.ignore_client_abort,
prev->upstream.ignore_client_abort, 0);
+ ngx_conf_merge_value(conf->upstream.force_ranges,
+ prev->upstream.force_ranges, 0);
+
ngx_conf_merge_ptr_value(conf->upstream.local,
prev->upstream.local, NULL);
@@ -1189,6 +1208,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
+ ngx_conf_merge_size_value(conf->upstream.limit_rate,
+ prev->upstream.limit_rate, 0);
+
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
8, ngx_pagesize);
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index 9556aa4a0..5114782b6 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -238,6 +238,20 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.busy_buffers_size_conf),
NULL },
+ { ngx_string("uwsgi_force_ranges"),
+ 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.force_ranges),
+ NULL },
+
+ { ngx_string("uwsgi_limit_rate"),
+ 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_uwsgi_loc_conf_t, upstream.limit_rate),
+ NULL },
+
#if (NGX_HTTP_CACHE)
{ ngx_string("uwsgi_cache"),
@@ -1271,6 +1285,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
+ conf->upstream.force_ranges = NGX_CONF_UNSET;
conf->upstream.local = NGX_CONF_UNSET_PTR;
@@ -1281,6 +1296,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+ conf->upstream.limit_rate = 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;
@@ -1354,6 +1370,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->upstream.ignore_client_abort,
prev->upstream.ignore_client_abort, 0);
+ ngx_conf_merge_value(conf->upstream.force_ranges,
+ prev->upstream.force_ranges, 0);
+
ngx_conf_merge_ptr_value(conf->upstream.local,
prev->upstream.local, NULL);
@@ -1376,6 +1395,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
+ ngx_conf_merge_size_value(conf->upstream.limit_rate,
+ prev->upstream.limit_rate, 0);
+
ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
8, ngx_pagesize);
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
index 1cfd9fe84..f89766d58 100644
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -25,8 +25,9 @@
#define NGX_HTTP_CACHE_KEY_LEN 16
#define NGX_HTTP_CACHE_ETAG_LEN 42
+#define NGX_HTTP_CACHE_VARY_LEN 42
-#define NGX_HTTP_CACHE_VERSION 2
+#define NGX_HTTP_CACHE_VERSION 3
typedef struct {
@@ -64,6 +65,7 @@ struct ngx_http_cache_s {
ngx_array_t keys;
uint32_t crc32;
u_char key[NGX_HTTP_CACHE_KEY_LEN];
+ u_char main[NGX_HTTP_CACHE_KEY_LEN];
ngx_file_uniq_t uniq;
time_t valid_sec;
@@ -71,6 +73,8 @@ struct ngx_http_cache_s {
time_t date;
ngx_str_t etag;
+ ngx_str_t vary;
+ u_char variant[NGX_HTTP_CACHE_KEY_LEN];
size_t header_start;
size_t body_start;
@@ -98,6 +102,8 @@ struct ngx_http_cache_s {
unsigned updating:1;
unsigned exists:1;
unsigned temp_file:1;
+ unsigned reading:1;
+ unsigned secondary:1;
};
@@ -112,6 +118,9 @@ typedef struct {
u_short body_start;
u_char etag_len;
u_char etag[NGX_HTTP_CACHE_ETAG_LEN];
+ u_char vary_len;
+ u_char vary[NGX_HTTP_CACHE_VARY_LEN];
+ u_char variant[NGX_HTTP_CACHE_KEY_LEN];
} ngx_http_file_cache_header_t;
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 2eebc3068..bc4c80602 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -29,6 +29,12 @@ static ngx_http_file_cache_node_t *
ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key);
static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+static void ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary,
+ size_t len, u_char *hash);
+static void ngx_http_file_cache_vary_header(ngx_http_request_t *r,
+ ngx_md5_t *md5, ngx_str_t *name);
+static ngx_int_t ngx_http_file_cache_reopen(ngx_http_request_t *r,
+ ngx_http_cache_t *c);
static void ngx_http_file_cache_cleanup(void *data);
static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache);
static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache);
@@ -235,6 +241,8 @@ ngx_http_file_cache_create_key(ngx_http_request_t *r)
ngx_crc32_final(c->crc32);
ngx_md5_final(c->key, &md5);
+
+ ngx_memcpy(c->main, c->key, NGX_HTTP_CACHE_KEY_LEN);
}
@@ -255,7 +263,7 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
return NGX_AGAIN;
}
- if (c->buf) {
+ if (c->reading) {
return ngx_http_file_cache_read(r, c);
}
@@ -519,6 +527,23 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c)
return NGX_DECLINED;
}
+ if (h->vary_len > NGX_HTTP_CACHE_VARY_LEN) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+ "cache file \"%s\" has incorrect vary length",
+ c->file.name.data);
+ return NGX_DECLINED;
+ }
+
+ if (h->vary_len) {
+ ngx_http_file_cache_vary(r, h->vary, h->vary_len, c->variant);
+
+ if (ngx_memcmp(c->variant, h->variant, NGX_HTTP_CACHE_KEY_LEN) != 0) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache vary mismatch");
+ return ngx_http_file_cache_reopen(r, c);
+ }
+ }
+
c->buf->last += n;
c->valid_sec = h->valid_sec;
@@ -599,9 +624,12 @@ ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c)
n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
if (n != NGX_AGAIN) {
+ c->reading = 0;
return n;
}
+ c->reading = 1;
+
c->file.aio->data = r;
c->file.aio->handler = ngx_http_cache_aio_event_handler;
@@ -870,6 +898,193 @@ ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
}
+static void
+ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary, size_t len,
+ u_char *hash)
+{
+ u_char *p, *last;
+ ngx_str_t name;
+ ngx_md5_t md5;
+ u_char buf[NGX_HTTP_CACHE_VARY_LEN];
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache vary: \"%*s\"", len, vary);
+
+ ngx_md5_init(&md5);
+ ngx_md5_update(&md5, r->cache->main, NGX_HTTP_CACHE_KEY_LEN);
+
+ ngx_strlow(buf, vary, len);
+
+ p = buf;
+ last = buf + len;
+
+ while (p < last) {
+
+ while (p < last && (*p == ' ' || *p == ',')) { p++; }
+
+ name.data = p;
+
+ while (p < last && *p != ',' && *p != ' ') { p++; }
+
+ name.len = p - name.data;
+
+ if (name.len == 0) {
+ break;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache vary: %V", &name);
+
+ ngx_md5_update(&md5, name.data, name.len);
+ ngx_md5_update(&md5, (u_char *) ":", sizeof(":") - 1);
+
+ ngx_http_file_cache_vary_header(r, &md5, &name);
+
+ ngx_md5_update(&md5, (u_char *) CRLF, sizeof(CRLF) - 1);
+ }
+
+ ngx_md5_final(hash, &md5);
+}
+
+
+static void
+ngx_http_file_cache_vary_header(ngx_http_request_t *r, ngx_md5_t *md5,
+ ngx_str_t *name)
+{
+ size_t len;
+ u_char *p, *start, *last;
+ ngx_uint_t i, multiple, normalize;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header;
+
+ multiple = 0;
+ normalize = 0;
+
+ if (name->len == sizeof("Accept-Charset") - 1
+ && ngx_strncasecmp(name->data, (u_char *) "Accept-Charset",
+ sizeof("Accept-Charset") - 1) == 0)
+ {
+ normalize = 1;
+
+ } else if (name->len == sizeof("Accept-Encoding") - 1
+ && ngx_strncasecmp(name->data, (u_char *) "Accept-Encoding",
+ sizeof("Accept-Encoding") - 1) == 0)
+ {
+ normalize = 1;
+
+ } else if (name->len == sizeof("Accept-Language") - 1
+ && ngx_strncasecmp(name->data, (u_char *) "Accept-Language",
+ sizeof("Accept-Language") - 1) == 0)
+ {
+ normalize = 1;
+ }
+
+ part = &r->headers_in.headers.part;
+ header = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ header = part->elts;
+ i = 0;
+ }
+
+ if (header[i].hash == 0) {
+ continue;
+ }
+
+ if (header[i].key.len != name->len) {
+ continue;
+ }
+
+ if (ngx_strncasecmp(header[i].key.data, name->data, name->len) != 0) {
+ continue;
+ }
+
+ if (!normalize) {
+
+ if (multiple) {
+ ngx_md5_update(md5, (u_char *) ",", sizeof(",") - 1);
+ }
+
+ ngx_md5_update(md5, header[i].value.data, header[i].value.len);
+
+ multiple = 1;
+
+ continue;
+ }
+
+ /* normalize spaces */
+
+ p = header[i].value.data;
+ start = p;
+ last = p + header[i].value.len;
+
+ while (p < last) {
+
+ while (p < last && (*p == ' ' || *p == ',')) { p++; }
+
+ start = p;
+
+ while (p < last && *p != ',' && *p != ' ') { p++; }
+
+ len = p - start;
+
+ if (len == 0) {
+ break;
+ }
+
+ if (multiple) {
+ ngx_md5_update(md5, (u_char *) ",", sizeof(",") - 1);
+ }
+
+ ngx_md5_update(md5, start, len);
+
+ multiple = 1;
+ }
+ }
+}
+
+
+static ngx_int_t
+ngx_http_file_cache_reopen(ngx_http_request_t *r, ngx_http_cache_t *c)
+{
+ ngx_http_file_cache_t *cache;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
+ "http file cache reopen");
+
+ if (c->secondary) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+ "cache file \"%s\" has incorrect vary hash",
+ c->file.name.data);
+ return NGX_DECLINED;
+ }
+
+ cache = c->file_cache;
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ c->node->count--;
+ c->node = NULL;
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ c->secondary = 1;
+ c->file.name.len = 0;
+ c->body_start = c->buf->end - c->buf->start;
+
+ ngx_memcpy(c->key, c->variant, NGX_HTTP_CACHE_KEY_LEN);
+
+ return ngx_http_file_cache_open(r);
+}
+
+
void
ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
{
@@ -901,6 +1116,22 @@ ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
ngx_memcpy(h->etag, c->etag.data, c->etag.len);
}
+ if (c->vary.len) {
+ if (c->vary.len > NGX_HTTP_CACHE_VARY_LEN) {
+ /* should not happen */
+ c->vary.len = NGX_HTTP_CACHE_VARY_LEN;
+ }
+
+ h->vary_len = (u_char) c->vary.len;
+ ngx_memcpy(h->vary, c->vary.data, c->vary.len);
+
+ ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant);
+ ngx_memcpy(h->variant, c->variant, NGX_HTTP_CACHE_KEY_LEN);
+
+ } else {
+ ngx_memzero(c->variant, NGX_HTTP_CACHE_KEY_LEN);
+ }
+
p = buf + sizeof(ngx_http_file_cache_header_t);
p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key));
@@ -934,11 +1165,43 @@ ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache update");
+ cache = c->file_cache;
+
+ if (c->secondary
+ && ngx_memcmp(c->variant, c->key, NGX_HTTP_CACHE_KEY_LEN) != 0)
+ {
+ /*
+ * if the variant hash doesn't match one we used as a secondary
+ * cache key, switch back to the original key
+ */
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache main key");
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ c->node->count--;
+ c->node->updating = 0;
+ c->node = NULL;
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ c->file.name.len = 0;
+
+ ngx_memcpy(c->key, c->main, NGX_HTTP_CACHE_KEY_LEN);
+
+ if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) {
+ return;
+ }
+
+ if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) {
+ return;
+ }
+ }
+
c->updated = 1;
c->updating = 0;
- cache = c->file_cache;
-
uniq = 0;
fs_size = 0;
@@ -1093,6 +1356,19 @@ ngx_http_file_cache_update_header(ngx_http_request_t *r)
ngx_memcpy(h.etag, c->etag.data, c->etag.len);
}
+ if (c->vary.len) {
+ if (c->vary.len > NGX_HTTP_CACHE_VARY_LEN) {
+ /* should not happen */
+ c->vary.len = NGX_HTTP_CACHE_VARY_LEN;
+ }
+
+ h.vary_len = (u_char) c->vary.len;
+ ngx_memcpy(h.vary, c->vary.data, c->vary.len);
+
+ ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant);
+ ngx_memcpy(h.variant, c->variant, NGX_HTTP_CACHE_KEY_LEN);
+ }
+
(void) ngx_write_file(&file, (u_char *) &h,
sizeof(ngx_http_file_cache_header_t), 0);
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 2b932dee4..18c3b04e4 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1227,12 +1227,11 @@ ngx_http_process_request_headers(ngx_event_t *rev)
if (len > NGX_MAX_ERROR_STR - 300) {
len = NGX_MAX_ERROR_STR - 300;
- p[len++] = '.'; p[len++] = '.'; p[len++] = '.';
}
ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "client sent too long header line: \"%*s\"",
- len, r->header_name_start);
+ "client sent too long header line: \"%*s...\"",
+ len, r->header_name_start);
ngx_http_finalize_request(r,
NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index d547ca74e..3e8ce09e1 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -113,6 +113,8 @@ static ngx_int_t ngx_http_upstream_process_connection(ngx_http_request_t *r,
static ngx_int_t
ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_process_vary(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t
@@ -250,6 +252,10 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_ignore_header_line, 0, 0 },
+ { ngx_string("Vary"),
+ ngx_http_upstream_process_vary, 0,
+ ngx_http_upstream_copy_header_line, 0, 0 },
+
{ ngx_string("X-Powered-By"),
ngx_http_upstream_ignore_header_line, 0,
ngx_http_upstream_copy_header_line, 0, 0 },
@@ -407,6 +413,7 @@ ngx_conf_bitmask_t ngx_http_upstream_ignore_headers_masks[] = {
{ ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES },
{ ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL },
{ ngx_string("Set-Cookie"), NGX_HTTP_UPSTREAM_IGN_SET_COOKIE },
+ { ngx_string("Vary"), NGX_HTTP_UPSTREAM_IGN_VARY },
{ ngx_null_string, 0 }
};
@@ -441,6 +448,7 @@ ngx_http_upstream_create(ngx_http_request_t *r)
#endif
u->headers_in.content_length_n = -1;
+ u->headers_in.last_modified_time = -1;
return NGX_OK;
}
@@ -885,6 +893,7 @@ ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
u->headers_in.content_length_n = -1;
+ u->headers_in.last_modified_time = -1;
if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
sizeof(ngx_table_elt_t))
@@ -972,6 +981,14 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
ngx_resolve_name_done(ctx);
ur->ctx = NULL;
+ u->peer.start_time = ngx_current_msec;
+
+ if (u->conf->next_upstream_tries
+ && u->peer.tries > u->conf->next_upstream_tries)
+ {
+ u->peer.tries = u->conf->next_upstream_tries;
+ }
+
ngx_http_upstream_connect(r, u);
failed:
@@ -1582,6 +1599,7 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
u->headers_in.content_length_n = -1;
+ u->headers_in.last_modified_time = -1;
if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
sizeof(ngx_table_elt_t))
@@ -2273,6 +2291,17 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
r->disable_not_modified = !u->cacheable;
+ if (u->conf->force_ranges) {
+ r->allow_ranges = 1;
+ r->single_range = 1;
+
+#if (NGX_HTTP_CACHE)
+ if (r->cached) {
+ r->single_range = 0;
+ }
+#endif
+ }
+
u->length = -1;
return NGX_OK;
@@ -2558,6 +2587,8 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
p->downstream = c;
p->pool = r->pool;
p->log = c->log;
+ p->limit_rate = u->conf->limit_rate;
+ p->start_sec = ngx_time();
p->cacheable = u->cacheable || u->store;
@@ -3232,21 +3263,61 @@ static void
ngx_http_upstream_process_upstream(ngx_http_request_t *r,
ngx_http_upstream_t *u)
{
+ ngx_event_t *rev;
+ ngx_event_pipe_t *p;
ngx_connection_t *c;
c = u->peer.connection;
+ p = u->pipe;
+ rev = c->read;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream process upstream");
c->log->action = "reading upstream";
- if (c->read->timedout) {
- u->pipe->upstream_error = 1;
- ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
+ if (rev->timedout) {
+
+ if (rev->delayed) {
+
+ rev->timedout = 0;
+ rev->delayed = 0;
+
+ if (!rev->ready) {
+ ngx_add_timer(rev, p->read_timeout);
+
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
+ }
+
+ return;
+ }
+
+ if (ngx_event_pipe(p, 0) == NGX_ABORT) {
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
+ return;
+ }
+
+ } else {
+ p->upstream_error = 1;
+ ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
+ }
} else {
- if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) {
+
+ if (rev->delayed) {
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "http upstream delayed");
+
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
+ }
+
+ return;
+ }
+
+ if (ngx_event_pipe(p, 0) == NGX_ABORT) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
@@ -4125,6 +4196,39 @@ ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
static ngx_int_t
+ngx_http_upstream_process_vary(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset)
+{
+ ngx_http_upstream_t *u;
+
+ u = r->upstream;
+ u->headers_in.vary = h;
+
+#if (NGX_HTTP_CACHE)
+
+ if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) {
+ return NGX_OK;
+ }
+
+ if (r->cache == NULL) {
+ return NGX_OK;
+ }
+
+ if (h->value.len > NGX_HTTP_CACHE_VARY_LEN
+ || (h->value.len == 1 && h->value.data[0] == '*'))
+ {
+ u->cacheable = 0;
+ }
+
+ r->cache->vary = h->value;
+
+#endif
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
@@ -4390,6 +4494,10 @@ ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
{
ngx_table_elt_t *ho;
+ if (r->upstream->conf->force_ranges) {
+ return NGX_OK;
+ }
+
#if (NGX_HTTP_CACHE)
if (r->cached) {
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index 2ee899d83..0032c2c22 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -50,6 +50,7 @@
#define NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE 0x00000040
#define NGX_HTTP_UPSTREAM_IGN_XA_BUFFERING 0x00000080
#define NGX_HTTP_UPSTREAM_IGN_XA_CHARSET 0x00000100
+#define NGX_HTTP_UPSTREAM_IGN_VARY 0x00000200
typedef struct {
@@ -140,6 +141,7 @@ typedef struct {
size_t send_lowat;
size_t buffer_size;
+ size_t limit_rate;
size_t busy_buffers_size;
size_t max_temp_file_size;
@@ -162,6 +164,7 @@ typedef struct {
ngx_flag_t ignore_client_abort;
ngx_flag_t intercept_errors;
ngx_flag_t cyclic_temp_file;
+ ngx_flag_t force_ranges;
ngx_path_t *temp_path;
@@ -243,6 +246,7 @@ typedef struct {
ngx_table_elt_t *accept_ranges;
ngx_table_elt_t *www_authenticate;
ngx_table_elt_t *transfer_encoding;
+ ngx_table_elt_t *vary;
#if (NGX_HTTP_GZIP)
ngx_table_elt_t *content_encoding;
diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c
index 83cb1fa1e..b19f75bda 100644
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -219,8 +219,8 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
if (limit <= 0) {
c->write->delayed = 1;
- ngx_add_timer(c->write,
- (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1));
+ delay = (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1);
+ ngx_add_timer(c->write, delay);
c->buffered |= NGX_HTTP_WRITE_BUFFERED;
diff --git a/src/os/unix/ngx_aio_read_chain.c b/src/os/unix/ngx_aio_read_chain.c
index 8c831b951..d8722b2c1 100644
--- a/src/os/unix/ngx_aio_read_chain.c
+++ b/src/os/unix/ngx_aio_read_chain.c
@@ -11,7 +11,7 @@
ssize_t
-ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl)
+ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit)
{
int n;
u_char *buf, *prev;
diff --git a/src/os/unix/ngx_darwin_sendfile_chain.c b/src/os/unix/ngx_darwin_sendfile_chain.c
index dd574e5ac..8485f9749 100644
--- a/src/os/unix/ngx_darwin_sendfile_chain.c
+++ b/src/os/unix/ngx_darwin_sendfile_chain.c
@@ -308,6 +308,7 @@ ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
in = ngx_handle_sent_chain(in, sent);
if (eintr) {
+ send = prev_send + sent;
continue;
}
diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c
index f5d0f3a8a..88eacc2d1 100644
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -378,6 +378,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
}
if (eintr) {
+ send = prev_send + sent;
continue;
}
diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c
index 1060852a0..60867c51e 100644
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -316,6 +316,7 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
in = ngx_handle_sent_chain(in, sent);
if (eintr) {
+ send = prev_send;
continue;
}
diff --git a/src/os/unix/ngx_os.h b/src/os/unix/ngx_os.h
index 1033d8825..a1586426c 100644
--- a/src/os/unix/ngx_os.h
+++ b/src/os/unix/ngx_os.h
@@ -17,7 +17,8 @@
typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size);
-typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in);
+typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
+ off_t limit);
typedef ssize_t (*ngx_send_pt)(ngx_connection_t *c, u_char *buf, size_t size);
typedef ngx_chain_t *(*ngx_send_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
@@ -41,7 +42,7 @@ ngx_int_t ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_int_t pid);
ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size);
-ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry);
+ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry, off_t limit);
ssize_t ngx_udp_unix_recv(ngx_connection_t *c, u_char *buf, size_t size);
ssize_t ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size);
ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in,
@@ -49,7 +50,7 @@ ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in,
#if (NGX_HAVE_AIO)
ssize_t ngx_aio_read(ngx_connection_t *c, u_char *buf, size_t size);
-ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl);
+ssize_t ngx_aio_read_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit);
ssize_t ngx_aio_write(ngx_connection_t *c, u_char *buf, size_t size);
ngx_chain_t *ngx_aio_write_chain(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c
index 3cba80ccc..3544b4b17 100644
--- a/src/os/unix/ngx_readv_chain.c
+++ b/src/os/unix/ngx_readv_chain.c
@@ -11,7 +11,7 @@
ssize_t
-ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
+ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit)
{
u_char *prev;
ssize_t n, size;
@@ -66,8 +66,20 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
/* coalesce the neighbouring bufs */
while (chain) {
+ n = chain->buf->end - chain->buf->last;
+
+ if (limit) {
+ if (size >= limit) {
+ break;
+ }
+
+ if (size + n > limit) {
+ n = (ssize_t) (limit - size);
+ }
+ }
+
if (prev == chain->buf->last) {
- iov->iov_len += chain->buf->end - chain->buf->last;
+ iov->iov_len += n;
} else {
if (vec.nelts >= IOV_MAX) {
@@ -80,10 +92,10 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
}
iov->iov_base = (void *) chain->buf->last;
- iov->iov_len = chain->buf->end - chain->buf->last;
+ iov->iov_len = n;
}
- size += chain->buf->end - chain->buf->last;
+ size += n;
prev = chain->buf->end;
chain = chain->next;
}
diff --git a/src/os/unix/ngx_solaris_sendfilev_chain.c b/src/os/unix/ngx_solaris_sendfilev_chain.c
index ba328c810..1b71f1dd8 100644
--- a/src/os/unix/ngx_solaris_sendfilev_chain.c
+++ b/src/os/unix/ngx_solaris_sendfilev_chain.c
@@ -200,6 +200,7 @@ ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
in = ngx_handle_sent_chain(in, sent);
if (eintr) {
+ send = prev_send + sent;
continue;
}
diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c
index 95af2da7a..c7b6ebf7c 100644
--- a/src/os/unix/ngx_writev_chain.c
+++ b/src/os/unix/ngx_writev_chain.c
@@ -134,6 +134,7 @@ ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
in = ngx_handle_sent_chain(in, sent);
if (eintr) {
+ send = prev_send;
continue;
}