]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: cache: Add a process-vary option that can enable/disable Vary processing
authorRemi Tricot-Le Breton <rlebreton@haproxy.com>
Mon, 16 Nov 2020 14:56:10 +0000 (15:56 +0100)
committerWilliam Lallemand <wlallemand@haproxy.org>
Tue, 24 Nov 2020 15:52:57 +0000 (16:52 +0100)
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).

doc/configuration.txt
reg-tests/cache/vary.vtc
src/cache.c

index b24c61b849245ddc5acd90d994c6da67b5905393..ee93b396932690f78174819e870b621f685f6fbb 100644 (file)
@@ -14336,6 +14336,13 @@ max-age <seconds>
   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
 ---------------------
index aeffbf68b0dfb0fb150dae855f79cf6a3d422271..969049042761a8ee32e99ae31464426a3b764715 100644 (file)
@@ -93,6 +93,30 @@ server s1 {
        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 @@ haproxy h1 -conf {
 
        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 @@ haproxy h1 -conf {
                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 @@ client c1 -connect ${h1_fe_sock} {
        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
index 07ecc03d46d826346faf78273dd5d868f89549de..bdad8fdb7c9c2aec53f37bee80e659e93aedc785 100644 (file)
@@ -49,6 +49,7 @@ struct cache {
        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 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
        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 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
 
        /* 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 @@ enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *p
 
        /* 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 @@ int cfg_parse_cache(const char *file, int linenum, char **args, int kwm)
                        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]);