MINOR: cache: Add a process-vary option that can enable/disable Vary processing
The cache section's process-vary option takes a 0 or 1 value to disable
or enable the vary processing.
When disabled, a response containing such a header will never be cached.
When enabled, we will calculate a preliminary hash for a subset of request
headers on all the incoming requests (which might come with a cpu cost) which
will be used to build a secondary key for a given request (see RFC 7234#4.1).
The default value is 0 (disabled).
diff --git a/doc/configuration.txt b/doc/configuration.txt
index b24c61b..ee93b39 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -14336,6 +14336,13 @@
seconds, which means that you can't cache an object more than 60 seconds by
default.
+process-vary <0 or 1>
+ Disable or enable the processing of the Vary header. When disabled, a response
+ containing such a header will never be cached. When enabled, we need to calculate
+ a preliminary hash for a subset of request headers on all the incoming requests
+ (which might come with a cpu cost) which will be used to build a secondary key
+ for a given request (see RFC 7234#4.1). The default value is 0 (disabled).
+
6.2.2. Proxy section
---------------------
diff --git a/reg-tests/cache/vary.vtc b/reg-tests/cache/vary.vtc
index aeffbf6..9690490 100644
--- a/reg-tests/cache/vary.vtc
+++ b/reg-tests/cache/vary.vtc
@@ -93,6 +93,30 @@
chunkedlen 19
chunkedlen 0
+
+} -start
+
+server s2 {
+ # Responses that should not be cached
+ rxreq
+ expect req.url == "/no_vary_support"
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5"
+ chunkedlen 19
+ chunkedlen 19
+ chunkedlen 19
+ chunkedlen 0
+
+ rxreq
+ expect req.url == "/no_vary_support"
+ txresp -nolen -hdr "Transfer-Encoding: chunked" \
+ -hdr "Vary: accept-encoding" \
+ -hdr "Cache-Control: max-age=5"
+ chunkedlen 19
+ chunkedlen 19
+ chunkedlen 19
+ chunkedlen 0
} -start
haproxy h1 -conf {
@@ -105,6 +129,7 @@
frontend fe
bind "fd@${fe}"
+ use_backend no_vary_be if { path_beg /no_vary_support }
default_backend test
backend test
@@ -113,10 +138,23 @@
http-response cache-store my_cache
http-response set-header X-Cache-Hit %[res.cache_hit]
+ backend no_vary_be
+ http-request cache-use no_vary_cache
+ server www ${s2_addr}:${s2_port}
+ http-response cache-store no_vary_cache
+ http-response set-header X-Cache-Hit %[res.cache_hit]
+
cache my_cache
total-max-size 3
max-age 20
max-object-size 3072
+ process-vary 1
+
+ cache no_vary_cache
+ total-max-size 3
+ max-age 20
+ max-object-size 3072
+ process-vary 0
} -start
@@ -231,4 +269,20 @@
expect resp.status == 200
expect resp.bodylen == 57
expect resp.http.X-Cache-Hit == 1
+
+ # The following requests are trated by a backend that does not cache
+ # responses containing a Vary header
+ txreq -url "/no_vary_support"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 57
+ expect resp.http.X-Cache-Hit == 0
+
+ txreq -url "/no_vary_support"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 57
+ expect resp.http.X-Cache-Hit == 0
+
+
} -run
diff --git a/src/cache.c b/src/cache.c
index 07ecc03..bdad8fd 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -49,6 +49,7 @@
unsigned int maxage; /* max-age */
unsigned int maxblocks;
unsigned int maxobjsz; /* max-object-size (in bytes) */
+ uint8_t vary_processing_enabled; /* boolean : manage Vary header (disabled by default) */
char id[33]; /* cache name */
};
@@ -706,7 +707,8 @@
struct filter *filter;
struct shared_block *first = NULL;
struct cache_flt_conf *cconf = rule->arg.act.p[0];
- struct shared_context *shctx = shctx_ptr(cconf->c.cache);
+ struct cache *cache = cconf->c.cache;
+ struct shared_context *shctx = shctx_ptr(cache);
struct cache_st *cache_ctx = NULL;
struct cache_entry *object, *old;
unsigned int key = read_u32(txn->cache_hash);
@@ -763,8 +765,14 @@
/* Only a subset of headers are supported in our Vary implementation. If
* any other header is present in the Vary header value, we won't be
- * able to use the cache. */
- if (!http_check_vary_header(htx, &vary_signature)) {
+ * able to use the cache. Likewise, if Vary header support is disabled,
+ * avoid caching responses that contain such a header. */
+ ctx.blk = NULL;
+ if (cache->vary_processing_enabled) {
+ if (!http_check_vary_header(htx, &vary_signature))
+ goto out;
+ }
+ else if (http_find_header(htx, ist("Vary"), &ctx, 0)) {
goto out;
}
@@ -1507,7 +1515,7 @@
/* Shared context does not need to be locked while we calculate the
* secondary hash. */
- if (!res) {
+ if (!res && cache->vary_processing_enabled) {
/* Build a complete secondary hash until the server response
* tells us which fields should be kept (if any). */
http_request_prebuild_full_secondary_key(s);
@@ -1640,6 +1648,19 @@
goto out;
}
tmp_cache_config->maxobjsz = maxobjsz;
+ } else if (strcmp(args[0], "process-vary") == 0) {
+ if (alertif_too_many_args(1, file, linenum, args, &err_code)) {
+ err_code |= ERR_ABORT;
+ goto out;
+ }
+
+ if (!*args[1]) {
+ ha_warning("parsing [%s:%d]: '%s' expects 0 or 1 (disable or enable vary processing).\n",
+ file, linenum, args[0]);
+ err_code |= ERR_WARN;
+ }
+
+ tmp_cache_config->vary_processing_enabled = atoi(args[1]);
}
else if (*args[0] != 0) {
ha_alert("parsing [%s:%d] : unknown keyword '%s' in 'cache' section\n", file, linenum, args[0]);