From: Amos Jeffries Date: Fri, 28 Oct 2016 07:56:00 +0000 (+1300) Subject: HTTP: initial support for Cache-Control:immutable X-Git-Tag: SQUID_4_0_16~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=caf653518ed88e91606b4eea451dc200ed81d0fe;p=thirdparty%2Fsquid.git HTTP: initial support for Cache-Control:immutable The 'immutable' cache control is a proposed standardization of behaviour equivalent to the refresh_pattern 'ignore-reload' option. Reducing latency delays from revalidation when an object is known not to be updated until it expires. When a server emits it on responses a recipient cache is expected to treat the response as not requiring any revalidation until it becomes stale. For the duration of its freshness period it may be used as-is to respond to client requests - including reload (CC:max-age=0) requests. This initial code does not yet support preventing IMS conditional requests behaviour when the 'immutable' signal is received. Note that CC:no-cache in requests, and If-None-Match ETag based conditionals can still make an 'immutable' response be irrelevant to a particular client request. So server contact is not completely prevented. Use 'immutable' option in preference over the refresh_pattern 'ignore-reload' in order to track whether that override is still relevant. --- diff --git a/src/HttpHdrCc.cc b/src/HttpHdrCc.cc index d4d2090c0a..b3c65ba487 100644 --- a/src/HttpHdrCc.cc +++ b/src/HttpHdrCc.cc @@ -40,6 +40,7 @@ static LookupTable::Record CcAttrs[] = { {"min-fresh", HttpHdrCcType::CC_MIN_FRESH}, {"only-if-cached", HttpHdrCcType::CC_ONLY_IF_CACHED}, {"stale-if-error", HttpHdrCcType::CC_STALE_IF_ERROR}, + {"immutable", HttpHdrCcType::CC_IMMUTABLE}, {"Other,", HttpHdrCcType::CC_OTHER}, /* ',' will protect from matches */ {nullptr, HttpHdrCcType::CC_ENUM_END} }; @@ -202,6 +203,9 @@ HttpHdrCc::parse(const String & str) case HttpHdrCcType::CC_ONLY_IF_CACHED: onlyIfCached(true); break; + case HttpHdrCcType::CC_IMMUTABLE: + Immutable(true); + break; case HttpHdrCcType::CC_OTHER: if (other.size()) @@ -277,6 +281,8 @@ HttpHdrCc::packInto(Packable * p) const case HttpHdrCcType::CC_STALE_IF_ERROR: p->appendf("=%d", staleIfError()); break; + case HttpHdrCcType::CC_IMMUTABLE: + break; case HttpHdrCcType::CC_OTHER: case HttpHdrCcType::CC_ENUM_END: // done below after the loop diff --git a/src/HttpHdrCc.h b/src/HttpHdrCc.h index f2b25af8f9..337130c444 100644 --- a/src/HttpHdrCc.h +++ b/src/HttpHdrCc.h @@ -30,6 +30,7 @@ enum HttpHdrCcType : unsigned char { CC_MIN_FRESH, CC_ONLY_IF_CACHED, CC_STALE_IF_ERROR, + CC_IMMUTABLE, /* draft-mcmanus-immutable-00 */ CC_OTHER, CC_ENUM_END /* also used to mean "invalid" */ }; @@ -160,6 +161,11 @@ public: void staleIfError(int32_t v) {setValue(stale_if_error,v,HttpHdrCcType::CC_STALE_IF_ERROR); } void clearStaleIfError() {setValue(stale_if_error,STALE_IF_ERROR_UNKNOWN,HttpHdrCcType::CC_STALE_IF_ERROR,false);} + //manipulation for Cache-Control: immutable header + bool Immutable() const {return isSet(HttpHdrCcType::CC_IMMUTABLE);} + void Immutable(bool v) {setMask(HttpHdrCcType::CC_IMMUTABLE,v);} + void clearImmutable() {setMask(HttpHdrCcType::CC_IMMUTABLE,false);} + /// check whether the attribute value supplied by id is set _SQUID_INLINE_ bool isSet(HttpHdrCcType id) const; diff --git a/src/refresh.cc b/src/refresh.cc index e82a912031..6a56547ccf 100644 --- a/src/refresh.cc +++ b/src/refresh.cc @@ -327,10 +327,12 @@ refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta) debugs(22, 3, "Staleness = " << staleness); + const auto *reply = (entry->mem_obj && entry->mem_obj->getReply() ? entry->mem_obj->getReply() : nullptr); + // stale-if-error requires any failure be passed thru when its period is over. - if (request && entry->mem_obj && entry->mem_obj->getReply() && entry->mem_obj->getReply()->cache_control && - entry->mem_obj->getReply()->cache_control->hasStaleIfError() && - entry->mem_obj->getReply()->cache_control->staleIfError() < staleness) { + if (request && reply && reply->cache_control && + reply->cache_control->hasStaleIfError() && + reply->cache_control->staleIfError() < staleness) { debugs(22, 3, "stale-if-error period expired. Will produce error if validation fails."); request->flags.failOnValidationError = true; @@ -415,18 +417,21 @@ refreshCheck(const StoreEntry * entry, HttpRequest * request, time_t delta) // max-age directive if (cc->hasMaxAge()) { + + // draft-mcmanus-immutable-00: reply contains CC:immutable then ignore client CC:max-age=N + if (reply && reply->cache_control && reply->cache_control->Immutable()) { + debugs(22, 3, "MAYBE: Ignoring client CC:max-age=" << cc->maxAge() << " request - 'Cache-Control: immutable'"); + #if USE_HTTP_VIOLATIONS - // Ignore client "Cache-Control: max-age=0" header - if (R->flags.ignore_reload && cc->maxAge() == 0) { + // Ignore of client "Cache-Control: max-age=0" header + } else if (R->flags.ignore_reload && cc->maxAge() == 0) { debugs(22, 3, "MAYBE: Ignoring client reload request - trying to serve from cache (ignore-reload option)"); - } else #endif - { - // Honour client "Cache-Control: max-age=x" header - if (age > cc->maxAge() || cc->maxAge() == 0) { - debugs(22, 3, "YES: Revalidating object - client 'Cache-Control: max-age=" << cc->maxAge() << "'"); - return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE; - } + + // Honour client "Cache-Control: max-age=x" header + } else if (age > cc->maxAge() || cc->maxAge() == 0) { + debugs(22, 3, "YES: Revalidating object - client 'Cache-Control: max-age=" << cc->maxAge() << "'"); + return STALE_EXCEEDS_REQUEST_MAX_AGE_VALUE; } }