Mercurial > hg > nginx-quic
comparison src/http/ngx_http_file_cache.c @ 5878:2c89956b6a76
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.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 27 Oct 2014 21:13:58 +0300 |
parents | 063f7e75f9ef |
children | c525c0454aa5 |
comparison
equal
deleted
inserted
replaced
5877:60fde1bc7236 | 5878:2c89956b6a76 |
---|---|
27 ngx_path_t *path); | 27 ngx_path_t *path); |
28 static ngx_http_file_cache_node_t * | 28 static ngx_http_file_cache_node_t * |
29 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key); | 29 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key); |
30 static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, | 30 static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, |
31 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); | 31 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); |
32 static void ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary, | |
33 size_t len, u_char *hash); | |
34 static void ngx_http_file_cache_vary_header(ngx_http_request_t *r, | |
35 ngx_md5_t *md5, ngx_str_t *name); | |
32 static void ngx_http_file_cache_cleanup(void *data); | 36 static void ngx_http_file_cache_cleanup(void *data); |
33 static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache); | 37 static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache); |
34 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache); | 38 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache); |
35 static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, | 39 static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, |
36 ngx_queue_t *q, u_char *name); | 40 ngx_queue_t *q, u_char *name); |
517 "cache file \"%s\" has too long header", | 521 "cache file \"%s\" has too long header", |
518 c->file.name.data); | 522 c->file.name.data); |
519 return NGX_DECLINED; | 523 return NGX_DECLINED; |
520 } | 524 } |
521 | 525 |
526 if (h->vary_len > NGX_HTTP_CACHE_VARY_LEN) { | |
527 ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, | |
528 "cache file \"%s\" has incorrect vary length", | |
529 c->file.name.data); | |
530 return NGX_DECLINED; | |
531 } | |
532 | |
533 if (h->vary_len) { | |
534 ngx_http_file_cache_vary(r, h->vary, h->vary_len, c->variant); | |
535 | |
536 if (ngx_memcmp(c->variant, h->variant, NGX_HTTP_CACHE_KEY_LEN) != 0) { | |
537 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
538 "http file cache vary mismatch"); | |
539 return NGX_DECLINED; | |
540 } | |
541 } | |
542 | |
522 c->buf->last += n; | 543 c->buf->last += n; |
523 | 544 |
524 c->valid_sec = h->valid_sec; | 545 c->valid_sec = h->valid_sec; |
525 c->last_modified = h->last_modified; | 546 c->last_modified = h->last_modified; |
526 c->date = h->date; | 547 c->date = h->date; |
868 node->right = sentinel; | 889 node->right = sentinel; |
869 ngx_rbt_red(node); | 890 ngx_rbt_red(node); |
870 } | 891 } |
871 | 892 |
872 | 893 |
894 static void | |
895 ngx_http_file_cache_vary(ngx_http_request_t *r, u_char *vary, size_t len, | |
896 u_char *hash) | |
897 { | |
898 u_char *p, *last; | |
899 ngx_str_t name; | |
900 ngx_md5_t md5; | |
901 u_char buf[NGX_HTTP_CACHE_VARY_LEN]; | |
902 | |
903 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
904 "http file cache vary: \"%*s\"", len, vary); | |
905 | |
906 ngx_md5_init(&md5); | |
907 | |
908 ngx_strlow(buf, vary, len); | |
909 | |
910 p = buf; | |
911 last = buf + len; | |
912 | |
913 while (p < last) { | |
914 | |
915 while (p < last && (*p == ' ' || *p == ',')) { p++; } | |
916 | |
917 name.data = p; | |
918 | |
919 while (p < last && *p != ',' && *p != ' ') { p++; } | |
920 | |
921 name.len = p - name.data; | |
922 | |
923 if (name.len == 0) { | |
924 break; | |
925 } | |
926 | |
927 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
928 "http file cache vary: %V", &name); | |
929 | |
930 ngx_md5_update(&md5, name.data, name.len); | |
931 ngx_md5_update(&md5, (u_char *) ":", sizeof(":") - 1); | |
932 | |
933 ngx_http_file_cache_vary_header(r, &md5, &name); | |
934 | |
935 ngx_md5_update(&md5, (u_char *) CRLF, sizeof(CRLF) - 1); | |
936 } | |
937 | |
938 ngx_md5_final(hash, &md5); | |
939 } | |
940 | |
941 | |
942 static void | |
943 ngx_http_file_cache_vary_header(ngx_http_request_t *r, ngx_md5_t *md5, | |
944 ngx_str_t *name) | |
945 { | |
946 ngx_uint_t i; | |
947 ngx_list_part_t *part; | |
948 ngx_table_elt_t *header; | |
949 | |
950 part = &r->headers_in.headers.part; | |
951 header = part->elts; | |
952 | |
953 for (i = 0; /* void */ ; i++) { | |
954 | |
955 if (i >= part->nelts) { | |
956 if (part->next == NULL) { | |
957 break; | |
958 } | |
959 | |
960 part = part->next; | |
961 header = part->elts; | |
962 i = 0; | |
963 } | |
964 | |
965 if (header[i].hash == 0) { | |
966 continue; | |
967 } | |
968 | |
969 if (header[i].key.len != name->len) { | |
970 continue; | |
971 } | |
972 | |
973 if (ngx_strncasecmp(header[i].key.data, name->data, name->len) != 0) { | |
974 continue; | |
975 } | |
976 | |
977 ngx_md5_update(md5, header[i].value.data, header[i].value.len); | |
978 } | |
979 } | |
980 | |
981 | |
873 void | 982 void |
874 ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) | 983 ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) |
875 { | 984 { |
876 ngx_http_file_cache_header_t *h = (ngx_http_file_cache_header_t *) buf; | 985 ngx_http_file_cache_header_t *h = (ngx_http_file_cache_header_t *) buf; |
877 | 986 |
897 h->body_start = (u_short) c->body_start; | 1006 h->body_start = (u_short) c->body_start; |
898 | 1007 |
899 if (c->etag.len <= NGX_HTTP_CACHE_ETAG_LEN) { | 1008 if (c->etag.len <= NGX_HTTP_CACHE_ETAG_LEN) { |
900 h->etag_len = (u_char) c->etag.len; | 1009 h->etag_len = (u_char) c->etag.len; |
901 ngx_memcpy(h->etag, c->etag.data, c->etag.len); | 1010 ngx_memcpy(h->etag, c->etag.data, c->etag.len); |
1011 } | |
1012 | |
1013 if (c->vary.len) { | |
1014 if (c->vary.len > NGX_HTTP_CACHE_VARY_LEN) { | |
1015 /* should not happen */ | |
1016 c->vary.len = NGX_HTTP_CACHE_VARY_LEN; | |
1017 } | |
1018 | |
1019 h->vary_len = (u_char) c->vary.len; | |
1020 ngx_memcpy(h->vary, c->vary.data, c->vary.len); | |
1021 | |
1022 ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant); | |
1023 ngx_memcpy(h->variant, c->variant, NGX_HTTP_CACHE_KEY_LEN); | |
902 } | 1024 } |
903 | 1025 |
904 p = buf + sizeof(ngx_http_file_cache_header_t); | 1026 p = buf + sizeof(ngx_http_file_cache_header_t); |
905 | 1027 |
906 p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key)); | 1028 p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key)); |
1091 if (c->etag.len <= NGX_HTTP_CACHE_ETAG_LEN) { | 1213 if (c->etag.len <= NGX_HTTP_CACHE_ETAG_LEN) { |
1092 h.etag_len = (u_char) c->etag.len; | 1214 h.etag_len = (u_char) c->etag.len; |
1093 ngx_memcpy(h.etag, c->etag.data, c->etag.len); | 1215 ngx_memcpy(h.etag, c->etag.data, c->etag.len); |
1094 } | 1216 } |
1095 | 1217 |
1218 if (c->vary.len) { | |
1219 if (c->vary.len > NGX_HTTP_CACHE_VARY_LEN) { | |
1220 /* should not happen */ | |
1221 c->vary.len = NGX_HTTP_CACHE_VARY_LEN; | |
1222 } | |
1223 | |
1224 h.vary_len = (u_char) c->vary.len; | |
1225 ngx_memcpy(h.vary, c->vary.data, c->vary.len); | |
1226 | |
1227 ngx_http_file_cache_vary(r, c->vary.data, c->vary.len, c->variant); | |
1228 ngx_memcpy(h.variant, c->variant, NGX_HTTP_CACHE_KEY_LEN); | |
1229 } | |
1230 | |
1096 (void) ngx_write_file(&file, (u_char *) &h, | 1231 (void) ngx_write_file(&file, (u_char *) &h, |
1097 sizeof(ngx_http_file_cache_header_t), 0); | 1232 sizeof(ngx_http_file_cache_header_t), 0); |
1098 | 1233 |
1099 done: | 1234 done: |
1100 | 1235 |