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