summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES32
-rw-r--r--CHANGES.ru32
-rw-r--r--src/core/nginx.h4
-rw-r--r--src/core/ngx_string.c52
-rw-r--r--src/core/ngx_string.h1
-rw-r--r--src/event/ngx_event_openssl.c65
-rw-r--r--src/http/modules/ngx_http_autoindex_module.c487
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c158
-rw-r--r--src/http/modules/ngx_http_headers_filter_module.c234
-rw-r--r--src/http/modules/ngx_http_proxy_module.c171
-rw-r--r--src/http/modules/ngx_http_scgi_module.c155
-rw-r--r--src/http/modules/ngx_http_uwsgi_module.c161
-rw-r--r--src/http/ngx_http_file_cache.c16
-rw-r--r--src/http/ngx_http_upstream.c87
-rw-r--r--src/http/ngx_http_upstream.h9
15 files changed, 1323 insertions, 341 deletions
diff --git a/CHANGES b/CHANGES
index 8b2c1ccc2..9932ca0b4 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,36 @@
+Changes with nginx 1.7.9 23 Dec 2014
+
+ *) Feature: variables support in the "proxy_cache", "fastcgi_cache",
+ "scgi_cache", and "uwsgi_cache" directives.
+
+ *) Feature: variables support in the "expires" directive.
+
+ *) Feature: loading of secret keys from hardware tokens with OpenSSL
+ engines.
+ Thanks to Dmitrii Pichulin.
+
+ *) Feature: the "autoindex_format" directive.
+
+ *) Bugfix: cache revalidation is now only used for responses with 200
+ and 206 status codes.
+ Thanks to Piotr Sikora.
+
+ *) Bugfix: the "TE" client request header line was passed to backends
+ while proxying.
+
+ *) Bugfix: the "proxy_pass", "fastcgi_pass", "scgi_pass", and
+ "uwsgi_pass" directives might not work correctly inside the "if" and
+ "limit_except" blocks.
+
+ *) Bugfix: the "proxy_store" directive with the "on" parameter was
+ ignored if the "proxy_store" directive with an explicitly specified
+ file path was used on a previous level.
+
+ *) Bugfix: nginx could not be built with BoringSSL.
+ Thanks to Lukas Tribus.
+
+
Changes with nginx 1.7.8 02 Dec 2014
*) Change: now the "If-Modified-Since", "If-Range", etc. client request
diff --git a/CHANGES.ru b/CHANGES.ru
index d648c1cf6..7ba7aa79c 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,36 @@
+Изменения в nginx 1.7.9 23.12.2014
+
+ *) Добавление: директивы proxy_cache, fastcgi_cache, scgi_cache и
+ uwsgi_cache поддерживают переменные.
+
+ *) Добавление: директива expires поддерживает переменные.
+
+ *) Добавление: возможность загрузки секретных ключей с аппаратных
+ устройств с помощью OpenSSL engines.
+ Спасибо Дмитрию Пичулину.
+
+ *) Добавление: директива autoindex_format.
+
+ *) Исправление: ревалидация элементов кэша теперь используется только
+ для ответов с кодами 200 и 206.
+ Спасибо Piotr Sikora.
+
+ *) Исправление: строка "TE" заголовка запроса клиента передавалась на
+ бэкенд при проксировании.
+
+ *) Исправление: директивы proxy_pass, fastcgi_pass, scgi_pass и
+ uwsgi_pass могли неправильно работать внутри блоков if и
+ limit_except.
+
+ *) Исправление: директива proxy_store с параметром "on" игнорировалась,
+ если на предыдущем уровне использовалась директива proxy_store с явно
+ заданным путём к файлам.
+
+ *) Исправление: nginx не собирался с BoringSSL.
+ Спасибо Lukas Tribus.
+
+
Изменения в nginx 1.7.8 02.12.2014
*) Изменение: теперь строки "If-Modified-Since", "If-Range" и им
diff --git a/src/core/nginx.h b/src/core/nginx.h
index c9007a138..4c4b8e404 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1007008
-#define NGINX_VERSION "1.7.8"
+#define nginx_version 1007009
+#define NGINX_VERSION "1.7.9"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index 9d854fa0e..a41c38d37 100644
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1773,6 +1773,58 @@ ngx_escape_html(u_char *dst, u_char *src, size_t size)
}
+uintptr_t
+ngx_escape_json(u_char *dst, u_char *src, size_t size)
+{
+ u_char ch;
+ ngx_uint_t len;
+
+ if (dst == NULL) {
+ len = 0;
+
+ while (size) {
+ ch = *src++;
+
+ if (ch == '\\' || ch == '"') {
+ len++;
+
+ } else if (ch <= 0x1f) {
+ len += sizeof("\\u001F") - 2;
+ }
+
+ size--;
+ }
+
+ return (uintptr_t) len;
+ }
+
+ while (size) {
+ ch = *src++;
+
+ if (ch > 0x1f) {
+
+ if (ch == '\\' || ch == '"') {
+ *dst++ = '\\';
+ }
+
+ *dst++ = ch;
+
+ } else {
+ *dst++ = '\\'; *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
+ *dst++ = '0' + (ch >> 4);
+
+ ch &= 0xf;
+
+ *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
+ }
+
+ size--;
+ }
+
+ return (uintptr_t) dst;
+}
+
+
void
ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h
index 712e7d0bf..7363bd242 100644
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -207,6 +207,7 @@ uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
ngx_uint_t type);
void ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type);
uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size);
+uintptr_t ngx_escape_json(u_char *dst, u_char *src, size_t size);
typedef struct {
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index ab54d88c4..d5d4a1ac9 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -376,6 +376,67 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
BIO_free(bio);
+ if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {
+
+#ifndef OPENSSL_NO_ENGINE
+
+ u_char *p, *last;
+ ENGINE *engine;
+ EVP_PKEY *pkey;
+
+ p = key->data + sizeof("engine:") - 1;
+ last = (u_char *) ngx_strchr(p, ':');
+
+ if (last == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid syntax in \"%V\"", key);
+ return NGX_ERROR;
+ }
+
+ *last = '\0';
+
+ engine = ENGINE_by_id((char *) p);
+
+ if (engine == NULL) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "ENGINE_by_id(\"%s\") failed", p);
+ return NGX_ERROR;
+ }
+
+ *last++ = ':';
+
+ pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);
+
+ if (pkey == NULL) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "ENGINE_load_private_key(\"%s\") failed", last);
+ ENGINE_free(engine);
+ return NGX_ERROR;
+ }
+
+ ENGINE_free(engine);
+
+ if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_use_PrivateKey(\"%s\") failed", last);
+ EVP_PKEY_free(pkey);
+ return NGX_ERROR;
+ }
+
+ EVP_PKEY_free(pkey);
+
+ return NGX_OK;
+
+#else
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "loading \"engine:...\" certificate keys "
+ "is not supported");
+ return NGX_ERROR;
+
+#endif
+ }
+
if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
return NGX_ERROR;
}
@@ -1085,11 +1146,15 @@ ngx_ssl_handshake(ngx_connection_t *c)
c->recv_chain = ngx_ssl_recv_chain;
c->send_chain = ngx_ssl_send_chain;
+#ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS
+
/* initial handshake done, disable renegotiation (CVE-2009-3555) */
if (c->ssl->connection->s3) {
c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
}
+#endif
+
return NGX_OK;
}
diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c
index f694df075..b3bf65286 100644
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -30,6 +30,7 @@ typedef struct {
size_t escape_html;
unsigned dir:1;
+ unsigned file:1;
time_t mtime;
off_t size;
@@ -38,26 +39,51 @@ typedef struct {
typedef struct {
ngx_flag_t enable;
+ ngx_uint_t format;
ngx_flag_t localtime;
ngx_flag_t exact_size;
} ngx_http_autoindex_loc_conf_t;
+#define NGX_HTTP_AUTOINDEX_HTML 0
+#define NGX_HTTP_AUTOINDEX_JSON 1
+#define NGX_HTTP_AUTOINDEX_JSONP 2
+#define NGX_HTTP_AUTOINDEX_XML 3
+
#define NGX_HTTP_AUTOINDEX_PREALLOCATE 50
#define NGX_HTTP_AUTOINDEX_NAME_LEN 50
+static ngx_buf_t *ngx_http_autoindex_html(ngx_http_request_t *r,
+ ngx_array_t *entries);
+static ngx_buf_t *ngx_http_autoindex_json(ngx_http_request_t *r,
+ ngx_array_t *entries, ngx_str_t *callback);
+static ngx_int_t ngx_http_autoindex_jsonp_callback(ngx_http_request_t *r,
+ ngx_str_t *callback);
+static ngx_buf_t *ngx_http_autoindex_xml(ngx_http_request_t *r,
+ ngx_array_t *entries);
+
static int ngx_libc_cdecl ngx_http_autoindex_cmp_entries(const void *one,
const void *two);
static ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r,
ngx_dir_t *dir, ngx_str_t *name);
+
static ngx_int_t ngx_http_autoindex_init(ngx_conf_t *cf);
static void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
+static ngx_conf_enum_t ngx_http_autoindex_format[] = {
+ { ngx_string("html"), NGX_HTTP_AUTOINDEX_HTML },
+ { ngx_string("json"), NGX_HTTP_AUTOINDEX_JSON },
+ { ngx_string("jsonp"), NGX_HTTP_AUTOINDEX_JSONP },
+ { ngx_string("xml"), NGX_HTTP_AUTOINDEX_XML },
+ { ngx_null_string, 0 }
+};
+
+
static ngx_command_t ngx_http_autoindex_commands[] = {
{ ngx_string("autoindex"),
@@ -67,6 +93,13 @@ static ngx_command_t ngx_http_autoindex_commands[] = {
offsetof(ngx_http_autoindex_loc_conf_t, enable),
NULL },
+ { ngx_string("autoindex_format"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_enum_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_autoindex_loc_conf_t, format),
+ &ngx_http_autoindex_format },
+
{ ngx_string("autoindex_localtime"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -116,47 +149,23 @@ ngx_module_t ngx_http_autoindex_module = {
};
-static u_char title[] =
-"<html>" CRLF
-"<head><title>Index of "
-;
-
-
-static u_char header[] =
-"</title></head>" CRLF
-"<body bgcolor=\"white\">" CRLF
-"<h1>Index of "
-;
-
-static u_char tail[] =
-"</body>" CRLF
-"</html>" CRLF
-;
-
-
static ngx_int_t
ngx_http_autoindex_handler(ngx_http_request_t *r)
{
- u_char *last, *filename, scale;
- off_t length;
- size_t len, char_len, escape_html, allocated, root;
- ngx_tm_t tm;
+ u_char *last, *filename;
+ size_t len, allocated, root;
ngx_err_t err;
ngx_buf_t *b;
- ngx_int_t rc, size;
- ngx_str_t path;
+ ngx_int_t rc;
+ ngx_str_t path, callback;
ngx_dir_t dir;
- ngx_uint_t i, level, utf8;
+ ngx_uint_t level, format;
ngx_pool_t *pool;
- ngx_time_t *tp;
ngx_chain_t out;
ngx_array_t entries;
ngx_http_autoindex_entry_t *entry;
ngx_http_autoindex_loc_conf_t *alcf;
- static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-
if (r->uri.data[r->uri.len - 1] != '/') {
return NGX_DECLINED;
}
@@ -189,6 +198,18 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http autoindex: \"%s\"", path.data);
+ format = alcf->format;
+
+ if (format == NGX_HTTP_AUTOINDEX_JSONP) {
+ if (ngx_http_autoindex_jsonp_callback(r, &callback) != NGX_OK) {
+ return NGX_HTTP_BAD_REQUEST;
+ }
+
+ if (callback.len == 0) {
+ format = NGX_HTTP_AUTOINDEX_JSON;
+ }
+ }
+
if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
err = ngx_errno;
@@ -231,8 +252,28 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
}
r->headers_out.status = NGX_HTTP_OK;
- r->headers_out.content_type_len = sizeof("text/html") - 1;
- ngx_str_set(&r->headers_out.content_type, "text/html");
+
+ switch (format) {
+
+ case NGX_HTTP_AUTOINDEX_JSON:
+ ngx_str_set(&r->headers_out.content_type, "application/json");
+ break;
+
+ case NGX_HTTP_AUTOINDEX_JSONP:
+ ngx_str_set(&r->headers_out.content_type, "application/javascript");
+ break;
+
+ case NGX_HTTP_AUTOINDEX_XML:
+ ngx_str_set(&r->headers_out.content_type, "text/xml");
+ ngx_str_set(&r->headers_out.charset, "utf-8");
+ break;
+
+ default: /* NGX_HTTP_AUTOINDEX_HTML */
+ ngx_str_set(&r->headers_out.content_type, "text/html");
+ break;
+ }
+
+ r->headers_out.content_type_len = r->headers_out.content_type.len;
r->headers_out.content_type_lowcase = NULL;
rc = ngx_http_send_header(r);
@@ -249,16 +290,6 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
filename = path.data;
filename[path.len] = '/';
- if (r->headers_out.charset.len == 5
- && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5)
- == 0)
- {
- utf8 = 1;
-
- } else {
- utf8 = 0;
- }
-
for ( ;; ) {
ngx_set_errno(0);
@@ -339,19 +370,8 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);
- entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len,
- NGX_ESCAPE_URI_COMPONENT);
-
- entry->escape_html = ngx_escape_html(NULL, entry->name.data,
- entry->name.len);
-
- if (utf8) {
- entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len);
- } else {
- entry->utf_len = len;
- }
-
entry->dir = ngx_de_is_dir(&dir);
+ entry->file = ngx_de_is_file(&dir);
entry->mtime = ngx_de_mtime(&dir);
entry->size = ngx_de_size(&dir);
}
@@ -361,6 +381,93 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
ngx_close_dir_n " \"%V\" failed", &path);
}
+ if (entries.nelts > 1) {
+ ngx_qsort(entries.elts, (size_t) entries.nelts,
+ sizeof(ngx_http_autoindex_entry_t),
+ ngx_http_autoindex_cmp_entries);
+ }
+
+ switch (format) {
+
+ case NGX_HTTP_AUTOINDEX_JSON:
+ b = ngx_http_autoindex_json(r, &entries, NULL);
+ break;
+
+ case NGX_HTTP_AUTOINDEX_JSONP:
+ b = ngx_http_autoindex_json(r, &entries, &callback);
+ break;
+
+ case NGX_HTTP_AUTOINDEX_XML:
+ b = ngx_http_autoindex_xml(r, &entries);
+ break;
+
+ default: /* NGX_HTTP_AUTOINDEX_HTML */
+ b = ngx_http_autoindex_html(r, &entries);
+ break;
+ }
+
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ /* TODO: free temporary pool */
+
+ if (r == r->main) {
+ b->last_buf = 1;
+ }
+
+ b->last_in_chain = 1;
+
+ out.buf = b;
+ out.next = NULL;
+
+ return ngx_http_output_filter(r, &out);
+}
+
+
+static ngx_buf_t *
+ngx_http_autoindex_html(ngx_http_request_t *r, ngx_array_t *entries)
+{
+ u_char *last, scale;
+ off_t length;
+ size_t len, char_len, escape_html;
+ ngx_tm_t tm;
+ ngx_buf_t *b;
+ ngx_int_t size;
+ ngx_uint_t i, utf8;
+ ngx_time_t *tp;
+ ngx_http_autoindex_entry_t *entry;
+ ngx_http_autoindex_loc_conf_t *alcf;
+
+ static u_char title[] =
+ "<html>" CRLF
+ "<head><title>Index of "
+ ;
+
+ static u_char header[] =
+ "</title></head>" CRLF
+ "<body bgcolor=\"white\">" CRLF
+ "<h1>Index of "
+ ;
+
+ static u_char tail[] =
+ "</body>" CRLF
+ "</html>" CRLF
+ ;
+
+ static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+ if (r->headers_out.charset.len == 5
+ && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5)
+ == 0)
+ {
+ utf8 = 1;
+
+ } else {
+ utf8 = 0;
+ }
+
escape_html = ngx_escape_html(NULL, r->uri.data, r->uri.len);
len = sizeof(title) - 1
@@ -372,8 +479,22 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
+ sizeof("</pre><hr>") - 1
+ sizeof(tail) - 1;
- entry = entries.elts;
- for (i = 0; i < entries.nelts; i++) {
+ entry = entries->elts;
+ for (i = 0; i < entries->nelts; i++) {
+ entry[i].escape = 2 * ngx_escape_uri(NULL, entry[i].name.data,
+ entry[i].name.len,
+ NGX_ESCAPE_URI_COMPONENT);
+
+ entry[i].escape_html = ngx_escape_html(NULL, entry[i].name.data,
+ entry[i].name.len);
+
+ if (utf8) {
+ entry[i].utf_len = ngx_utf8_length(entry[i].name.data,
+ entry[i].name.len);
+ } else {
+ entry[i].utf_len = entry[i].name.len;
+ }
+
len += sizeof("<a href=\"") - 1
+ entry[i].name.len + entry[i].escape
+ 1 /* 1 is for "/" */
@@ -389,13 +510,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
b = ngx_create_temp_buf(r->pool, len);
if (b == NULL) {
- return NGX_ERROR;
- }
-
- if (entries.nelts > 1) {
- ngx_qsort(entry, (size_t) entries.nelts,
- sizeof(ngx_http_autoindex_entry_t),
- ngx_http_autoindex_cmp_entries);
+ return NULL;
}
b->last = ngx_cpymem(b->last, title, sizeof(title) - 1);
@@ -416,9 +531,10 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF,
sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1);
+ alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module);
tp = ngx_timeofday();
- for (i = 0; i < entries.nelts; i++) {
+ for (i = 0; i < entries->nelts; i++) {
b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1);
if (entry[i].escape) {
@@ -565,22 +681,248 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
*b->last++ = LF;
}
- /* TODO: free temporary pool */
-
b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1);
b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1);
- if (r == r->main) {
- b->last_buf = 1;
+ return b;
+}
+
+
+static ngx_buf_t *
+ngx_http_autoindex_json(ngx_http_request_t *r, ngx_array_t *entries,
+ ngx_str_t *callback)
+{
+ size_t len;
+ ngx_buf_t *b;
+ ngx_uint_t i;
+ ngx_http_autoindex_entry_t *entry;
+
+ len = sizeof("[" CRLF CRLF "]") - 1;
+
+ if (callback) {
+ len += sizeof("/* callback */" CRLF "();") - 1 + callback->len;
}
- b->last_in_chain = 1;
+ entry = entries->elts;
- out.buf = b;
- out.next = NULL;
+ for (i = 0; i < entries->nelts; i++) {
+ entry[i].escape = ngx_escape_json(NULL, entry[i].name.data,
+ entry[i].name.len);
- return ngx_http_output_filter(r, &out);
+ len += sizeof("{ }," CRLF) - 1
+ + sizeof("\"name\":\"\"") - 1
+ + entry[i].name.len + entry[i].escape
+ + sizeof(", \"type\":\"directory\"") - 1
+ + sizeof(", \"mtime\":\"Wed, 31 Dec 1986 10:00:00 GMT\"") - 1;
+
+ if (entry[i].file) {
+ len += sizeof(", \"size\":") - 1 + NGX_OFF_T_LEN;
+ }
+ }
+
+ b = ngx_create_temp_buf(r->pool, len);
+ if (b == NULL) {
+ return NULL;
+ }
+
+ if (callback) {
+ b->last = ngx_cpymem(b->last, "/* callback */" CRLF,
+ sizeof("/* callback */" CRLF) - 1);
+
+ b->last = ngx_cpymem(b->last, callback->data, callback->len);
+
+ *b->last++ = '(';
+ }
+
+ *b->last++ = '[';
+
+ for (i = 0; i < entries->nelts; i++) {
+ b->last = ngx_cpymem(b->last, CRLF "{ \"name\":\"",
+ sizeof(CRLF "{ \"name\":\"") - 1);
+
+ if (entry[i].escape) {
+ b->last = (u_char *) ngx_escape_json(b->last, entry[i].name.data,
+ entry[i].name.len);
+ } else {
+ b->last = ngx_cpymem(b->last, entry[i].name.data,
+ entry[i].name.len);
+ }
+
+ b->last = ngx_cpymem(b->last, "\", \"type\":\"",
+ sizeof("\", \"type\":\"") - 1);
+
+ if (entry[i].dir) {
+ b->last = ngx_cpymem(b->last, "directory", sizeof("directory") - 1);
+
+ } else if (entry[i].file) {
+ b->last = ngx_cpymem(b->last, "file", sizeof("file") - 1);
+
+ } else {
+ b->last = ngx_cpymem(b->last, "other", sizeof("other") - 1);
+ }
+
+ b->last = ngx_cpymem(b->last, "\", \"mtime\":\"",
+ sizeof("\", \"mtime\":\"") - 1);
+
+ b->last = ngx_http_time(b->last, entry[i].mtime);
+
+ if (entry[i].file) {
+ b->last = ngx_cpymem(b->last, "\", \"size\":",
+ sizeof("\", \"size\":") - 1);
+ b->last = ngx_sprintf(b->last, "%O", entry[i].size);
+
+ } else {
+ *b->last++ = '"';
+ }
+
+ b->last = ngx_cpymem(b->last, " },", sizeof(" },") - 1);
+ }
+
+ if (i > 0) {
+ b->last--; /* strip last comma */
+ }
+
+ b->last = ngx_cpymem(b->last, CRLF "]", sizeof(CRLF "]") - 1);
+
+ if (callback) {
+ *b->last++ = ')'; *b->last++ = ';';
+ }
+
+ return b;
+}
+
+
+static ngx_int_t
+ngx_http_autoindex_jsonp_callback(ngx_http_request_t *r, ngx_str_t *callback)
+{
+ u_char *p, c, ch;
+ ngx_uint_t i;
+
+ if (ngx_http_arg(r, (u_char *) "callback", 8, callback) != NGX_OK) {
+ callback->len = 0;
+ return NGX_OK;
+ }
+
+ if (callback->len > 128) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent too long callback name: \"%V\"", callback);
+ return NGX_DECLINED;
+ }
+
+ p = callback->data;
+
+ for (i = 0; i < callback->len; i++) {
+ ch = p[i];
+
+ c = (u_char) (ch | 0x20);
+ if (c >= 'a' && c <= 'z') {
+ continue;
+ }
+
+ if ((ch >= '0' && ch <= '9') || ch == '_' || ch == '.') {
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent invalid callback name: \"%V\"", callback);
+
+ return NGX_DECLINED;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_buf_t *
+ngx_http_autoindex_xml(ngx_http_request_t *r, ngx_array_t *entries)
+{
+ size_t len;
+ ngx_tm_t tm;
+ ngx_buf_t *b;
+ ngx_str_t type;
+ ngx_uint_t i;
+ ngx_http_autoindex_entry_t *entry;
+
+ static u_char head[] = "<?xml version=\"1.0\"?>" CRLF "<list>" CRLF;
+ static u_char tail[] = "</list>" CRLF;
+
+ len = sizeof(head) - 1 + sizeof(tail) - 1;
+
+ entry = entries->elts;
+
+ for (i = 0; i < entries->nelts; i++) {
+ entry[i].escape = ngx_escape_html(NULL, entry[i].name.data,
+ entry[i].name.len);
+
+ len += sizeof("<directory></directory>" CRLF) - 1
+ + entry[i].name.len + entry[i].escape
+ + sizeof(" mtime=\"1986-12-31T10:00:00Z\"") - 1;
+
+ if (entry[i].file) {
+ len += sizeof(" size=\"\"") - 1 + NGX_OFF_T_LEN;
+ }
+ }
+
+ b = ngx_create_temp_buf(r->pool, len);
+ if (b == NULL) {
+ return NULL;
+ }
+
+ b->last = ngx_cpymem(b->last, head, sizeof(head) - 1);
+
+ for (i = 0; i < entries->nelts; i++) {
+ *b->last++ = '<';
+
+ if (entry[i].dir) {
+ ngx_str_set(&type, "directory");
+
+ } else if (entry[i].file) {
+ ngx_str_set(&type, "file");
+
+ } else {
+ ngx_str_set(&type, "other");
+ }
+
+ b->last = ngx_cpymem(b->last, type.data, type.len);
+
+ b->last = ngx_cpymem(b->last, " mtime=\"", sizeof(" mtime=\"") - 1);
+
+ ngx_gmtime(entry[i].mtime, &tm);
+
+ b->last = ngx_sprintf(b->last, "%4d-%02d-%02dT%02d:%02d:%02dZ",
+ tm.ngx_tm_year, tm.ngx_tm_mon,
+ tm.ngx_tm_mday, tm.ngx_tm_hour,
+ tm.ngx_tm_min, tm.ngx_tm_sec);
+
+ if (entry[i].file) {
+ b->last = ngx_cpymem(b->last, "\" size=\"",
+ sizeof("\" size=\"") - 1);
+ b->last = ngx_sprintf(b->last, "%O", entry[i].size);
+ }
+
+ *b->last++ = '"'; *b->last++ = '>';
+
+ if (entry[i].escape) {
+ b->last = (u_char *) ngx_escape_html(b->last, entry[i].name.data,
+ entry[i].name.len);
+ } else {
+ b->last = ngx_cpymem(b->last, entry[i].name.data,
+ entry[i].name.len);
+ }
+
+ *b->last++ = '<'; *b->last++ = '/';
+
+ b->last = ngx_cpymem(b->last, type.data, type.len);
+
+ *b->last++ = '>';
+
+ *b->last++ = CR; *b->last++ = LF;
+ }
+
+ b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1);
+
+ return b;
}
@@ -665,6 +1007,7 @@ ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf)
}
conf->enable = NGX_CONF_UNSET;
+ conf->format = NGX_CONF_UNSET_UINT;
conf->localtime = NGX_CONF_UNSET;
conf->exact_size = NGX_CONF_UNSET;
@@ -679,6 +1022,8 @@ ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_autoindex_loc_conf_t *conf = child;
ngx_conf_merge_value(conf->enable, prev->enable, 0);
+ ngx_conf_merge_uint_value(conf->format, prev->format,
+ NGX_HTTP_AUTOINDEX_HTML);
ngx_conf_merge_value(conf->localtime, prev->localtime, 0);
ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1);
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index cc93570b1..1bf4ac332 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -11,6 +11,11 @@
typedef struct {
+ ngx_array_t caches; /* ngx_http_file_cache_t * */
+} ngx_http_fastcgi_main_conf_t;
+
+
+typedef struct {
ngx_array_t *flushes;
ngx_array_t *lengths;
ngx_array_t *values;
@@ -155,6 +160,7 @@ static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r,
ngx_int_t rc);
static ngx_int_t ngx_http_fastcgi_add_variables(ngx_conf_t *cf);
+static void *ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf);
static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
@@ -368,8 +374,8 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
{ ngx_string("fastcgi_cache_path"),
NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
ngx_http_file_cache_set_slot,
- 0,
- 0,
+ NGX_HTTP_MAIN_CONF_OFFSET,
+ offsetof(ngx_http_fastcgi_main_conf_t, caches),
&ngx_http_fastcgi_module },
{ ngx_string("fastcgi_cache_bypass"),
@@ -536,7 +542,7 @@ static ngx_http_module_t ngx_http_fastcgi_module_ctx = {
ngx_http_fastcgi_add_variables, /* preconfiguration */
NULL, /* postconfiguration */
- NULL, /* create main configuration */
+ ngx_http_fastcgi_create_main_conf, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
@@ -635,10 +641,13 @@ static ngx_path_init_t ngx_http_fastcgi_temp_path = {
static ngx_int_t
ngx_http_fastcgi_handler(ngx_http_request_t *r)
{
- ngx_int_t rc;
- ngx_http_upstream_t *u;
- ngx_http_fastcgi_ctx_t *f;
- ngx_http_fastcgi_loc_conf_t *flcf;
+ ngx_int_t rc;
+ ngx_http_upstream_t *u;
+ ngx_http_fastcgi_ctx_t *f;
+ ngx_http_fastcgi_loc_conf_t *flcf;
+#if (NGX_HTTP_CACHE)
+ ngx_http_fastcgi_main_conf_t *fmcf;
+#endif
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -667,8 +676,12 @@ ngx_http_fastcgi_handler(ngx_http_request_t *r)
u->conf = &flcf->upstream;
#if (NGX_HTTP_CACHE)
+ fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module);
+
+ u->caches = &fmcf->caches;
u->create_key = ngx_http_fastcgi_create_key;
#endif
+
u->create_request = ngx_http_fastcgi_create_request;
u->reinit_request = ngx_http_fastcgi_reinit_request;
u->process_header = ngx_http_fastcgi_process_header;
@@ -2337,6 +2350,29 @@ ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
static void *
+ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf)
+{
+ ngx_http_fastcgi_main_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+#if (NGX_HTTP_CACHE)
+ if (ngx_array_init(&conf->caches, cf->pool, 4,
+ sizeof(ngx_http_file_cache_t *))
+ != NGX_OK)
+ {
+ return NULL;
+ }
+#endif
+
+ return conf;
+}
+
+
+static void *
ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_fastcgi_loc_conf_t *conf;
@@ -2352,6 +2388,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
* conf->upstream.bufs.num = 0;
* conf->upstream.ignore_headers = 0;
* conf->upstream.next_upstream = 0;
+ * conf->upstream.cache_zone = NULL;
* conf->upstream.cache_use_stale = 0;
* conf->upstream.cache_methods = 0;
* conf->upstream.temp_path = NULL;
@@ -2390,7 +2427,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.pass_request_body = NGX_CONF_UNSET;
#if (NGX_HTTP_CACHE)
- conf->upstream.cache = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache = NGX_CONF_UNSET;
conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
@@ -2432,14 +2469,24 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_hash_init_t hash;
ngx_http_core_loc_conf_t *clcf;
- if (conf->upstream.store != 0) {
+#if (NGX_HTTP_CACHE)
+
+ if (conf->upstream.store > 0) {
+ conf->upstream.cache = 0;
+ }
+
+ if (conf->upstream.cache > 0) {
+ conf->upstream.store = 0;
+ }
+
+#endif
+
+ if (conf->upstream.store == NGX_CONF_UNSET) {
ngx_conf_merge_value(conf->upstream.store,
prev->upstream.store, 0);
- if (conf->upstream.store_lengths == NULL) {
- conf->upstream.store_lengths = prev->upstream.store_lengths;
- conf->upstream.store_values = prev->upstream.store_values;
- }
+ conf->upstream.store_lengths = prev->upstream.store_lengths;
+ conf->upstream.store_values = prev->upstream.store_values;
}
ngx_conf_merge_uint_value(conf->upstream.store_access,
@@ -2601,13 +2648,18 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
#if (NGX_HTTP_CACHE)
- ngx_conf_merge_ptr_value(conf->upstream.cache,
- prev->upstream.cache, NULL);
+ if (conf->upstream.cache == NGX_CONF_UNSET) {
+ ngx_conf_merge_value(conf->upstream.cache,
+ prev->upstream.cache, 0);
- if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
+ conf->upstream.cache_zone = prev->upstream.cache_zone;
+ conf->upstream.cache_value = prev->upstream.cache_value;
+ }
+
+ if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
ngx_shm_zone_t *shm_zone;
- shm_zone = conf->upstream.cache;
+ shm_zone = conf->upstream.cache_zone;
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"fastcgi_cache\" zone \"%V\" is unknown",
@@ -2697,20 +2749,20 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
- if (conf->upstream.upstream == NULL) {
- conf->upstream.upstream = prev->upstream.upstream;
- }
+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
- if (conf->fastcgi_lengths == NULL) {
+ if (clcf->noname
+ && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL)
+ {
+ conf->upstream.upstream = prev->upstream.upstream;
conf->fastcgi_lengths = prev->fastcgi_lengths;
conf->fastcgi_values = prev->fastcgi_values;
}
- if (conf->upstream.upstream || conf->fastcgi_lengths) {
- clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
- if (clcf->handler == NULL && clcf->lmt_excpt) {
- clcf->handler = ngx_http_fastcgi_handler;
- }
+ if (clcf->lmt_excpt && clcf->handler == NULL
+ && (conf->upstream.upstream || conf->fastcgi_lengths))
+ {
+ clcf->handler = ngx_http_fastcgi_handler;
}
#if (NGX_PCRE)
@@ -3206,9 +3258,7 @@ ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_str_t *value;
ngx_http_script_compile_t sc;
- if (flcf->upstream.store != NGX_CONF_UNSET
- || flcf->upstream.store_lengths)
- {
+ if (flcf->upstream.store != NGX_CONF_UNSET) {
return "is duplicate";
}
@@ -3220,17 +3270,14 @@ ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
#if (NGX_HTTP_CACHE)
-
- if (flcf->upstream.cache != NGX_CONF_UNSET_PTR
- && flcf->upstream.cache != NULL)
- {
+ if (flcf->upstream.cache > 0) {
return "is incompatible with \"fastcgi_cache\"";
}
-
#endif
+ flcf->upstream.store = 1;
+
if (ngx_strcmp(value[1].data, "on") == 0) {
- flcf->upstream.store = 1;
return NGX_CONF_OK;
}
@@ -3262,26 +3309,53 @@ ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_fastcgi_loc_conf_t *flcf = conf;
- ngx_str_t *value;
+ ngx_str_t *value;
+ ngx_http_complex_value_t cv;
+ ngx_http_compile_complex_value_t ccv;
value = cf->args->elts;
- if (flcf->upstream.cache != NGX_CONF_UNSET_PTR) {
+ if (flcf->upstream.cache != NGX_CONF_UNSET) {
return "is duplicate";
}
if (ngx_strcmp(value[1].data, "off") == 0) {
- flcf->upstream.cache = NULL;
+ flcf->upstream.cache = 0;
return NGX_CONF_OK;
}
- if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) {
+ if (flcf->upstream.store > 0) {
return "is incompatible with \"fastcgi_store\"";
}
- flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
- &ngx_http_fastcgi_module);
- if (flcf->upstream.cache == NULL) {
+ flcf->upstream.cache = 1;
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = &cv;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (cv.lengths != NULL) {
+
+ flcf->upstream.cache_value = ngx_palloc(cf->pool,
+ sizeof(ngx_http_complex_value_t));
+ if (flcf->upstream.cache_value == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ *flcf->upstream.cache_value = cv;
+
+ return NGX_CONF_OK;
+ }
+
+ flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
+ &ngx_http_fastcgi_module);
+ if (flcf->upstream.cache_zone == NULL) {
return NGX_CONF_ERROR;
}
diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c
index f33cfb78e..a10056903 100644
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -44,14 +44,17 @@ typedef enum {
typedef struct {
- ngx_http_expires_t expires;
- time_t expires_time;
- ngx_array_t *headers;
+ ngx_http_expires_t expires;
+ time_t expires_time;
+ ngx_http_complex_value_t *expires_value;
+ ngx_array_t *headers;
} ngx_http_headers_conf_t;
static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r,
ngx_http_headers_conf_t *conf);
+static ngx_int_t ngx_http_parse_expires(ngx_str_t *value,
+ ngx_http_expires_t *expires, time_t *expires_time, char **err);
static ngx_int_t ngx_http_add_cache_control(ngx_http_request_t *r,
ngx_http_header_val_t *hv, ngx_str_t *value);
static ngx_int_t ngx_http_add_header(ngx_http_request_t *r,
@@ -209,28 +212,52 @@ ngx_http_headers_filter(ngx_http_request_t *r)
static ngx_int_t
ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
{
- size_t len;
- time_t now, expires_time, max_age;
- ngx_uint_t i;
- ngx_table_elt_t *expires, *cc, **ccp;
+ char *err;
+ size_t len;
+ time_t now, expires_time, max_age;
+ ngx_str_t value;
+ ngx_int_t rc;
+ ngx_uint_t i;
+ ngx_table_elt_t *e, *cc, **ccp;
+ ngx_http_expires_t expires;
- expires = r->headers_out.expires;
+ expires = conf->expires;
+ expires_time = conf->expires_time;
- if (expires == NULL) {
+ if (conf->expires_value != NULL) {
- expires = ngx_list_push(&r->headers_out.headers);
- if (expires == NULL) {
+ if (ngx_http_complex_value(r, conf->expires_value, &value) != NGX_OK) {
return NGX_ERROR;
}
- r->headers_out.expires = expires;
+ rc = ngx_http_parse_expires(&value, &expires, &expires_time, &err);
- expires->hash = 1;
- ngx_str_set(&expires->key, "Expires");
+ if (rc != NGX_OK) {
+ return NGX_OK;
+ }
+
+ if (expires == NGX_HTTP_EXPIRES_OFF) {
+ return NGX_OK;
+ }
+ }
+
+ e = r->headers_out.expires;
+
+ if (e == NULL) {
+
+ e = ngx_list_push(&r->headers_out.headers);
+ if (e == NULL) {
+ return NGX_ERROR;
+ }
+
+ r->headers_out.expires = e;
+
+ e->hash = 1;
+ ngx_str_set(&e->key, "Expires");
}
len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT");
- expires->value.len = len - 1;
+ e->value.len = len - 1;
ccp = r->headers_out.cache_control.elts;
@@ -265,26 +292,26 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
cc = ccp[0];
}
- if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) {
- expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT";
+ if (expires == NGX_HTTP_EXPIRES_EPOCH) {
+ e->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT";
ngx_str_set(&cc->value, "no-cache");
return NGX_OK;
}
- if (conf->expires == NGX_HTTP_EXPIRES_MAX) {
- expires->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT";
+ if (expires == NGX_HTTP_EXPIRES_MAX) {
+ e->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT";
/* 10 years */
ngx_str_set(&cc->value, "max-age=315360000");
return NGX_OK;
}
- expires->value.data = ngx_pnalloc(r->pool, len);
- if (expires->value.data == NULL) {
+ e->value.data = ngx_pnalloc(r->pool, len);
+ if (e->value.data == NULL) {
return NGX_ERROR;
}
- if (conf->expires_time == 0 && conf->expires != NGX_HTTP_EXPIRES_DAILY) {
- ngx_memcpy(expires->value.data, ngx_cached_http_time.data,
+ if (expires_time == 0 && expires != NGX_HTTP_EXPIRES_DAILY) {
+ ngx_memcpy(e->value.data, ngx_cached_http_time.data,
ngx_cached_http_time.len + 1);
ngx_str_set(&cc->value, "max-age=0");
return NGX_OK;
@@ -292,22 +319,22 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
now = ngx_time();
- if (conf->expires == NGX_HTTP_EXPIRES_DAILY) {
- expires_time = ngx_next_time(conf->expires_time);
+ if (expires == NGX_HTTP_EXPIRES_DAILY) {
+ expires_time = ngx_next_time(expires_time);
max_age = expires_time - now;
- } else if (conf->expires == NGX_HTTP_EXPIRES_ACCESS
+ } else if (expires == NGX_HTTP_EXPIRES_ACCESS
|| r->headers_out.last_modified_time == -1)
{
- expires_time = now + conf->expires_time;
- max_age = conf->expires_time;
+ max_age = expires_time;
+ expires_time += now;
} else {
- expires_time = r->headers_out.last_modified_time + conf->expires_time;
+ expires_time += r->headers_out.last_modified_time;
max_age = expires_time - now;
}
- ngx_http_time(expires->value.data, expires_time);
+ ngx_http_time(e->value.data, expires_time);
if (conf->expires_time < 0 || max_age < 0) {
ngx_str_set(&cc->value, "no-cache");
@@ -328,6 +355,78 @@ ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
static ngx_int_t
+ngx_http_parse_expires(ngx_str_t *value, ngx_http_expires_t *expires,
+ time_t *expires_time, char **err)
+{
+ ngx_uint_t minus;
+
+ if (*expires != NGX_HTTP_EXPIRES_MODIFIED) {
+
+ if (value->len == 5 && ngx_strncmp(value->data, "epoch", 5) == 0) {
+ *expires = NGX_HTTP_EXPIRES_EPOCH;
+ return NGX_OK;
+ }
+
+ if (value->len == 3 && ngx_strncmp(value->data, "max", 3) == 0) {
+ *expires = NGX_HTTP_EXPIRES_MAX;
+ return NGX_OK;
+ }
+
+ if (value->len == 3 && ngx_strncmp(value->data, "off", 3) == 0) {
+ *expires = NGX_HTTP_EXPIRES_OFF;
+ return NGX_OK;
+ }
+ }
+
+ if (value->data[0] == '@') {
+ value->data++;
+ value->len--;
+ minus = 0;
+
+ if (*expires == NGX_HTTP_EXPIRES_MODIFIED) {
+ *err = "daily time cannot be used with \"modified\" parameter";
+ return NGX_ERROR;
+ }
+
+ *expires = NGX_HTTP_EXPIRES_DAILY;
+
+ } else if (value->data[0] == '+') {
+ value->data++;
+ value->len--;
+ minus = 0;
+
+ } else if (value->data[0] == '-') {
+ value->data++;
+ value->len--;
+ minus = 1;
+
+ } else {
+ minus = 0;
+ }
+
+ *expires_time = ngx_parse_time(value, 1);
+
+ if (*expires_time == (time_t) NGX_ERROR) {
+ *err = "invalid value";
+ return NGX_ERROR;
+ }
+
+ if (*expires == NGX_HTTP_EXPIRES_DAILY
+ && *expires_time > 24 * 60 * 60)
+ {
+ *err = "daily time value must be less than 24 hours";
+ return NGX_ERROR;
+ }
+
+ if (minus) {
+ *expires_time = - *expires_time;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_add_header(ngx_http_request_t *r, ngx_http_header_val_t *hv,
ngx_str_t *value)
{
@@ -457,6 +556,7 @@ ngx_http_headers_create_conf(ngx_conf_t *cf)
*
* conf->headers = NULL;
* conf->expires_time = 0;
+ * conf->expires_value = NULL;
*/
conf->expires = NGX_HTTP_EXPIRES_UNSET;
@@ -474,6 +574,7 @@ ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->expires == NGX_HTTP_EXPIRES_UNSET) {
conf->expires = prev->expires;
conf->expires_time = prev->expires_time;
+ conf->expires_value = prev->expires_value;
if (conf->expires == NGX_HTTP_EXPIRES_UNSET) {
conf->expires = NGX_HTTP_EXPIRES_OFF;
@@ -503,8 +604,12 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_headers_conf_t *hcf = conf;
- ngx_uint_t minus, n;
- ngx_str_t *value;
+ char *err;
+ ngx_str_t *value;
+ ngx_int_t rc;
+ ngx_uint_t n;
+ ngx_http_complex_value_t cv;
+ ngx_http_compile_complex_value_t ccv;
if (hcf->expires != NGX_HTTP_EXPIRES_UNSET) {
return "is duplicate";
@@ -514,21 +619,6 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (cf->args->nelts == 2) {
- if (ngx_strcmp(value[1].data, "epoch") == 0) {
- hcf->expires = NGX_HTTP_EXPIRES_EPOCH;
- return NGX_CONF_OK;
- }
-
- if (ngx_strcmp(value[1].data, "max") == 0) {
- hcf->expires = NGX_HTTP_EXPIRES_MAX;
- return NGX_CONF_OK;
- }
-
- if (ngx_strcmp(value[1].data, "off") == 0) {
- hcf->expires = NGX_HTTP_EXPIRES_OFF;
- return NGX_CONF_OK;
- }
-
hcf->expires = NGX_HTTP_EXPIRES_ACCESS;
n = 1;
@@ -544,45 +634,33 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
n = 2;
}
- if (value[n].data[0] == '@') {
- value[n].data++;
- value[n].len--;
- minus = 0;
-
- if (hcf->expires == NGX_HTTP_EXPIRES_MODIFIED) {
- return "daily time cannot be used with \"modified\" parameter";
- }
-
- hcf->expires = NGX_HTTP_EXPIRES_DAILY;
-
- } else if (value[n].data[0] == '+') {
- value[n].data++;
- value[n].len--;
- minus = 0;
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
- } else if (value[n].data[0] == '-') {
- value[n].data++;
- value[n].len--;
- minus = 1;
+ ccv.cf = cf;
+ ccv.value = &value[n];
+ ccv.complex_value = &cv;
- } else {
- minus = 0;
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
}
- hcf->expires_time = ngx_parse_time(&value[n], 1);
+ if (cv.lengths != NULL) {
- if (hcf->expires_time == (time_t) NGX_ERROR) {
- return "invalid value";
- }
+ hcf->expires_value = ngx_palloc(cf->pool,
+ sizeof(ngx_http_complex_value_t));
+ if (hcf->expires_value == NULL) {
+ return NGX_CONF_ERROR;
+ }
- if (hcf->expires == NGX_HTTP_EXPIRES_DAILY
- && hcf->expires_time > 24 * 60 * 60)
- {
- return "daily time value must be less than 24 hours";
+ *hcf->expires_value = cv;
+
+ return NGX_CONF_OK;
}
- if (minus) {
- hcf->expires_time = - hcf->expires_time;
+ rc = ngx_http_parse_expires(&value[n], &hcf->expires, &hcf->expires_time,
+ &err);
+ if (rc != NGX_OK) {
+ return err;
}
return NGX_CONF_OK;
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 41bf1c91f..d7675d468 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -10,6 +10,11 @@
#include <ngx_http.h>
+typedef struct {
+ ngx_array_t caches; /* ngx_http_file_cache_t * */
+} ngx_http_proxy_main_conf_t;
+
+
typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t;
typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
@@ -151,6 +156,7 @@ static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
+static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf);
static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
@@ -438,8 +444,8 @@ static ngx_command_t ngx_http_proxy_commands[] = {
{ ngx_string("proxy_cache_path"),
NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
ngx_http_file_cache_set_slot,
- 0,
- 0,
+ NGX_HTTP_MAIN_CONF_OFFSET,
+ offsetof(ngx_http_proxy_main_conf_t, caches),
&ngx_http_proxy_module },
{ ngx_string("proxy_cache_bypass"),
@@ -680,7 +686,7 @@ static ngx_http_module_t ngx_http_proxy_module_ctx = {
ngx_http_proxy_add_variables, /* preconfiguration */
NULL, /* postconfiguration */
- NULL, /* create main configuration */
+ ngx_http_proxy_create_main_conf, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
@@ -715,6 +721,7 @@ static ngx_keyval_t ngx_http_proxy_headers[] = {
{ ngx_string("Host"), ngx_string("$proxy_host") },
{ ngx_string("Connection"), ngx_string("close") },
{ ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
+ { ngx_string("TE"), ngx_string("") },
{ ngx_string("Transfer-Encoding"), ngx_string("") },
{ ngx_string("Keep-Alive"), ngx_string("") },
{ ngx_string("Expect"), ngx_string("") },
@@ -742,6 +749,7 @@ static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
{ ngx_string("Host"), ngx_string("$proxy_host") },
{ ngx_string("Connection"), ngx_string("close") },
{ ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
+ { ngx_string("TE"), ngx_string("") },
{ ngx_string("Transfer-Encoding"), ngx_string("") },
{ ngx_string("Keep-Alive"), ngx_string("") },
{ ngx_string("Expect"), ngx_string("") },
@@ -790,10 +798,13 @@ static ngx_path_init_t ngx_http_proxy_temp_path = {
static ngx_int_t
ngx_http_proxy_handler(ngx_http_request_t *r)
{
- ngx_int_t rc;
- ngx_http_upstream_t *u;
- ngx_http_proxy_ctx_t *ctx;
- ngx_http_proxy_loc_conf_t *plcf;
+ ngx_int_t rc;
+ ngx_http_upstream_t *u;
+ ngx_http_proxy_ctx_t *ctx;
+ ngx_http_proxy_loc_conf_t *plcf;
+#if (NGX_HTTP_CACHE)
+ ngx_http_proxy_main_conf_t *pmcf;
+#endif
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -828,8 +839,12 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
u->conf = &plcf->upstream;
#if (NGX_HTTP_CACHE)
+ pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module);
+
+ u->caches = &pmcf->caches;
u->create_key = ngx_http_proxy_create_key;
#endif
+
u->create_request = ngx_http_proxy_create_request;
u->reinit_request = ngx_http_proxy_reinit_request;
u->process_header = ngx_http_proxy_process_status_line;
@@ -2492,6 +2507,29 @@ ngx_http_proxy_add_variables(ngx_conf_t *cf)
static void *
+ngx_http_proxy_create_main_conf(ngx_conf_t *cf)
+{
+ ngx_http_proxy_main_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_main_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+#if (NGX_HTTP_CACHE)
+ if (ngx_array_init(&conf->caches, cf->pool, 4,
+ sizeof(ngx_http_file_cache_t *))
+ != NGX_OK)
+ {
+ return NULL;
+ }
+#endif
+
+ return conf;
+}
+
+
+static void *
ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_proxy_loc_conf_t *conf;
@@ -2507,6 +2545,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
* conf->upstream.bufs.num = 0;
* conf->upstream.ignore_headers = 0;
* conf->upstream.next_upstream = 0;
+ * conf->upstream.cache_zone = NULL;
* conf->upstream.cache_use_stale = 0;
* conf->upstream.cache_methods = 0;
* conf->upstream.temp_path = NULL;
@@ -2564,7 +2603,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.pass_request_body = NGX_CONF_UNSET;
#if (NGX_HTTP_CACHE)
- conf->upstream.cache = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache = NGX_CONF_UNSET;
conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
@@ -2622,14 +2661,24 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_proxy_rewrite_t *pr;
ngx_http_script_compile_t sc;
- if (conf->upstream.store != 0) {
+#if (NGX_HTTP_CACHE)
+
+ if (conf->upstream.store > 0) {
+ conf->upstream.cache = 0;
+ }
+
+ if (conf->upstream.cache > 0) {
+ conf->upstream.store = 0;
+ }
+
+#endif
+
+ if (conf->upstream.store == NGX_CONF_UNSET) {
ngx_conf_merge_value(conf->upstream.store,
prev->upstream.store, 0);
- if (conf->upstream.store_lengths == NULL) {
- conf->upstream.store_lengths = prev->upstream.store_lengths;
- conf->upstream.store_values = prev->upstream.store_values;
- }
+ conf->upstream.store_lengths = prev->upstream.store_lengths;
+ conf->upstream.store_values = prev->upstream.store_values;
}
ngx_conf_merge_uint_value(conf->upstream.store_access,
@@ -2790,13 +2839,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
#if (NGX_HTTP_CACHE)
- ngx_conf_merge_ptr_value(conf->upstream.cache,
- prev->upstream.cache, NULL);
+ if (conf->upstream.cache == NGX_CONF_UNSET) {
+ ngx_conf_merge_value(conf->upstream.cache,
+ prev->upstream.cache, 0);
+
+ conf->upstream.cache_zone = prev->upstream.cache_zone;
+ conf->upstream.cache_value = prev->upstream.cache_value;
+ }
- if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
+ if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
ngx_shm_zone_t *shm_zone;
- shm_zone = conf->upstream.cache;
+ shm_zone = conf->upstream.cache_zone;
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"proxy_cache\" zone \"%V\" is unknown",
@@ -2966,12 +3020,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
-#if (NGX_HTTP_SSL)
- if (conf->upstream.ssl == NULL) {
- conf->upstream.ssl = prev->upstream.ssl;
- }
-#endif
-
ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
NGX_HTTP_VERSION_10);
@@ -2995,22 +3043,27 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
- if (conf->upstream.upstream == NULL) {
+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+
+ if (clcf->noname
+ && conf->upstream.upstream == NULL && conf->proxy_lengths == NULL)
+ {
conf->upstream.upstream = prev->upstream.upstream;
+ conf->location = prev->location;
conf->vars = prev->vars;
- }
- if (conf->proxy_lengths == NULL) {
conf->proxy_lengths = prev->proxy_lengths;
conf->proxy_values = prev->proxy_values;
+
+#if (NGX_HTTP_SSL)
+ conf->upstream.ssl = prev->upstream.ssl;
+#endif
}
- if (conf->upstream.upstream || conf->proxy_lengths) {
- clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
- if (clcf->handler == NULL && clcf->lmt_excpt) {
- clcf->handler = ngx_http_proxy_handler;
- conf->location = prev->location;
- }
+ if (clcf->lmt_excpt && clcf->handler == NULL
+ && (conf->upstream.upstream || conf->proxy_lengths))
+ {
+ clcf->handler = ngx_http_proxy_handler;
}
if (conf->body_source.data == NULL) {
@@ -3793,9 +3846,7 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_str_t *value;
ngx_http_script_compile_t sc;
- if (plcf->upstream.store != NGX_CONF_UNSET
- || plcf->upstream.store_lengths)
- {
+ if (plcf->upstream.store != NGX_CONF_UNSET) {
return "is duplicate";
}
@@ -3807,17 +3858,14 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
#if (NGX_HTTP_CACHE)
-
- if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
- && plcf->upstream.cache != NULL)
- {
+ if (plcf->upstream.cache > 0) {
return "is incompatible with \"proxy_cache\"";
}
-
#endif
+ plcf->upstream.store = 1;
+
if (ngx_strcmp(value[1].data, "on") == 0) {
- plcf->upstream.store = 1;
return NGX_CONF_OK;
}
@@ -3849,26 +3897,53 @@ ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_proxy_loc_conf_t *plcf = conf;
- ngx_str_t *value;
+ ngx_str_t *value;
+ ngx_http_complex_value_t cv;
+ ngx_http_compile_complex_value_t ccv;
value = cf->args->elts;
- if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) {
+ if (plcf->upstream.cache != NGX_CONF_UNSET) {
return "is duplicate";
}
if (ngx_strcmp(value[1].data, "off") == 0) {
- plcf->upstream.cache = NULL;
+ plcf->upstream.cache = 0;
return NGX_CONF_OK;
}
- if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
+ if (plcf->upstream.store > 0) {
return "is incompatible with \"proxy_store\"";
}
- plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
- &ngx_http_proxy_module);
- if (plcf->upstream.cache == NULL) {
+ plcf->upstream.cache = 1;
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = &cv;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (cv.lengths != NULL) {
+
+ plcf->upstream.cache_value = ngx_palloc(cf->pool,
+ sizeof(ngx_http_complex_value_t));
+ if (plcf->upstream.cache_value == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ *plcf->upstream.cache_value = cv;
+
+ return NGX_CONF_OK;
+ }
+
+ plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
+ &ngx_http_proxy_module);
+ if (plcf->upstream.cache_zone == NULL) {
return NGX_CONF_ERROR;
}
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index 53a90d99a..33c23a5a1 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -12,6 +12,11 @@
typedef struct {
+ ngx_array_t caches; /* ngx_http_file_cache_t * */
+} ngx_http_scgi_main_conf_t;
+
+
+typedef struct {
ngx_array_t *flushes;
ngx_array_t *lengths;
ngx_array_t *values;
@@ -47,6 +52,7 @@ 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);
+static void *ngx_http_scgi_create_main_conf(ngx_conf_t *cf);
static void *ngx_http_scgi_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
void *child);
@@ -224,8 +230,8 @@ static ngx_command_t ngx_http_scgi_commands[] = {
{ ngx_string("scgi_cache_path"),
NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
ngx_http_file_cache_set_slot,
- 0,
- 0,
+ NGX_HTTP_MAIN_CONF_OFFSET,
+ offsetof(ngx_http_scgi_main_conf_t, caches),
&ngx_http_scgi_module },
{ ngx_string("scgi_cache_bypass"),
@@ -378,7 +384,7 @@ static ngx_http_module_t ngx_http_scgi_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */
- NULL, /* create main configuration */
+ ngx_http_scgi_create_main_conf, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
@@ -440,10 +446,13 @@ static ngx_path_init_t ngx_http_scgi_temp_path = {
static ngx_int_t
ngx_http_scgi_handler(ngx_http_request_t *r)
{
- ngx_int_t rc;
- ngx_http_status_t *status;
- ngx_http_upstream_t *u;
- ngx_http_scgi_loc_conf_t *scf;
+ ngx_int_t rc;
+ ngx_http_status_t *status;
+ ngx_http_upstream_t *u;
+ ngx_http_scgi_loc_conf_t *scf;
+#if (NGX_HTTP_CACHE)
+ ngx_http_scgi_main_conf_t *smcf;
+#endif
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -472,8 +481,12 @@ ngx_http_scgi_handler(ngx_http_request_t *r)
u->conf = &scf->upstream;
#if (NGX_HTTP_CACHE)
+ smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module);
+
+ u->caches = &smcf->caches;
u->create_key = ngx_http_scgi_create_key;
#endif
+
u->create_request = ngx_http_scgi_create_request;
u->reinit_request = ngx_http_scgi_reinit_request;
u->process_header = ngx_http_scgi_process_status_line;
@@ -1113,6 +1126,29 @@ ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
static void *
+ngx_http_scgi_create_main_conf(ngx_conf_t *cf)
+{
+ ngx_http_scgi_main_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_main_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+#if (NGX_HTTP_CACHE)
+ if (ngx_array_init(&conf->caches, cf->pool, 4,
+ sizeof(ngx_http_file_cache_t *))
+ != NGX_OK)
+ {
+ return NULL;
+ }
+#endif
+
+ return conf;
+}
+
+
+static void *
ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_scgi_loc_conf_t *conf;
@@ -1148,7 +1184,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.pass_request_body = NGX_CONF_UNSET;
#if (NGX_HTTP_CACHE)
- conf->upstream.cache = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache = NGX_CONF_UNSET;
conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
@@ -1186,13 +1222,23 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_hash_init_t hash;
ngx_http_core_loc_conf_t *clcf;
- if (conf->upstream.store != 0) {
+#if (NGX_HTTP_CACHE)
+
+ if (conf->upstream.store > 0) {
+ conf->upstream.cache = 0;
+ }
+
+ if (conf->upstream.cache > 0) {
+ conf->upstream.store = 0;
+ }
+
+#endif
+
+ if (conf->upstream.store == NGX_CONF_UNSET) {
ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);
- if (conf->upstream.store_lengths == NULL) {
- conf->upstream.store_lengths = prev->upstream.store_lengths;
- conf->upstream.store_values = prev->upstream.store_values;
- }
+ conf->upstream.store_lengths = prev->upstream.store_lengths;
+ conf->upstream.store_values = prev->upstream.store_values;
}
ngx_conf_merge_uint_value(conf->upstream.store_access,
@@ -1354,13 +1400,18 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
#if (NGX_HTTP_CACHE)
- ngx_conf_merge_ptr_value(conf->upstream.cache,
- prev->upstream.cache, NULL);
+ if (conf->upstream.cache == NGX_CONF_UNSET) {
+ ngx_conf_merge_value(conf->upstream.cache,
+ prev->upstream.cache, 0);
- if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
+ conf->upstream.cache_zone = prev->upstream.cache_zone;
+ conf->upstream.cache_value = prev->upstream.cache_value;
+ }
+
+ if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
ngx_shm_zone_t *shm_zone;
- shm_zone = conf->upstream.cache;
+ shm_zone = conf->upstream.cache_zone;
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"scgi_cache\" zone \"%V\" is unknown",
@@ -1443,20 +1494,20 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
- if (conf->upstream.upstream == NULL) {
- conf->upstream.upstream = prev->upstream.upstream;
- }
+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
- if (conf->scgi_lengths == NULL) {
+ if (clcf->noname
+ && conf->upstream.upstream == NULL && conf->scgi_lengths == NULL)
+ {
+ conf->upstream.upstream = prev->upstream.upstream;
conf->scgi_lengths = prev->scgi_lengths;
conf->scgi_values = prev->scgi_values;
}
- if (conf->upstream.upstream || conf->scgi_lengths) {
- clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
- if (clcf->handler == NULL && clcf->lmt_excpt) {
- clcf->handler = ngx_http_scgi_handler;
- }
+ if (clcf->lmt_excpt && clcf->handler == NULL
+ && (conf->upstream.upstream || conf->scgi_lengths))
+ {
+ clcf->handler = ngx_http_scgi_handler;
}
if (conf->params_source == NULL) {
@@ -1760,7 +1811,7 @@ ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_str_t *value;
ngx_http_script_compile_t sc;
- if (scf->upstream.store != NGX_CONF_UNSET || scf->upstream.store_lengths) {
+ if (scf->upstream.store != NGX_CONF_UNSET) {
return "is duplicate";
}
@@ -1772,17 +1823,14 @@ ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
#if (NGX_HTTP_CACHE)
-
- if (scf->upstream.cache != NGX_CONF_UNSET_PTR
- && scf->upstream.cache != NULL)
- {
+ if (scf->upstream.cache > 0) {
return "is incompatible with \"scgi_cache\"";
}
-
#endif
+ scf->upstream.store = 1;
+
if (ngx_strcmp(value[1].data, "on") == 0) {
- scf->upstream.store = 1;
return NGX_CONF_OK;
}
@@ -1814,26 +1862,53 @@ ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_scgi_loc_conf_t *scf = conf;
- ngx_str_t *value;
+ ngx_str_t *value;
+ ngx_http_complex_value_t cv;
+ ngx_http_compile_complex_value_t ccv;
value = cf->args->elts;
- if (scf->upstream.cache != NGX_CONF_UNSET_PTR) {
+ if (scf->upstream.cache != NGX_CONF_UNSET) {
return "is duplicate";
}
if (ngx_strcmp(value[1].data, "off") == 0) {
- scf->upstream.cache = NULL;
+ scf->upstream.cache = 0;
return NGX_CONF_OK;
}
- if (scf->upstream.store > 0 || scf->upstream.store_lengths) {
+ if (scf->upstream.store > 0) {
return "is incompatible with \"scgi_store\"";
}
- scf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
- &ngx_http_scgi_module);
- if (scf->upstream.cache == NULL) {
+ scf->upstream.cache = 1;
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = &cv;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (cv.lengths != NULL) {
+
+ scf->upstream.cache_value = ngx_palloc(cf->pool,
+ sizeof(ngx_http_complex_value_t));
+ if (scf->upstream.cache_value == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ *scf->upstream.cache_value = cv;
+
+ return NGX_CONF_OK;
+ }
+
+ scf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
+ &ngx_http_scgi_module);
+ if (scf->upstream.cache_zone == NULL) {
return NGX_CONF_ERROR;
}
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index d12fbdf7b..f833d675c 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -13,6 +13,11 @@
typedef struct {
+ ngx_array_t caches; /* ngx_http_file_cache_t * */
+} ngx_http_uwsgi_main_conf_t;
+
+
+typedef struct {
ngx_array_t *flushes;
ngx_array_t *lengths;
ngx_array_t *values;
@@ -66,6 +71,7 @@ static void ngx_http_uwsgi_abort_request(ngx_http_request_t *r);
static void ngx_http_uwsgi_finalize_request(ngx_http_request_t *r,
ngx_int_t rc);
+static void *ngx_http_uwsgi_create_main_conf(ngx_conf_t *cf);
static void *ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
void *child);
@@ -284,8 +290,8 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
{ ngx_string("uwsgi_cache_path"),
NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
ngx_http_file_cache_set_slot,
- 0,
- 0,
+ NGX_HTTP_MAIN_CONF_OFFSET,
+ offsetof(ngx_http_uwsgi_main_conf_t, caches),
&ngx_http_uwsgi_module },
{ ngx_string("uwsgi_cache_bypass"),
@@ -533,7 +539,7 @@ static ngx_http_module_t ngx_http_uwsgi_module_ctx = {
NULL, /* preconfiguration */
NULL, /* postconfiguration */
- NULL, /* create main configuration */
+ ngx_http_uwsgi_create_main_conf, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
@@ -594,10 +600,13 @@ static ngx_path_init_t ngx_http_uwsgi_temp_path = {
static ngx_int_t
ngx_http_uwsgi_handler(ngx_http_request_t *r)
{
- ngx_int_t rc;
- ngx_http_status_t *status;
- ngx_http_upstream_t *u;
- ngx_http_uwsgi_loc_conf_t *uwcf;
+ ngx_int_t rc;
+ ngx_http_status_t *status;
+ ngx_http_upstream_t *u;
+ ngx_http_uwsgi_loc_conf_t *uwcf;
+#if (NGX_HTTP_CACHE)
+ ngx_http_uwsgi_main_conf_t *uwmcf;
+#endif
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -640,8 +649,12 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r)
u->conf = &uwcf->upstream;
#if (NGX_HTTP_CACHE)
+ uwmcf = ngx_http_get_module_main_conf(r, ngx_http_uwsgi_module);
+
+ u->caches = &uwmcf->caches;
u->create_key = ngx_http_uwsgi_create_key;
#endif
+
u->create_request = ngx_http_uwsgi_create_request;
u->reinit_request = ngx_http_uwsgi_reinit_request;
u->process_header = ngx_http_uwsgi_process_status_line;
@@ -1316,6 +1329,29 @@ ngx_http_uwsgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
static void *
+ngx_http_uwsgi_create_main_conf(ngx_conf_t *cf)
+{
+ ngx_http_uwsgi_main_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_uwsgi_main_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+#if (NGX_HTTP_CACHE)
+ if (ngx_array_init(&conf->caches, cf->pool, 4,
+ sizeof(ngx_http_file_cache_t *))
+ != NGX_OK)
+ {
+ return NULL;
+ }
+#endif
+
+ return conf;
+}
+
+
+static void *
ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_uwsgi_loc_conf_t *conf;
@@ -1354,7 +1390,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.pass_request_body = NGX_CONF_UNSET;
#if (NGX_HTTP_CACHE)
- conf->upstream.cache = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache = NGX_CONF_UNSET;
conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
@@ -1400,13 +1436,23 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_hash_init_t hash;
ngx_http_core_loc_conf_t *clcf;
- if (conf->upstream.store != 0) {
+#if (NGX_HTTP_CACHE)
+
+ if (conf->upstream.store > 0) {
+ conf->upstream.cache = 0;
+ }
+
+ if (conf->upstream.cache > 0) {
+ conf->upstream.store = 0;
+ }
+
+#endif
+
+ if (conf->upstream.store == NGX_CONF_UNSET) {
ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);
- if (conf->upstream.store_lengths == NULL) {
- conf->upstream.store_lengths = prev->upstream.store_lengths;
- conf->upstream.store_values = prev->upstream.store_values;
- }
+ conf->upstream.store_lengths = prev->upstream.store_lengths;
+ conf->upstream.store_values = prev->upstream.store_values;
}
ngx_conf_merge_uint_value(conf->upstream.store_access,
@@ -1568,13 +1614,18 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
#if (NGX_HTTP_CACHE)
- ngx_conf_merge_ptr_value(conf->upstream.cache,
- prev->upstream.cache, NULL);
+ if (conf->upstream.cache == NGX_CONF_UNSET) {
+ ngx_conf_merge_value(conf->upstream.cache,
+ prev->upstream.cache, 0);
+
+ conf->upstream.cache_zone = prev->upstream.cache_zone;
+ conf->upstream.cache_value = prev->upstream.cache_value;
+ }
- if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
+ if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
ngx_shm_zone_t *shm_zone;
- shm_zone = conf->upstream.cache;
+ shm_zone = conf->upstream.cache_zone;
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"uwsgi_cache\" zone \"%V\" is unknown",
@@ -1683,10 +1734,6 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
- if (conf->upstream.ssl == NULL) {
- conf->upstream.ssl = prev->upstream.ssl;
- }
-
#endif
ngx_conf_merge_str_value(conf->uwsgi_string, prev->uwsgi_string, "");
@@ -1702,20 +1749,25 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
- if (conf->upstream.upstream == NULL) {
+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+
+ if (clcf->noname
+ && conf->upstream.upstream == NULL && conf->uwsgi_lengths == NULL)
+ {
conf->upstream.upstream = prev->upstream.upstream;
- }
- if (conf->uwsgi_lengths == NULL) {
conf->uwsgi_lengths = prev->uwsgi_lengths;
conf->uwsgi_values = prev->uwsgi_values;
+
+#if (NGX_HTTP_SSL)
+ conf->upstream.ssl = prev->upstream.ssl;
+#endif
}
- if (conf->upstream.upstream || conf->uwsgi_lengths) {
- clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
- if (clcf->handler == NULL && clcf->lmt_excpt) {
- clcf->handler = ngx_http_uwsgi_handler;
- }
+ if (clcf->lmt_excpt && clcf->handler == NULL
+ && (conf->upstream.upstream || conf->uwsgi_lengths))
+ {
+ clcf->handler = ngx_http_uwsgi_handler;
}
ngx_conf_merge_uint_value(conf->modifier1, prev->modifier1, 0);
@@ -2046,8 +2098,7 @@ ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_str_t *value;
ngx_http_script_compile_t sc;
- if (uwcf->upstream.store != NGX_CONF_UNSET || uwcf->upstream.store_lengths)
- {
+ if (uwcf->upstream.store != NGX_CONF_UNSET) {
return "is duplicate";
}
@@ -2060,16 +2111,15 @@ ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#if (NGX_HTTP_CACHE)
- if (uwcf->upstream.cache != NGX_CONF_UNSET_PTR
- && uwcf->upstream.cache != NULL)
- {
+ if (uwcf->upstream.cache > 0) {
return "is incompatible with \"uwsgi_cache\"";
}
#endif
+ uwcf->upstream.store = 1;
+
if (ngx_strcmp(value[1].data, "on") == 0) {
- uwcf->upstream.store = 1;
return NGX_CONF_OK;
}
@@ -2101,26 +2151,53 @@ ngx_http_uwsgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_uwsgi_loc_conf_t *uwcf = conf;
- ngx_str_t *value;
+ ngx_str_t *value;
+ ngx_http_complex_value_t cv;
+ ngx_http_compile_complex_value_t ccv;
value = cf->args->elts;
- if (uwcf->upstream.cache != NGX_CONF_UNSET_PTR) {
+ if (uwcf->upstream.cache != NGX_CONF_UNSET) {
return "is duplicate";
}
if (ngx_strcmp(value[1].data, "off") == 0) {
- uwcf->upstream.cache = NULL;
+ uwcf->upstream.cache = 0;
return NGX_CONF_OK;
}
- if (uwcf->upstream.store > 0 || uwcf->upstream.store_lengths) {
+ if (uwcf->upstream.store > 0) {
return "is incompatible with \"uwsgi_store\"";
}
- uwcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
- &ngx_http_uwsgi_module);
- if (uwcf->upstream.cache == NULL) {
+ uwcf->upstream.cache = 1;
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = &cv;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (cv.lengths != NULL) {
+
+ uwcf->upstream.cache_value = ngx_palloc(cf->pool,
+ sizeof(ngx_http_complex_value_t));
+ if (uwcf->upstream.cache_value == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ *uwcf->upstream.cache_value = cv;
+
+ return NGX_CONF_OK;
+ }
+
+ uwcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
+ &ngx_http_uwsgi_module);
+ if (uwcf->upstream.cache_zone == NULL) {
return NGX_CONF_ERROR;
}
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index c3f4f05d2..681c913c6 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -177,6 +177,8 @@ ngx_http_file_cache_new(ngx_http_request_t *r)
c->file.log = r->connection->log;
c->file.fd = NGX_INVALID_FILE;
+ c->last_modified = -1;
+
return NGX_OK;
}
@@ -2030,6 +2032,8 @@ ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status)
char *
ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
+ char *confp = conf;
+
off_t max_size;
u_char *last, *p;
time_t inactive;
@@ -2038,7 +2042,8 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_int_t loader_files;
ngx_msec_t loader_sleep, loader_threshold;
ngx_uint_t i, n;
- ngx_http_file_cache_t *cache;
+ ngx_array_t *caches;
+ ngx_http_file_cache_t *cache, **ce;
cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));
if (cache == NULL) {
@@ -2250,6 +2255,15 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
cache->inactive = inactive;
cache->max_size = max_size;
+ caches = (ngx_array_t *) (confp + cmd->offset);
+
+ ce = ngx_array_push(caches);
+ if (ce == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ *ce = cache;
+
return NGX_CONF_OK;
}
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 4c768b1bc..c9a998001 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -13,6 +13,8 @@
#if (NGX_HTTP_CACHE)
static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r,
ngx_http_upstream_t *u);
+static ngx_int_t ngx_http_upstream_cache_get(ngx_http_request_t *r,
+ ngx_http_upstream_t *u, ngx_http_file_cache_t **cache);
static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
@@ -540,7 +542,7 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
#endif
- u->store = (u->conf->store || u->conf->store_lengths);
+ u->store = u->conf->store;
if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
@@ -723,8 +725,9 @@ found:
static ngx_int_t
ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
- ngx_int_t rc;
- ngx_http_cache_t *c;
+ ngx_int_t rc;
+ ngx_http_cache_t *c;
+ ngx_http_file_cache_t *cache;
c = r->cache;
@@ -734,6 +737,12 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
return NGX_DECLINED;
}
+ rc = ngx_http_upstream_cache_get(r, u, &cache);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
if (r->method & NGX_HTTP_HEAD) {
u->method = ngx_http_core_get_method;
}
@@ -763,6 +772,12 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
u->cacheable = 1;
+ c = r->cache;
+
+ c->body_start = u->conf->buffer_size;
+ c->min_uses = u->conf->cache_min_uses;
+ c->file_cache = cache;
+
switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) {
case NGX_ERROR:
@@ -776,12 +791,6 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
break;
}
- c = r->cache;
-
- c->min_uses = u->conf->cache_min_uses;
- 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;
c->lock_age = u->conf->cache_lock_age;
@@ -874,6 +883,49 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
static ngx_int_t
+ngx_http_upstream_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u,
+ ngx_http_file_cache_t **cache)
+{
+ ngx_str_t *name, val;
+ ngx_uint_t i;
+ ngx_http_file_cache_t **caches;
+
+ if (u->conf->cache_zone) {
+ *cache = u->conf->cache_zone->data;
+ return NGX_OK;
+ }
+
+ if (ngx_http_complex_value(r, u->conf->cache_value, &val) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (val.len == 0
+ || (val.len == 3 && ngx_strncmp(val.data, "off", 3) == 0))
+ {
+ return NGX_DECLINED;
+ }
+
+ caches = u->caches->elts;
+
+ for (i = 0; i < u->caches->nelts; i++) {
+ name = &caches[i]->shm_zone->shm.name;
+
+ if (name->len == val.len
+ && ngx_strncmp(name->data, val.data, val.len) == 0)
+ {
+ *cache = caches[i];
+ return NGX_OK;
+ }
+ }
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "cache \"%V\" not found", &val);
+
+ return NGX_ERROR;
+}
+
+
+static ngx_int_t
ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
ngx_int_t rc;
@@ -2536,9 +2588,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
if (u->cache_status == NGX_HTTP_CACHE_BYPASS) {
- r->cache->min_uses = u->conf->cache_min_uses;
- r->cache->body_start = u->conf->buffer_size;
- r->cache->file_cache = u->conf->cache->data;
+ /* create cache if previously bypassed */
if (ngx_http_file_cache_create(r) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
@@ -2565,12 +2615,17 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
}
if (valid) {
- 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;
+ if (u->headers_in.status_n == NGX_HTTP_OK
+ || u->headers_in.status_n == NGX_HTTP_PARTIAL_CONTENT)
+ {
+ r->cache->last_modified = u->headers_in.last_modified_time;
+
+ if (u->headers_in.etag) {
+ r->cache->etag = u->headers_in.etag->value;
+ }
}
ngx_http_file_cache_set_header(r, u->buffer.start);
@@ -5540,7 +5595,7 @@ ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
if (conf->hide_headers_hash.buckets
#if (NGX_HTTP_CACHE)
- && ((conf->cache == NULL) == (prev->cache == NULL))
+ && ((conf->cache == 0) == (prev->cache == 0))
#endif
)
{
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index d04b66906..9d2ec9345 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -175,7 +175,8 @@ typedef struct {
ngx_http_upstream_local_t *local;
#if (NGX_HTTP_CACHE)
- ngx_shm_zone_t *cache;
+ ngx_shm_zone_t *cache_zone;
+ ngx_http_complex_value_t *cache_value;
ngx_uint_t cache_min_uses;
ngx_uint_t cache_use_stale;
@@ -195,6 +196,9 @@ typedef struct {
ngx_array_t *store_lengths;
ngx_array_t *store_values;
+#if (NGX_HTTP_CACHE)
+ signed cache:2;
+#endif
signed store:2;
unsigned intercept_404:1;
unsigned change_buffering:1;
@@ -297,6 +301,9 @@ struct ngx_http_upstream_s {
ngx_chain_writer_ctx_t writer;
ngx_http_upstream_conf_t *conf;
+#if (NGX_HTTP_CACHE)
+ ngx_array_t *caches;
+#endif
ngx_http_upstream_headers_in_t headers_in;