diff --git a/reg-tests/cache/expires.vtc b/reg-tests/cache/expires.vtc new file mode 100644 index 000000000..51c748748 --- /dev/null +++ b/reg-tests/cache/expires.vtc @@ -0,0 +1,122 @@ +varnishtest "Expires support" + +#REQUIRE_VERSION=2.3 + +feature ignore_unknown_macro + +server s1 { + rxreq + txresp -nolen -hdr "Transfer-Encoding: chunked" \ + -hdr "Cache-Control: max-age=5" + chunkedlen 15 + chunkedlen 15 + chunkedlen 15 + chunkedlen 0 +} -start + +server s2 { + rxreq + txresp -nolen -hdr "Transfer-Encoding: chunked" + chunkedlen 16 + chunkedlen 16 + chunkedlen 16 + chunkedlen 0 +} -start + +server s3 { + rxreq + txresp -nolen -hdr "Transfer-Encoding: chunked" + chunkedlen 16 + chunkedlen 16 + chunkedlen 16 + chunkedlen 0 + + rxreq + txresp -nolen -hdr "Transfer-Encoding: chunked" + chunkedlen 17 + chunkedlen 17 + chunkedlen 17 + chunkedlen 0 +} -start + +haproxy h1 -conf { + defaults + mode http + ${no-htx} option http-use-htx + timeout connect 1s + timeout client 1s + timeout server 1s + + frontend fe + bind "fd@${fe}" + use_backend cache_control_be if { path_beg /cache_control } + use_backend future_expires_be if { path_beg /future } + default_backend past_expires_be + + backend cache_control_be + # Expires header should be ignored since a Cache-Control one is present + http-request cache-use my_cache + server www ${s1_addr}:${s1_port} + http-response set-header X-Cache-Hit %[res.cache_hit] + http-response set-header Expires %[date(-1),http_date] + http-response cache-store my_cache + + backend future_expires_be + # Expires value set in the future (current_time+5s) + http-request cache-use my_cache + server www ${s2_addr}:${s2_port} + http-response set-header X-Cache-Hit %[res.cache_hit] + http-response set-header Expires %[date(5),http_date] + http-response cache-store my_cache + + backend past_expires_be + # Expires value set in the past + http-request cache-use my_cache + server www ${s3_addr}:${s3_port} + http-response set-header X-Cache-Hit %[res.cache_hit] + http-response set-header Expires %[date(-1),http_date] + http-response cache-store my_cache + + cache my_cache + total-max-size 3 + max-age 20 + max-object-size 3072 +} -start + + +client c1 -connect ${h1_fe_sock} { + txreq -url "/cache_control" + rxresp + expect resp.status == 200 + expect resp.bodylen == 45 + + txreq -url "/cache_control" + rxresp + expect resp.status == 200 + expect resp.bodylen == 45 + expect resp.http.X-Cache-Hit == 1 + + txreq -url "/future" + rxresp + expect resp.status == 200 + expect resp.bodylen == 48 + + txreq -url "/future" + rxresp + expect resp.status == 200 + expect resp.bodylen == 48 + expect resp.http.X-Cache-Hit == 1 + + txreq -url "/past" + rxresp + expect resp.status == 200 + expect resp.bodylen == 48 + + txreq -url "/past" + rxresp + expect resp.status == 200 + expect resp.bodylen == 51 + expect resp.http.X-Cache-Hit == 0 + +} -run + diff --git a/src/cache.c b/src/cache.c index 2c37ca13b..a73f2668f 100644 --- a/src/cache.c +++ b/src/cache.c @@ -482,6 +482,9 @@ int http_calc_maxage(struct stream *s, struct cache *cache) struct http_hdr_ctx ctx = { .blk = NULL }; int smaxage = -1; int maxage = -1; + int expires = -1; + struct tm tm = {}; + time_t expires_val = 0; while (http_find_header(htx, ist("cache-control"), &ctx, 0)) { char *value; @@ -505,7 +508,28 @@ int http_calc_maxage(struct stream *s, struct cache *cache) } } - /* TODO: Expires - Data */ + /* Look for Expires header if no s-maxage or max-age Cache-Control data + * was found. */ + if (maxage == -1 && smaxage == -1) { + ctx.blk = NULL; + if (http_find_header(htx, ist("expires"), &ctx, 1)) { + if (parse_http_date(istptr(ctx.value), istlen(ctx.value), &tm)) { + expires_val = my_timegm(&tm); + /* A request having an expiring date earlier + * than the current date should be considered as + * stale. */ + expires = (expires_val >= now.tv_sec) ? + (expires_val - now.tv_sec) : 0; + } + else { + /* Following RFC 7234#5.3, an invalid date + * format must be treated as a date in the past + * so the cache entry must be seen as already + * expired. */ + expires = 0; + } + } + } if (smaxage > 0) @@ -514,6 +538,9 @@ int http_calc_maxage(struct stream *s, struct cache *cache) if (maxage > 0) return MIN(maxage, cache->maxage); + if (expires >= 0) + return MIN(expires, cache->maxage); + return cache->maxage; }