# HG changeset patch # User Igor Sysoev # Date 1324843200 -14400 # Node ID 9d21dad0b5a102d08e1fb17822291fcad16cae64 # Parent 189afff6503fdb14e2ba72336a68d6673637f7d7 nginx 1.1.12 *) Change: a "proxy_pass" directive without URI part now uses changed URI after redirection with the "error_page" directive; Thanks to Lanshun Zhou. *) Feature: the "proxy/fastcgi/scgi/uwsgi_cache_lock", "proxy/fastcgi/scgi/uwsgi_cache_lock_timeout" directives. *) Feature: the "pcre_jit" directive. *) Feature: the "if" SSI command supports captures in regular expressions. *) Bugfix: the "if" SSI command did not work inside the "block" command. *) Bugfix: the "limit_conn_log_level" and "limit_req_log_level" directives might not work. *) Bugfix: the "limit_rate" directive did not allow to use full throughput, even if limit value was very high. *) Bugfix: the "sendfile_max_chunk" directive did not work, if the "limit_rate" directive was used. *) Bugfix: a "proxy_pass" directive without URI part always used original request URI if variables were used. *) Bugfix: a "proxy_pass" directive without URI part might use original request after redirection with the "try_files" directive; Thanks to Lanshun Zhou. *) Bugfix: in the ngx_http_scgi_module. *) Bugfix: in the ngx_http_mp4_module. *) Bugfix: nginx could not be built on Solaris; the bug had appeared in 1.1.9. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,44 @@ +Changes with nginx 1.1.12 26 Dec 2011 + + *) Change: a "proxy_pass" directive without URI part now uses changed + URI after redirection with the "error_page" directive; + Thanks to Lanshun Zhou. + + *) Feature: the "proxy/fastcgi/scgi/uwsgi_cache_lock", + "proxy/fastcgi/scgi/uwsgi_cache_lock_timeout" directives. + + *) Feature: the "pcre_jit" directive. + + *) Feature: the "if" SSI command supports captures in regular + expressions. + + *) Bugfix: the "if" SSI command did not work inside the "block" command. + + *) Bugfix: the "limit_conn_log_level" and "limit_req_log_level" + directives might not work. + + *) Bugfix: the "limit_rate" directive did not allow to use full + throughput, even if limit value was very high. + + *) Bugfix: the "sendfile_max_chunk" directive did not work, if the + "limit_rate" directive was used. + + *) Bugfix: a "proxy_pass" directive without URI part always used + original request URI if variables were used. + + *) Bugfix: a "proxy_pass" directive without URI part might use original + request after redirection with the "try_files" directive; + Thanks to Lanshun Zhou. + + *) Bugfix: in the ngx_http_scgi_module. + + *) Bugfix: in the ngx_http_mp4_module. + + *) Bugfix: nginx could not be built on Solaris; the bug had appeared in + 1.1.9. + + Changes with nginx 1.1.11 12 Dec 2011 *) Feature: the "so_keepalive" parameter of the "listen" directive. @@ -4564,8 +4604,8 @@ Changes with nginx 0.3.6 *) Bugfix: if at least in one server was no the "listen" directive, then nginx did not listen on the 80 port; the bug had appeared in 0.3.3. - *) Bugfix: if the URI part is omitted in "proxy_pass" directive, the the - 80 port was always used. + *) Bugfix: if the URI part is omitted in "proxy_pass" directive, the 80 + port was always used. Changes with nginx 0.3.5 21 Oct 2005 @@ -4810,7 +4850,7 @@ Changes with nginx 0.1.43 *) Bugfix: the segmentation fault occurred or the worker process may got caught in an endless loop if the proxied or FastCGI server sent the "Cache-Control" header line and the "expires" directive was used; in - the proxied mode the the bug had appeared in 0.1.29. + the proxied mode the bug had appeared in 0.1.29. Changes with nginx 0.1.42 23 Aug 2005 @@ -4885,8 +4925,8 @@ Changes with nginx 0.1.39 Changes with nginx 0.1.38 08 Jul 2005 - *) Feature: the "limit_rate" directive is supported in in proxy and - FastCGI mode. + *) Feature: the "limit_rate" directive is supported in proxy and FastCGI + mode. *) Feature: the "X-Accel-Limit-Rate" response header line is supported in proxy and FastCGI mode. @@ -5038,8 +5078,7 @@ Changes with nginx 0.1.30 *) Bugfix: if the length of the response part received at once from proxied or FastCGI server was equal to 500, then nginx returns the - 500 response code; in proxy mode the the bug had appeared in 0.1.29 - only. + 500 response code; in proxy mode the bug had appeared in 0.1.29 only. *) Bugfix: nginx did not consider the directives with 8 or 9 parameters as invalid. @@ -5282,7 +5321,7 @@ Changes with nginx 0.1.19 *) Bugfix: nginx could not be built on NetBSD 2.0. - *) Bugfix: the timeout may occur while reading of the the client request + *) Bugfix: the timeout may occur while reading of the client request body via SSL connections. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,45 @@ +Изменения в nginx 1.1.12 26.12.2011 + + *) Изменение: после перенаправления запроса с помощью директивы + error_page директива proxy_pass без URI теперь использует изменённый + URI; + Спасибо Lanshun Zhou. + + *) Добавление: директивы proxy/fastcgi/scgi/uwsgi_cache_lock, + proxy/fastcgi/scgi/uwsgi_cache_lock_timeout. + + *) Добавление: директива pcre_jit. + + *) Добавление: SSI команда if поддерживает выделения в регулярных + выражениях. + + *) Исправление: SSI команда if не работала внутри команды block. + + *) Исправление: директивы limit_conn_log_level и limit_req_log_level + могли не работать. + + *) Исправление: директива limit_rate не позволяла передавать на полной + скорости, даже если был указан очень большой лимит. + + *) Исправление: директива sendfile_max_chunk не работала, если + использовалась директива limit_rate. + + *) Исправление: если в директиве proxy_pass использовались переменные и + не был указан URI, всегда использовался URI исходного запроса. + + *) Исправление: после перенаправления запроса с помощью директивы + try_files директива proxy_pass без URI могла использовать URI + исходного запроса; + Спасибо Lanshun Zhou. + + *) Исправление: в модуле ngx_http_scgi_module. + + *) Исправление: в модуле ngx_http_mp4_module. + + *) Исправление: nginx не собирался на Solaris; ошибка появилась в 1.1.9. + + Изменения в nginx 1.1.11 12.12.2011 *) Добавление: параметр so_keepalive в директиве listen. diff --git a/auto/install b/auto/install --- a/auto/install +++ b/auto/install @@ -72,7 +72,7 @@ case ".$NGX_HTTP_LOG_PATH" in esac -if test -e man/nginx.8 ; then +if test -f man/nginx.8 ; then NGX_MAN=man/nginx.8 else NGX_MAN=docs/man/nginx.8 diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -4,8 +4,6 @@ if [ $PCRE != NONE ]; then CORE_INCS="$CORE_INCS $PCRE" - CORE_DEPS="$CORE_DEPS $REGEX_DEPS" - CORE_SRCS="$CORE_SRCS $REGEX_SRCS" case "$NGX_CC_NAME" in @@ -81,6 +79,12 @@ if [ $PCRE != NONE ]; then esac + + if [ $PCRE_JIT = YES ]; then + have=NGX_HAVE_PCRE_JIT . auto/have + PCRE_CONF_OPT="$PCRE_CONF_OPT --enable-jit" + fi + else if [ "$NGX_PLATFORM" != win32 ]; then @@ -156,12 +160,23 @@ else fi if [ $ngx_found = yes ]; then - CORE_DEPS="$CORE_DEPS $REGEX_DEPS" - CORE_SRCS="$CORE_SRCS $REGEX_SRCS" CORE_INCS="$CORE_INCS $ngx_feature_path" CORE_LIBS="$CORE_LIBS $ngx_feature_libs" PCRE=YES fi + + if [ $PCRE == YES ]; then + ngx_feature="PCRE JIT support" + ngx_feature_name="NGX_HAVE_PCRE_JIT" + ngx_feature_test="int jit = 0; + pcre_config(PCRE_CONFIG_JIT, &jit); + if (jit != 1) return 1;" + . auto/feature + + if [ $ngx_found = yes ]; then + PCRE_JIT=YES + fi + fi fi if [ $PCRE != YES ]; then diff --git a/auto/lib/pcre/make b/auto/lib/pcre/make --- a/auto/lib/pcre/make +++ b/auto/lib/pcre/make @@ -50,7 +50,7 @@ END cd $PCRE \\ && if [ -f Makefile ]; then \$(MAKE) distclean; fi \\ && CC="\$(CC)" CFLAGS="$PCRE_OPT" \\ - ./configure --disable-shared + ./configure --disable-shared $PCRE_CONF_OPT $PCRE/.libs/libpcre.a: $PCRE/Makefile cd $PCRE \\ diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -396,6 +396,12 @@ if [ $USE_OPENSSL = YES ]; then CORE_SRCS="$CORE_SRCS $OPENSSL_SRCS" fi +if [ $USE_PCRE = YES ]; then + modules="$modules $REGEX_MODULE" + CORE_DEPS="$CORE_DEPS $REGEX_DEPS" + CORE_SRCS="$CORE_SRCS $REGEX_SRCS" +fi + if [ $HTTP = YES ]; then modules="$modules $HTTP_MODULES $HTTP_FILTER_MODULES \ $HTTP_HEADERS_FILTER_MODULE \ diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -111,6 +111,8 @@ NGX_ADDONS= USE_PCRE=NO PCRE=NONE PCRE_OPT= +PCRE_CONF_OPT= +PCRE_JIT=NO USE_OPENSSL=NO OPENSSL=NONE @@ -274,6 +276,7 @@ use the \"--without-http_limit_conn_modu --with-pcre) USE_PCRE=YES ;; --with-pcre=*) PCRE="$value" ;; --with-pcre-opt=*) PCRE_OPT="$value" ;; + --with-pcre-jit) PCRE_JIT=YES ;; --with-openssl=*) OPENSSL="$value" ;; --with-openssl-opt=*) OPENSSL_OPT="$value" ;; @@ -421,6 +424,7 @@ cat << END --with-pcre force PCRE library usage --with-pcre=DIR set path to PCRE library sources --with-pcre-opt=OPTIONS set additional build options for PCRE + --with-pcre-jit build PCRE with JIT compilation support --with-md5=DIR set path to md5 library sources --with-md5-opt=OPTIONS set additional build options for md5 diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -69,6 +69,7 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_crypt.c" +REGEX_MODULE=ngx_regex_module REGEX_DEPS=src/core/ngx_regex.h REGEX_SRCS=src/core/ngx_regex.c diff --git a/conf/fastcgi.conf b/conf/fastcgi.conf --- a/conf/fastcgi.conf +++ b/conf/fastcgi.conf @@ -10,6 +10,7 @@ fastcgi_param REQUEST_URI $reque fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; +fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,7 +9,7 @@ #define nginx_version 1001011 -#define NGINX_VERSION "1.1.11" +#define NGINX_VERSION "1.1.12" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -8,11 +8,61 @@ #include +typedef struct { + ngx_flag_t pcre_jit; +} ngx_regex_conf_t; + + static void * ngx_libc_cdecl ngx_regex_malloc(size_t size); static void ngx_libc_cdecl ngx_regex_free(void *p); +static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle); + +static void *ngx_regex_create_conf(ngx_cycle_t *cycle); +static char *ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf); + +static char *ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data); +static ngx_conf_post_t ngx_regex_pcre_jit_post = { ngx_regex_pcre_jit }; + + +static ngx_command_t ngx_regex_commands[] = { + + { ngx_string("pcre_jit"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + 0, + offsetof(ngx_regex_conf_t, pcre_jit), + &ngx_regex_pcre_jit_post }, + + ngx_null_command +}; + + +static ngx_core_module_t ngx_regex_module_ctx = { + ngx_string("regex"), + ngx_regex_create_conf, + ngx_regex_init_conf +}; + + +ngx_module_t ngx_regex_module = { + NGX_MODULE_V1, + &ngx_regex_module_ctx, /* module context */ + ngx_regex_commands, /* module directives */ + NGX_CORE_MODULE, /* module type */ + NULL, /* init master */ + ngx_regex_module_init, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + static ngx_pool_t *ngx_pcre_pool; +static ngx_list_t *ngx_pcre_studies; void @@ -62,10 +112,11 @@ ngx_regex_malloc_done(void) ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc) { - int n, erroff; - char *p; - const char *errstr; - ngx_regex_t *re; + int n, erroff; + char *p; + pcre *re; + const char *errstr; + ngx_regex_elt_t *elt; ngx_regex_malloc_init(rc->pool); @@ -92,7 +143,24 @@ ngx_regex_compile(ngx_regex_compile_t *r return NGX_ERROR; } - rc->regex = re; + rc->regex = ngx_pcalloc(rc->pool, sizeof(ngx_regex_t)); + if (rc->regex == NULL) { + return NGX_ERROR; + } + + rc->regex->pcre = re; + + /* do not study at runtime */ + + if (ngx_pcre_studies != NULL) { + elt = ngx_list_push(ngx_pcre_studies); + if (elt == NULL) { + return NGX_ERROR; + } + + elt->regex = rc->regex; + elt->name = rc->pattern.data; + } n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures); if (n < 0) { @@ -203,3 +271,140 @@ ngx_regex_free(void *p) { return; } + + +static ngx_int_t +ngx_regex_module_init(ngx_cycle_t *cycle) +{ + int opt; + const char *errstr; + ngx_uint_t i; + ngx_list_part_t *part; + ngx_regex_elt_t *elts; + + opt = 0; + +#if (NGX_HAVE_PCRE_JIT) + { + ngx_regex_conf_t *rcf; + + rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module); + + if (rcf->pcre_jit) { + opt = PCRE_STUDY_JIT_COMPILE; + } + } +#endif + + ngx_regex_malloc_init(cycle->pool); + + part = &ngx_pcre_studies->part; + elts = part->elts; + + for (i = 0 ; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + elts = part->elts; + i = 0; + } + + elts[i].regex->extra = pcre_study(elts[i].regex->pcre, opt, &errstr); + + if (errstr != NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "pcre_study() failed: %s in \"%s\"", + errstr, elts[i].name); + } + +#if (NGX_HAVE_PCRE_JIT) + if (opt & PCRE_STUDY_JIT_COMPILE) { + int jit, n; + + jit = 0; + n = pcre_fullinfo(elts[i].regex->pcre, elts[i].regex->extra, + PCRE_INFO_JIT, &jit); + + if (n != 0 || jit != 1) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "JIT compiler does not support pattern: \"%s\"", + elts[i].name); + } + } +#endif + } + + ngx_regex_malloc_done(); + + ngx_pcre_studies = NULL; + + return NGX_OK; +} + + +static void * +ngx_regex_create_conf(ngx_cycle_t *cycle) +{ + ngx_regex_conf_t *rcf; + + rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t)); + if (rcf == NULL) { + return NULL; + } + + rcf->pcre_jit = NGX_CONF_UNSET; + + ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); + if (ngx_pcre_studies == NULL) { + return NULL; + } + + return rcf; +} + + +static char * +ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_regex_conf_t *rcf = conf; + + ngx_conf_init_value(rcf->pcre_jit, 0); + + return NGX_CONF_OK; +} + + +static char * +ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data) +{ + ngx_flag_t *fp = data; + + if (*fp == 0) { + return NGX_CONF_OK; + } + +#if (NGX_HAVE_PCRE_JIT) + { + int jit, r; + + jit = 0; + r = pcre_config(PCRE_CONFIG_JIT, &jit); + + if (r != 0 || jit != 1) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "PCRE library does not support JIT"); + *fp = 0; + } + } +#else + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "nginx was build without PCRE JIT support"); + *fp = 0; +#endif + + return NGX_CONF_OK; +} diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -18,7 +18,11 @@ #define NGX_REGEX_CASELESS PCRE_CASELESS -typedef pcre ngx_regex_t; + +typedef struct { + pcre *pcre; + pcre_extra *extra; +} ngx_regex_t; typedef struct { @@ -45,7 +49,7 @@ void ngx_regex_init(void); ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc); #define ngx_regex_exec(re, s, captures, size) \ - pcre_exec(re, NULL, (const char *) (s)->data, (s)->len, 0, 0, \ + pcre_exec(re->pcre, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \ captures, size) #define ngx_regex_exec_n "pcre_exec()" diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -380,6 +380,20 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_methods), &ngx_http_upstream_cache_method_mask }, + { ngx_string("fastcgi_cache_lock"), + 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_lock), + NULL }, + + { ngx_string("fastcgi_cache_lock_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout), + NULL }, + #endif { ngx_string("fastcgi_temp_path"), @@ -2086,6 +2100,8 @@ ngx_http_fastcgi_create_loc_conf(ngx_con conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; + conf->upstream.cache_lock = NGX_CONF_UNSET; + conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC; #endif conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; @@ -2323,6 +2339,12 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf conf->cache_key = prev->cache_key; } + ngx_conf_merge_value(conf->upstream.cache_lock, + prev->upstream.cache_lock, 0); + + ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout, + prev->upstream.cache_lock_timeout, 5000); + #endif ngx_conf_merge_value(conf->upstream.pass_request_headers, diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c --- a/src/http/modules/ngx_http_limit_conn_module.c +++ b/src/http/modules/ngx_http_limit_conn_module.c @@ -483,7 +483,7 @@ ngx_http_limit_conn_merge_conf(ngx_conf_ ngx_http_limit_conn_conf_t *conf = child; if (conf->limits.elts == NULL) { - *conf = *prev; + conf->limits = prev->limits; } ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR); diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -569,7 +569,7 @@ ngx_http_limit_req_merge_conf(ngx_conf_t ngx_http_limit_req_conf_t *conf = child; if (conf->shm_zone == NULL) { - *conf = *prev; + conf->shm_zone = prev->shm_zone; } ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level, diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -2382,6 +2382,8 @@ found: data->pos = (u_char *) entry; atom_size = sizeof(ngx_mp4_stsc_atom_t) + (data->last - data->pos); + ngx_mp4_set_32value(entry->chunk, 1); + if (trak->chunk_samples) { first = &trak->stsc_chunk_entry; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -402,6 +402,20 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods), &ngx_http_upstream_cache_method_mask }, + { ngx_string("proxy_cache_lock"), + 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_lock), + NULL }, + + { ngx_string("proxy_cache_lock_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout), + NULL }, + #endif { ngx_string("proxy_temp_path"), @@ -736,9 +750,6 @@ ngx_http_proxy_eval(ngx_http_request_t * url.uri.len++; url.uri.data = p - 1; } - - } else { - url.uri = r->unparsed_uri; } ctx->vars.key_start = u->schema; @@ -806,7 +817,7 @@ ngx_http_proxy_create_key(ngx_http_reque return NGX_ERROR; } - if (plcf->proxy_lengths) { + if (plcf->proxy_lengths && ctx->vars.uri.len) { *key = ctx->vars.uri; u->uri = ctx->vars.uri; @@ -916,7 +927,7 @@ ngx_http_proxy_create_request(ngx_http_r loc_len = 0; unparsed_uri = 0; - if (plcf->proxy_lengths) { + if (plcf->proxy_lengths && ctx->vars.uri.len) { uri_len = ctx->vars.uri.len; } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main) @@ -1022,7 +1033,7 @@ ngx_http_proxy_create_request(ngx_http_r u->uri.data = b->last; - if (plcf->proxy_lengths) { + if (plcf->proxy_lengths && ctx->vars.uri.len) { b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len); } else if (unparsed_uri) { @@ -2438,6 +2449,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; + conf->upstream.cache_lock = NGX_CONF_UNSET; + conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC; #endif conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; @@ -2684,6 +2697,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t conf->cache_key = prev->cache_key; } + ngx_conf_merge_value(conf->upstream.cache_lock, + prev->upstream.cache_lock, 0); + + ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout, + prev->upstream.cache_lock_timeout, 5000); + #endif if (conf->method.len == 0) { diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -36,7 +36,6 @@ static ngx_int_t ngx_http_scgi_create_re static ngx_int_t ngx_http_scgi_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_scgi_process_status_line(ngx_http_request_t *r); static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r); -static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r); static void ngx_http_scgi_abort_request(ngx_http_request_t *r); static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc); @@ -247,6 +246,20 @@ static ngx_command_t ngx_http_scgi_comma offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_methods), &ngx_http_upstream_cache_method_mask }, + { ngx_string("scgi_cache_lock"), + 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_lock), + NULL }, + + { ngx_string("scgi_cache_lock_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout), + NULL }, + #endif { ngx_string("scgi_temp_path"), @@ -857,11 +870,7 @@ ngx_http_scgi_process_status_line(ngx_ht } if (rc == NGX_ERROR) { - - r->http_version = NGX_HTTP_VERSION_9; - u->process_header = ngx_http_scgi_process_header; - return ngx_http_scgi_process_header(r); } @@ -961,12 +970,12 @@ ngx_http_scgi_process_header(ngx_http_re ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http scgi header done"); - if (r->http_version > NGX_HTTP_VERSION_9) { + u = r->upstream; + + if (u->headers_in.status_n) { return NGX_OK; } - u = r->upstream; - if (u->headers_in.status) { status_line = &u->headers_in.status->value; @@ -978,20 +987,15 @@ ngx_http_scgi_process_header(ngx_http_re return NGX_HTTP_UPSTREAM_INVALID_HEADER; } - r->http_version = NGX_HTTP_VERSION_10; u->headers_in.status_n = status; u->headers_in.status_line = *status_line; } else if (u->headers_in.location) { - r->http_version = NGX_HTTP_VERSION_10; u->headers_in.status_n = 302; ngx_str_set(&u->headers_in.status_line, "302 Moved Temporarily"); } else { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent neither valid HTTP/1.0 header " - "nor \"Status\" header line"); u->headers_in.status_n = 200; ngx_str_set(&u->headers_in.status_line, "200 OK"); } @@ -1072,6 +1076,8 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; + conf->upstream.cache_lock = NGX_CONF_UNSET; + conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC; #endif conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; @@ -1299,6 +1305,12 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t conf->cache_key = prev->cache_key; } + ngx_conf_merge_value(conf->upstream.cache_lock, + prev->upstream.cache_lock, 0); + + ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout, + prev->upstream.cache_lock_timeout, 5000); + #endif ngx_conf_merge_value(conf->upstream.pass_request_headers, diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -78,6 +78,8 @@ static ngx_str_t *ngx_http_ssi_get_varia ngx_str_t *name, ngx_uint_t key); static ngx_int_t ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t *text, ngx_uint_t flags); +static ngx_int_t ngx_http_ssi_regex_match(ngx_http_request_t *r, + ngx_str_t *pattern, ngx_str_t *str); static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); @@ -624,16 +626,6 @@ ngx_http_ssi_body_filter(ngx_http_reques continue; } - if (cmd->conditional - && (ctx->conditional == 0 - || ctx->conditional > cmd->conditional)) - { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid context of SSI command: \"%V\"", - &ctx->command); - goto ssi_error; - } - if (!ctx->output && !cmd->block) { if (ctx->block) { @@ -709,6 +701,16 @@ ngx_http_ssi_body_filter(ngx_http_reques } } + if (cmd->conditional + && (ctx->conditional == 0 + || ctx->conditional > cmd->conditional)) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid context of SSI command: \"%V\"", + &ctx->command); + goto ssi_error; + } + if (ctx->params.nelts > NGX_HTTP_SSI_MAX_PARAMS) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "too many SSI command paramters: \"%V\"", @@ -1531,6 +1533,30 @@ ngx_http_ssi_get_variable(ngx_http_reque ctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module); +#if (NGX_PCRE) + { + ngx_str_t *value; + + if (key >= '0' && key <= '9') { + i = key - '0'; + + if (i < ctx->ncaptures) { + value = ngx_palloc(r->pool, sizeof(ngx_str_t)); + if (value == NULL) { + return NULL; + } + + i *= 2; + + value->data = ctx->captures_data + ctx->captures[i]; + value->len = ctx->captures[i + 1] - ctx->captures[i]; + + return value; + } + } + } +#endif + if (ctx->variables == NULL) { return NULL; } @@ -1820,6 +1846,115 @@ invalid_variable: static ngx_int_t +ngx_http_ssi_regex_match(ngx_http_request_t *r, ngx_str_t *pattern, + ngx_str_t *str) +{ +#if (NGX_PCRE) + int rc, *captures; + u_char *p, errstr[NGX_MAX_CONF_ERRSTR]; + size_t size; + ngx_int_t key; + ngx_str_t *vv, name, value; + ngx_uint_t i, n; + ngx_http_ssi_ctx_t *ctx; + ngx_http_ssi_var_t *var; + ngx_regex_compile_t rgc; + + ngx_memzero(&rgc, sizeof(ngx_regex_compile_t)); + + rgc.pattern = *pattern; + rgc.pool = r->pool; + rgc.err.len = NGX_MAX_CONF_ERRSTR; + rgc.err.data = errstr; + + if (ngx_regex_compile(&rgc) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V", &rgc.err); + return NGX_HTTP_SSI_ERROR; + } + + n = (rgc.captures + 1) * 3; + + captures = ngx_palloc(r->pool, n * sizeof(int)); + if (captures == NULL) { + return NGX_ERROR; + } + + rc = ngx_regex_exec(rgc.regex, str, captures, n); + + if (rc < NGX_REGEX_NO_MATCHED) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", + rc, str, pattern); + return NGX_HTTP_SSI_ERROR; + } + + if (rc == NGX_REGEX_NO_MATCHED) { + return NGX_DECLINED; + } + + ctx = ngx_http_get_module_ctx(r->main, ngx_http_ssi_filter_module); + + ctx->ncaptures = rc; + ctx->captures = captures; + ctx->captures_data = str->data; + + if (rgc.named_captures > 0) { + + if (ctx->variables == NULL) { + ctx->variables = ngx_list_create(r->pool, 4, + sizeof(ngx_http_ssi_var_t)); + if (ctx->variables == NULL) { + return NGX_ERROR; + } + } + + size = rgc.name_size; + p = rgc.names; + + for (i = 0; i < (ngx_uint_t) rgc.named_captures; i++, p += size) { + + name.data = &p[2]; + name.len = ngx_strlen(name.data); + + n = 2 * ((p[0] << 8) + p[1]); + + value.data = &str->data[captures[n]]; + value.len = captures[n + 1] - captures[n]; + + key = ngx_hash_strlow(name.data, name.data, name.len); + + vv = ngx_http_ssi_get_variable(r, &name, key); + + if (vv) { + *vv = value; + continue; + } + + var = ngx_list_push(ctx->variables); + if (var == NULL) { + return NGX_ERROR; + } + + var->name = name; + var->key = key; + var->value = value; + } + } + + return NGX_OK; + +#else + + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "the using of the regex \"%V\" in SSI requires PCRE library", + pattern); + return NGX_HTTP_SSI_ERROR; + +#endif +} + + +static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { @@ -2451,39 +2586,17 @@ ngx_http_ssi_if(ngx_http_request_t *r, n } } else { -#if (NGX_PCRE) - ngx_regex_compile_t rgc; - u_char errstr[NGX_MAX_CONF_ERRSTR]; - right.data[right.len] = '\0'; - ngx_memzero(&rgc, sizeof(ngx_regex_compile_t)); - - rgc.pattern = right; - rgc.pool = r->pool; - rgc.err.len = NGX_MAX_CONF_ERRSTR; - rgc.err.data = errstr; - - if (ngx_regex_compile(&rgc) != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%V", &rgc.err); - return NGX_HTTP_SSI_ERROR; + rc = ngx_http_ssi_regex_match(r, &right, &left); + + if (rc == NGX_OK) { + rc = 0; + } else if (rc == NGX_DECLINED) { + rc = -1; + } else { + return rc; } - - rc = ngx_regex_exec(rgc.regex, &left, NULL, 0); - - if (rc < NGX_REGEX_NO_MATCHED) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"", - rc, &left, &right); - return NGX_HTTP_SSI_ERROR; - } -#else - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "the using of the regex \"%V\" in SSI " - "requires PCRE library", &right); - - return NGX_HTTP_SSI_ERROR; -#endif } if ((rc == 0 && !negative) || (rc != 0 && negative)) { diff --git a/src/http/modules/ngx_http_ssi_filter_module.h b/src/http/modules/ngx_http_ssi_filter_module.h --- a/src/http/modules/ngx_http_ssi_filter_module.h +++ b/src/http/modules/ngx_http_ssi_filter_module.h @@ -64,6 +64,12 @@ typedef struct { ngx_list_t *variables; ngx_array_t *blocks; +#if (NGX_PCRE) + ngx_uint_t ncaptures; + int *captures; + u_char *captures_data; +#endif + unsigned conditional:2; unsigned encoding:2; unsigned block:1; diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -274,6 +274,20 @@ static ngx_command_t ngx_http_uwsgi_comm offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_methods), &ngx_http_upstream_cache_method_mask }, + { ngx_string("uwsgi_cache_lock"), + 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_lock), + NULL }, + + { ngx_string("uwsgi_cache_lock_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock_timeout), + NULL }, + #endif { ngx_string("uwsgi_temp_path"), @@ -1114,6 +1128,8 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_ conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; + conf->upstream.cache_lock = NGX_CONF_UNSET; + conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC; #endif conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; @@ -1341,6 +1357,12 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t conf->cache_key = prev->cache_key; } + ngx_conf_merge_value(conf->upstream.cache_lock, + prev->upstream.cache_lock, 0); + + ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout, + prev->upstream.cache_lock_timeout, 5000); + #endif ngx_conf_merge_value(conf->upstream.pass_request_headers, diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -48,7 +48,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.1.11'; +our $VERSION = '1.1.12'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -79,6 +79,14 @@ struct ngx_http_cache_s { ngx_http_file_cache_t *file_cache; ngx_http_file_cache_node_t *node; + ngx_msec_t lock_timeout; + ngx_msec_t wait_time; + + ngx_event_t wait_event; + + unsigned lock:1; + unsigned waiting:1; + unsigned updated:1; unsigned updating:1; unsigned exists:1; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2506,6 +2506,7 @@ ngx_http_internal_redirect(ngx_http_requ #endif r->internal = 1; + r->valid_unparsed_uri = 0; r->add_uri_to_alias = 0; r->main->count++; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -10,6 +10,9 @@ #include +static ngx_int_t ngx_http_file_cache_lock(ngx_http_request_t *r, + ngx_http_cache_t *c); +static void ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev); static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c); static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, @@ -181,13 +184,13 @@ ngx_http_file_cache_create(ngx_http_requ return NGX_ERROR; } + cln->handler = ngx_http_file_cache_cleanup; + cln->data = c; + if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) { return NGX_ERROR; } - cln->handler = ngx_http_file_cache_cleanup; - cln->data = c; - if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) { return NGX_ERROR; } @@ -244,15 +247,24 @@ ngx_http_file_cache_open(ngx_http_reques c = r->cache; + if (c->waiting) { + return NGX_AGAIN; + } + if (c->buf) { return ngx_http_file_cache_read(r, c); } cache = c->file_cache; - cln = ngx_pool_cleanup_add(r->pool, 0); - if (cln == NULL) { - return NGX_ERROR; + if (c->node == NULL) { + cln = ngx_pool_cleanup_add(r->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_http_file_cache_cleanup; + cln->data = c; } rc = ngx_http_file_cache_exists(cache, c); @@ -264,9 +276,6 @@ ngx_http_file_cache_open(ngx_http_reques return rc; } - cln->handler = ngx_http_file_cache_cleanup; - cln->data = c; - if (rc == NGX_AGAIN) { return NGX_HTTP_CACHE_SCARCE; } @@ -306,7 +315,7 @@ ngx_http_file_cache_open(ngx_http_reques } if (!test) { - return NGX_DECLINED; + goto done; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -330,7 +339,7 @@ ngx_http_file_cache_open(ngx_http_reques case NGX_ENOENT: case NGX_ENOTDIR: - return rv; + goto done; default: ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, @@ -354,6 +363,114 @@ ngx_http_file_cache_open(ngx_http_reques } return ngx_http_file_cache_read(r, c); + +done: + + if (rv == NGX_DECLINED) { + return ngx_http_file_cache_lock(r, c); + } + + return rv; +} + + +static ngx_int_t +ngx_http_file_cache_lock(ngx_http_request_t *r, ngx_http_cache_t *c) +{ + ngx_msec_t now, timer; + ngx_http_file_cache_t *cache; + + if (!c->lock) { + return NGX_DECLINED; + } + + cache = c->file_cache; + + ngx_shmtx_lock(&cache->shpool->mutex); + + if (!c->node->updating) { + c->node->updating = 1; + c->updating = 1; + } + + ngx_shmtx_unlock(&cache->shpool->mutex); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache lock u:%d wt:%M", + c->updating, c->wait_time); + + if (c->updating) { + return NGX_DECLINED; + } + + c->waiting = 1; + + now = ngx_current_msec; + + if (c->wait_time == 0) { + c->wait_time = now + c->lock_timeout; + + c->wait_event.handler = ngx_http_file_cache_lock_wait_handler; + c->wait_event.data = r; + c->wait_event.log = r->connection->log; + } + + timer = c->wait_time - now; + + ngx_add_timer(&c->wait_event, (timer > 500) ? 500 : timer); + + r->main->blocked++; + + return NGX_AGAIN; +} + + +static void +ngx_http_file_cache_lock_wait_handler(ngx_event_t *ev) +{ + ngx_uint_t wait; + ngx_msec_t timer; + ngx_http_cache_t *c; + ngx_http_request_t *r; + ngx_http_file_cache_t *cache; + + r = ev->data; + c = r->cache; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http file cache wait handler wt:%M cur:%M", + c->wait_time, ngx_current_msec); + + timer = c->wait_time - ngx_current_msec; + + if ((ngx_msec_int_t) timer <= 0) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http file cache lock timeout"); + c->lock = 0; + goto wakeup; + } + + cache = c->file_cache; + wait = 0; + + ngx_shmtx_lock(&cache->shpool->mutex); + + if (c->node->updating) { + wait = 1; + } + + ngx_shmtx_unlock(&cache->shpool->mutex); + + if (wait) { + ngx_add_timer(ev, (timer > 500) ? 500 : timer); + return; + } + +wakeup: + + c->waiting = 0; + r->main->blocked--; + r->connection->write->handler(r->connection->write); } @@ -518,13 +635,19 @@ ngx_http_file_cache_exists(ngx_http_file ngx_shmtx_lock(&cache->shpool->mutex); - fcn = ngx_http_file_cache_lookup(cache, c->key); + fcn = c->node; + + if (fcn == NULL) { + fcn = ngx_http_file_cache_lookup(cache, c->key); + } if (fcn) { ngx_queue_remove(&fcn->queue); - fcn->uses++; - fcn->count++; + if (c->node == NULL) { + fcn->uses++; + fcn->count++; + } if (fcn->error) { @@ -621,6 +744,10 @@ ngx_http_file_cache_name(ngx_http_reques c = r->cache; + if (c->file.name.len) { + return NGX_OK; + } + c->file.name.len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; @@ -957,6 +1084,10 @@ ngx_http_file_cache_free(ngx_http_cache_ } } } + + if (c->wait_event.timer_set) { + ngx_del_timer(&c->wait_event); + } } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -707,6 +707,9 @@ ngx_http_upstream_cache(ngx_http_request c->body_start = u->conf->buffer_size; c->file_cache = u->conf->cache->data; + c->lock = u->conf->cache_lock; + c->lock_timeout = u->conf->cache_lock_timeout; + u->cache_status = NGX_HTTP_CACHE_MISS; } @@ -1895,8 +1898,6 @@ ngx_http_upstream_process_headers(ngx_ht r->method = NGX_HTTP_GET; } - r->valid_unparsed_uri = 0; - ngx_http_internal_redirect(r, uri, &args); ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -165,6 +165,9 @@ typedef struct { ngx_uint_t cache_use_stale; ngx_uint_t cache_methods; + ngx_flag_t cache_lock; + ngx_msec_t cache_lock_timeout; + ngx_array_t *cache_valid; ngx_array_t *cache_bypass; ngx_array_t *no_cache; diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -223,11 +223,14 @@ ngx_http_write_filter(ngx_http_request_t return NGX_AGAIN; } - } else if (clcf->sendfile_max_chunk) { - limit = clcf->sendfile_max_chunk; + if (clcf->sendfile_max_chunk + && (off_t) clcf->sendfile_max_chunk < limit) + { + limit = clcf->sendfile_max_chunk; + } } else { - limit = 0; + limit = clcf->sendfile_max_chunk; } sent = c->sent; @@ -262,17 +265,18 @@ ngx_http_write_filter(ngx_http_request_t } } - delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate + 1); + delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate); if (delay > 0) { + limit = 0; c->write->delayed = 1; ngx_add_timer(c->write, delay); } + } - } else if (c->write->ready - && clcf->sendfile_max_chunk - && (size_t) (c->sent - sent) - >= clcf->sendfile_max_chunk - 2 * ngx_pagesize) + if (limit + && c->write->ready + && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize)) { c->write->delayed = 1; ngx_add_timer(c->write, 1);