summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES41
-rw-r--r--CHANGES.ru43
-rw-r--r--auto/lib/libatomic/make4
-rw-r--r--auto/lib/openssl/make2
-rw-r--r--src/core/nginx.h4
-rw-r--r--src/core/ngx_connection.c12
-rw-r--r--src/core/ngx_cycle.c10
-rw-r--r--src/event/ngx_event.c1
-rw-r--r--src/event/ngx_event_openssl.c235
-rw-r--r--src/event/ngx_event_openssl.h13
-rw-r--r--src/http/modules/ngx_http_auth_basic_module.c2
-rw-r--r--src/http/modules/ngx_http_dav_module.c2
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c14
-rw-r--r--src/http/modules/ngx_http_gunzip_filter_module.c14
-rw-r--r--src/http/modules/ngx_http_gzip_filter_module.c2
-rw-r--r--src/http/modules/ngx_http_headers_filter_module.c4
-rw-r--r--src/http/modules/ngx_http_limit_req_module.c2
-rw-r--r--src/http/modules/ngx_http_proxy_module.c14
-rw-r--r--src/http/modules/ngx_http_scgi_module.c14
-rw-r--r--src/http/modules/ngx_http_ssl_module.c17
-rw-r--r--src/http/modules/ngx_http_ssl_module.h2
-rw-r--r--src/http/modules/ngx_http_uwsgi_module.c14
-rw-r--r--src/http/ngx_http_cache.h6
-rw-r--r--src/http/ngx_http_core_module.c4
-rw-r--r--src/http/ngx_http_file_cache.c111
-rw-r--r--src/http/ngx_http_parse.c2
-rw-r--r--src/http/ngx_http_request_body.c2
-rw-r--r--src/http/ngx_http_script.c2
-rw-r--r--src/http/ngx_http_upstream.c89
-rw-r--r--src/http/ngx_http_upstream.h2
-rw-r--r--src/http/ngx_http_upstream_round_robin.c16
-rw-r--r--src/http/ngx_http_variables.c3
-rw-r--r--src/mail/ngx_mail_ssl_module.c17
-rw-r--r--src/mail/ngx_mail_ssl_module.h2
-rw-r--r--src/os/unix/ngx_errno.h1
35 files changed, 681 insertions, 42 deletions
diff --git a/CHANGES b/CHANGES
index 4425a29d7..4a7e5225d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,45 @@
+Changes with nginx 1.5.7 19 Nov 2013
+
+ *) Security: a character following an unescaped space in a request line
+ was handled incorrectly (CVE-2013-4547); the bug had appeared in
+ 0.8.41.
+ Thanks to Ivan Fratric of the Google Security Team.
+
+ *) Change: a logging level of auth_basic errors about no user/password
+ provided has been lowered from "error" to "info".
+
+ *) Feature: the "proxy_cache_revalidate", "fastcgi_cache_revalidate",
+ "scgi_cache_revalidate", and "uwsgi_cache_revalidate" directives.
+
+ *) Feature: the "ssl_session_ticket_key" directive.
+ Thanks to Piotr Sikora.
+
+ *) Bugfix: the directive "add_header Cache-Control ''" added a
+ "Cache-Control" response header line with an empty value.
+
+ *) Bugfix: the "satisfy any" directive might return 403 error instead of
+ 401 if auth_request and auth_basic directives were used.
+ Thanks to Jan Marc Hoffmann.
+
+ *) Bugfix: the "accept_filter" and "deferred" parameters of the "listen"
+ directive were ignored for listen sockets created during binary
+ upgrade.
+ Thanks to Piotr Sikora.
+
+ *) Bugfix: some data received from a backend with unbufferred proxy
+ might not be sent to a client immediately if "gzip" or "gunzip"
+ directives were used.
+ Thanks to Yichun Zhang.
+
+ *) Bugfix: in error handling in ngx_http_gunzip_filter_module.
+
+ *) Bugfix: responses might hang if the ngx_http_spdy_module was used
+ with the "auth_request" directive.
+
+ *) Bugfix: memory leak in nginx/Windows.
+
+
Changes with nginx 1.5.6 01 Oct 2013
*) Feature: the "fastcgi_buffering" directive.
diff --git a/CHANGES.ru b/CHANGES.ru
index 7beb4ebac..3d73b0d3e 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,47 @@
+Изменения в nginx 1.5.7 19.11.2013
+
+ *) Безопасность: символ, следующий за незакодированным пробелом в строке
+ запроса, обрабатывался неправильно (CVE-2013-4547); ошибка появилась
+ в 0.8.41.
+ Спасибо Ivan Fratric из Google Security Team.
+
+ *) Изменение: уровень логгирования ошибок auth_basic об отсутствии
+ пароля понижен с уровня error до info.
+
+ *) Добавление: директивы proxy_cache_revalidate,
+ fastcgi_cache_revalidate, scgi_cache_revalidate и
+ uwsgi_cache_revalidate.
+
+ *) Добавление: директива ssl_session_ticket_key.
+ Спасибо Piotr Sikora.
+
+ *) Исправление: директива "add_header Cache-Control ''" добавляла строку
+ заголовка ответа "Cache-Control" с пустым значением.
+
+ *) Исправление: директива "satisfy any" могла вернуть ошибку 403 вместо
+ 401 при использовании директив auth_request и auth_basic.
+ Спасибо Jan Marc Hoffmann.
+
+ *) Исправление: параметры accept_filter и deferred директивы listen
+ игнорировались для listen-сокетов, создаваемых в процессе обновления
+ исполняемого файла.
+ Спасибо Piotr Sikora.
+
+ *) Исправление: часть данных, полученных от бэкенда при
+ небуферизированном проксировании, могла не отправляться клиенту
+ сразу, если использовались директивы gzip или gunzip.
+ Спасибо Yichun Zhang.
+
+ *) Исправление: в обработке ошибок в модуле
+ ngx_http_gunzip_filter_module.
+
+ *) Исправление: ответы могли зависать если использовался модуль
+ ngx_http_spdy_module и директива auth_request.
+
+ *) Исправление: утечки памяти в nginx/Windows.
+
+
Изменения в nginx 1.5.6 01.10.2013
*) Добавление: директива fastcgi_buffering.
diff --git a/auto/lib/libatomic/make b/auto/lib/libatomic/make
index 023ed18fb..c90318ea1 100644
--- a/auto/lib/libatomic/make
+++ b/auto/lib/libatomic/make
@@ -9,6 +9,8 @@ $NGX_LIBATOMIC/src/libatomic_ops.a: $NGX_LIBATOMIC/Makefile
cd $NGX_LIBATOMIC && \$(MAKE)
$NGX_LIBATOMIC/Makefile: $NGX_MAKEFILE
- cd $NGX_LIBATOMIC && ./configure
+ cd $NGX_LIBATOMIC \\
+ && if [ -f Makefile ]; then \$(MAKE) distclean; fi \\
+ && ./configure
END
diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make
index 9090fcbfd..e64acd973 100644
--- a/auto/lib/openssl/make
+++ b/auto/lib/openssl/make
@@ -55,7 +55,7 @@ END
$OPENSSL/.openssl/include/openssl/ssl.h: $NGX_MAKEFILE
cd $OPENSSL \\
- && \$(MAKE) clean \\
+ && if [ -f Makefile ]; then \$(MAKE) clean; fi \\
&& ./config --prefix=$ngx_prefix no-shared $OPENSSL_OPT \\
&& \$(MAKE) \\
&& \$(MAKE) install LIBDIR=lib
diff --git a/src/core/nginx.h b/src/core/nginx.h
index ea6b1a87f..5c42c4737 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1005006
-#define NGINX_VERSION "1.5.6"
+#define nginx_version 1005007
+#define NGINX_VERSION "1.5.7"
#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 28bf6ba06..fbcd5f719 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -93,8 +93,10 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
ngx_uint_t i;
ngx_listening_t *ls;
socklen_t olen;
-#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+#if (NGX_HAVE_DEFERRED_ACCEPT)
ngx_err_t err;
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
struct accept_filter_arg af;
#endif
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
@@ -248,7 +250,13 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen)
== -1)
{
- ngx_log_error(NGX_LOG_NOTICE, cycle->log, ngx_errno,
+ err = ngx_errno;
+
+ if (err == NGX_EOPNOTSUPP) {
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
"getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored",
&ls[i].addr_text);
continue;
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index eb39ab253..96345192a 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -545,6 +545,16 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
if (nls[n].fd == (ngx_socket_t) -1) {
nls[n].open = 1;
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+ if (nls[n].accept_filter) {
+ nls[n].add_deferred = 1;
+ }
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+ if (nls[n].deferred_accept) {
+ nls[n].add_deferred = 1;
+ }
+#endif
}
}
diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c
index c4c61204b..e2857f0c0 100644
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -56,7 +56,6 @@ ngx_uint_t ngx_accept_events;
ngx_uint_t ngx_accept_mutex_held;
ngx_msec_t ngx_accept_mutex_delay;
ngx_int_t ngx_accept_disabled;
-ngx_file_t ngx_accept_mutex_lock_file;
#if (NGX_STAT_STUB)
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index cd8f0e711..e4bc1a2c7 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -38,6 +38,12 @@ static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
+static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
+ unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
+ HMAC_CTX *hctx, int enc);
+#endif
+
static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static void ngx_openssl_exit(ngx_cycle_t *cycle);
@@ -82,6 +88,7 @@ ngx_module_t ngx_openssl_module = {
int ngx_ssl_connection_index;
int ngx_ssl_server_conf_index;
int ngx_ssl_session_cache_index;
+int ngx_ssl_session_ticket_keys_index;
int ngx_ssl_certificate_index;
int ngx_ssl_stapling_index;
@@ -139,6 +146,14 @@ ngx_ssl_init(ngx_log_t *log)
return NGX_ERROR;
}
+ ngx_ssl_session_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL,
+ NULL, NULL);
+ if (ngx_ssl_session_ticket_keys_index == -1) {
+ ngx_ssl_error(NGX_LOG_ALERT, log, 0,
+ "SSL_CTX_get_ex_new_index() failed");
+ return NGX_ERROR;
+ }
+
ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
NULL);
if (ngx_ssl_certificate_index == -1) {
@@ -548,8 +563,8 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
* added to wbio, and set buffer size.
*/
- rbio = SSL_get_rbio(ssl_conn);
- wbio = SSL_get_wbio(ssl_conn);
+ rbio = SSL_get_rbio((ngx_ssl_conn_t *) ssl_conn);
+ wbio = SSL_get_wbio((ngx_ssl_conn_t *) ssl_conn);
if (rbio != wbio) {
(void) BIO_set_write_buffer_size(wbio, NGX_SSL_BUFSIZE);
@@ -1704,6 +1719,8 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
{
long cache_mode;
+ SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
+
if (builtin_session_cache == NGX_SSL_NO_SCACHE) {
SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF);
return NGX_OK;
@@ -1749,8 +1766,6 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
}
}
- SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
-
if (shm_zone) {
SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session);
SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session);
@@ -2240,6 +2255,218 @@ ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
}
+#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
+
+ngx_int_t
+ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
+{
+ u_char buf[48];
+ ssize_t n;
+ ngx_str_t *path;
+ ngx_file_t file;
+ ngx_uint_t i;
+ ngx_array_t *keys;
+ ngx_file_info_t fi;
+ ngx_ssl_session_ticket_key_t *key;
+
+ if (paths == NULL) {
+ return NGX_OK;
+ }
+
+ keys = ngx_array_create(cf->pool, paths->nelts,
+ sizeof(ngx_ssl_session_ticket_key_t));
+ if (keys == NULL) {
+ return NGX_ERROR;
+ }
+
+ path = paths->elts;
+ for (i = 0; i < paths->nelts; i++) {
+
+ if (ngx_conf_full_name(cf->cycle, &path[i], 1) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&file, sizeof(ngx_file_t));
+ file.name = path[i];
+ file.log = cf->log;
+
+ file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, 0, 0);
+ if (file.fd == NGX_INVALID_FILE) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
+ ngx_open_file_n " \"%V\" failed", &file.name);
+ return NGX_ERROR;
+ }
+
+ if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
+ ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
+ ngx_fd_info_n " \"%V\" failed", &file.name);
+ goto failed;
+ }
+
+ if (ngx_file_size(&fi) != 48) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%V\" must be 48 bytes", &file.name);
+ goto failed;
+ }
+
+ n = ngx_read_file(&file, buf, 48, 0);
+
+ if (n == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
+ ngx_read_file_n " \"%V\" failed", &file.name);
+ goto failed;
+ }
+
+ if (n != 48) {
+ ngx_conf_log_error(NGX_LOG_CRIT, cf, 0,
+ ngx_read_file_n " \"%V\" returned only "
+ "%z bytes instead of 48", &file.name, n);
+ goto failed;
+ }
+
+ key = ngx_array_push(keys);
+ if (key == NULL) {
+ goto failed;
+ }
+
+ ngx_memcpy(key->name, buf, 16);
+ ngx_memcpy(key->aes_key, buf + 16, 16);
+ ngx_memcpy(key->hmac_key, buf + 32, 16);
+
+ if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", &file.name);
+ }
+ }
+
+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_ticket_keys_index, keys)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_set_ex_data() failed");
+ return NGX_ERROR;
+ }
+
+ if (SSL_CTX_set_tlsext_ticket_key_cb(ssl->ctx,
+ ngx_ssl_session_ticket_key_callback)
+ == 0)
+ {
+ ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+ "nginx was built with Session Tickets support, however, "
+ "now it is linked dynamically to an OpenSSL library "
+ "which has no tlsext support, therefore Session Tickets "
+ "are not available");
+ }
+
+ return NGX_OK;
+
+failed:
+
+ if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", &file.name);
+ }
+
+ return NGX_ERROR;
+}
+
+
+#ifdef OPENSSL_NO_SHA256
+#define ngx_ssl_session_ticket_md EVP_sha1
+#else
+#define ngx_ssl_session_ticket_md EVP_sha256
+#endif
+
+
+static int
+ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
+ unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
+ HMAC_CTX *hctx, int enc)
+{
+ SSL_CTX *ssl_ctx;
+ ngx_uint_t i;
+ ngx_array_t *keys;
+ ngx_ssl_session_ticket_key_t *key;
+#if (NGX_DEBUG)
+ u_char buf[32];
+ ngx_connection_t *c;
+#endif
+
+ ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
+
+ keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index);
+ if (keys == NULL) {
+ return -1;
+ }
+
+ key = keys->elts;
+
+#if (NGX_DEBUG)
+ c = ngx_ssl_get_connection(ssl_conn);
+#endif
+
+ if (enc == 1) {
+ /* encrypt session ticket */
+
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "ssl session ticket encrypt, key: \"%*s\" (%s session)",
+ ngx_hex_dump(buf, key[0].name, 16) - buf, buf,
+ SSL_session_reused(ssl_conn) ? "reused" : "new");
+
+ RAND_pseudo_bytes(iv, 16);
+ EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[0].aes_key, iv);
+ HMAC_Init_ex(hctx, key[0].hmac_key, 16,
+ ngx_ssl_session_ticket_md(), NULL);
+ memcpy(name, key[0].name, 16);
+
+ return 0;
+
+ } else {
+ /* decrypt session ticket */
+
+ for (i = 0; i < keys->nelts; i++) {
+ if (ngx_memcmp(name, key[i].name, 16) == 0) {
+ goto found;
+ }
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "ssl session ticket decrypt, key: \"%*s\" not found",
+ ngx_hex_dump(buf, name, 16) - buf, buf);
+
+ return 0;
+
+ found:
+
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "ssl session ticket decrypt, key: \"%*s\"%s",
+ ngx_hex_dump(buf, key[i].name, 16) - buf, buf,
+ (i == 0) ? " (default)" : "");
+
+ HMAC_Init_ex(hctx, key[i].hmac_key, 16,
+ ngx_ssl_session_ticket_md(), NULL);
+ EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[i].aes_key, iv);
+
+ return (i == 0) ? 1 : 2 /* renew */;
+ }
+}
+
+#else
+
+ngx_int_t
+ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
+{
+ if (paths) {
+ ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
+ "\"ssl_session_ticket_keys\" ignored, not supported");
+ }
+
+ return NGX_OK;
+}
+
+#endif
+
+
void
ngx_ssl_cleanup_ctx(void *data)
{
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index cca01c679..841e82569 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -83,6 +83,16 @@ typedef struct {
} ngx_ssl_session_cache_t;
+#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
+
+typedef struct {
+ u_char name[16];
+ u_char aes_key[16];
+ u_char hmac_key[16];
+} ngx_ssl_session_ticket_key_t;
+
+#endif
+
#define NGX_SSL_SSLv2 0x0002
#define NGX_SSL_SSLv3 0x0004
@@ -116,6 +126,8 @@ ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout);
+ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ ngx_array_t *paths);
ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c,
ngx_uint_t flags);
@@ -173,6 +185,7 @@ void ngx_ssl_cleanup_ctx(void *data);
extern int ngx_ssl_connection_index;
extern int ngx_ssl_server_conf_index;
extern int ngx_ssl_session_cache_index;
+extern int ngx_ssl_session_ticket_keys_index;
extern int ngx_ssl_certificate_index;
extern int ngx_ssl_stapling_index;
diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c
index e8709e5e9..8ec53295f 100644
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -137,7 +137,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r)
if (rc == NGX_DECLINED) {
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"no user/password was provided for basic authentication");
return ngx_http_auth_basic_set_realm(r, &realm);
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c
index a97c60e44..2a179922c 100644
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -10,8 +10,6 @@
#include <ngx_http.h>
-#define NGX_HTTP_DAV_COPY_BLOCK 65536
-
#define NGX_HTTP_DAV_OFF 2
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index dd79418a2..51672e227 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -405,6 +405,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout),
NULL },
+ { ngx_string("fastcgi_cache_revalidate"),
+ 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.cache_revalidate),
+ NULL },
+
#endif
{ ngx_string("fastcgi_temp_path"),
@@ -563,7 +570,8 @@ static ngx_str_t ngx_http_fastcgi_hide_headers[] = {
#if (NGX_HTTP_CACHE)
static ngx_keyval_t ngx_http_fastcgi_cache_headers[] = {
- { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
+ { ngx_string("HTTP_IF_MODIFIED_SINCE"),
+ ngx_string("$upstream_cache_last_modified") },
{ ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
{ ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
{ ngx_string("HTTP_IF_MATCH"), ngx_string("") },
@@ -2336,6 +2344,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
conf->upstream.cache_lock = NGX_CONF_UNSET;
conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
+ conf->upstream.cache_revalidate = NGX_CONF_UNSET;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -2582,6 +2591,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
prev->upstream.cache_lock_timeout, 5000);
+ ngx_conf_merge_value(conf->upstream.cache_revalidate,
+ prev->upstream.cache_revalidate, 0);
+
#endif
ngx_conf_merge_value(conf->upstream.pass_request_headers,
diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c
index d4e41e4a0..adadc9da6 100644
--- a/src/http/modules/ngx_http_gunzip_filter_module.c
+++ b/src/http/modules/ngx_http_gunzip_filter_module.c
@@ -199,7 +199,7 @@ ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
}
- if (ctx->nomem) {
+ if (ctx->nomem || in == NULL) {
/* flush busy buffers */
@@ -422,7 +422,7 @@ ngx_http_gunzip_filter_inflate(ngx_http_request_t *r,
rc = inflate(&ctx->zstream, ctx->flush);
if (rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"inflate() failed: %d, %d", ctx->flush, rc);
return NGX_ERROR;
}
@@ -500,9 +500,13 @@ ngx_http_gunzip_filter_inflate(ngx_http_request_t *r,
return NGX_OK;
}
- if (rc == Z_STREAM_END && ctx->flush == Z_FINISH
- && ctx->zstream.avail_in == 0)
- {
+ if (ctx->flush == Z_FINISH && ctx->zstream.avail_in == 0) {
+
+ if (rc != Z_STREAM_END) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "inflate() returned %d on response end", rc);
+ return NGX_ERROR;
+ }
if (ngx_http_gunzip_filter_inflate_end(r, ctx) != NGX_OK) {
return NGX_ERROR;
diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c
index 837b0bc98..ea1f1d0b9 100644
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -372,7 +372,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) {
+ if (ctx->nomem || in == NULL) {
/* flush busy buffers */
diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c
index 0dfe8101e..e33e7ce52 100644
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -339,6 +339,10 @@ ngx_http_add_cache_control(ngx_http_request_t *r, ngx_http_header_val_t *hv,
{
ngx_table_elt_t *cc, **ccp;
+ if (value->len == 0) {
+ return NGX_OK;
+ }
+
ccp = r->headers_out.cache_control.elts;
if (ccp == NULL) {
diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c
index 90434c956..d4c1ff6c3 100644
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -912,7 +912,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
- if (ngx_strncmp(value[i].data, "nodelay", 7) == 0) {
+ if (ngx_strcmp(value[i].data, "nodelay") == 0) {
nodelay = 1;
continue;
}
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index cf68711cd..404607511 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -465,6 +465,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
NULL },
+ { ngx_string("proxy_cache_revalidate"),
+ 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.cache_revalidate),
+ NULL },
+
#endif
{ ngx_string("proxy_temp_path"),
@@ -622,7 +629,8 @@ static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
{ ngx_string("Keep-Alive"), ngx_string("") },
{ ngx_string("Expect"), ngx_string("") },
{ ngx_string("Upgrade"), ngx_string("") },
- { ngx_string("If-Modified-Since"), ngx_string("") },
+ { ngx_string("If-Modified-Since"),
+ ngx_string("$upstream_cache_last_modified") },
{ ngx_string("If-Unmodified-Since"), ngx_string("") },
{ ngx_string("If-None-Match"), ngx_string("") },
{ ngx_string("If-Match"), ngx_string("") },
@@ -2454,6 +2462,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
conf->upstream.cache_lock = NGX_CONF_UNSET;
conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
+ conf->upstream.cache_revalidate = NGX_CONF_UNSET;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -2710,6 +2719,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
prev->upstream.cache_lock_timeout, 5000);
+ ngx_conf_merge_value(conf->upstream.cache_revalidate,
+ prev->upstream.cache_revalidate, 0);
+
#endif
ngx_conf_merge_str_value(conf->method, prev->method, "");
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index f9c0d1427..9163c6b3c 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -262,6 +262,13 @@ static ngx_command_t ngx_http_scgi_commands[] = {
offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout),
NULL },
+ { ngx_string("scgi_cache_revalidate"),
+ 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.cache_revalidate),
+ NULL },
+
#endif
{ ngx_string("scgi_temp_path"),
@@ -369,7 +376,8 @@ static ngx_str_t ngx_http_scgi_hide_headers[] = {
#if (NGX_HTTP_CACHE)
static ngx_keyval_t ngx_http_scgi_cache_headers[] = {
- { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
+ { ngx_string("HTTP_IF_MODIFIED_SINCE"),
+ ngx_string("$upstream_cache_last_modified") },
{ ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
{ ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
{ ngx_string("HTTP_IF_MATCH"), ngx_string("") },
@@ -1093,6 +1101,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
conf->upstream.cache_lock = NGX_CONF_UNSET;
conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
+ conf->upstream.cache_revalidate = NGX_CONF_UNSET;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -1333,6 +1342,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
prev->upstream.cache_lock_timeout, 5000);
+ ngx_conf_merge_value(conf->upstream.cache_revalidate,
+ prev->upstream.cache_revalidate, 0);
+
#endif
ngx_conf_merge_value(conf->upstream.pass_request_headers,
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index 75dd7f4b0..7ac96c621 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -153,6 +153,13 @@ static ngx_command_t ngx_http_ssl_commands[] = {
0,
NULL },
+ { ngx_string("ssl_session_ticket_key"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_array_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_ssl_srv_conf_t, session_ticket_keys),
+ NULL },
+
{ ngx_string("ssl_session_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_sec_slot,
@@ -421,6 +428,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
sscf->verify_depth = NGX_CONF_UNSET_UINT;
sscf->builtin_session_cache = NGX_CONF_UNSET;
sscf->session_timeout = NGX_CONF_UNSET;
+ sscf->session_ticket_keys = NGX_CONF_UNSET_PTR;
sscf->stapling = NGX_CONF_UNSET;
sscf->stapling_verify = NGX_CONF_UNSET;
@@ -623,6 +631,15 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
+ ngx_conf_merge_ptr_value(conf->session_ticket_keys,
+ prev->session_ticket_keys, NULL);
+
+ if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
if (conf->stapling) {
if (ngx_ssl_stapling(cf, &conf->ssl, &conf->stapling_file,
diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h
index c4c576ef6..3feb4b6d2 100644
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -42,6 +42,8 @@ typedef struct {
ngx_shm_zone_t *shm_zone;
+ ngx_array_t *session_ticket_keys;
+
ngx_flag_t stapling;
ngx_flag_t stapling_verify;
ngx_str_t stapling_file;
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index 0635299e8..9c5d76213 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -289,6 +289,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock_timeout),
NULL },
+ { ngx_string("uwsgi_cache_revalidate"),
+ 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.cache_revalidate),
+ NULL },
+
#endif
{ ngx_string("uwsgi_temp_path"),
@@ -402,7 +409,8 @@ static ngx_str_t ngx_http_uwsgi_hide_headers[] = {
#if (NGX_HTTP_CACHE)
static ngx_keyval_t ngx_http_uwsgi_cache_headers[] = {
- { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
+ { ngx_string("HTTP_IF_MODIFIED_SINCE"),
+ ngx_string("$upstream_cache_last_modified") },
{ ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
{ ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
{ ngx_string("HTTP_IF_MATCH"), ngx_string("") },
@@ -1130,6 +1138,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
conf->upstream.cache_lock = NGX_CONF_UNSET;
conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
+ conf->upstream.cache_revalidate = NGX_CONF_UNSET;
#endif
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
@@ -1370,6 +1379,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
prev->upstream.cache_lock_timeout, 5000);
+ ngx_conf_merge_value(conf->upstream.cache_revalidate,
+ prev->upstream.cache_revalidate, 0);
+
#endif
ngx_conf_merge_value(conf->upstream.pass_request_headers,
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
index 2a2d72291..193a35322 100644
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -19,8 +19,9 @@
#define NGX_HTTP_CACHE_EXPIRED 3
#define NGX_HTTP_CACHE_STALE 4
#define NGX_HTTP_CACHE_UPDATING 5
-#define NGX_HTTP_CACHE_HIT 6
-#define NGX_HTTP_CACHE_SCARCE 7
+#define NGX_HTTP_CACHE_REVALIDATED 6
+#define NGX_HTTP_CACHE_HIT 7
+#define NGX_HTTP_CACHE_SCARCE 8
#define NGX_HTTP_CACHE_KEY_LEN 16
@@ -143,6 +144,7 @@ void ngx_http_file_cache_create_key(ngx_http_request_t *r);
ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r);
void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf);
void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf);
+void ngx_http_file_cache_update_header(ngx_http_request_t *r);
ngx_int_t ngx_http_cache_send(ngx_http_request_t *);
void ngx_http_file_cache_free(ngx_http_cache_t *c, ngx_temp_file_t *tf);
time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status);
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index f8c695645..d2e29136d 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1144,7 +1144,9 @@ ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
}
if (rc == NGX_HTTP_FORBIDDEN || rc == NGX_HTTP_UNAUTHORIZED) {
- r->access_code = rc;
+ if (r->access_code != NGX_HTTP_UNAUTHORIZED) {
+ r->access_code = rc;
+ }
r->phase_handler++;
return NGX_AGAIN;
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 7e46d1295..9e6be1584 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -53,6 +53,7 @@ ngx_str_t ngx_http_cache_status[] = {
ngx_string("EXPIRED"),
ngx_string("STALE"),
ngx_string("UPDATING"),
+ ngx_string("REVALIDATED"),
ngx_string("HIT")
};
@@ -971,6 +972,116 @@ ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
}
+void
+ngx_http_file_cache_update_header(ngx_http_request_t *r)
+{
+ ssize_t n;
+ ngx_err_t err;
+ ngx_file_t file;
+ ngx_file_info_t fi;
+ ngx_http_cache_t *c;
+ ngx_http_file_cache_header_t h;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache update header");
+
+ c = r->cache;
+
+ ngx_memzero(&file, sizeof(ngx_file_t));
+
+ file.name = c->file.name;
+ file.log = r->connection->log;
+ file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);
+
+ if (file.fd == NGX_INVALID_FILE) {
+ err = ngx_errno;
+
+ /* cache file may have been deleted */
+
+ if (err == NGX_ENOENT) {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache \"%s\" not found",
+ file.name.data);
+ return;
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
+ ngx_open_file_n " \"%s\" failed", file.name.data);
+ return;
+ }
+
+ /*
+ * make sure cache file wasn't replaced;
+ * if it was, do nothing
+ */
+
+ if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_fd_info_n " \"%s\" failed", file.name.data);
+ goto done;
+ }
+
+ if (c->uniq != ngx_file_uniq(&fi)
+ || c->length != ngx_file_size(&fi))
+ {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache \"%s\" changed",
+ file.name.data);
+ goto done;
+ }
+
+ n = ngx_read_file(&file, (u_char *) &h,
+ sizeof(ngx_http_file_cache_header_t), 0);
+
+ if (n == NGX_ERROR) {
+ goto done;
+ }
+
+ if ((size_t) n != sizeof(ngx_http_file_cache_header_t)) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+ ngx_read_file_n " read only %z of %z from \"%s\"",
+ n, sizeof(ngx_http_file_cache_header_t), file.name.data);
+ goto done;
+ }
+
+ if (h.last_modified != c->last_modified
+ || h.crc32 != c->crc32
+ || h.header_start != c->header_start
+ || h.body_start != c->body_start)
+ {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache \"%s\" content changed",
+ file.name.data);
+ goto done;
+ }
+
+ /*
+ * update cache file header with new data,
+ * notably h.valid_sec and h.date
+ */
+
+ ngx_memzero(&h, sizeof(ngx_http_file_cache_header_t));
+
+ h.valid_sec = c->valid_sec;
+ h.last_modified = c->last_modified;
+ h.date = c->date;
+ h.crc32 = c->crc32;
+ h.valid_msec = (u_short) c->valid_msec;
+ h.header_start = (u_short) c->header_start;
+ h.body_start = (u_short) c->body_start;
+
+ (void) ngx_write_file(&file, (u_char *) &h,
+ sizeof(ngx_http_file_cache_header_t), 0);
+
+done:
+
+ if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", file.name.data);
+ }
+}
+
+
ngx_int_t
ngx_http_cache_send(ngx_http_request_t *r)
{
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index 973bc7430..cf89b8cfe 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -617,6 +617,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
default:
r->space_in_uri = 1;
state = sw_check_uri;
+ p--;
break;
}
break;
@@ -670,6 +671,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
default:
r->space_in_uri = 1;
state = sw_uri;
+ p--;
break;
}
break;
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index dc1fcde1c..97df69c05 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -43,7 +43,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
r->main->count++;
#if (NGX_HTTP_SPDY)
- if (r->spdy_stream) {
+ if (r->spdy_stream && r == r->main) {
rc = ngx_http_spdy_read_request_body(r, post_handler);
goto done;
}
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index 5fc4cfca0..02e2be3bb 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -1394,7 +1394,7 @@ ngx_http_script_if_code(ngx_http_script_engine_t *e)
e->sp--;
- if (e->sp->len && (e->sp->len !=1 || e->sp->data[0] != '0')) {
+ if (e->sp->len && (e->sp->len != 1 || e->sp->data[0] != '0')) {
if (code->loc_conf) {
e->request->loc_conf = code->loc_conf;
ngx_http_update_location_config(e->request);
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 4a4f8eba2..9570ccc7e 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -17,6 +17,8 @@ static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
#endif
static void ngx_http_upstream_init_request(ngx_http_request_t *r);
@@ -358,6 +360,10 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = {
ngx_http_upstream_cache_status, 0,
NGX_HTTP_VAR_NOCACHEABLE, 0 },
+ { ngx_string("upstream_cache_last_modified"), NULL,
+ ngx_http_upstream_cache_last_modified, 0,
+ NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+
#endif
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
@@ -1806,6 +1812,56 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
#endif
}
+#if (NGX_HTTP_CACHE)
+
+ if (status == NGX_HTTP_NOT_MODIFIED
+ && u->cache_status == NGX_HTTP_CACHE_EXPIRED
+ && u->conf->cache_revalidate)
+ {
+ time_t now, valid;
+ ngx_int_t rc;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http upstream not modified");
+
+ now = ngx_time();
+ valid = r->cache->valid_sec;
+
+ rc = u->reinit_request(r);
+
+ if (rc != NGX_OK) {
+ ngx_http_upstream_finalize_request(r, u, rc);
+ return NGX_OK;
+ }
+
+ u->cache_status = NGX_HTTP_CACHE_REVALIDATED;
+ rc = ngx_http_upstream_cache_send(r, u);
+
+ if (valid == 0) {
+ valid = r->cache->valid_sec;
+ }
+
+ if (valid == 0) {
+ valid = ngx_http_file_cache_valid(u->conf->cache_valid,
+ u->headers_in.status_n);
+ if (valid) {
+ valid = now + valid;
+ }
+ }
+
+ if (valid) {
+ r->cache->valid_sec = valid;
+ r->cache->date = now;
+
+ ngx_http_file_cache_update_header(r);
+ }
+
+ ngx_http_upstream_finalize_request(r, u, rc);
+ return NGX_OK;
+ }
+
+#endif
+
return NGX_DECLINED;
}
@@ -4492,6 +4548,35 @@ ngx_http_upstream_cache_status(ngx_http_request_t *r,
return NGX_OK;
}
+
+static ngx_int_t
+ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ u_char *p;
+
+ if (!r->upstream->conf->cache_revalidate
+ || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED
+ || r->cache->last_modified == -1)
+ {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ p = ngx_pnalloc(r->pool, sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ v->len = ngx_http_time(p, r->cache->last_modified) - p;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->data = p;
+
+ return NGX_OK;
+}
+
#endif
@@ -4701,7 +4786,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
- if (ngx_strncmp(value[i].data, "backup", 6) == 0) {
+ if (ngx_strcmp(value[i].data, "backup") == 0) {
if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
goto invalid;
@@ -4712,7 +4797,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
- if (ngx_strncmp(value[i].data, "down", 4) == 0) {
+ if (ngx_strcmp(value[i].data, "down") == 0) {
if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
goto invalid;
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index fd4e36b1f..469988eed 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -178,6 +178,8 @@ typedef struct {
ngx_flag_t cache_lock;
ngx_msec_t cache_lock_timeout;
+ ngx_flag_t cache_revalidate;
+
ngx_array_t *cache_valid;
ngx_array_t *cache_bypass;
ngx_array_t *no_cache;
diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
index e0c6c58c7..02dbf0a16 100644
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -71,11 +71,11 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
n = 0;
for (i = 0; i < us->servers->nelts; i++) {
- for (j = 0; j < server[i].naddrs; j++) {
- if (server[i].backup) {
- continue;
- }
+ if (server[i].backup) {
+ continue;
+ }
+ for (j = 0; j < server[i].naddrs; j++) {
peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
peers->peer[n].socklen = server[i].addrs[j].socklen;
peers->peer[n].name = server[i].addrs[j].name;
@@ -125,11 +125,11 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
n = 0;
for (i = 0; i < us->servers->nelts; i++) {
- for (j = 0; j < server[i].naddrs; j++) {
- if (!server[i].backup) {
- continue;
- }
+ if (!server[i].backup) {
+ continue;
+ }
+ for (j = 0; j < server[i].naddrs; j++) {
backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
backup->peer[n].socklen = server[i].addrs[j].socklen;
backup->peer[n].name = server[i].addrs[j].name;
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 3ec038aef..e49d2023b 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -1744,8 +1744,7 @@ ngx_http_variable_sent_last_modified(ngx_http_request_t *r,
}
if (r->headers_out.last_modified_time >= 0) {
- p = ngx_pnalloc(r->pool,
- sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT") - 1);
+ p = ngx_pnalloc(r->pool, sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
if (p == NULL) {
return NGX_ERROR;
}
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index 18fd66aed..94c015700 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_ticket_key"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_array_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+ offsetof(ngx_mail_ssl_conf_t, session_ticket_keys),
+ NULL },
+
{ ngx_string("ssl_session_timeout"),
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_sec_slot,
@@ -184,6 +191,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_ticket_keys = NGX_CONF_UNSET_PTR;
return scf;
}
@@ -331,6 +339,15 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
+ ngx_conf_merge_ptr_value(conf->session_ticket_keys,
+ prev->session_ticket_keys, NULL);
+
+ if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
return NGX_CONF_OK;
}
diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h
index 7f59b38ae..54e057721 100644
--- a/src/mail/ngx_mail_ssl_module.h
+++ b/src/mail/ngx_mail_ssl_module.h
@@ -41,6 +41,8 @@ typedef struct {
ngx_shm_zone_t *shm_zone;
+ ngx_array_t *session_ticket_keys;
+
u_char *file;
ngx_uint_t line;
} ngx_mail_ssl_conf_t;
diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h
index 6d1a4889a..663e460d9 100644
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -34,6 +34,7 @@ typedef int ngx_err_t;
#define NGX_ENOSPC ENOSPC
#define NGX_EPIPE EPIPE
#define NGX_EINPROGRESS EINPROGRESS
+#define NGX_EOPNOTSUPP EOPNOTSUPP
#define NGX_EADDRINUSE EADDRINUSE
#define NGX_ECONNABORTED ECONNABORTED
#define NGX_ECONNRESET ECONNRESET