diff options
35 files changed, 681 insertions, 42 deletions
@@ -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 |