summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES42
-rw-r--r--CHANGES.ru46
-rw-r--r--LICENSE4
-rw-r--r--src/core/nginx.h4
-rw-r--r--src/core/ngx_connection.c8
-rw-r--r--src/core/ngx_connection.h4
-rw-r--r--src/core/ngx_palloc.c7
-rw-r--r--src/core/ngx_resolver.c17
-rw-r--r--src/event/ngx_event_openssl.c25
-rw-r--r--src/event/ngx_event_openssl.h2
-rw-r--r--src/http/modules/ngx_http_autoindex_module.c1
-rw-r--r--src/http/modules/ngx_http_dav_module.c2
-rw-r--r--src/http/modules/ngx_http_image_filter_module.c1
-rw-r--r--src/http/modules/ngx_http_mp4_module.c2
-rw-r--r--src/http/modules/ngx_http_scgi_module.c2
-rw-r--r--src/http/modules/ngx_http_ssi_filter_module.c14
-rw-r--r--src/http/modules/ngx_http_ssl_module.c31
-rw-r--r--src/http/modules/ngx_http_ssl_module.h3
-rw-r--r--src/http/modules/ngx_http_stub_status_module.c2
-rw-r--r--src/http/modules/ngx_http_upstream_ip_hash_module.c46
-rw-r--r--src/http/modules/ngx_http_uwsgi_module.c2
-rw-r--r--src/http/ngx_http_copy_filter_module.c6
-rw-r--r--src/http/ngx_http_parse.c73
-rw-r--r--src/http/ngx_http_request_body.c58
-rw-r--r--src/http/ngx_http_spdy.c284
-rw-r--r--src/http/ngx_http_spdy.h21
-rw-r--r--src/http/ngx_http_spdy_filter_module.c341
-rw-r--r--src/http/ngx_http_spdy_module.c65
-rw-r--r--src/http/ngx_http_spdy_module.h5
-rw-r--r--src/http/ngx_http_upstream.c16
-rw-r--r--src/http/ngx_http_write_filter_module.c5
-rw-r--r--src/mail/ngx_mail_proxy_module.c33
-rw-r--r--src/mail/ngx_mail_ssl_module.c17
-rw-r--r--src/mail/ngx_mail_ssl_module.h1
-rw-r--r--src/os/unix/ngx_process_cycle.c2
35 files changed, 787 insertions, 405 deletions
diff --git a/CHANGES b/CHANGES
index c47a5816c..5b1678eea 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,44 @@
+Changes with nginx 1.5.9 22 Jan 2014
+
+ *) Change: now nginx expects escaped URIs in "X-Accel-Redirect" headers.
+
+ *) Feature: the "ssl_buffer_size" directive.
+
+ *) Feature: the "limit_rate" directive can now be used to rate limit
+ responses sent in SPDY connections.
+
+ *) Feature: the "spdy_chunk_size" directive.
+
+ *) Feature: the "ssl_session_tickets" directive.
+ Thanks to Dirkjan Bussink.
+
+ *) Bugfix: the $ssl_session_id variable contained full session
+ serialized instead of just a session id.
+ Thanks to Ivan Ristić.
+
+ *) Bugfix: nginx incorrectly handled escaped "?" character in the
+ "include" SSI command.
+
+ *) Bugfix: the ngx_http_dav_module did not unescape destination URI of
+ the COPY and MOVE methods.
+
+ *) Bugfix: resolver did not understand domain names with a trailing dot.
+ Thanks to Yichun Zhang.
+
+ *) Bugfix: alerts "zero size buf in output" might appear in logs while
+ proxying; the bug had appeared in 1.3.9.
+
+ *) Bugfix: a segmentation fault might occur in a worker process if the
+ ngx_http_spdy_module was used.
+
+ *) Bugfix: proxied WebSocket connections might hang right after
+ handshake if the select, poll, or /dev/poll methods were used.
+
+ *) Bugfix: the "xclient" directive of the mail proxy module incorrectly
+ handled IPv6 client addresses.
+
+
Changes with nginx 1.5.8 17 Dec 2013
*) Feature: IPv6 support in resolver.
@@ -6218,7 +6258,7 @@ Changes with nginx 0.1.16 25 Jan 2005
*) Bugfix: the compressed response encrypted by SSL may not transferred
complete.
- *) Bugfix: the TCP-specific TCP_NODELAY, TCP_NOPSUH, and TCP_CORK
+ *) Bugfix: the TCP-specific TCP_NODELAY, TCP_NOPUSH, and TCP_CORK
options, are not used for the unix domain sockets.
*) Feature: the rewrite directive supports the arguments rewriting.
diff --git a/CHANGES.ru b/CHANGES.ru
index f50fd2aeb..580bba300 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,46 @@
+Изменения в nginx 1.5.9 22.01.2014
+
+ *) Изменение: теперь в заголовке X-Accel-Redirect nginx ожидает
+ закодированный URI.
+
+ *) Добавление: директива ssl_buffer_size.
+
+ *) Добавление: директиву limit_rate теперь можно использовать для
+ ограничения скорости передачи ответов клиенту в SPDY-соединениях.
+
+ *) Добавление: директива spdy_chunk_size.
+
+ *) Добавление: директива ssl_session_tickets.
+ Спасибо Dirkjan Bussink.
+
+ *) Исправление: переменная $ssl_session_id содержала всю сессию в
+ сериализованном виде вместо её идентификатора.
+ Спасибо Ivan Ristić.
+
+ *) Исправление: nginx неправильно обрабатывал закодированный символ "?"
+ в команде SSI include.
+
+ *) Исправление: модуль ngx_http_dav_module не раскодировал целевой URI
+ при обработке методов COPY и MOVE.
+
+ *) Исправление: resolver не понимал доменные имена с точкой в конце.
+ Спасибо Yichun Zhang.
+
+ *) Исправление: при проксировании в логах могли появляться сообщения
+ "zero size buf in output"; ошибка появилась в 1.3.9.
+
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если использовался модуль ngx_http_spdy_module.
+
+ *) Исправление: при использовании методов обработки соединений select,
+ poll и /dev/poll проксируемые WebSocket-соединения могли зависать
+ сразу после открытия.
+
+ *) Исправление: директива xclient почтового прокси-сервера некорректно
+ передавала IPv6-адреса.
+
+
Изменения в nginx 1.5.8 17.12.2013
*) Добавление: теперь resolver поддерживает IPv6.
@@ -2826,7 +2868,7 @@
умолчанию; ошибка появилась в 0.7.18.
Спасибо Максиму Дунину.
- *) Исправление: при проксировании SMPT nginx выдавал сообщение
+ *) Исправление: при проксировании SMTP nginx выдавал сообщение
"250 2.0.0 OK" вместо "235 2.0.0 OK"; ошибка появилась в 0.7.22.
Спасибо Максиму Дунину.
@@ -6312,7 +6354,7 @@
*) Исправление: при использовании SSL сжатый ответ мог передаваться не
до конца.
- *) Исправление: опции TCP_NODELAY, TCP_NOPSUH и TCP_CORK, специфичные
+ *) Исправление: опции TCP_NODELAY, TCP_NOPUSH и TCP_CORK, специфичные
для TCP сокетов, не используются для unix domain сокетов.
*) Добавление: директива rewrite поддерживает перезаписывание
diff --git a/LICENSE b/LICENSE
index 5d8097000..4ed7a6fc7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2002-2013 Igor Sysoev
- * Copyright (C) 2011-2013 Nginx, Inc.
+ * Copyright (C) 2002-2014 Igor Sysoev
+ * Copyright (C) 2011-2014 Nginx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 220d55a29..76d43c6d4 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1005008
-#define NGINX_VERSION "1.5.8"
+#define nginx_version 1005009
+#define NGINX_VERSION "1.5.9"
#define NGINX_VER "nginx/" NGINX_VERSION
#define NGINX_VAR "NGINX"
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 57e26912d..08a547d42 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -199,7 +199,9 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
#if (NGX_HAVE_SETFIB)
- if (getsockopt(ls[i].setfib, SOL_SOCKET, SO_SETFIB,
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
(void *) &ls[i].setfib, &olen)
== -1)
{
@@ -215,7 +217,9 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
#if (NGX_HAVE_TCP_FASTOPEN)
- if (getsockopt(ls[i].fastopen, IPPROTO_TCP, TCP_FASTOPEN,
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
(void *) &ls[i].fastopen, &olen)
== -1)
{
diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
index c7b3b315c..d9bc60a77 100644
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -112,6 +112,7 @@ typedef enum {
#define NGX_LOWLEVEL_BUFFERED 0x0f
#define NGX_SSL_BUFFERED 0x01
+#define NGX_SPDY_BUFFERED 0x02
struct ngx_connection_s {
@@ -171,12 +172,15 @@ struct ngx_connection_s {
unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */
unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */
+ unsigned need_last_buf:1;
+
#if (NGX_HAVE_IOCP)
unsigned accept_context_updated:1;
#endif
#if (NGX_HAVE_AIO_SENDFILE)
unsigned aio_sendfile:1;
+ unsigned busy_count:2;
ngx_buf_t *busy_sendfile;
#endif
diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c
index efbc24452..1f70f9eee 100644
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -105,11 +105,14 @@ ngx_reset_pool(ngx_pool_t *pool)
}
}
- pool->large = NULL;
-
for (p = pool; p; p = p->d.next) {
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
+ p->d.failed = 0;
}
+
+ pool->current = pool;
+ pool->chain = NULL;
+ pool->large = NULL;
}
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index a446f98b6..abf82d85b 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -356,6 +356,10 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx)
r = ctx->resolver;
+ if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') {
+ ctx->name.len--;
+ }
+
ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolve: \"%V\"", &ctx->name);
@@ -678,6 +682,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
rn->code = 0;
rn->cnlen = 0;
rn->valid = 0;
+ rn->ttl = NGX_MAX_UINT32_VALUE;
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
@@ -871,6 +876,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
rn->name = NULL;
rn->nlen = 0;
rn->valid = 0;
+ rn->ttl = NGX_MAX_UINT32_VALUE;
rn->waiting = ctx;
/* unlock addr mutex */
@@ -1574,7 +1580,6 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
i = ans;
naddrs = 0;
cname = NULL;
- ttl = 0;
for (a = 0; a < nan; a++) {
@@ -1628,6 +1633,8 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
ttl = 0;
}
+ rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
+
i += sizeof(ngx_resolver_an_t);
switch (type) {
@@ -1694,8 +1701,8 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
}
ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver naddrs:%ui cname:%p ttl:%d",
- naddrs, cname, ttl);
+ "resolver naddrs:%ui cname:%p ttl:%uD",
+ naddrs, cname, rn->ttl);
if (naddrs) {
@@ -1746,8 +1753,6 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
#endif
}
- rn->ttl = ttl;
-
n = 0;
i = ans;
@@ -1915,7 +1920,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
rn->cnlen = (u_short) name.len;
rn->u.cname = name.data;
- rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
+ rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
rn->expire = ngx_time() + r->expire;
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index ee6671350..9935fb098 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -190,6 +190,8 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
return NGX_ERROR;
}
+ ssl->buffer_size = NGX_SSL_BUFSIZE;
+
/* client side options */
SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
@@ -726,6 +728,7 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
}
sc->buffer = ((flags & NGX_SSL_BUFFER) != 0);
+ sc->buffer_size = ssl->buffer_size;
sc->connection = SSL_new(ssl->ctx);
@@ -1222,7 +1225,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
buf = c->ssl->buf;
if (buf == NULL) {
- buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE);
+ buf = ngx_create_temp_buf(c->pool, c->ssl->buffer_size);
if (buf == NULL) {
return NGX_CHAIN_ERROR;
}
@@ -1231,14 +1234,14 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
}
if (buf->start == NULL) {
- buf->start = ngx_palloc(c->pool, NGX_SSL_BUFSIZE);
+ buf->start = ngx_palloc(c->pool, c->ssl->buffer_size);
if (buf->start == NULL) {
return NGX_CHAIN_ERROR;
}
buf->pos = buf->start;
buf->last = buf->start;
- buf->end = buf->start + NGX_SSL_BUFSIZE;
+ buf->end = buf->start + c->ssl->buffer_size;
}
send = buf->last - buf->pos;
@@ -2501,32 +2504,22 @@ ngx_int_t
ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
{
int len;
- u_char *p, *buf;
+ u_char *buf;
SSL_SESSION *sess;
sess = SSL_get0_session(c->ssl->connection);
- len = i2d_SSL_SESSION(sess, NULL);
-
- buf = ngx_alloc(len, c->log);
- if (buf == NULL) {
- return NGX_ERROR;
- }
+ buf = sess->session_id;
+ len = sess->session_id_length;
s->len = 2 * len;
s->data = ngx_pnalloc(pool, 2 * len);
if (s->data == NULL) {
- ngx_free(buf);
return NGX_ERROR;
}
- p = buf;
- i2d_SSL_SESSION(sess, &p);
-
ngx_hex_dump(s->data, buf, len);
- ngx_free(buf);
-
return NGX_OK;
}
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 841e82569..907639e83 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -29,6 +29,7 @@
typedef struct {
SSL_CTX *ctx;
ngx_log_t *log;
+ size_t buffer_size;
} ngx_ssl_t;
@@ -37,6 +38,7 @@ typedef struct {
ngx_int_t last;
ngx_buf_t *buf;
+ size_t buffer_size;
ngx_connection_handler_pt handler;
diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c
index 221455120..f694df075 100644
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -233,6 +233,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_type_len = sizeof("text/html") - 1;
ngx_str_set(&r->headers_out.content_type, "text/html");
+ r->headers_out.content_type_lowcase = NULL;
rc = ngx_http_send_header(r);
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c
index 2a179922c..e7f9e9ae3 100644
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -604,7 +604,7 @@ destination_done:
duri.len = last - p;
duri.data = p;
- flags = 0;
+ flags = NGX_HTTP_LOG_UNSAFE;
if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) {
goto invalid_destination;
diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c
index cc41ef0d5..c983b973b 100644
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -572,6 +572,7 @@ ngx_http_image_json(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
ngx_http_clean_header(r);
r->headers_out.status = NGX_HTTP_OK;
+ r->headers_out.content_type_len = sizeof("application/json") - 1;
ngx_str_set(&r->headers_out.content_type, "application/json");
r->headers_out.content_type_lowcase = NULL;
diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c
index c44dc52c9..d900fb8d1 100644
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -542,7 +542,7 @@ ngx_http_mp4_handler(ngx_http_request_t *r)
mp4->file.fd = of.fd;
mp4->file.name = path;
- mp4->file.log = r->connection->log;;
+ mp4->file.log = r->connection->log;
mp4->end = of.size;
mp4->start = (ngx_uint_t) start;
mp4->request = r;
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index d396b27c8..70f6ac1de 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -1734,7 +1734,7 @@ ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
sc.source = &value[1];
sc.lengths = &scf->upstream.store_lengths;
sc.values = &scf->upstream.store_values;
- sc.variables = ngx_http_script_variables_count(&value[1]);;
+ sc.variables = ngx_http_script_variables_count(&value[1]);
sc.complete_lengths = 1;
sc.complete_values = 1;
diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c
index c70b17e09..a53cd1472 100644
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -1982,8 +1982,6 @@ static ngx_int_t
ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
ngx_str_t **params)
{
- u_char *dst, *src;
- size_t len;
ngx_int_t rc, key;
ngx_str_t *uri, *file, *wait, *set, *stub, args;
ngx_buf_t *b;
@@ -2054,18 +2052,6 @@ ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
return rc;
}
- dst = uri->data;
- src = uri->data;
-
- ngx_unescape_uri(&dst, &src, uri->len, NGX_UNESCAPE_URI);
-
- len = (uri->data + uri->len) - src;
- if (len) {
- dst = ngx_movemem(dst, src, len);
- }
-
- uri->len = dst - uri->data;
-
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"ssi include: \"%V\"", uri);
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index 7ac96c621..1a2669065 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -111,6 +111,13 @@ static ngx_command_t ngx_http_ssl_commands[] = {
offsetof(ngx_http_ssl_srv_conf_t, ciphers),
NULL },
+ { ngx_string("ssl_buffer_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_ssl_srv_conf_t, buffer_size),
+ NULL },
+
{ ngx_string("ssl_verify_client"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
@@ -119,7 +126,7 @@ static ngx_command_t ngx_http_ssl_commands[] = {
&ngx_http_ssl_verify },
{ ngx_string("ssl_verify_depth"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, verify_depth),
@@ -153,6 +160,13 @@ static ngx_command_t ngx_http_ssl_commands[] = {
0,
NULL },
+ { ngx_string("ssl_session_tickets"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_ssl_srv_conf_t, session_tickets),
+ NULL },
+
{ ngx_string("ssl_session_ticket_key"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_array_slot,
@@ -424,10 +438,12 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
sscf->enable = NGX_CONF_UNSET;
sscf->prefer_server_ciphers = NGX_CONF_UNSET;
+ sscf->buffer_size = NGX_CONF_UNSET_SIZE;
sscf->verify = NGX_CONF_UNSET_UINT;
sscf->verify_depth = NGX_CONF_UNSET_UINT;
sscf->builtin_session_cache = NGX_CONF_UNSET;
sscf->session_timeout = NGX_CONF_UNSET;
+ sscf->session_tickets = NGX_CONF_UNSET;
sscf->session_ticket_keys = NGX_CONF_UNSET_PTR;
sscf->stapling = NGX_CONF_UNSET;
sscf->stapling_verify = NGX_CONF_UNSET;
@@ -465,6 +481,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
(NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1
|NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+ ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
+ NGX_SSL_BUFSIZE);
+
ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
@@ -572,6 +591,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
+ conf->ssl.buffer_size = conf->buffer_size;
+
if (conf->verify) {
if (conf->client_certificate.len == 0 && conf->verify != 3) {
@@ -631,6 +652,14 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
+ ngx_conf_merge_value(conf->session_tickets, prev->session_tickets, 1);
+
+#ifdef SSL_OP_NO_TICKET
+ if (!conf->session_tickets) {
+ SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_NO_TICKET);
+ }
+#endif
+
ngx_conf_merge_ptr_value(conf->session_ticket_keys,
prev->session_ticket_keys, NULL);
diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h
index 3feb4b6d2..ec2c62f6f 100644
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -26,6 +26,8 @@ typedef struct {
ngx_uint_t verify;
ngx_uint_t verify_depth;
+ size_t buffer_size;
+
ssize_t builtin_session_cache;
time_t session_timeout;
@@ -42,6 +44,7 @@ typedef struct {
ngx_shm_zone_t *shm_zone;
+ ngx_flag_t session_tickets;
ngx_array_t *session_ticket_keys;
ngx_flag_t stapling;
diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c
index fe9132df8..b5ecd6d9e 100644
--- a/src/http/modules/ngx_http_stub_status_module.c
+++ b/src/http/modules/ngx_http_stub_status_module.c
@@ -98,7 +98,9 @@ static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r)
return rc;
}
+ r->headers_out.content_type_len = sizeof("text/plain") - 1;
ngx_str_set(&r->headers_out.content_type, "text/plain");
+ r->headers_out.content_type_lowcase = NULL;
if (r->method == NGX_HTTP_HEAD) {
r->headers_out.status = NGX_HTTP_OK;
diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
index 0e5cf416a..041883fec 100644
--- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
+++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
@@ -197,33 +197,39 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
n = p / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
- if (!(iphp->rrp.tried[n] & m)) {
+ if (iphp->rrp.tried[n] & m) {
+ goto next;
+ }
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
- "get ip hash peer, hash: %ui %04XA", p, m);
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "get ip hash peer, hash: %ui %04XA", p, m);
- peer = &iphp->rrp.peers->peer[p];
+ peer = &iphp->rrp.peers->peer[p];
- /* ngx_lock_mutex(iphp->rrp.peers->mutex); */
+ /* ngx_lock_mutex(iphp->rrp.peers->mutex); */
- if (!peer->down) {
+ if (peer->down) {
+ goto next_try;
+ }
- if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
- break;
- }
+ if (peer->max_fails
+ && peer->fails >= peer->max_fails
+ && now - peer->checked <= peer->fail_timeout)
+ {
+ goto next_try;
+ }
- if (now - peer->checked > peer->fail_timeout) {
- peer->checked = now;
- break;
- }
- }
+ break;
- iphp->rrp.tried[n] |= m;
+ next_try:
- /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
+ iphp->rrp.tried[n] |= m;
- pc->tries--;
- }
+ /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
+
+ pc->tries--;
+
+ next:
if (++iphp->tries >= 20) {
return iphp->get_rr_peer(pc, &iphp->rrp);
@@ -236,6 +242,10 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
pc->socklen = peer->socklen;
pc->name = &peer->name;
+ if (now - peer->checked > peer->fail_timeout) {
+ peer->checked = now;
+ }
+
/* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
iphp->rrp.tried[n] |= m;
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index 0ddea57df..f55e606c8 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -1916,7 +1916,7 @@ ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
sc.source = &value[1];
sc.lengths = &uwcf->upstream.store_lengths;
sc.values = &uwcf->upstream.store_values;
- sc.variables = ngx_http_script_variables_count(&value[1]);;
+ sc.variables = ngx_http_script_variables_count(&value[1]);
sc.complete_lengths = 1;
sc.complete_values = 1;
diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c
index 95bc0b835..3ad27b042 100644
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -169,13 +169,15 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
offset = c->busy_sendfile->file_pos;
if (file->aio) {
- c->aio_sendfile = (offset != file->aio->last_offset);
+ c->busy_count = (offset == file->aio->last_offset) ?
+ c->busy_count + 1 : 0;
file->aio->last_offset = offset;
- if (c->aio_sendfile == 0) {
+ if (c->busy_count > 2) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"sendfile(%V) returned busy again",
&file->name);
+ c->aio_sendfile = 0;
}
}
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index cf89b8cfe..8c1a62a7b 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -1780,17 +1780,21 @@ ngx_int_t
ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
ngx_str_t *args, ngx_uint_t *flags)
{
- u_char ch, *p;
- size_t len;
+ u_char ch, *p, *src, *dst;
+ size_t len;
+ ngx_uint_t quoted;
len = uri->len;
p = uri->data;
+ quoted = 0;
if (len == 0 || p[0] == '?') {
goto unsafe;
}
- if (p[0] == '.' && len == 3 && p[1] == '.' && (ngx_path_separator(p[2]))) {
+ if (p[0] == '.' && len > 1 && p[1] == '.'
+ && (len == 2 || ngx_path_separator(p[2])))
+ {
goto unsafe;
}
@@ -1798,6 +1802,11 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
ch = *p++;
+ if (ch == '%') {
+ quoted = 1;
+ continue;
+ }
+
if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
continue;
}
@@ -1807,7 +1816,7 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
args->data = p;
uri->len -= len;
- return NGX_OK;
+ break;
}
if (ch == '\0') {
@@ -1816,14 +1825,66 @@ ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
if (ngx_path_separator(ch) && len > 2) {
- /* detect "/../" */
+ /* detect "/../" and "/.." */
- if (p[0] == '.' && p[1] == '.' && ngx_path_separator(p[2])) {
+ if (p[0] == '.' && p[1] == '.'
+ && (len == 3 || ngx_path_separator(p[2])))
+ {
goto unsafe;
}
}
}
+ if (quoted) {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "escaped URI: \"%V\"", uri);
+
+ src = uri->data;
+
+ dst = ngx_pnalloc(r->pool, uri->len);
+ if (dst == NULL) {
+ return NGX_ERROR;
+ }
+
+ uri->data = dst;
+
+ ngx_unescape_uri(&dst, &src, uri->len, 0);
+
+ uri->len = dst - uri->data;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "unescaped URI: \"%V\"", uri);
+
+ len = uri->len;
+ p = uri->data;
+
+ if (p[0] == '.' && len > 1 && p[1] == '.'
+ && (len == 2 || ngx_path_separator(p[2])))
+ {
+ goto unsafe;
+ }
+
+ for ( /* void */ ; len; len--) {
+
+ ch = *p++;
+
+ if (ch == '\0') {
+ goto unsafe;
+ }
+
+ if (ngx_path_separator(ch) && len > 2) {
+
+ /* detect "/../" and "/.." */
+
+ if (p[0] == '.' && p[1] == '.'
+ && (len == 3 || ngx_path_separator(p[2])))
+ {
+ goto unsafe;
+ }
+ }
+ }
+ }
+
return NGX_OK;
unsafe:
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index 97df69c05..94cdbeed6 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -150,21 +150,27 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
goto done;
}
- cl = ngx_chain_get_free_buf(r->pool, &rb->free);
- if (cl == NULL) {
- rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
- goto done;
- }
+ if (rb->temp_file->file.offset != 0) {
- b = cl->buf;
+ cl = ngx_chain_get_free_buf(r->pool, &rb->free);
+ if (cl == NULL) {
+ rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ goto done;
+ }
- ngx_memzero(b, sizeof(ngx_buf_t));
+ b = cl->buf;
- b->in_file = 1;
- b->file_last = rb->temp_file->file.offset;
- b->file = &rb->temp_file->file;
+ ngx_memzero(b, sizeof(ngx_buf_t));
- rb->bufs = cl;
+ b->in_file = 1;
+ b->file_last = rb->temp_file->file.offset;
+ b->file = &rb->temp_file->file;
+
+ rb->bufs = cl;
+
+ } else {
+ rb->bufs = NULL;
+ }
}
post_handler(r);
@@ -375,20 +381,26 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- cl = ngx_chain_get_free_buf(r->pool, &rb->free);
- if (cl == NULL) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
+ if (rb->temp_file->file.offset != 0) {
- b = cl->buf;
+ cl = ngx_chain_get_free_buf(r->pool, &rb->free);
+ if (cl == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
- ngx_memzero(b, sizeof(ngx_buf_t));
+ b = cl->buf;
+
+ ngx_memzero(b, sizeof(ngx_buf_t));
+
+ b->in_file = 1;
+ b->file_last = rb->temp_file->file.offset;
+ b->file = &rb->temp_file->file;
- b->in_file = 1;
- b->file_last = rb->temp_file->file.offset;
- b->file = &rb->temp_file->file;
+ rb->bufs = cl;
- rb->bufs = cl;
+ } else {
+ rb->bufs = NULL;
+ }
}
r->read_event_handler = ngx_http_block_reading;
@@ -843,6 +855,10 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
for (cl = in; cl; cl = cl->next) {
+ if (rb->rest == 0) {
+ break;
+ }
+
tl = ngx_chain_get_free_buf(r->pool, &rb->free);
if (tl == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c
index 2346ad7a1..27c8aa196 100644
--- a/src/http/ngx_http_spdy.c
+++ b/src/http/ngx_http_spdy.c
@@ -81,8 +81,6 @@ static void ngx_http_spdy_read_handler(ngx_event_t *rev);
static void ngx_http_spdy_write_handler(ngx_event_t *wev);
static void ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc);
-static u_char *ngx_http_spdy_state_detect_settings(
- ngx_http_spdy_connection_t *sc, u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc,
@@ -101,8 +99,10 @@ static u_char *ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
+#if 0
static u_char *ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
+#endif
static u_char *ngx_http_spdy_state_noop(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc,
@@ -235,7 +235,7 @@ ngx_http_spdy_init(ngx_event_t *rev)
sc->connection = c;
sc->http_connection = hc;
- sc->handler = ngx_http_spdy_state_detect_settings;
+ sc->handler = ngx_http_spdy_state_head;
sc->zstream_in.zalloc = ngx_http_spdy_zalloc;
sc->zstream_in.zfree = ngx_http_spdy_zfree;
@@ -297,6 +297,13 @@ ngx_http_spdy_init(ngx_event_t *rev)
return;
}
+ if (ngx_http_spdy_send_settings(sc) == NGX_ERROR) {
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ ngx_queue_init(&sc->posted);
+
c->data = sc;
rev->handler = ngx_http_spdy_read_handler;
@@ -346,7 +353,7 @@ ngx_http_spdy_read_handler(ngx_event_t *rev)
break;
}
- if (n == 0 && (sc->waiting || sc->processing)) {
+ if (n == 0 && (sc->incomplete || sc->processing)) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client closed prematurely connection");
}
@@ -360,7 +367,7 @@ ngx_http_spdy_read_handler(ngx_event_t *rev)
end += n;
sc->buffer_used = 0;
- sc->waiting = 0;
+ sc->incomplete = 0;
do {
p = sc->handler(sc, p, end);
@@ -378,6 +385,11 @@ ngx_http_spdy_read_handler(ngx_event_t *rev)
return;
}
+ if (sc->last_out && ngx_http_spdy_send_output_queue(sc) == NGX_ERROR) {
+ ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
+ return;
+ }
+
sc->blocked = 0;
if (sc->processing) {
@@ -395,8 +407,9 @@ static void
ngx_http_spdy_write_handler(ngx_event_t *wev)
{
ngx_int_t rc;
+ ngx_queue_t *q;
ngx_connection_t *c;
- ngx_http_spdy_stream_t *stream, *s, *sn;
+ ngx_http_spdy_stream_t *stream;
ngx_http_spdy_connection_t *sc;
c = wev->data;
@@ -411,7 +424,7 @@ ngx_http_spdy_write_handler(ngx_event_t *wev)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "spdy write handler");
- sc->blocked = 2;
+ sc->blocked = 1;
rc = ngx_http_spdy_send_output_queue(sc);
@@ -420,20 +433,13 @@ ngx_http_spdy_write_handler(ngx_event_t *wev)
return;
}
- stream = NULL;
+ while (!ngx_queue_empty(&sc->posted)) {
+ q = ngx_queue_head(&sc->posted);
- for (s = sc->last_stream; s; s = sn) {
- sn = s->next;
- s->next = stream;
- stream = s;
- }
+ ngx_queue_remove(q);
- sc->last_stream = NULL;
+ stream = ngx_queue_data(q, ngx_http_spdy_stream_t, queue);
- sc->blocked = 1;
-
- for ( /* void */ ; stream; stream = sn) {
- sn = stream->next;
stream->handled = 0;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
@@ -486,9 +492,9 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
out = frame;
ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
- "spdy frame out: %p sid:%ui prio:%ui bl:%ui size:%uz",
+ "spdy frame out: %p sid:%ui prio:%ui bl:%d len:%uz",
out, out->stream ? out->stream->id : 0, out->priority,
- out->blocked, out->size);
+ out->blocked, out->length);
}
cl = c->send_chain(c, cl, 0);
@@ -519,7 +525,9 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
}
}
- for ( /* void */ ; out; out = out->next) {
+ for ( /* void */ ; out; out = fn) {
+ fn = out->next;
+
if (out->handler(sc, out) != NGX_OK) {
out->blocked = 1;
out->priority = NGX_SPDY_HIGHEST_PRIORITY;
@@ -527,9 +535,9 @@ ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc)
}
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
- "spdy frame sent: %p sid:%ui bl:%ui size:%uz",
+ "spdy frame sent: %p sid:%ui bl:%d len:%uz",
out, out->stream ? out->stream->id : 0,
- out->blocked, out->size);
+ out->blocked, out->length);
}
frame = NULL;
@@ -569,7 +577,7 @@ ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc)
sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
ngx_http_spdy_module);
- if (sc->waiting) {
+ if (sc->incomplete) {
ngx_add_timer(c->read, sscf->recv_timeout);
return;
}
@@ -607,38 +615,6 @@ ngx_http_spdy_handle_connection(ngx_http_spdy_connection_t *sc)
static u_char *
-ngx_http_spdy_state_detect_settings(ngx_http_spdy_connection_t *sc,
- u_char *pos, u_char *end)
-{
- if (end - pos < NGX_SPDY_FRAME_HEADER_SIZE) {
- return ngx_http_spdy_state_save(sc, pos, end,
- ngx_http_spdy_state_detect_settings);
- }
-
- /*
- * Since this is the first frame in a buffer,
- * then it is properly aligned
- */
-
- if (*(uint32_t *) pos == htonl(ngx_spdy_ctl_frame_head(NGX_SPDY_SETTINGS)))
- {
- sc->length = ngx_spdy_frame_length(htonl(((uint32_t *) pos)[1]));
-
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy SETTINGS frame received, size: %uz", sc->length);
-
- pos += NGX_SPDY_FRAME_HEADER_SIZE;
-
- return ngx_http_spdy_state_settings(sc, pos, end);
- }
-
- ngx_http_spdy_send_settings(sc);
-
- return ngx_http_spdy_state_head(sc, pos, end);
-}
-
-
-static u_char *
ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
@@ -661,7 +637,7 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
pos += sizeof(uint32_t);
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy process frame head:%08Xd f:%ui l:%ui",
+ "spdy process frame head:%08XD f:%Xd l:%uz",
head, sc->flags, sc->length);
if (ngx_spdy_ctl_frame_check(head)) {
@@ -859,14 +835,15 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
ngx_http_spdy_state_headers);
}
- sc->headers = ngx_spdy_frame_parse_uint16(buf->pos);
+ sc->entries = ngx_spdy_frame_parse_uint16(buf->pos);
buf->pos += NGX_SPDY_NV_NUM_SIZE;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "spdy headers count: %ui", sc->headers);
+ "spdy HEADERS block consists of %ui entries",
+ sc->entries);
- if (ngx_list_init(&r->headers_in.headers, r->pool, sc->headers + 3,
+ if (ngx_list_init(&r->headers_in.headers, r->pool, sc->entries + 3,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
@@ -885,14 +862,14 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
}
}
- while (sc->headers) {
+ while (sc->entries) {
rc = ngx_http_spdy_parse_header(r);
switch (rc) {
case NGX_DONE:
- sc->headers--;
+ sc->entries--;
case NGX_OK:
break;
@@ -1250,7 +1227,6 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
ngx_uint_t sid, status;
ngx_event_t *ev;
ngx_connection_t *fc;
- ngx_http_request_t *r;
ngx_http_spdy_stream_t *stream;
if (end - pos < NGX_SPDY_RST_STREAM_SIZE) {
@@ -1259,7 +1235,10 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
}
if (sc->length != NGX_SPDY_RST_STREAM_SIZE) {
- /* TODO logging */
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent RST_STREAM frame with incorrect length %uz",
+ sc->length);
+
return ngx_http_spdy_state_protocol_error(sc);
}
@@ -1274,55 +1253,42 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
"spdy RST_STREAM sid:%ui st:%ui", sid, status);
+ stream = ngx_http_spdy_get_stream_by_id(sc, sid);
+ if (stream == NULL) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "unknown stream, probably it has been closed already");
+ return ngx_http_spdy_state_complete(sc, pos, end);
+ }
- switch (status) {
+ stream->in_closed = 1;
+ stream->out_closed = 1;
- case NGX_SPDY_PROTOCOL_ERROR:
- /* TODO logging */
- return ngx_http_spdy_state_protocol_error(sc);
+ fc = stream->request->connection;
+ fc->error = 1;
- case NGX_SPDY_INVALID_STREAM:
- /* TODO */
- break;
+ switch (status) {
- case NGX_SPDY_REFUSED_STREAM:
- /* TODO */
+ case NGX_SPDY_CANCEL:
+ ngx_log_error(NGX_LOG_INFO, fc->log, 0,
+ "client canceled stream %ui", sid);
break;
- case NGX_SPDY_UNSUPPORTED_VERSION:
- /* TODO logging */
- return ngx_http_spdy_state_protocol_error(sc);
-
- case NGX_SPDY_CANCEL:
case NGX_SPDY_INTERNAL_ERROR:
- stream = ngx_http_spdy_get_stream_by_id(sc, sid);
- if (stream == NULL) {
- /* TODO false cancel */
- break;
- }
-
- stream->in_closed = 1;
- stream->out_closed = 1;
-
- r = stream->request;
-
- fc = r->connection;
- fc->error = 1;
-
- ev = fc->read;
- ev->handler(ev);
-
+ ngx_log_error(NGX_LOG_INFO, fc->log, 0,
+ "client terminated stream %ui because of internal error",
+ sid);
break;
- case NGX_SPDY_FLOW_CONTROL_ERROR:
- /* TODO logging */
- return ngx_http_spdy_state_protocol_error(sc);
-
default:
- /* TODO */
- return ngx_http_spdy_state_protocol_error(sc);
+ ngx_log_error(NGX_LOG_INFO, fc->log, 0,
+ "client terminated stream %ui with status %ui",
+ sid, status);
+ break;
}
+ ev = fc->read;
+ ev->handler(ev);
+
return ngx_http_spdy_state_complete(sc, pos, end);
}
@@ -1391,66 +1357,51 @@ ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
}
+#if 0
+
static u_char *
ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
- ngx_uint_t v;
- ngx_http_spdy_srv_conf_t *sscf;
-
- if (sc->headers == 0) {
+ if (sc->entries == 0) {
if (end - pos < NGX_SPDY_SETTINGS_NUM_SIZE) {
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_settings);
}
- sc->headers = ngx_spdy_frame_parse_uint32(pos);
+ sc->entries = ngx_spdy_frame_parse_uint32(pos);
pos += NGX_SPDY_SETTINGS_NUM_SIZE;
sc->length -= NGX_SPDY_SETTINGS_NUM_SIZE;
- if (sc->length < sc->headers * NGX_SPDY_SETTINGS_PAIR_SIZE) {
+ if (sc->length < sc->entries * NGX_SPDY_SETTINGS_PAIR_SIZE) {
/* TODO logging */
return ngx_http_spdy_state_protocol_error(sc);
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
"spdy SETTINGS frame consists of %ui entries",
- sc->headers);
+ sc->entries);
}
- while (sc->headers) {
+ while (sc->entries) {
if (end - pos < NGX_SPDY_SETTINGS_PAIR_SIZE) {
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_settings);
}
- sc->headers--;
-
- if (pos[0] != NGX_SPDY_SETTINGS_MAX_STREAMS) {
- pos += NGX_SPDY_SETTINGS_PAIR_SIZE;
- sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE;
- continue;
- }
-
- v = ngx_spdy_frame_parse_uint32(pos + NGX_SPDY_SETTINGS_IDF_SIZE);
-
- sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
- ngx_http_spdy_module);
-
- if (v != sscf->concurrent_streams) {
- ngx_http_spdy_send_settings(sc);
- }
+ sc->entries--;
- return ngx_http_spdy_state_skip(sc, pos, end);
+ pos += NGX_SPDY_SETTINGS_PAIR_SIZE;
+ sc->length -= NGX_SPDY_SETTINGS_PAIR_SIZE;
}
- ngx_http_spdy_send_settings(sc);
-
return ngx_http_spdy_state_complete(sc, pos, end);
}
+#endif
+
static u_char *
ngx_http_spdy_state_noop(ngx_http_spdy_connection_t *sc, u_char *pos,
@@ -1482,7 +1433,7 @@ ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
if (end - pos > NGX_SPDY_STATE_BUFFER_SIZE) {
ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
"spdy state buffer overflow: "
- "%i bytes required", end - pos);
+ "%z bytes required", end - pos);
return ngx_http_spdy_state_internal_error(sc);
}
#endif
@@ -1491,7 +1442,7 @@ ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
sc->buffer_used = end - pos;
sc->handler = handler;
- sc->waiting = 1;
+ sc->incomplete = 1;
return end;
}
@@ -1600,7 +1551,6 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
{
u_char *p;
ngx_buf_t *buf;
- ngx_pool_t *pool;
ngx_chain_t *cl;
ngx_http_spdy_srv_conf_t *sscf;
ngx_http_spdy_out_frame_t *frame;
@@ -1608,21 +1558,19 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
"spdy create SETTINGS frame");
- pool = sc->connection->pool;
-
- frame = ngx_palloc(pool, sizeof(ngx_http_spdy_out_frame_t));
+ frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t));
if (frame == NULL) {
return NGX_ERROR;
}
- cl = ngx_alloc_chain_link(pool);
+ cl = ngx_alloc_chain_link(sc->pool);
if (cl == NULL) {
return NGX_ERROR;
}
- buf = ngx_create_temp_buf(pool, NGX_SPDY_FRAME_HEADER_SIZE
- + NGX_SPDY_SETTINGS_NUM_SIZE
- + NGX_SPDY_SETTINGS_PAIR_SIZE);
+ buf = ngx_create_temp_buf(sc->pool, NGX_SPDY_FRAME_HEADER_SIZE
+ + NGX_SPDY_SETTINGS_NUM_SIZE
+ + NGX_SPDY_SETTINGS_PAIR_SIZE);
if (buf == NULL) {
return NGX_ERROR;
}
@@ -1635,11 +1583,9 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
frame->first = cl;
frame->last = cl;
frame->handler = ngx_http_spdy_settings_frame_handler;
-#if (NGX_DEBUG)
frame->stream = NULL;
- frame->size = NGX_SPDY_FRAME_HEADER_SIZE
- + NGX_SPDY_SETTINGS_NUM_SIZE
- + NGX_SPDY_SETTINGS_PAIR_SIZE;
+#if (NGX_DEBUG)
+ frame->length = NGX_SPDY_SETTINGS_NUM_SIZE + NGX_SPDY_SETTINGS_PAIR_SIZE;
#endif
frame->priority = NGX_SPDY_HIGHEST_PRIORITY;
frame->blocked = 0;
@@ -1653,8 +1599,7 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
p = ngx_spdy_frame_aligned_write_uint32(p, 1);
p = ngx_spdy_frame_aligned_write_uint32(p,
- NGX_SPDY_SETTINGS_MAX_STREAMS << 24
- | NGX_SPDY_SETTINGS_FLAG_PERSIST);
+ NGX_SPDY_SETTINGS_MAX_STREAMS << 24);
sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
ngx_http_spdy_module);
@@ -1688,7 +1633,7 @@ ngx_http_spdy_settings_frame_handler(ngx_http_spdy_connection_t *sc,
static ngx_http_spdy_out_frame_t *
-ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size,
+ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t length,
ngx_uint_t priority)
{
ngx_chain_t *cl;
@@ -1697,7 +1642,7 @@ ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size,
frame = sc->free_ctl_frames;
if (frame) {
- sc->free_ctl_frames = frame->free;
+ sc->free_ctl_frames = frame->next;
cl = frame->first;
cl->buf->pos = cl->buf->start;
@@ -1724,19 +1669,17 @@ ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t size,
frame->first = cl;
frame->last = cl;
frame->handler = ngx_http_spdy_ctl_frame_handler;
+ frame->stream = NULL;
}
- frame->free = NULL;
-
#if (NGX_DEBUG)
- if (size > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) {
+ if (length > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) {
ngx_log_error(NGX_LOG_ALERT, sc->pool->log, 0,
- "requested control frame is too big: %z", size);
+ "requested control frame is too big: %uz", length);
return NULL;
}
- frame->stream = NULL;
- frame->size = size;
+ frame->length = length;
#endif
frame->priority = priority;
@@ -1758,7 +1701,7 @@ ngx_http_spdy_ctl_frame_handler(ngx_http_spdy_connection_t *sc,
return NGX_AGAIN;
}
- frame->free = sc->free_ctl_frames;
+ frame->next = sc->free_ctl_frames;
sc->free_ctl_frames = frame;
return NGX_OK;
@@ -2106,7 +2049,7 @@ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r)
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "spdy large header alloc: %p %uz",
+ "spdy large header alloc: %p %z",
buf->pos, buf->end - buf->last);
old = r->header_in->pos;
@@ -2644,9 +2587,21 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
sc = stream->connection;
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy close stream %ui, processing %ui",
- stream->id, sc->processing);
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy close stream %ui, queued %ui, processing %ui",
+ stream->id, stream->queued, sc->processing);
+
+ if (stream->handled) {
+ stream->handled = 0;
+ ngx_queue_remove(&stream->queue);
+ }
+
+ fc = stream->request->connection;
+
+ if (stream->queued) {
+ fc->write->handler = ngx_http_spdy_close_stream_handler;
+ return;
+ }
if (!stream->out_closed) {
if (ngx_http_spdy_send_rst_stream(sc, stream->id,
@@ -2658,6 +2613,10 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
}
}
+ if (sc->stream == stream) {
+ sc->stream = NULL;
+ }
+
sscf = ngx_http_get_module_srv_conf(sc->http_connection->conf_ctx,
ngx_http_spdy_module);
@@ -2678,8 +2637,6 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
index = &s->index;
}
- fc = stream->request->connection;
-
ngx_http_free_request(stream->request, rc);
ev = fc->read;
@@ -2847,14 +2804,15 @@ ngx_http_spdy_finalize_connection(ngx_http_spdy_connection_t *sc,
stream = sc->streams_index[i];
while (stream) {
- r = stream->request;
+ stream->handled = 0;
+ r = stream->request;
fc = r->connection;
+
fc->error = 1;
- if (stream->waiting) {
- r->blocked -= stream->waiting;
- stream->waiting = 0;
+ if (stream->queued) {
+ stream->queued = 0;
ev = fc->write;
ev->delayed = 0;
diff --git a/src/http/ngx_http_spdy.h b/src/http/ngx_http_spdy.h
index c47243fb0..8caa5b0c4 100644
--- a/src/http/ngx_http_spdy.h
+++ b/src/http/ngx_http_spdy.h
@@ -96,18 +96,19 @@ struct ngx_http_spdy_connection_s {
ngx_http_spdy_stream_t **streams_index;
ngx_http_spdy_out_frame_t *last_out;
- ngx_http_spdy_stream_t *last_stream;
+
+ ngx_queue_t posted;
ngx_http_spdy_stream_t *stream;
- ngx_uint_t headers;
+ ngx_uint_t entries;
size_t length;
u_char flags;
ngx_uint_t last_sid;
- unsigned blocked:2;
- unsigned waiting:1; /* FIXME better name */
+ unsigned blocked:1;
+ unsigned incomplete:1;
};
@@ -116,15 +117,19 @@ struct ngx_http_spdy_stream_s {
ngx_http_request_t *request;
ngx_http_spdy_connection_t *connection;
ngx_http_spdy_stream_t *index;
- ngx_http_spdy_stream_t *next;
ngx_uint_t header_buffers;
- ngx_uint_t waiting;
+ ngx_uint_t queued;
+
ngx_http_spdy_out_frame_t *free_frames;
ngx_chain_t *free_data_headers;
+ ngx_chain_t *free_bufs;
+
+ ngx_queue_t queue;
unsigned priority:2;
unsigned handled:1;
+ unsigned blocked:1;
unsigned in_closed:1;
unsigned out_closed:1;
unsigned skip_data:2;
@@ -138,10 +143,8 @@ struct ngx_http_spdy_out_frame_s {
ngx_int_t (*handler)(ngx_http_spdy_connection_t *sc,
ngx_http_spdy_out_frame_t *frame);
- ngx_http_spdy_out_frame_t *free;
-
ngx_http_spdy_stream_t *stream;
- size_t size;
+ size_t length;
ngx_uint_t priority;
unsigned blocked:1;
diff --git a/src/http/ngx_http_spdy_filter_module.c b/src/http/ngx_http_spdy_filter_module.c
index 805177651..0ec9028ce 100644
--- a/src/http/ngx_http_spdy_filter_module.c
+++ b/src/http/ngx_http_spdy_filter_module.c
@@ -14,8 +14,6 @@
#include <zlib.h>
-#define NGX_SPDY_WRITE_BUFFERED NGX_HTTP_WRITE_BUFFERED
-
#define ngx_http_spdy_nv_nsize(h) (NGX_SPDY_NV_NLEN_SIZE + sizeof(h) - 1)
#define ngx_http_spdy_nv_vsize(h) (NGX_SPDY_NV_VLEN_SIZE + sizeof(h) - 1)
@@ -29,12 +27,18 @@
#define ngx_http_spdy_nv_write_val(p, h) \
ngx_cpymem(ngx_http_spdy_nv_write_vlen(p, sizeof(h) - 1), h, sizeof(h) - 1)
+
+static ngx_chain_t *ngx_http_spdy_send_chain(ngx_connection_t *fc,
+ ngx_chain_t *in, off_t limit);
+
static ngx_inline ngx_int_t ngx_http_spdy_filter_send(
ngx_connection_t *fc, ngx_http_spdy_stream_t *stream);
+static ngx_chain_t *ngx_http_spdy_filter_get_shadow(
+ ngx_http_spdy_stream_t *stream, ngx_buf_t *buf, off_t offset, off_t size);
static ngx_http_spdy_out_frame_t *ngx_http_spdy_filter_get_data_frame(
- ngx_http_spdy_stream_t *stream, size_t len, ngx_uint_t flags,
- ngx_chain_t *first, ngx_chain_t *last);
+ ngx_http_spdy_stream_t *stream, size_t len, ngx_chain_t *first,
+ ngx_chain_t *last);
static ngx_int_t ngx_http_spdy_syn_frame_handler(
ngx_http_spdy_connection_t *sc, ngx_http_spdy_out_frame_t *frame);
@@ -82,7 +86,6 @@ ngx_module_t ngx_http_spdy_filter_module = {
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
-static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
@@ -557,13 +560,14 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
r->header_size = len;
+ len -= NGX_SPDY_FRAME_HEADER_SIZE;
+
if (r->header_only) {
b->last_buf = 1;
- p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_FIN,
- len - NGX_SPDY_FRAME_HEADER_SIZE);
+ p = ngx_spdy_frame_write_flags_and_len(p, NGX_SPDY_FLAG_FIN, len);
+
} else {
- p = ngx_spdy_frame_write_flags_and_len(p, 0,
- len - NGX_SPDY_FRAME_HEADER_SIZE);
+ p = ngx_spdy_frame_write_flags_and_len(p, 0, len);
}
(void) ngx_spdy_frame_write_sid(p, stream->id);
@@ -584,21 +588,18 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
frame->first = cl;
frame->last = cl;
frame->handler = ngx_http_spdy_syn_frame_handler;
- frame->free = NULL;
frame->stream = stream;
- frame->size = len;
+ frame->length = len;
frame->priority = stream->priority;
frame->blocked = 1;
frame->fin = r->header_only;
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0,
- "spdy:%ui create SYN_REPLY frame %p: size:%uz",
- stream->id, frame, frame->size);
+ "spdy:%ui create SYN_REPLY frame %p: len:%uz",
+ stream->id, frame, frame->length);
ngx_http_spdy_queue_blocked_frame(sc, frame);
- r->blocked++;
-
cln = ngx_http_cleanup_add(r, 0);
if (cln == NULL) {
return NGX_ERROR;
@@ -607,109 +608,208 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
cln->handler = ngx_http_spdy_filter_cleanup;
cln->data = stream;
- stream->waiting = 1;
+ stream->queued = 1;
+
+ c->send_chain = ngx_http_spdy_send_chain;
+ c->need_last_buf = 1;
return ngx_http_spdy_filter_send(c, stream);
}
-static ngx_int_t
-ngx_http_spdy_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
+static ngx_chain_t *
+ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
{
- off_t size;
- ngx_buf_t *b;
- ngx_chain_t *cl, *ll, *out, **ln;
+ off_t size, offset;
+ size_t rest, frame_size;
+ ngx_chain_t *cl, *out, **ln;
+ ngx_http_request_t *r;
ngx_http_spdy_stream_t *stream;
+ ngx_http_spdy_loc_conf_t *slcf;
ngx_http_spdy_out_frame_t *frame;
+ r = fc->data;
stream = r->spdy_stream;
- if (stream == NULL) {
- return ngx_http_next_body_filter(r, in);
- }
+ if (in == NULL) {
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "spdy body filter \"%V?%V\"", &r->uri, &r->args);
+ if (stream->queued) {
+ fc->write->delayed = 1;
+ } else {
+ fc->buffered &= ~NGX_SPDY_BUFFERED;
+ }
- if (in == NULL || r->header_only) {
+ return NULL;
+ }
- if (stream->waiting) {
- return NGX_AGAIN;
+ size = ngx_buf_size(in->buf);
+
+ if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) {
+ cl = ngx_alloc_chain_link(r->pool);
+ if (cl == NULL) {
+ return NGX_CHAIN_ERROR;
}
- r->connection->buffered &= ~NGX_SPDY_WRITE_BUFFERED;
+ cl->buf = in->buf;
+ in->buf = cl->buf->shadow;
- return NGX_OK;
+ offset = ngx_buf_in_memory(in->buf)
+ ? (cl->buf->pos - in->buf->pos)
+ : (cl->buf->file_pos - in->buf->file_pos);
+
+ cl->next = stream->free_bufs;
+ stream->free_bufs = cl;
+
+ } else {
+ offset = 0;
}
- size = 0;
- ln = &out;
- ll = in;
+#if (NGX_SUPPRESS_WARN)
+ cl = NULL;
+#endif
+
+ slcf = ngx_http_get_module_loc_conf(r, ngx_http_spdy_module);
+
+ frame_size = (limit && limit <= (off_t) slcf->chunk_size)
+ ? (size_t) limit
+ : slcf->chunk_size;
for ( ;; ) {
- b = ll->buf;
-#if 1
- if (ngx_buf_size(b) == 0 && !ngx_buf_special(b)) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "zero size buf in spdy body filter "
- "t:%d r:%d f:%d %p %p-%p %p %O-%O",
- b->temporary,
- b->recycled,
- b->in_file,
- b->start,
- b->pos,
- b->last,
- b->file,
- b->file_pos,
- b->file_last);
-
- ngx_debug_point();
- return NGX_ERROR;
+ ln = &out;
+ rest = frame_size;
+
+ while ((off_t) rest >= size) {
+
+ if (offset) {
+ cl = ngx_http_spdy_filter_get_shadow(stream, in->buf,
+ offset, size);
+ if (cl == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ offset = 0;
+
+ } else {
+ cl = ngx_alloc_chain_link(r->pool);
+ if (cl == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ cl->buf = in->buf;
+ }
+
+ *ln = cl;
+ ln = &cl->next;
+
+ rest -= (size_t) size;
+ in = in->next;
+
+ if (in == NULL) {
+ frame_size -= rest;
+ rest = 0;
+ break;
+ }
+
+ size = ngx_buf_size(in->buf);
}
-#endif
- cl = ngx_alloc_chain_link(r->pool);
- if (cl == NULL) {
- return NGX_ERROR;
+
+ if (rest) {
+ cl = ngx_http_spdy_filter_get_shadow(stream, in->buf,
+ offset, rest);
+ if (cl == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ cl->buf->flush = 0;
+ cl->buf->last_buf = 0;
+
+ *ln = cl;
+
+ offset += rest;
+ size -= rest;
+ }
+
+ frame = ngx_http_spdy_filter_get_data_frame(stream, frame_size,
+ out, cl);
+ if (frame == NULL) {
+ return NGX_CHAIN_ERROR;
}
- size += ngx_buf_size(b);
- cl->buf = b;
+ ngx_http_spdy_queue_frame(stream->connection, frame);
- *ln = cl;
- ln = &cl->next;
+ stream->queued++;
- if (ll->next == NULL) {
+ if (in == NULL) {
break;
}
- ll = ll->next;
+ if (limit) {
+ limit -= frame_size;
+
+ if (limit == 0) {
+ break;
+ }
+
+ if (limit < (off_t) slcf->chunk_size) {
+ frame_size = (size_t) limit;
+ }
+ }
}
- if (size > NGX_SPDY_MAX_FRAME_SIZE) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "FIXME: chain too big in spdy filter: %O", size);
- return NGX_ERROR;
+ if (offset) {
+ cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, offset, size);
+ if (cl == NULL) {
+ return NGX_CHAIN_ERROR;
+ }
+
+ in->buf = cl->buf;
+ ngx_free_chain(r->pool, cl);
}
- frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t) size,
- b->last_buf, out, cl);
- if (frame == NULL) {
- return NGX_ERROR;
+ if (ngx_http_spdy_filter_send(fc, stream) == NGX_ERROR) {
+ return NGX_CHAIN_ERROR;
}
- ngx_http_spdy_queue_frame(stream->connection, frame);
+ return in;
+}
+
+
+static ngx_chain_t *
+ngx_http_spdy_filter_get_shadow(ngx_http_spdy_stream_t *stream, ngx_buf_t *buf,
+ off_t offset, off_t size)
+{
+ ngx_buf_t *chunk;
+ ngx_chain_t *cl;
+
+ cl = ngx_chain_get_free_buf(stream->request->pool, &stream->free_bufs);
+ if (cl == NULL) {
+ return NULL;
+ }
+
+ chunk = cl->buf;
+
+ ngx_memcpy(chunk, buf, sizeof(ngx_buf_t));
- stream->waiting++;
+ chunk->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow;
+ chunk->shadow = buf;
- r->main->blocked++;
+ if (ngx_buf_in_memory(chunk)) {
+ chunk->pos += offset;
+ chunk->last = chunk->pos + size;
+ }
+
+ if (chunk->in_file) {
+ chunk->file_pos += offset;
+ chunk->file_last = chunk->file_pos + size;
+ }
- return ngx_http_spdy_filter_send(r->connection, stream);
+ return cl;
}
static ngx_http_spdy_out_frame_t *
ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
- size_t len, ngx_uint_t fin, ngx_chain_t *first, ngx_chain_t *last)
+ size_t len, ngx_chain_t *first, ngx_chain_t *last)
{
u_char *p;
ngx_buf_t *buf;
@@ -721,7 +821,7 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
frame = stream->free_frames;
if (frame) {
- stream->free_frames = frame->free;
+ stream->free_frames = frame->next;
} else {
frame = ngx_palloc(stream->request->pool,
@@ -731,13 +831,13 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
}
}
- ngx_log_debug4(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0,
- "spdy:%ui create DATA frame %p: len:%uz fin:%ui",
- stream->id, frame, len, fin);
+ flags = last->buf->last_buf ? NGX_SPDY_FLAG_FIN : 0;
- if (len || fin) {
+ ngx_log_debug4(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0,
+ "spdy:%ui create DATA frame %p: len:%uz flags:%ui",
+ stream->id, frame, len, flags);
- flags = fin ? NGX_SPDY_FLAG_FIN : 0;
+ if (len || flags) {
cl = ngx_chain_get_free_buf(stream->request->pool,
&stream->free_data_headers);
@@ -751,7 +851,7 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
p = buf->start;
buf->pos = p;
- p += sizeof(uint32_t);
+ p += NGX_SPDY_SID_SIZE;
(void) ngx_spdy_frame_write_flags_and_len(p, flags, len);
@@ -770,7 +870,7 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
buf->last = p;
buf->end = p;
- buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_module;
+ buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame;
buf->memory = 1;
}
@@ -781,12 +881,11 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
frame->first = first;
frame->last = last;
frame->handler = ngx_http_spdy_data_frame_handler;
- frame->free = NULL;
frame->stream = stream;
- frame->size = NGX_SPDY_FRAME_HEADER_SIZE + len;
+ frame->length = len;
frame->priority = stream->priority;
frame->blocked = 0;
- frame->fin = fin;
+ frame->fin = last->buf->last_buf;
return frame;
}
@@ -795,18 +894,22 @@ ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
static ngx_inline ngx_int_t
ngx_http_spdy_filter_send(ngx_connection_t *fc, ngx_http_spdy_stream_t *stream)
{
+ stream->blocked = 1;
+
if (ngx_http_spdy_send_output_queue(stream->connection) == NGX_ERROR) {
fc->error = 1;
return NGX_ERROR;
}
- if (stream->waiting) {
- fc->buffered |= NGX_SPDY_WRITE_BUFFERED;
+ stream->blocked = 0;
+
+ if (stream->queued) {
+ fc->buffered |= NGX_SPDY_BUFFERED;
fc->write->delayed = 1;
return NGX_AGAIN;
}
- fc->buffered &= ~NGX_SPDY_WRITE_BUFFERED;
+ fc->buffered &= ~NGX_SPDY_BUFFERED;
return NGX_OK;
}
@@ -844,6 +947,7 @@ static ngx_int_t
ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
ngx_http_spdy_out_frame_t *frame)
{
+ ngx_buf_t *buf;
ngx_chain_t *cl, *ln;
ngx_http_spdy_stream_t *stream;
@@ -851,7 +955,7 @@ ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
cl = frame->first;
- if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_module) {
+ if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame) {
if (cl->buf->pos != cl->buf->last) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
@@ -874,6 +978,18 @@ ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
}
for ( ;; ) {
+ if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) {
+ buf = cl->buf->shadow;
+
+ if (ngx_buf_in_memory(buf)) {
+ buf->pos = cl->buf->pos;
+ }
+
+ if (buf->in_file) {
+ buf->file_pos = cl->buf->file_pos;
+ }
+ }
+
if (ngx_buf_size(cl->buf) != 0) {
if (cl != frame->first) {
@@ -890,7 +1006,13 @@ ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
ln = cl->next;
- ngx_free_chain(stream->request->pool, cl);
+ if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) {
+ cl->next = stream->free_bufs;
+ stream->free_bufs = cl;
+
+ } else {
+ ngx_free_chain(stream->request->pool, cl);
+ }
if (cl == frame->last) {
goto done;
@@ -922,17 +1044,16 @@ ngx_http_spdy_handle_frame(ngx_http_spdy_stream_t *stream,
r = stream->request;
- r->connection->sent += frame->size;
- r->blocked--;
+ r->connection->sent += NGX_SPDY_FRAME_HEADER_SIZE + frame->length;
if (frame->fin) {
stream->out_closed = 1;
}
- frame->free = stream->free_frames;
+ frame->next = stream->free_frames;
stream->free_frames = frame;
- stream->waiting--;
+ stream->queued--;
}
@@ -940,21 +1061,19 @@ static ngx_inline void
ngx_http_spdy_handle_stream(ngx_http_spdy_connection_t *sc,
ngx_http_spdy_stream_t *stream)
{
- ngx_connection_t *fc;
-
- fc = stream->request->connection;
+ ngx_event_t *wev;
- fc->write->delayed = 0;
-
- if (stream->handled) {
+ if (stream->handled || stream->blocked) {
return;
}
- if (sc->blocked == 2) {
- stream->handled = 1;
+ wev = stream->request->connection->write;
+
+ if (!wev->timer_set) {
+ wev->delayed = 0;
- stream->next = sc->last_stream;
- sc->last_stream = stream;
+ stream->handled = 1;
+ ngx_queue_insert_tail(&sc->posted, &stream->queue);
}
}
@@ -964,15 +1083,12 @@ ngx_http_spdy_filter_cleanup(void *data)
{
ngx_http_spdy_stream_t *stream = data;
- ngx_http_request_t *r;
ngx_http_spdy_out_frame_t *frame, **fn;
- if (stream->waiting == 0) {
+ if (stream->queued == 0) {
return;
}
- r = stream->request;
-
fn = &stream->connection->last_out;
for ( ;; ) {
@@ -983,9 +1099,7 @@ ngx_http_spdy_filter_cleanup(void *data)
}
if (frame->stream == stream && !frame->blocked) {
-
- stream->waiting--;
- r->blocked--;
+ stream->queued--;
*fn = frame->next;
continue;
@@ -1002,8 +1116,5 @@ ngx_http_spdy_filter_init(ngx_conf_t *cf)
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_spdy_header_filter;
- ngx_http_next_body_filter = ngx_http_top_body_filter;
- ngx_http_top_body_filter = ngx_http_spdy_body_filter;
-
return NGX_OK;
}
diff --git a/src/http/ngx_http_spdy_module.c b/src/http/ngx_http_spdy_module.c
index 7f02a18ca..c706e3fe6 100644
--- a/src/http/ngx_http_spdy_module.c
+++ b/src/http/ngx_http_spdy_module.c
@@ -22,16 +22,19 @@ static ngx_int_t ngx_http_spdy_module_init(ngx_cycle_t *cycle);
static void *ngx_http_spdy_create_main_conf(ngx_conf_t *cf);
static char *ngx_http_spdy_init_main_conf(ngx_conf_t *cf, void *conf);
-
static void *ngx_http_spdy_create_srv_conf(ngx_conf_t *cf);
static char *ngx_http_spdy_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child);
+static void *ngx_http_spdy_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_spdy_merge_loc_conf(ngx_conf_t *cf, void *parent,
+ void *child);
static char *ngx_http_spdy_recv_buffer_size(ngx_conf_t *cf, void *post,
void *data);
static char *ngx_http_spdy_pool_size(ngx_conf_t *cf, void *post, void *data);
static char *ngx_http_spdy_streams_index_mask(ngx_conf_t *cf, void *post,
void *data);
+static char *ngx_http_spdy_chunk_size(ngx_conf_t *cf, void *post, void *data);
static ngx_conf_num_bounds_t ngx_http_spdy_headers_comp_bounds = {
@@ -44,6 +47,8 @@ static ngx_conf_post_t ngx_http_spdy_pool_size_post =
{ ngx_http_spdy_pool_size };
static ngx_conf_post_t ngx_http_spdy_streams_index_mask_post =
{ ngx_http_spdy_streams_index_mask };
+static ngx_conf_post_t ngx_http_spdy_chunk_size_post =
+ { ngx_http_spdy_chunk_size };
static ngx_command_t ngx_http_spdy_commands[] = {
@@ -97,6 +102,13 @@ static ngx_command_t ngx_http_spdy_commands[] = {
offsetof(ngx_http_spdy_srv_conf_t, headers_comp),
&ngx_http_spdy_headers_comp_bounds },
+ { ngx_string("spdy_chunk_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_spdy_loc_conf_t, chunk_size),
+ &ngx_http_spdy_chunk_size_post },
+
ngx_null_command
};
@@ -111,8 +123,8 @@ static ngx_http_module_t ngx_http_spdy_module_ctx = {
ngx_http_spdy_create_srv_conf, /* create server configuration */
ngx_http_spdy_merge_srv_conf, /* merge server configuration */
- NULL, /* create location configuration */
- NULL /* merge location configuration */
+ ngx_http_spdy_create_loc_conf, /* create location configuration */
+ ngx_http_spdy_merge_loc_conf /* merge location configuration */
};
@@ -296,6 +308,34 @@ ngx_http_spdy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
}
+static void *
+ngx_http_spdy_create_loc_conf(ngx_conf_t *cf)
+{
+ ngx_http_spdy_loc_conf_t *slcf;
+
+ slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_spdy_loc_conf_t));
+ if (slcf == NULL) {
+ return NULL;
+ }
+
+ slcf->chunk_size = NGX_CONF_UNSET_SIZE;
+
+ return slcf;
+}
+
+
+static char *
+ngx_http_spdy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+ ngx_http_spdy_loc_conf_t *prev = parent;
+ ngx_http_spdy_loc_conf_t *conf = child;
+
+ ngx_conf_merge_size_value(conf->chunk_size, prev->chunk_size, 8 * 1024);
+
+ return NGX_CONF_OK;
+}
+
+
static char *
ngx_http_spdy_recv_buffer_size(ngx_conf_t *cf, void *post, void *data)
{
@@ -349,3 +389,22 @@ ngx_http_spdy_streams_index_mask(ngx_conf_t *cf, void *post, void *data)
return NGX_CONF_OK;
}
+
+
+static char *
+ngx_http_spdy_chunk_size(ngx_conf_t *cf, void *post, void *data)
+{
+ size_t *sp = data;
+
+ if (*sp == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the spdy chunk size cannot be zero");
+ return NGX_CONF_ERROR;
+ }
+
+ if (*sp > NGX_SPDY_MAX_FRAME_SIZE) {
+ *sp = NGX_SPDY_MAX_FRAME_SIZE;
+ }
+
+ return NGX_CONF_OK;
+}
diff --git a/src/http/ngx_http_spdy_module.h b/src/http/ngx_http_spdy_module.h
index 97a7a13a6..5242322b3 100644
--- a/src/http/ngx_http_spdy_module.h
+++ b/src/http/ngx_http_spdy_module.h
@@ -30,6 +30,11 @@ typedef struct {
} ngx_http_spdy_srv_conf_t;
+typedef struct {
+ size_t chunk_size;
+} ngx_http_spdy_loc_conf_t;
+
+
extern ngx_module_t ngx_http_spdy_module;
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 8bf0ba218..0524144f2 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1994,7 +1994,7 @@ ngx_http_upstream_test_connect(ngx_connection_t *c)
static ngx_int_t
ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
- ngx_str_t *uri, args;
+ ngx_str_t uri, args;
ngx_uint_t i, flags;
ngx_list_part_t *part;
ngx_table_elt_t *h;
@@ -2035,11 +2035,11 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
}
}
- uri = &u->headers_in.x_accel_redirect->value;
+ uri = u->headers_in.x_accel_redirect->value;
ngx_str_null(&args);
flags = NGX_HTTP_LOG_UNSAFE;
- if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
+ if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
return NGX_DONE;
}
@@ -2048,7 +2048,7 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
r->method = NGX_HTTP_GET;
}
- ngx_http_internal_redirect(r, uri, &args);
+ ngx_http_internal_redirect(r, &uri, &args);
ngx_http_finalize_request(r, NGX_DONE);
return NGX_DONE;
}
@@ -2560,11 +2560,7 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u)
ngx_http_upstream_process_upgraded(r, 1, 1);
}
- if (c->read->ready
- || r->header_in->pos != r->header_in->last)
- {
- ngx_http_upstream_process_upgraded(r, 0, 1);
- }
+ ngx_http_upstream_process_upgraded(r, 0, 1);
}
@@ -3656,7 +3652,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
return NGX_OK;
}
- if (r->cache->valid_sec != 0) {
+ if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
return NGX_OK;
}
diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c
index f74dbc8ab..83cb1fa1e 100644
--- a/src/http/ngx_http_write_filter_module.c
+++ b/src/http/ngx_http_write_filter_module.c
@@ -184,7 +184,10 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
return NGX_AGAIN;
}
- if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED)) {
+ if (size == 0
+ && !(c->buffered & NGX_LOWLEVEL_BUFFERED)
+ && !(last && c->need_last_buf))
+ {
if (last || flush) {
for (cl = r->out; cl; /* void */) {
ln = cl;
diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c
index 02222c122..41cbcf6e3 100644
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -542,17 +542,40 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev)
CRLF) - 1
+ s->connection->addr_text.len + s->login.len + s->host.len;
+#if (NGX_HAVE_INET6)
+ if (s->connection->sockaddr->sa_family == AF_INET6) {
+ line.len += sizeof("IPV6:") - 1;
+ }
+#endif
+
line.data = ngx_pnalloc(c->pool, line.len);
if (line.data == NULL) {
ngx_mail_proxy_internal_server_error(s);
return;
}
- line.len = ngx_sprintf(line.data,
- "XCLIENT ADDR=%V%s%V NAME=%V" CRLF,
- &s->connection->addr_text,
- (s->login.len ? " LOGIN=" : ""), &s->login, &s->host)
- - line.data;
+ p = ngx_cpymem(line.data, "XCLIENT ADDR=", sizeof("XCLIENT ADDR=") - 1);
+
+#if (NGX_HAVE_INET6)
+ if (s->connection->sockaddr->sa_family == AF_INET6) {
+ p = ngx_cpymem(p, "IPV6:", sizeof("IPV6:") - 1);
+ }
+#endif
+
+ p = ngx_copy(p, s->connection->addr_text.data,
+ s->connection->addr_text.len);
+
+ if (s->login.len) {
+ p = ngx_cpymem(p, " LOGIN=", sizeof(" LOGIN=") - 1);
+ p = ngx_copy(p, s->login.data, s->login.len);
+ }
+
+ p = ngx_cpymem(p, " NAME=", sizeof(" NAME=") - 1);
+ p = ngx_copy(p, s->host.data, s->host.len);
+
+ *p++ = CR; *p++ = LF;
+
+ line.len = p - line.data;
if (s->smtp_helo.len) {
s->mail_state = ngx_smtp_xclient_helo;
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index 94c015700..fe88f48e4 100644
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -116,6 +116,13 @@ static ngx_command_t ngx_mail_ssl_commands[] = {
0,
NULL },
+ { ngx_string("ssl_session_tickets"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, session_tickets),
+ NULL },
+
{ ngx_string("ssl_session_ticket_key"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_array_slot,
@@ -191,6 +198,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
scf->prefer_server_ciphers = NGX_CONF_UNSET;
scf->builtin_session_cache = NGX_CONF_UNSET;
scf->session_timeout = NGX_CONF_UNSET;
+ scf->session_tickets = NGX_CONF_UNSET;
scf->session_ticket_keys = NGX_CONF_UNSET_PTR;
return scf;
@@ -339,6 +347,15 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
+ ngx_conf_merge_value(conf->session_tickets,
+ prev->session_tickets, 1);
+
+#ifdef SSL_OP_NO_TICKET
+ if (!conf->session_tickets) {
+ SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_NO_TICKET);
+ }
+#endif
+
ngx_conf_merge_ptr_value(conf->session_ticket_keys,
prev->session_ticket_keys, NULL);
diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h
index 54e057721..bef0e515a 100644
--- a/src/mail/ngx_mail_ssl_module.h
+++ b/src/mail/ngx_mail_ssl_module.h
@@ -41,6 +41,7 @@ typedef struct {
ngx_shm_zone_t *shm_zone;
+ ngx_flag_t session_tickets;
ngx_array_t *session_ticket_keys;
u_char *file;
diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
index 9d23a73d0..499039a7e 100644
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -959,6 +959,8 @@ ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
"sigprocmask() failed");
}
+ srandom((ngx_pid << 16) ^ ngx_time());
+
/*
* disable deleting previous events for the listening sockets because
* in the worker processes there are no events at all at this point