mirror of
https://github.com/nginx/nginx.git
synced 2024-12-20 06:03:31 -06:00
Cache: hash of Vary headers now stored in cache.
To cache responses with Vary, we now calculate hash of headers listed in Vary, and return the response from cache only if new request headers match. As of now, only one variant of the same resource can be stored in cache.
This commit is contained in:
parent
fc785b12a0
commit
1332e76b20
@ -25,8 +25,9 @@
|
||||
|
||||
#define NGX_HTTP_CACHE_KEY_LEN 16
|
||||
#define NGX_HTTP_CACHE_ETAG_LEN 42
|
||||
#define NGX_HTTP_CACHE_VARY_LEN 42
|
||||
|
||||
#define NGX_HTTP_CACHE_VERSION 2
|
||||
#define NGX_HTTP_CACHE_VERSION 3
|
||||
|
||||
|
||||
typedef struct {
|
||||
@ -71,6 +72,8 @@ struct ngx_http_cache_s {
|
||||
time_t date;
|
||||
|
||||
ngx_str_t etag;
|
||||
ngx_str_t vary;
|
||||
u_char variant[NGX_HTTP_CACHE_KEY_LEN];
|
||||
|
||||
size_t header_start;
|
||||
size_t body_start;
|
||||
@ -112,6 +115,9 @@ typedef struct {
|
||||
u_short body_start;
|
||||
u_char etag_len;
|
||||
u_char etag[NGX_HTTP_CACHE_ETAG_LEN];
|
||||
u_char vary_len;
|
||||
u_char vary[NGX_HTTP_CACHE_VARY_LEN];
|
||||
u_char variant[NGX_HTTP_CACHE_KEY_LEN];
|
||||
} ngx_http_file_cache_header_t;
|
||||
|
||||
|
||||
|
@ -29,6 +29,10 @@ static ngx_http_file_cache_node_t *
|
||||
ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key);
|
||||
static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
|
||||
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
|
||||
static void ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary,
|
||||
size_t len, u_char *hash);
|
||||
static void ngx_http_file_cache_vary_header(ngx_http_request_t *r,
|
||||
ngx_md5_t *md5, ngx_str_t *name);
|
||||
static void ngx_http_file_cache_cleanup(void *data);
|
||||
static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache);
|
||||
static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache);
|
||||
@ -519,6 +523,23 @@ ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c)
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (h->vary_len > NGX_HTTP_CACHE_VARY_LEN) {
|
||||
ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
|
||||
"cache file \"%s\" has incorrect vary length",
|
||||
c->file.name.data);
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (h->vary_len) {
|
||||
ngx_http_file_cache_vary(r, h->vary, h->vary_len, c->variant);
|
||||
|
||||
if (ngx_memcmp(c->variant, h->variant, NGX_HTTP_CACHE_KEY_LEN) != 0) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http file cache vary mismatch");
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
}
|
||||
|
||||
c->buf->last += n;
|
||||
|
||||
c->valid_sec = h->valid_sec;
|
||||
@ -870,6 +891,94 @@ ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary, size_t len,
|
||||
u_char *hash)
|
||||
{
|
||||
u_char *p, *last;
|
||||
ngx_str_t name;
|
||||
ngx_md5_t md5;
|
||||
u_char buf[NGX_HTTP_CACHE_VARY_LEN];
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http file cache vary: \"%*s\"", len, vary);
|
||||
|
||||
ngx_md5_init(&md5);
|
||||
|
||||
ngx_strlow(buf, vary, len);
|
||||
|
||||
p = buf;
|
||||
last = buf + len;
|
||||
|
||||
while (p < last) {
|
||||
|
||||
while (p < last && (*p == ' ' || *p == ',')) { p++; }
|
||||
|
||||
name.data = p;
|
||||
|
||||
while (p < last && *p != ',' && *p != ' ') { p++; }
|
||||
|
||||
name.len = p - name.data;
|
||||
|
||||
if (name.len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http file cache vary: %V", &name);
|
||||
|
||||
ngx_md5_update(&md5, name.data, name.len);
|
||||
ngx_md5_update(&md5, (u_char *) ":", sizeof(":") - 1);
|
||||
|
||||
ngx_http_file_cache_vary_header(r, &md5, &name);
|
||||
|
||||
ngx_md5_update(&md5, (u_char *) CRLF, sizeof(CRLF) - 1);
|
||||
}
|
||||
|
||||
ngx_md5_final(hash, &md5);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_file_cache_vary_header(ngx_http_request_t *r, ngx_md5_t *md5,
|
||||
ngx_str_t *name)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_list_part_t *part;
|
||||
ngx_table_elt_t *header;
|
||||
|
||||
part = &r->headers_in.headers.part;
|
||||
header = part->elts;
|
||||
|
||||
for (i = 0; /* void */ ; i++) {
|
||||
|
||||
if (i >= part->nelts) {
|
||||
if (part->next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
part = part->next;
|
||||
header = part->elts;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if (header[i].hash == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (header[i].key.len != name->len) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_strncasecmp(header[i].key.data, name->data, name->len) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ngx_md5_update(md5, header[i].value.data, header[i].value.len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
|
||||
{
|
||||
@ -901,6 +1010,19 @@ ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
|
||||
ngx_memcpy(h->etag, c->etag.data, c->etag.len);
|
||||
}
|
||||
|
||||
if (c->vary.len) {
|
||||
if (c->vary.len > NGX_HTTP_CACHE_VARY_LEN) {
|
||||
/* should not happen */
|
||||
c->vary.len = NGX_HTTP_CACHE_VARY_LEN;
|
||||
}
|
||||
|
||||
h->vary_len = (u_char) c->vary.len;
|
||||
ngx_memcpy(h->vary, c->vary.data, c->vary.len);
|
||||
|
||||
ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant);
|
||||
ngx_memcpy(h->variant, c->variant, NGX_HTTP_CACHE_KEY_LEN);
|
||||
}
|
||||
|
||||
p = buf + sizeof(ngx_http_file_cache_header_t);
|
||||
|
||||
p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key));
|
||||
@ -1093,6 +1215,19 @@ ngx_http_file_cache_update_header(ngx_http_request_t *r)
|
||||
ngx_memcpy(h.etag, c->etag.data, c->etag.len);
|
||||
}
|
||||
|
||||
if (c->vary.len) {
|
||||
if (c->vary.len > NGX_HTTP_CACHE_VARY_LEN) {
|
||||
/* should not happen */
|
||||
c->vary.len = NGX_HTTP_CACHE_VARY_LEN;
|
||||
}
|
||||
|
||||
h.vary_len = (u_char) c->vary.len;
|
||||
ngx_memcpy(h.vary, c->vary.data, c->vary.len);
|
||||
|
||||
ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant);
|
||||
ngx_memcpy(h.variant, c->variant, NGX_HTTP_CACHE_KEY_LEN);
|
||||
}
|
||||
|
||||
(void) ngx_write_file(&file, (u_char *) &h,
|
||||
sizeof(ngx_http_file_cache_header_t), 0);
|
||||
|
||||
|
@ -4160,7 +4160,17 @@ ngx_http_upstream_process_vary(ngx_http_request_t *r,
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
u->cacheable = 0;
|
||||
if (r->cache == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (h->value.len > NGX_HTTP_CACHE_VARY_LEN
|
||||
|| (h->value.len == 1 && h->value.data[0] == '*'))
|
||||
{
|
||||
u->cacheable = 0;
|
||||
}
|
||||
|
||||
r->cache->vary = h->value;
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user