]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: cache: also recognize directives in the form "token="
authorWilly Tarreau <w@1wt.eu>
Sun, 24 May 2026 19:52:54 +0000 (21:52 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 26 May 2026 11:13:24 +0000 (13:13 +0200)
The caching RFC (9111, but was present since 2616) indicate that
cache-control supports both the "token" and "token=..." forms and that
consumers are supposed to recognize both. In addition, "private=..." is
explicitly mentioned, so servers could very well emit it. However,
haproxy only recognizes the short form without argument, except for
"no-cache" where it also supports it followed by the beginning of a
set-cookie argument. Thus it could miss "private=" or "no-store=".

Let's refine the checks. Now we explicitly recognize the form
no-cache="set-cookie", and all variants of "token" or "token=" as
identical to disable caching. It will more reliably catch such edge
cases and make sure we never cache a response marked like this.

This should be backported, at least to the latest LTS (3.2), maybe
further after some observation.

src/http_ana.c

index c687b57d91c5066eccd2156185fdaff621afec4b..d2c2d9c1b6beab09e9a61113d879d58394e5baf7 100644 (file)
@@ -3996,19 +3996,19 @@ void http_check_response_for_cacheability(struct stream *s, struct channel *res)
                        continue;
                }
 
-               if (isteqi(ctx.value, ist("private")) ||
-                   isteqi(ctx.value, ist("no-cache")) ||
-                   isteqi(ctx.value, ist("no-store")) ||
-                   isteqi(ctx.value, ist("s-maxage=0"))) {
-                       txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
-                       continue;
-               }
                /* We might have a no-cache="set-cookie" form. */
-               if (istmatchi(ctx.value, ist("no-cache=\"set-cookie"))) {
+               if (isteqi(ctx.value, ist("no-cache=\"set-cookie\""))) {
                        txn->flags &= ~TX_CACHE_COOK;
                        continue;
                }
 
+               if (isteqi(ctx.value, ist("private"))  || istmatchi(ctx.value, ist("private="))  ||
+                   isteqi(ctx.value, ist("no-cache")) || istmatchi(ctx.value, ist("no-cache=")) ||
+                   isteqi(ctx.value, ist("no-store")) || istmatchi(ctx.value, ist("no-store=")) ||
+                   isteqi(ctx.value, ist("s-maxage=0"))) {
+                       txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
+                       continue;
+               }
                if (istmatchi(ctx.value, ist("s-maxage"))) {
                        has_freshness_info = 1;
                        has_null_maxage = 0;    /* The null max-age is overridden, ignore it */