diff --git a/src/http_ana.c b/src/http_ana.c index c2080bf9a..a877794ec 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -3847,68 +3847,46 @@ void http_check_request_for_cacheability(struct stream *s, struct channel *req) { struct http_txn *txn = s->txn; struct htx *htx; - int32_t pos; - int pragma_found, cc_found, i; + struct http_hdr_ctx ctx = { .blk = NULL }; + int pragma_found, cc_found; if ((txn->flags & (TX_CACHEABLE|TX_CACHE_IGNORE)) == TX_CACHE_IGNORE) return; /* nothing more to do here */ htx = htxbuf(&req->buf); pragma_found = cc_found = 0; - for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) { - struct htx_blk *blk = htx_get_blk(htx, pos); - enum htx_blk_type type = htx_get_blk_type(blk); - struct ist n, v; - if (type == HTX_BLK_EOH) - break; - if (type != HTX_BLK_HDR) - continue; - - n = htx_get_blk_name(htx, blk); - v = htx_get_blk_value(htx, blk); - - if (isteq(n, ist("pragma"))) { - if (v.len >= 8 && strncasecmp(v.ptr, "no-cache", 8) == 0) { - pragma_found = 1; - continue; - } + /* Check "pragma" header for HTTP/1.0 compatibility. */ + if (http_find_header(htx, ist("pragma"), &ctx, 1)) { + if (isteqi(ctx.value, ist("no-cache"))) { + pragma_found = 1; } + } - /* Don't use the cache and don't try to store if we found the - * Authorization header */ - if (isteq(n, ist("authorization"))) { - txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK; - txn->flags |= TX_CACHE_IGNORE; - continue; - } + ctx.blk = NULL; + /* Don't use the cache and don't try to store if we found the + * Authorization header */ + if (http_find_header(htx, ist("authorization"), &ctx, 1)) { + txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK; + txn->flags |= TX_CACHE_IGNORE; + } - if (!isteq(n, ist("cache-control"))) - continue; - /* OK, right now we know we have a cache-control header */ + /* Look for "cache-control" header and iterate over all the values + * until we find one that specifies that caching is possible or not. */ + ctx.blk = NULL; + while (http_find_header(htx, ist("cache-control"), &ctx, 0)) { cc_found = 1; - if (!v.len) /* no info */ - continue; - - i = 0; - while (i < v.len && *(v.ptr+i) != '=' && *(v.ptr+i) != ',' && - !isspace((unsigned char)*(v.ptr+i))) - i++; - - /* we have a complete value between v.ptr and (v.ptr+i). We don't check the - * values after max-age, max-stale nor min-fresh, we simply don't - * use the cache when they're specified. - */ - if (((i == 7) && strncasecmp(v.ptr, "max-age", 7) == 0) || - ((i == 8) && strncasecmp(v.ptr, "no-cache", 8) == 0) || - ((i == 9) && strncasecmp(v.ptr, "max-stale", 9) == 0) || - ((i == 9) && strncasecmp(v.ptr, "min-fresh", 9) == 0)) { + /* We don't check the values after max-age, max-stale nor min-fresh, + * we simply don't use the cache when they're specified. */ + if (istmatchi(ctx.value, ist("max-age")) || + istmatchi(ctx.value, ist("no-cache")) || + istmatchi(ctx.value, ist("max-stale")) || + istmatchi(ctx.value, ist("min-fresh"))) { txn->flags |= TX_CACHE_IGNORE; continue; } - - if ((i == 8) && strncasecmp(v.ptr, "no-store", 8) == 0) { + if (istmatchi(ctx.value, ist("no-store"))) { txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK; continue; } @@ -3932,9 +3910,8 @@ void http_check_request_for_cacheability(struct stream *s, struct channel *req) void http_check_response_for_cacheability(struct stream *s, struct channel *res) { struct http_txn *txn = s->txn; + struct http_hdr_ctx ctx = { .blk = NULL }; struct htx *htx; - int32_t pos; - int i; if (txn->status < 200) { /* do not try to cache interim responses! */ @@ -3943,66 +3920,35 @@ void http_check_response_for_cacheability(struct stream *s, struct channel *res) } htx = htxbuf(&res->buf); - for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) { - struct htx_blk *blk = htx_get_blk(htx, pos); - enum htx_blk_type type = htx_get_blk_type(blk); - struct ist n, v; - - if (type == HTX_BLK_EOH) - break; - if (type != HTX_BLK_HDR) - continue; - - n = htx_get_blk_name(htx, blk); - v = htx_get_blk_value(htx, blk); - - if (isteq(n, ist("pragma"))) { - if ((v.len >= 8) && strncasecmp(v.ptr, "no-cache", 8) == 0) { - txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK; - return; - } - } - - if (!isteq(n, ist("cache-control"))) - continue; - - /* OK, right now we know we have a cache-control header */ - if (!v.len) /* no info */ - continue; - - i = 0; - while (i < v.len && *(v.ptr+i) != '=' && *(v.ptr+i) != ',' && - !isspace((unsigned char)*(v.ptr+i))) - i++; - - /* we have a complete value between v.ptr and (v.ptr+i) */ - if (i < v.len && *(v.ptr + i) == '=') { - if (((v.len - i) > 1 && (i == 7) && strncasecmp(v.ptr, "max-age=0", 9) == 0) || - ((v.len - i) > 1 && (i == 8) && strncasecmp(v.ptr, "s-maxage=0", 10) == 0)) { - txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK; - continue; - } - - /* we have something of the form no-cache="set-cookie" */ - if ((v.len >= 21) && - strncasecmp(v.ptr, "no-cache=\"set-cookie", 20) == 0 - && (*(v.ptr + 20) == '"' || *(v.ptr + 20 ) == ',')) - txn->flags &= ~TX_CACHE_COOK; - continue; - } - - /* OK, so we know that either p2 points to the end of string or to a comma */ - if (((i == 7) && strncasecmp(v.ptr, "private", 7) == 0) || - ((i == 8) && strncasecmp(v.ptr, "no-cache", 8) == 0) || - ((i == 8) && strncasecmp(v.ptr, "no-store", 8) == 0)) { + /* Check "pragma" header for HTTP/1.0 compatibility. */ + if (http_find_header(htx, ist("pragma"), &ctx, 1)) { + if (isteqi(ctx.value, ist("no-cache"))) { txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK; return; } + } - if ((i == 6) && strncasecmp(v.ptr, "public", 6) == 0) { + /* Look for "cache-control" header and iterate over all the values + * until we find one that specifies that caching is possible or not. */ + ctx.blk = NULL; + while (http_find_header(htx, ist("cache-control"), &ctx, 0)) { + if (isteqi(ctx.value, ist("public"))) { txn->flags |= TX_CACHEABLE | TX_CACHE_COOK; continue; } + if (isteqi(ctx.value, ist("private")) || + isteqi(ctx.value, ist("no-cache")) || + isteqi(ctx.value, ist("no-store")) || + isteqi(ctx.value, ist("max-age=0")) || + 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"))) { + txn->flags &= ~TX_CACHE_COOK; + continue; + } } }