From d3900cc31d4ca14a9c45902b2543da2f39ce2c26 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 22 Dec 2017 15:35:11 +0100 Subject: [PATCH] BUG/MINOR: http: properly detect max-age=0 and s-maxage=0 in responses In 1.3.8, commit a15645d ("[MAJOR] completed the HTTP response processing.") improved the response parser by taking care of the cache-control header field. The parser is wrong because it is split in two parts, one checking for elements containing an equal sign and the other one for those without. The "max-age=0" and "s-maxage=0" tests were located at the wrong place and thus have never matched. In practice the side effect was very minimal given that this code used to be enabled only when checking if a cookie had the risk of being cached or not. Recently in 1.8 it was also used to decide if the response could be cached but in practice the cache takes care of these values by itself so there is very limited impact. This fix can be backported to all stable versions. --- src/proto_http.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/proto_http.c b/src/proto_http.c index 42e253aeb..701ced43c 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -7680,7 +7680,7 @@ void manage_server_side_cookies(struct stream *s, struct channel *res) /* - * Check if response is cacheable or not. Updates s->flags. + * Check if response is cacheable or not. Updates s->txn->flags. */ void check_response_for_cacheability(struct stream *s, struct channel *rtr) { @@ -7712,8 +7712,7 @@ void check_response_for_cacheability(struct stream *s, struct channel *rtr) cur_next = cur_end + cur_hdr->cr + 1; /* We have one full header between cur_ptr and cur_end, and the - * next header starts at cur_next. We're only interested in - * "Cookie:" headers. + * next header starts at cur_next. */ val = http_header_match2(cur_ptr, cur_end, "Pragma", 6); @@ -7744,6 +7743,12 @@ void check_response_for_cacheability(struct stream *s, struct channel *rtr) /* we have a complete value between p1 and p2 */ if (p2 < cur_end && *p2 == '=') { + if (((cur_end - p2) > 1 && (p2 - p1 == 7) && strncasecmp(p1, "max-age=0", 9) == 0) || + ((cur_end - p2) > 1 && (p2 - p1 == 8) && strncasecmp(p1, "s-maxage=0", 10) == 0)) { + txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK; + continue; + } + /* we have something of the form no-cache="set-cookie" */ if ((cur_end - p1 >= 21) && strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0 @@ -7755,9 +7760,7 @@ void check_response_for_cacheability(struct stream *s, struct channel *rtr) /* OK, so we know that either p2 points to the end of string or to a comma */ if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) || ((p2 - p1 == 8) && strncasecmp(p1, "no-cache", 8) == 0) || - ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) || - ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) || - ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) { + ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0)) { txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK; return; }