diff options
author | Igor Sysoev <igor@sysoev.ru> | 2011-12-26 15:47:52 +0000 |
---|---|---|
committer | Jonathan Kolb <jon@b0g.us> | 2011-12-26 15:47:52 +0000 |
commit | 009625684c294b0d8512d4dc70749d88b161de25 (patch) | |
tree | 0787ee0cd662c479e1903251e8800056441270ce /src/http | |
parent | f3f84820db369aade03ed922872e206760e0ce0f (diff) | |
download | nginx-009625684c294b0d8512d4dc70749d88b161de25.tar.gz |
Changes with nginx 1.1.12 26 Dec 2011v1.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.
Maxim Dounin
_______________________________________________
nginx-announce mailing list
nginx-announce@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-announce
Diffstat (limited to 'src/http')
-rw-r--r-- | src/http/modules/ngx_http_fastcgi_module.c | 22 | ||||
-rw-r--r-- | src/http/modules/ngx_http_limit_conn_module.c | 2 | ||||
-rw-r--r-- | src/http/modules/ngx_http_limit_req_module.c | 2 | ||||
-rw-r--r-- | src/http/modules/ngx_http_mp4_module.c | 2 | ||||
-rw-r--r-- | src/http/modules/ngx_http_proxy_module.c | 31 | ||||
-rw-r--r-- | src/http/modules/ngx_http_scgi_module.c | 38 | ||||
-rw-r--r-- | src/http/modules/ngx_http_ssi_filter_module.c | 191 | ||||
-rw-r--r-- | src/http/modules/ngx_http_ssi_filter_module.h | 6 | ||||
-rw-r--r-- | src/http/modules/ngx_http_uwsgi_module.c | 22 | ||||
-rw-r--r-- | src/http/modules/perl/nginx.pm | 2 | ||||
-rw-r--r-- | src/http/ngx_http_cache.h | 8 | ||||
-rw-r--r-- | src/http/ngx_http_core_module.c | 1 | ||||
-rw-r--r-- | src/http/ngx_http_file_cache.c | 159 | ||||
-rw-r--r-- | src/http/ngx_http_upstream.c | 5 | ||||
-rw-r--r-- | src/http/ngx_http_upstream.h | 3 | ||||
-rw-r--r-- | src/http/ngx_http_write_filter_module.c | 20 |
16 files changed, 429 insertions, 85 deletions
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 599edc77c..f976b7aea 100644 --- 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_commands[] = { 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_conf_t *cf) 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_t *cf, void *parent, void *child) 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 index a84d54d7e..40f05a22e 100644 --- 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_t *cf, void *parent, void *child) 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 index 718fae8e2..865f7666d 100644 --- 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 *cf, void *parent, void *child) 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 index 3c9f88cfc..7bfb3db66 100644 --- 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 index 5ce875f62..b65093b72 100644 --- 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_commands[] = { 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 *r, ngx_http_proxy_ctx_t *ctx, 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_request_t *r) 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_request_t *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_request_t *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_t *cf) 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 *cf, void *parent, void *child) 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 index 41cf23bc6..9fd60147e 100644 --- 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_request(ngx_http_request_t *r); 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_commands[] = { 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_http_request_t *r) } 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_request_t *r) 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_request_t *r) 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 *cf) 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 *cf, void *parent, void *child) 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 index 0b8bc9bf8..e33782166 100644 --- 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_variable(ngx_http_request_t *r, 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_request_t *r, ngx_chain_t *in) 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_request_t *r, ngx_chain_t *in) } } + 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_request_t *r, ngx_str_t *name, 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, ngx_http_ssi_ctx_t *ctx, } } 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); - 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; + if (rc == NGX_OK) { + rc = 0; + } else if (rc == NGX_DECLINED) { + rc = -1; + } else { + return rc; } -#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 index 6ab18841c..2b0018662 100644 --- 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 index 2916a5916..86959b3e3 100644 --- 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_commands[] = { 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_t *cf) 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 *cf, void *parent, void *child) 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 index ec49d7bad..8cd3b7469 100644 --- 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 index bd02100da..ae8b8c376 100644 --- 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 index 3c5711748..1d5ee5dc6 100644 --- 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_request_t *r, #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 index 050f356f1..dccbbac68 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -10,6 +10,9 @@ #include <ngx_md5.h> +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_request_t *r) 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_request_t *r) 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_request_t *r) 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_request_t *r) } 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_request_t *r) 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_request_t *r) } 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_cache_t *cache, ngx_http_cache_t *c) 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_request_t *r, ngx_path_t *path) 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_t *c, ngx_temp_file_t *tf) } } } + + 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 index 9f0ff3a54..781ef1f96 100644 --- 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_t *r, ngx_http_upstream_t *u) 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_http_request_t *r, ngx_http_upstream_t *u) 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 index fa93be69f..62cbf533e 100644 --- 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 index 46351349c..a9660ee1f 100644 --- 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 *r, ngx_chain_t *in) 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 *r, ngx_chain_t *in) } } - 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); |