diff options
author | nginx <nginx@nginx.org> | 2014-07-08 13:45:06 +0000 |
---|---|---|
committer | Jon Kolb <kolbyjack@gmail.com> | 2014-07-08 13:45:06 +0000 |
commit | 251331cd59f780fca94bef334f58a6e311e4ad32 (patch) | |
tree | 529cad425bb96637cb24ee746ea34f598f40a237 | |
parent | a995714bb2b96df7f846a8eec89715000f0699dd (diff) | |
download | nginx-251331cd59f780fca94bef334f58a6e311e4ad32.tar.gz |
Changes with nginx 1.7.3 08 Jul 2014v1.7.3
*) Feature: weak entity tags are now preserved on response
modifications, and strong ones are changed to weak.
*) Feature: cache revalidation now uses If-None-Match header if
possible.
*) Feature: the "ssl_password_file" directive.
*) Bugfix: the If-None-Match request header line was ignored if there
was no Last-Modified header in a response returned from cache.
*) Bugfix: "peer closed connection in SSL handshake" messages were
logged at "info" level instead of "error" while connecting to
backends.
*) Bugfix: in the ngx_http_dav_module module in nginx/Windows.
*) Bugfix: SPDY connections might be closed prematurely if caching was
used.
36 files changed, 636 insertions, 136 deletions
@@ -1,4 +1,27 @@ +Changes with nginx 1.7.3 08 Jul 2014 + + *) Feature: weak entity tags are now preserved on response + modifications, and strong ones are changed to weak. + + *) Feature: cache revalidation now uses If-None-Match header if + possible. + + *) Feature: the "ssl_password_file" directive. + + *) Bugfix: the If-None-Match request header line was ignored if there + was no Last-Modified header in a response returned from cache. + + *) Bugfix: "peer closed connection in SSL handshake" messages were + logged at "info" level instead of "error" while connecting to + backends. + + *) Bugfix: in the ngx_http_dav_module module in nginx/Windows. + + *) Bugfix: SPDY connections might be closed prematurely if caching was + used. + + Changes with nginx 1.7.2 17 Jun 2014 *) Feature: the "hash" directive inside the "upstream" block. diff --git a/CHANGES.ru b/CHANGES.ru index 67ac3f5df..f87375fc5 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,27 @@ +Изменения в nginx 1.7.3 08.07.2014 + + *) Добавление: weak entity tags теперь не удаляются при изменениях + ответа, а strong entity tags преобразуются в weak. + + *) Добавление: ревалидация элементов кэша теперь, если это возможно, + использует заголовок If-None-Match. + + *) Добавление: директива ssl_password_file. + + *) Исправление: при возврате ответа из кэша заголовок запроса + If-None-Match игнорировался, если в ответе не было заголовка + Last-Modified. + + *) Исправление: сообщения "peer closed connection in SSL handshake" при + соединении с бэкендами логгировались на уровне info вместо error. + + *) Исправление: в модуле ngx_http_dav_module в nginx/Windows. + + *) Исправление: SPDY-соединения могли неожиданно закрываться, если + использовалось кэширование. + + Изменения в nginx 1.7.2 17.06.2014 *) Добавление: директива hash в блоке upstream. diff --git a/auto/lib/perl/conf b/auto/lib/perl/conf index 91009f15e..2a1a3fe3c 100644 --- a/auto/lib/perl/conf +++ b/auto/lib/perl/conf @@ -41,6 +41,8 @@ if test -n "$NGX_PERL_VER"; then ngx_perl_ldopts=`$NGX_PERL -MExtUtils::Embed -e ldopts` ngx_perl_dlext=`$NGX_PERL -MConfig -e 'print $Config{dlext}'` + ngx_perl_libdir="src/http/modules/perl/blib/arch/auto" + ngx_perl_module="$ngx_perl_libdir/nginx/nginx.$ngx_perl_dlext" if $NGX_PERL -V:usemultiplicity | grep define > /dev/null; then have=NGX_HAVE_PERL_MULTIPLICITY . auto/have @@ -54,11 +56,12 @@ if test -n "$NGX_PERL_VER"; then if [ "$NGX_SYSTEM" = "Darwin" ]; then # OS X system perl wants to link universal binaries - ngx_perl_ldopts=`echo $ngx_perl_ldopts | sed -e 's/-arch x86_64 -arch i386//'` + ngx_perl_ldopts=`echo $ngx_perl_ldopts \ + | sed -e 's/-arch x86_64 -arch i386//'` fi CORE_LINK="$CORE_LINK $ngx_perl_ldopts" - LINK_DEPS="$LINK_DEPS $NGX_OBJS/src/http/modules/perl/blib/arch/auto/nginx/nginx.$ngx_perl_dlext" + LINK_DEPS="$LINK_DEPS $NGX_OBJS/$ngx_perl_module" if test -n "$NGX_PERL_MODULES"; then have=NGX_PERL_MODULES value="(u_char *) \"$NGX_PERL_MODULES\"" diff --git a/src/core/nginx.h b/src/core/nginx.h index 81e351c2a..8d134487a 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1007002 -#define NGINX_VERSION "1.7.2" +#define nginx_version 1007003 +#define NGINX_VERSION "1.7.3" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 6b6e3b3a5..4c42ffc0d 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -411,13 +411,11 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { err = ngx_socket_errno; - if (err == NGX_EADDRINUSE && ngx_test_config) { - continue; + if (err != NGX_EADDRINUSE || !ngx_test_config) { + ngx_log_error(NGX_LOG_EMERG, log, err, + "bind() to %V failed", &ls[i].addr_text); } - ngx_log_error(NGX_LOG_EMERG, log, err, - "bind() to %V failed", &ls[i].addr_text); - if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", @@ -428,7 +426,9 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) return NGX_ERROR; } - failed = 1; + if (!ngx_test_config) { + failed = 1; + } continue; } diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c index 1f70f9eee..ef4a64771 100644 --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -181,7 +181,7 @@ ngx_palloc_block(ngx_pool_t *pool, size_t size) { u_char *m; size_t psize; - ngx_pool_t *p, *new, *current; + ngx_pool_t *p, *new; psize = (size_t) (pool->d.end - (u_char *) pool); @@ -200,18 +200,14 @@ ngx_palloc_block(ngx_pool_t *pool, size_t size) m = ngx_align_ptr(m, NGX_ALIGNMENT); new->d.last = m + size; - current = pool->current; - - for (p = current; p->d.next; p = p->d.next) { + for (p = pool->current; p->d.next; p = p->d.next) { if (p->d.failed++ > 4) { - current = p->d.next; + pool->current = p->d.next; } } p->d.next = new; - pool->current = current ? current : new; - return m; } diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index be3e54084..24f2ff16a 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -398,6 +398,35 @@ done: } +void * +ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size) +{ + void *p; + + ngx_shmtx_lock(&pool->mutex); + + p = ngx_slab_calloc_locked(pool, size); + + ngx_shmtx_unlock(&pool->mutex); + + return p; +} + + +void * +ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size) +{ + void *p; + + p = ngx_slab_alloc_locked(pool, size); + if (p) { + ngx_memzero(p, size); + } + + return p; +} + + void ngx_slab_free(ngx_slab_pool_t *pool, void *p) { diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h index 1ee65d531..2922a80c7 100644 --- a/src/core/ngx_slab.h +++ b/src/core/ngx_slab.h @@ -50,6 +50,8 @@ typedef struct { void ngx_slab_init(ngx_slab_pool_t *pool); void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size); +void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size); +void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size); void ngx_slab_free(ngx_slab_pool_t *pool, void *p); void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p); diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 0c5ecda98..50691ade7 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -10,14 +10,20 @@ #include <ngx_event.h> +#define NGX_SSL_PASSWORD_BUFFER_SIZE 4096 + + typedef struct { ngx_uint_t engine; /* unsigned engine:1; */ } ngx_openssl_conf_t; +static int ngx_ssl_password_callback(char *buf, int size, int rwflag, + void *userdata); static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret); +static void ngx_ssl_passwords_cleanup(void *data); static void ngx_ssl_handshake_handler(ngx_event_t *ev); static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); static void ngx_ssl_write_handler(ngx_event_t *wev); @@ -257,11 +263,13 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, - ngx_str_t *key) + ngx_str_t *key, ngx_array_t *passwords) { - BIO *bio; - X509 *x509; - u_long n; + BIO *bio; + X509 *x509; + u_long n; + ngx_str_t *pwd; + ngx_uint_t tries; if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { return NGX_ERROR; @@ -348,19 +356,76 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, return NGX_ERROR; } - if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data, - SSL_FILETYPE_PEM) - == 0) - { + if (passwords) { + tries = passwords->nelts; + pwd = passwords->elts; + + SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback); + SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd); + + } else { + tries = 1; +#if (NGX_SUPPRESS_WARN) + pwd = NULL; +#endif + } + + for ( ;; ) { + + if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data, + SSL_FILETYPE_PEM) + != 0) + { + break; + } + + if (--tries) { + n = ERR_peek_error(); + + if (ERR_GET_LIB(n) == ERR_LIB_EVP + && ERR_GET_REASON(n) == EVP_R_BAD_DECRYPT) + { + ERR_clear_error(); + SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd); + continue; + } + } + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data); return NGX_ERROR; } + SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL); + return NGX_OK; } +static int +ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata) +{ + ngx_str_t *pwd = userdata; + + if (rwflag) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "ngx_ssl_password_callback() is called for encryption"); + return 0; + } + + if (pwd->len > (size_t) size) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, + "password is truncated to %d bytes", size); + } else { + size = pwd->len; + } + + ngx_memcpy(buf, pwd->data, size); + + return size; +} + + ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth) @@ -597,6 +662,148 @@ ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, } +ngx_array_t * +ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) +{ + u_char *p, *last, *end; + size_t len; + ssize_t n; + ngx_fd_t fd; + ngx_str_t *pwd; + ngx_array_t *passwords; + ngx_pool_cleanup_t *cln; + u_char buf[NGX_SSL_PASSWORD_BUFFER_SIZE]; + + if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) { + return NULL; + } + + cln = ngx_pool_cleanup_add(cf->temp_pool, 0); + passwords = ngx_array_create(cf->temp_pool, 4, sizeof(ngx_str_t)); + + if (cln == NULL || passwords == NULL) { + return NULL; + } + + cln->handler = ngx_ssl_passwords_cleanup; + cln->data = passwords; + + fd = ngx_open_file(file->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + ngx_open_file_n " \"%s\" failed", file->data); + return NULL; + } + + len = 0; + last = buf; + + do { + n = ngx_read_fd(fd, last, NGX_SSL_PASSWORD_BUFFER_SIZE - len); + + if (n == -1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, + ngx_read_fd_n " \"%s\" failed", file->data); + passwords = NULL; + goto cleanup; + } + + end = last + n; + + if (len && n == 0) { + *end++ = LF; + } + + p = buf; + + for ( ;; ) { + last = ngx_strlchr(last, end, LF); + + if (last == NULL) { + break; + } + + len = last++ - p; + + if (len && p[len - 1] == CR) { + len--; + } + + if (len) { + pwd = ngx_array_push(passwords); + if (pwd == NULL) { + passwords = NULL; + goto cleanup; + } + + pwd->len = len; + pwd->data = ngx_pnalloc(cf->temp_pool, len); + + if (pwd->data == NULL) { + passwords->nelts--; + passwords = NULL; + goto cleanup; + } + + ngx_memcpy(pwd->data, p, len); + } + + p = last; + } + + len = end - p; + + if (len == NGX_SSL_PASSWORD_BUFFER_SIZE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too long line in \"%s\"", file->data); + passwords = NULL; + goto cleanup; + } + + ngx_memmove(buf, p, len); + last = buf + len; + + } while (n != 0); + + if (passwords->nelts == 0) { + pwd = ngx_array_push(passwords); + if (pwd == NULL) { + passwords = NULL; + goto cleanup; + } + + ngx_memzero(pwd, sizeof(ngx_str_t)); + } + +cleanup: + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_conf_log_error(NGX_LOG_ALERT, cf, ngx_errno, + ngx_close_file_n " \"%s\" failed", file->data); + } + + ngx_memzero(buf, NGX_SSL_PASSWORD_BUFFER_SIZE); + + return passwords; +} + + +static void +ngx_ssl_passwords_cleanup(void *data) +{ + ngx_array_t *passwords = data; + + ngx_str_t *pwd; + ngx_uint_t i; + + pwd = passwords->elts; + + for (i = 0; i < passwords->nelts; i++) { + ngx_memzero(pwd[i].data, pwd[i].len); + } +} + + ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) { @@ -905,8 +1112,8 @@ ngx_ssl_handshake(ngx_connection_t *c) c->read->eof = 1; if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { - ngx_log_error(NGX_LOG_INFO, c->log, err, - "peer closed connection in SSL handshake"); + ngx_connection_error(c, err, + "peer closed connection in SSL handshake"); return NGX_ERROR; } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index d632eb274..0194602f6 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -112,7 +112,7 @@ typedef struct { ngx_int_t ngx_ssl_init(ngx_log_t *log); ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data); ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, - ngx_str_t *cert, ngx_str_t *key); + ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth); ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, @@ -124,6 +124,7 @@ ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_resolver_t *resolver, ngx_msec_t resolver_timeout); RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, int key_length); +ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); 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, diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c index eed807d61..64fb07bde 100644 --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -439,7 +439,11 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) } } - if (p->cacheable && p->in) { + if (p->cacheable && (p->in || p->buf_to_file)) { + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, + "pipe write chain"); + if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { return NGX_ABORT; } @@ -515,15 +519,6 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) p->in = NULL; } - if (p->cacheable && p->buf_to_file) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, - "pipe write chain"); - - if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { - return NGX_ABORT; - } - } - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream done"); diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c index f598ceab3..db4970bf1 100644 --- a/src/http/modules/ngx_http_addition_filter_module.c +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -121,7 +121,7 @@ ngx_http_addition_header_filter(ngx_http_request_t *r) ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); - ngx_http_clear_etag(r); + ngx_http_weak_etag(r); return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 80cd1a220..8016f5b75 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -573,7 +573,7 @@ static ngx_keyval_t ngx_http_fastcgi_cache_headers[] = { { 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_NONE_MATCH"), ngx_string("$upstream_cache_etag") }, { ngx_string("HTTP_IF_MATCH"), ngx_string("") }, { ngx_string("HTTP_RANGE"), ngx_string("") }, { ngx_string("HTTP_IF_RANGE"), ngx_string("") }, diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c index adadc9da6..70ec0aace 100644 --- a/src/http/modules/ngx_http_gunzip_filter_module.c +++ b/src/http/modules/ngx_http_gunzip_filter_module.c @@ -165,7 +165,7 @@ ngx_http_gunzip_header_filter(ngx_http_request_t *r) ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); - ngx_http_clear_etag(r); + ngx_http_weak_etag(r); return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index ea1f1d0b9..c57a4a3c7 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -306,7 +306,7 @@ ngx_http_gzip_header_filter(ngx_http_request_t *r) ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); - ngx_http_clear_etag(r); + ngx_http_weak_etag(r); return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c index 7f1ab6236..acc94ded3 100644 --- a/src/http/modules/ngx_http_not_modified_filter_module.c +++ b/src/http/modules/ngx_http_not_modified_filter_module.c @@ -13,7 +13,7 @@ static ngx_uint_t ngx_http_test_if_unmodified(ngx_http_request_t *r); static ngx_uint_t ngx_http_test_if_modified(ngx_http_request_t *r); static ngx_uint_t ngx_http_test_if_match(ngx_http_request_t *r, - ngx_table_elt_t *header); + ngx_table_elt_t *header, ngx_uint_t weak); static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf); @@ -56,7 +56,7 @@ ngx_http_not_modified_header_filter(ngx_http_request_t *r) { if (r->headers_out.status != NGX_HTTP_OK || r != r->main - || r->headers_out.last_modified_time == -1) + || r->disable_not_modified) { return ngx_http_next_header_filter(r); } @@ -69,7 +69,7 @@ ngx_http_not_modified_header_filter(ngx_http_request_t *r) } if (r->headers_in.if_match - && !ngx_http_test_if_match(r, r->headers_in.if_match)) + && !ngx_http_test_if_match(r, r->headers_in.if_match, 0)) { return ngx_http_filter_finalize_request(r, NULL, NGX_HTTP_PRECONDITION_FAILED); @@ -84,7 +84,7 @@ ngx_http_not_modified_header_filter(ngx_http_request_t *r) } if (r->headers_in.if_none_match - && !ngx_http_test_if_match(r, r->headers_in.if_none_match)) + && !ngx_http_test_if_match(r, r->headers_in.if_none_match, 1)) { return ngx_http_next_header_filter(r); } @@ -114,11 +114,15 @@ ngx_http_test_if_unmodified(ngx_http_request_t *r) { time_t iums; + if (r->headers_out.last_modified_time == (time_t) -1) { + return 0; + } + iums = ngx_http_parse_time(r->headers_in.if_unmodified_since->value.data, r->headers_in.if_unmodified_since->value.len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http iums:%d lm:%d", iums, r->headers_out.last_modified_time); + "http iums:%T lm:%T", iums, r->headers_out.last_modified_time); if (iums >= r->headers_out.last_modified_time) { return 1; @@ -134,6 +138,10 @@ ngx_http_test_if_modified(ngx_http_request_t *r) time_t ims; ngx_http_core_loc_conf_t *clcf; + if (r->headers_out.last_modified_time == (time_t) -1) { + return 1; + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) { @@ -144,7 +152,7 @@ ngx_http_test_if_modified(ngx_http_request_t *r) r->headers_in.if_modified_since->value.len); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http ims:%d lm:%d", ims, r->headers_out.last_modified_time); + "http ims:%T lm:%T", ims, r->headers_out.last_modified_time); if (ims == r->headers_out.last_modified_time) { return 0; @@ -161,10 +169,11 @@ ngx_http_test_if_modified(ngx_http_request_t *r) static ngx_uint_t -ngx_http_test_if_match(ngx_http_request_t *r, ngx_table_elt_t *header) +ngx_http_test_if_match(ngx_http_request_t *r, ngx_table_elt_t *header, + ngx_uint_t weak) { u_char *start, *end, ch; - ngx_str_t *etag, *list; + ngx_str_t etag, *list; list = &header->value; @@ -176,25 +185,42 @@ ngx_http_test_if_match(ngx_http_request_t *r, ngx_table_elt_t *header) return 0; } - etag = &r->headers_out.etag->value; + etag = r->headers_out.etag->value; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http im:\"%V\" etag:%V", list, etag); + "http im:\"%V\" etag:%V", list, &etag); + + if (weak + && etag.len > 2 + && etag.data[0] == 'W' + && etag.data[1] == '/') + { + etag.len -= 2; + etag.data += 2; + } start = list->data; end = list->data + list->len; while (start < end) { - if (etag->len > (size_t) (end - start)) { + if (weak + && end - start > 2 + && start[0] == 'W' + && start[1] == '/') + { + start += 2; + } + + if (etag.len > (size_t) (end - start)) { return 0; } - if (ngx_strncmp(start, etag->data, etag->len) != 0) { + if (ngx_strncmp(start, etag.data, etag.len) != 0) { goto skip; } - start += etag->len; + start += etag.len; while (start < end) { ch = *start; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 61af3dfd3..52c63e138 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -677,7 +677,7 @@ static ngx_keyval_t ngx_http_proxy_cache_headers[] = { { 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-None-Match"), ngx_string("$upstream_cache_etag") }, { ngx_string("If-Match"), ngx_string("") }, { ngx_string("Range"), ngx_string("") }, { ngx_string("If-Range"), ngx_string("") }, diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 884cb500a..d3a8f11b6 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -379,7 +379,7 @@ static ngx_keyval_t ngx_http_scgi_cache_headers[] = { { 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_NONE_MATCH"), ngx_string("$upstream_cache_etag") }, { ngx_string("HTTP_IF_MATCH"), ngx_string("") }, { ngx_string("HTTP_RANGE"), ngx_string("") }, { ngx_string("HTTP_IF_RANGE"), ngx_string("") }, diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index aeb1376b7..8236320c2 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -369,10 +369,13 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r) if (r == r->main) { ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); - ngx_http_clear_etag(r); if (!slcf->last_modified) { ngx_http_clear_last_modified(r); + ngx_http_clear_etag(r); + + } else { + ngx_http_weak_etag(r); } } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 730204cbb..4c69091d6 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -43,6 +43,8 @@ static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -91,6 +93,13 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, certificate_key), NULL }, + { ngx_string("ssl_password_file"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_http_ssl_password_file, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("ssl_dhparam"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -514,6 +523,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) sscf->buffer_size = NGX_CONF_UNSET_SIZE; sscf->verify = NGX_CONF_UNSET_UINT; sscf->verify_depth = NGX_CONF_UNSET_UINT; + sscf->passwords = NGX_CONF_UNSET_PTR; sscf->builtin_session_cache = NGX_CONF_UNSET; sscf->session_timeout = NGX_CONF_UNSET; sscf->session_tickets = NGX_CONF_UNSET; @@ -563,6 +573,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); + ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); + ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, @@ -652,7 +664,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) cln->data = &conf->ssl; if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, - &conf->certificate_key) + &conf->certificate_key, conf->passwords) != NGX_OK) { return NGX_CONF_ERROR; @@ -782,6 +794,29 @@ ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static char * +ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_ssl_srv_conf_t *sscf = conf; + + ngx_str_t *value; + + if (sscf->passwords != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + sscf->passwords = ngx_ssl_read_password_file(cf, &value[1]); + + if (sscf->passwords == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_ssl_srv_conf_t *sscf = conf; diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index ec2c62f6f..8e69e9e4d 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_str_t ciphers; + ngx_array_t *passwords; + ngx_shm_zone_t *shm_zone; ngx_flag_t session_tickets; diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c index 3ba59d627..5e6e038bf 100644 --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -175,10 +175,13 @@ ngx_http_sub_header_filter(ngx_http_request_t *r) if (r == r->main) { ngx_http_clear_content_length(r); - ngx_http_clear_etag(r); if (!slcf->last_modified) { ngx_http_clear_last_modified(r); + ngx_http_clear_etag(r); + + } else { + ngx_http_weak_etag(r); } } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 1d515cdf5..588b13547 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -507,7 +507,7 @@ static ngx_keyval_t ngx_http_uwsgi_cache_headers[] = { { 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_NONE_MATCH"), ngx_string("$upstream_cache_etag") }, { ngx_string("HTTP_IF_MATCH"), ngx_string("") }, { ngx_string("HTTP_RANGE"), ngx_string("") }, { ngx_string("HTTP_IF_RANGE"), ngx_string("") }, diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c index 9e85693bc..315081e47 100644 --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -337,12 +337,14 @@ ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, r->headers_out.content_length = NULL; } - ngx_http_clear_etag(r); - conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module); if (!conf->last_modified) { ngx_http_clear_last_modified(r); + ngx_http_clear_etag(r); + + } else { + ngx_http_weak_etag(r); } } diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index ce5adb737..31577f9a2 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -742,7 +742,7 @@ ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, if (named) { clcfp = ngx_palloc(cf->pool, - (n + 1) * sizeof(ngx_http_core_loc_conf_t **)); + (n + 1) * sizeof(ngx_http_core_loc_conf_t *)); if (clcfp == NULL) { return NGX_ERROR; } @@ -768,7 +768,7 @@ ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, if (regex) { clcfp = ngx_palloc(cf->pool, - (r + 1) * sizeof(ngx_http_core_loc_conf_t **)); + (r + 1) * sizeof(ngx_http_core_loc_conf_t *)); if (clcfp == NULL) { return NGX_ERROR; } diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h index 193a35322..1cfd9fe84 100644 --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -24,6 +24,9 @@ #define NGX_HTTP_CACHE_SCARCE 8 #define NGX_HTTP_CACHE_KEY_LEN 16 +#define NGX_HTTP_CACHE_ETAG_LEN 42 + +#define NGX_HTTP_CACHE_VERSION 2 typedef struct { @@ -67,6 +70,8 @@ struct ngx_http_cache_s { time_t last_modified; time_t date; + ngx_str_t etag; + size_t header_start; size_t body_start; off_t length; @@ -97,6 +102,7 @@ struct ngx_http_cache_s { typedef struct { + ngx_uint_t version; time_t valid_sec; time_t last_modified; time_t date; @@ -104,6 +110,8 @@ typedef struct { u_short valid_msec; u_short header_start; u_short body_start; + u_char etag_len; + u_char etag[NGX_HTTP_CACHE_ETAG_LEN]; } ngx_http_file_cache_header_t; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index fb02dd465..2947ad32a 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1851,6 +1851,46 @@ ngx_http_set_etag(ngx_http_request_t *r) } +void +ngx_http_weak_etag(ngx_http_request_t *r) +{ + size_t len; + u_char *p; + ngx_table_elt_t *etag; + + etag = r->headers_out.etag; + + if (etag == NULL) { + return; + } + + if (etag->value.len > 2 + && etag->value.data[0] == 'W' + && etag->value.data[1] == '/') + { + return; + } + + if (etag->value.len < 1 || etag->value.data[0] != '"') { + r->headers_out.etag->hash = 0; + r->headers_out.etag = NULL; + return; + } + + p = ngx_pnalloc(r->pool, etag->value.len + 2); + if (p == NULL) { + r->headers_out.etag->hash = 0; + r->headers_out.etag = NULL; + return; + } + + len = ngx_sprintf(p, "W/%V", &etag->value) - p; + + etag->value.data = p; + etag->value.len = len; +} + + ngx_int_t ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, ngx_str_t *ct, ngx_http_complex_value_t *cv) diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 799d2fe0d..285120de7 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -501,6 +501,7 @@ void *ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash); ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r); void ngx_http_set_exten(ngx_http_request_t *r); ngx_int_t ngx_http_set_etag(ngx_http_request_t *r); +void ngx_http_weak_etag(ngx_http_request_t *r); ngx_int_t ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status, ngx_str_t *ct, ngx_http_complex_value_t *cv); u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name, diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index 49abdb400..71e6e36c2 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -498,6 +498,12 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) h = (ngx_http_file_cache_header_t *) c->buf->pos; + if (h->version != NGX_HTTP_CACHE_VERSION) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "cache file \"%s\" version mismatch", c->file.name.data); + return NGX_DECLINED; + } + if (h->crc32 != c->crc32) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, "cache file \"%s\" has md5 collision", c->file.name.data); @@ -519,6 +525,8 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c) c->valid_msec = h->valid_msec; c->header_start = h->header_start; c->body_start = h->body_start; + c->etag.len = h->etag_len; + c->etag.data = h->etag; r->cached = 1; @@ -678,8 +686,8 @@ ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) goto done; } - fcn = ngx_slab_alloc_locked(cache->shpool, - sizeof(ngx_http_file_cache_node_t)); + fcn = ngx_slab_calloc_locked(cache->shpool, + sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { ngx_shmtx_unlock(&cache->shpool->mutex); @@ -687,8 +695,8 @@ ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) ngx_shmtx_lock(&cache->shpool->mutex); - fcn = ngx_slab_alloc_locked(cache->shpool, - sizeof(ngx_http_file_cache_node_t)); + fcn = ngx_slab_calloc_locked(cache->shpool, + sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { rc = NGX_ERROR; goto failed; @@ -704,8 +712,6 @@ ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) fcn->uses = 1; fcn->count = 1; - fcn->updating = 0; - fcn->deleting = 0; renew: @@ -877,6 +883,7 @@ ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) ngx_memzero(h, sizeof(ngx_http_file_cache_header_t)); + h->version = NGX_HTTP_CACHE_VERSION; h->valid_sec = c->valid_sec; h->last_modified = c->last_modified; h->date = c->date; @@ -885,6 +892,11 @@ ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) h->header_start = (u_short) c->header_start; h->body_start = (u_short) c->body_start; + if (c->etag.len <= NGX_HTTP_CACHE_ETAG_LEN) { + h->etag_len = (u_char) c->etag.len; + ngx_memcpy(h->etag, c->etag.data, c->etag.len); + } + p = buf + sizeof(ngx_http_file_cache_header_t); p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key)); @@ -1044,7 +1056,8 @@ ngx_http_file_cache_update_header(ngx_http_request_t *r) goto done; } - if (h.last_modified != c->last_modified + if (h.version != NGX_HTTP_CACHE_VERSION + || h.last_modified != c->last_modified || h.crc32 != c->crc32 || h.header_start != c->header_start || h.body_start != c->body_start) @@ -1062,6 +1075,7 @@ ngx_http_file_cache_update_header(ngx_http_request_t *r) ngx_memzero(&h, sizeof(ngx_http_file_cache_header_t)); + h.version = NGX_HTTP_CACHE_VERSION; h.valid_sec = c->valid_sec; h.last_modified = c->last_modified; h.date = c->date; @@ -1070,6 +1084,11 @@ ngx_http_file_cache_update_header(ngx_http_request_t *r) h.header_start = (u_short) c->header_start; h.body_start = (u_short) c->body_start; + if (c->etag.len <= NGX_HTTP_CACHE_ETAG_LEN) { + h.etag_len = (u_char) c->etag.len; + ngx_memcpy(h.etag, c->etag.data, c->etag.len); + } + (void) ngx_write_file(&file, (u_char *) &h, sizeof(ngx_http_file_cache_header_t), 0); @@ -1618,8 +1637,8 @@ ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) if (fcn == NULL) { - fcn = ngx_slab_alloc_locked(cache->shpool, - sizeof(ngx_http_file_cache_node_t)); + fcn = ngx_slab_calloc_locked(cache->shpool, + sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { ngx_shmtx_unlock(&cache->shpool->mutex); return NGX_ERROR; @@ -1633,15 +1652,7 @@ ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node); fcn->uses = 1; - fcn->count = 0; - fcn->valid_msec = 0; - fcn->error = 0; fcn->exists = 1; - fcn->updating = 0; - fcn->deleting = 0; - fcn->uniq = 0; - fcn->valid_sec = 0; - fcn->body_start = 0; fcn->fs_size = c->fs_size; cache->sh->size += c->fs_size; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 0d3a79915..f6ea6fb56 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -528,6 +528,7 @@ struct ngx_http_request_s { unsigned filter_need_temporary:1; unsigned allow_ranges:1; unsigned single_range:1; + unsigned disable_not_modified:1; #if (NGX_STAT_STUB) unsigned stat_reading:1; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 8b6d3f69f..012969170 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -19,6 +19,8 @@ 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); +static ngx_int_t ngx_http_upstream_cache_etag(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); @@ -87,6 +89,8 @@ static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_process_last_modified(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t @@ -174,8 +178,7 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { ngx_http_upstream_copy_content_type, 0, 1 }, { ngx_string("Content-Length"), - ngx_http_upstream_process_content_length, - offsetof(ngx_http_upstream_headers_in_t, content_length), + ngx_http_upstream_process_content_length, 0, ngx_http_upstream_ignore_header_line, 0, 0 }, { ngx_string("Date"), @@ -185,8 +188,7 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { offsetof(ngx_http_headers_out_t, date), 0 }, { ngx_string("Last-Modified"), - ngx_http_upstream_process_header_line, - offsetof(ngx_http_upstream_headers_in_t, last_modified), + ngx_http_upstream_process_last_modified, 0, ngx_http_upstream_copy_last_modified, 0, 0 }, { ngx_string("ETag"), @@ -367,6 +369,10 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { ngx_http_upstream_cache_last_modified, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + { ngx_string("upstream_cache_etag"), NULL, + ngx_http_upstream_cache_etag, 0, + NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + #endif { ngx_null_string, NULL, NULL, 0, 0, 0 } @@ -1668,13 +1674,6 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; } - ngx_add_timer(c->read, u->conf->read_timeout); - - if (c->read->ready) { - ngx_http_upstream_process_header(r, u); - return; - } - u->write_event_handler = ngx_http_upstream_dummy_handler; if (ngx_handle_write_event(c->write, 0) != NGX_OK) { @@ -1682,6 +1681,13 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) NGX_HTTP_INTERNAL_SERVER_ERROR); return; } + + ngx_add_timer(c->read, u->conf->read_timeout); + + if (c->read->ready) { + ngx_http_upstream_process_header(r, u); + return; + } } @@ -2238,6 +2244,8 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) r->headers_out.content_length_n = u->headers_in.content_length_n; + r->disable_not_modified = !u->cacheable; + u->length = -1; return NGX_OK; @@ -2349,21 +2357,17 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) if (r->header_only) { - if (u->cacheable || u->store) { - - if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { - ngx_connection_error(c, ngx_socket_errno, - ngx_shutdown_socket_n " failed"); - } - - r->read_event_handler = ngx_http_request_empty_handler; - r->write_event_handler = ngx_http_request_empty_handler; - c->error = 1; + if (!u->buffering) { + ngx_http_upstream_finalize_request(r, u, rc); + return; + } - } else { + if (!u->cacheable && !u->store) { ngx_http_upstream_finalize_request(r, u, rc); return; } + + u->pipe->downstream_error = 1; } if (r->request_body && r->request_body->temp_file) { @@ -2492,15 +2496,18 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) } if (valid) { - r->cache->last_modified = r->headers_out.last_modified_time; + r->cache->last_modified = u->headers_in.last_modified_time; r->cache->date = now; r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start); + if (u->headers_in.etag) { + r->cache->etag = u->headers_in.etag->value; + } + ngx_http_file_cache_set_header(r, u->buffer.start); } else { u->cacheable = 0; - r->headers_out.last_modified_time = -1; } } @@ -3730,6 +3737,29 @@ ngx_http_upstream_process_content_length(ngx_http_request_t *r, static ngx_int_t +ngx_http_upstream_process_last_modified(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_http_upstream_t *u; + + u = r->upstream; + + u->headers_in.last_modified = h; + +#if (NGX_HTTP_CACHE) + + if (u->cacheable) { + u->headers_in.last_modified_time = ngx_http_parse_time(h->value.data, + h->value.len); + } + +#endif + + return NGX_OK; +} + + +static ngx_int_t ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { @@ -4185,8 +4215,8 @@ ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h, #if (NGX_HTTP_CACHE) if (r->upstream->cacheable) { - r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data, - h->value.len); + r->headers_out.last_modified_time = + r->upstream->headers_in.last_modified_time; } #endif @@ -4764,6 +4794,29 @@ ngx_http_upstream_cache_last_modified(ngx_http_request_t *r, return NGX_OK; } + +static ngx_int_t +ngx_http_upstream_cache_etag(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->upstream == NULL + || !r->upstream->conf->cache_revalidate + || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED + || r->cache->etag.len == 0) + { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = r->cache->etag.len; + v->data = r->cache->etag.data; + + return NGX_OK; +} + #endif @@ -4851,6 +4904,12 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) } } + uscf->servers = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_upstream_server_t)); + if (uscf->servers == NULL) { + return NGX_CONF_ERROR; + } + /* parse inside upstream{} */ @@ -4866,7 +4925,7 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) return rv; } - if (uscf->servers == NULL) { + if (uscf->servers->nelts == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no servers are inside upstream"); return NGX_CONF_ERROR; @@ -4888,14 +4947,6 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_uint_t i; ngx_http_upstream_server_t *us; - if (uscf->servers == NULL) { - uscf->servers = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_upstream_server_t)); - if (uscf->servers == NULL) { - return NGX_CONF_ERROR; - } - } - us = ngx_array_push(uscf->servers); if (us == NULL) { return NGX_CONF_ERROR; @@ -4905,20 +4956,6 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) value = cf->args->elts; - ngx_memzero(&u, sizeof(ngx_url_t)); - - u.url = value[1]; - u.default_port = 80; - - if (ngx_parse_url(cf->pool, &u) != NGX_OK) { - if (u.err) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "%s in upstream \"%V\"", u.err, &u.url); - } - - return NGX_CONF_ERROR; - } - weight = 1; max_fails = 1; fail_timeout = 10; @@ -4998,6 +5035,20 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) goto invalid; } + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = value[1]; + u.default_port = 80; + + if (ngx_parse_url(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in upstream \"%V\"", u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + us->name = u.url; us->addrs = u.addrs; us->naddrs = u.naddrs; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 3128ccef0..dafb5a319 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -246,11 +246,12 @@ typedef struct { ngx_table_elt_t *content_encoding; #endif - off_t content_length_n; - ngx_array_t cache_control; ngx_array_t cookies; + off_t content_length_n; + time_t last_modified_time; + unsigned connection_close:1; unsigned chunked:1; } ngx_http_upstream_headers_in_t; diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index fe88f48e4..f864d9910 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -21,6 +21,8 @@ static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -74,6 +76,13 @@ static ngx_command_t ngx_mail_ssl_commands[] = { offsetof(ngx_mail_ssl_conf_t, certificate_key), NULL }, + { ngx_string("ssl_password_file"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_mail_ssl_password_file, + NGX_MAIL_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("ssl_dhparam"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -195,6 +204,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) scf->enable = NGX_CONF_UNSET; scf->starttls = NGX_CONF_UNSET_UINT; + scf->passwords = NGX_CONF_UNSET_PTR; scf->prefer_server_ciphers = NGX_CONF_UNSET; scf->builtin_session_cache = NGX_CONF_UNSET; scf->session_timeout = NGX_CONF_UNSET; @@ -231,6 +241,8 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); + ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); + ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, @@ -302,7 +314,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) cln->data = &conf->ssl; if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, - &conf->certificate_key) + &conf->certificate_key, conf->passwords) != NGX_OK) { return NGX_CONF_ERROR; @@ -422,6 +434,29 @@ ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static char * +ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_ssl_conf_t *scf = conf; + + ngx_str_t *value; + + if (scf->passwords != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + scf->passwords = ngx_ssl_read_password_file(cf, &value[1]); + + if (scf->passwords == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_mail_ssl_conf_t *scf = conf; diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h index bef0e515a..987d029ef 100644 --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -39,6 +39,8 @@ typedef struct { ngx_str_t ciphers; + ngx_array_t *passwords; + ngx_shm_zone_t *shm_zone; ngx_flag_t session_tickets; diff --git a/src/os/unix/ngx_darwin_sendfile_chain.c b/src/os/unix/ngx_darwin_sendfile_chain.c index 76c4a3a4d..ee44e1d58 100644 --- a/src/os/unix/ngx_darwin_sendfile_chain.c +++ b/src/os/unix/ngx_darwin_sendfile_chain.c @@ -13,7 +13,7 @@ /* * It seems that Darwin 9.4 (Mac OS X 1.5) sendfile() has the same * old bug as early FreeBSD sendfile() syscall: - * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771 + * http://bugs.freebsd.org/33771 * * Besides sendfile() has another bug: if one calls sendfile() * with both a header and a trailer, then sendfile() ignores a file part diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index 11cec8226..6491e928f 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -265,7 +265,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) /* * the "nbytes bug" of the old sendfile() syscall: - * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771 + * http://bugs.freebsd.org/33771 */ if (!ngx_freebsd_sendfile_nbytes_bug) { |