Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1471)

Unified Diff: net/http/http_response_headers.cc

Issue 154243006: Add GetExpirationTimes() to HttpResponseHeader. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: move a function body Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/http/http_response_headers.cc
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc
index 9574b03bc851209f6d53797d7019690fcfd8d76b..89c1b1eeb37ee101f21069ba99828af3ca312f22 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.cc
@@ -777,6 +777,132 @@ bool HttpResponseHeaders::GetCacheControlDirective(const StringPiece& directive,
return false;
}
+// From RFC 2616 section 13.2.4:
+//
+// The max-age directive takes priority over Expires, so if max-age is present
+// in a response, the calculation is simply:
+//
+// freshness_lifetime = max_age_value
+//
+// Otherwise, if Expires is present in the response, the calculation is:
+//
+// freshness_lifetime = expires_value - date_value
+//
+// Note that neither of these calculations is vulnerable to clock skew, since
+// all of the information comes from the origin server.
+//
+// Also, if the response does have a Last-Modified time, the heuristic
+// expiration value SHOULD be no more than some fraction of the interval since
+// that time. A typical setting of this fraction might be 10%:
+//
+// freshness_lifetime = (date_value - last_modified_value) * 0.10
+//
+// If the stale-while-revalidate directive is present, then it is used to set
+// the |staleness| time, unless it overridden by another directive.
+//
+void HttpResponseHeaders::CalculateLifetimes(
mmenke 2016/04/29 16:15:53 Definition order should match delcaration order.
+ const Time& response_time,
mmenke 2016/04/29 16:15:53 nit: Believe the preferred style is not to pass t
+ TimeDelta* out_freshness_lifetime,
+ TimeDelta* out_staleness_lifetime) const {
+ *out_freshness_lifetime = TimeDelta();
+ *out_staleness_lifetime = TimeDelta();
+
+ // Check for headers that force a response to never be fresh. For backwards
+ // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control:
+ // no-cache" even though RFC 2616 does not specify it.
+ if (HasHeaderValue("cache-control", "no-cache") ||
+ HasHeaderValue("cache-control", "no-store") ||
+ HasHeaderValue("pragma", "no-cache") ||
+ // Vary: * is never usable: see RFC 2616 section 13.6.
+ HasHeaderValue("vary", "*")) {
+ return;
+ }
+
+ // Cache-Control directive must_revalidate overrides stale-while-revalidate.
mmenke 2016/04/29 16:15:53 nit: must-revalidate
+ bool must_revalidate = HasHeaderValue("cache-control", "must-revalidate");
+
+ if (must_revalidate ||
+ !GetStaleWhileRevalidateValue(out_staleness_lifetime)) {
+ DCHECK_EQ(TimeDelta(), *out_staleness_lifetime);
mmenke 2016/04/29 16:15:53 This DCHECK seems out of place - we aren't DCHECKi
+ }
+
+ // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the
+ // Expires header after checking for max-age in GetFreshnessLifetimes. This
Randy Smith (Not in Mondays) 2016/05/04 19:22:15 This comment seems out of date, since I don't thin
+ // is important since "Expires: <date in the past>" means not fresh, but
+ // it should not trump a max-age value.
+ if (GetMaxAgeValue(out_freshness_lifetime))
+ return;
+
+ // If there is no Date header, then assume that the server response was
+ // generated at the time when we received the response.
+ Time date_value;
+ if (!GetDateValue(&date_value))
+ date_value = response_time;
+
+ Time expires_value;
+ if (GetExpiresValue(&expires_value)) {
+ // The expires value can be a date in the past!
Randy Smith (Not in Mondays) 2016/05/04 19:22:15 nit, suggestion: I'd value a comment here indicati
+ if (expires_value > date_value) {
+ *out_freshness_lifetime = expires_value - date_value;
+ return;
+ }
+
+ DCHECK_EQ(TimeDelta(), *out_freshness_lifetime);
mmenke 2016/04/29 16:15:53 Should this be under GetDateValue? How many DCHEC
+ return;
+ }
+
+ // From RFC 2616 section 13.4:
+ //
+ // A response received with a status code of 200, 203, 206, 300, 301 or 410
+ // MAY be stored by a cache and used in reply to a subsequent request,
+ // subject to the expiration mechanism, unless a cache-control directive
+ // prohibits caching.
+ // ...
+ // A response received with any other status code (e.g. status codes 302
+ // and 307) MUST NOT be returned in a reply to a subsequent request unless
+ // there are cache-control directives or another header(s) that explicitly
+ // allow it.
+ //
+ // From RFC 2616 section 14.9.4:
+ //
+ // When the must-revalidate directive is present in a response received by
+ // a cache, that cache MUST NOT use the entry after it becomes stale to
+ // respond to a subsequent request without first revalidating it with the
+ // origin server. (I.e., the cache MUST do an end-to-end revalidation every
+ // time, if, based solely on the origin server's Expires or max-age value,
+ // the cached response is stale.)
+ //
+ // https://datatracker.ietf.org/doc/draft-reschke-http-status-308/ is an
+ // experimental RFC that adds 308 permanent redirect as well, for which "any
+ // future references ... SHOULD use one of the returned URIs."
+ if ((response_code_ == 200 || response_code_ == 203 ||
+ response_code_ == 206) && !must_revalidate) {
+ // TODO(darin): Implement a smarter heuristic.
+ Time last_modified_value;
+ if (GetLastModifiedValue(&last_modified_value)) {
+ // The last-modified value can be a date in the future!
+ if (last_modified_value <= date_value) {
+ *out_freshness_lifetime = (date_value - last_modified_value) / 10;
mmenke 2016/04/29 16:15:53 This "/ 10" is just a magic heuristic? Maybe comm
Randy Smith (Not in Mondays) 2016/05/04 19:22:15 There's a comment about it at the top of the funct
+ return;
+ }
+ }
+ }
+
+ // These responses are implicitly fresh (unless otherwise overruled):
mmenke 2016/04/29 16:15:53 "Otherwise overruled" does not include having the
+ if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 ||
+ response_code_ == 410) {
+ *out_freshness_lifetime = TimeDelta::Max();
+ *out_staleness_lifetime = TimeDelta(); // It should never be stale.
mmenke 2016/04/29 16:15:53 In the calling function, should we just always set
+ return;
+ }
+
+ // Our heuristic freshness estimate for this resource is 0 seconds, in
+ // accordance with common browser behaviour. However, stale-while-revalidate
+ // may still apply.
+ DCHECK_EQ(TimeDelta(), *out_freshness_lifetime);
+ return;
+}
+
void HttpResponseHeaders::AddHeader(std::string::const_iterator name_begin,
std::string::const_iterator name_end,
std::string::const_iterator values_begin,
@@ -944,189 +1070,44 @@ bool HttpResponseHeaders::IsRedirectResponseCode(int response_code) {
response_code == 308);
}
-// From RFC 2616 section 13.2.4:
+// We calculate and return |corrected_response_time|, defined by:
//
-// The calculation to determine if a response has expired is quite simple:
+// current_age = now - corrected_response_time
//
-// response_is_fresh = (freshness_lifetime > current_age)
+// So a caller can store an ExpirationTimes object and use it to determine
+// freshness throughout the objects lifetime.
//
// Of course, there are other factors that can force a response to always be
// validated or re-fetched.
-//
-// From RFC 5861 section 3, a stale response may be used while revalidation is
-// performed in the background if
-//
-// freshness_lifetime + stale_while_revalidate > current_age
-//
-ValidationType HttpResponseHeaders::RequiresValidation(
+HttpResponseHeaders::ExpirationTimes HttpResponseHeaders::GetExpirationTimes(
const Time& request_time,
- const Time& response_time,
- const Time& current_time) const {
- FreshnessLifetimes lifetimes = GetFreshnessLifetimes(response_time);
- if (lifetimes.freshness.is_zero() && lifetimes.staleness.is_zero())
- return VALIDATION_SYNCHRONOUS;
-
- TimeDelta age = GetCurrentAge(request_time, response_time, current_time);
-
- if (lifetimes.freshness > age)
- return VALIDATION_NONE;
-
- if (lifetimes.freshness + lifetimes.staleness > age)
- return VALIDATION_ASYNCHRONOUS;
-
- return VALIDATION_SYNCHRONOUS;
-}
-
-// From RFC 2616 section 13.2.4:
-//
-// The max-age directive takes priority over Expires, so if max-age is present
-// in a response, the calculation is simply:
-//
-// freshness_lifetime = max_age_value
-//
-// Otherwise, if Expires is present in the response, the calculation is:
-//
-// freshness_lifetime = expires_value - date_value
-//
-// Note that neither of these calculations is vulnerable to clock skew, since
-// all of the information comes from the origin server.
-//
-// Also, if the response does have a Last-Modified time, the heuristic
-// expiration value SHOULD be no more than some fraction of the interval since
-// that time. A typical setting of this fraction might be 10%:
-//
-// freshness_lifetime = (date_value - last_modified_value) * 0.10
-//
-// If the stale-while-revalidate directive is present, then it is used to set
-// the |staleness| time, unless it overridden by another directive.
-//
-HttpResponseHeaders::FreshnessLifetimes
-HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const {
- FreshnessLifetimes lifetimes;
- // Check for headers that force a response to never be fresh. For backwards
- // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control:
- // no-cache" even though RFC 2616 does not specify it.
- if (HasHeaderValue("cache-control", "no-cache") ||
- HasHeaderValue("cache-control", "no-store") ||
- HasHeaderValue("pragma", "no-cache") ||
- // Vary: * is never usable: see RFC 2616 section 13.6.
- HasHeaderValue("vary", "*")) {
- return lifetimes;
- }
-
- // Cache-Control directive must_revalidate overrides stale-while-revalidate.
- bool must_revalidate = HasHeaderValue("cache-control", "must-revalidate");
-
- if (must_revalidate || !GetStaleWhileRevalidateValue(&lifetimes.staleness)) {
- DCHECK_EQ(TimeDelta(), lifetimes.staleness);
- }
-
- // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the
- // Expires header after checking for max-age in GetFreshnessLifetimes. This
- // is important since "Expires: <date in the past>" means not fresh, but
- // it should not trump a max-age value.
- if (GetMaxAgeValue(&lifetimes.freshness))
- return lifetimes;
-
- // If there is no Date header, then assume that the server response was
- // generated at the time when we received the response.
- Time date_value;
- if (!GetDateValue(&date_value))
- date_value = response_time;
-
- Time expires_value;
- if (GetExpiresValue(&expires_value)) {
- // The expires value can be a date in the past!
- if (expires_value > date_value) {
- lifetimes.freshness = expires_value - date_value;
- return lifetimes;
- }
-
- DCHECK_EQ(TimeDelta(), lifetimes.freshness);
- return lifetimes;
- }
-
- // From RFC 2616 section 13.4:
- //
- // A response received with a status code of 200, 203, 206, 300, 301 or 410
- // MAY be stored by a cache and used in reply to a subsequent request,
- // subject to the expiration mechanism, unless a cache-control directive
- // prohibits caching.
- // ...
- // A response received with any other status code (e.g. status codes 302
- // and 307) MUST NOT be returned in a reply to a subsequent request unless
- // there are cache-control directives or another header(s) that explicitly
- // allow it.
- //
- // From RFC 2616 section 14.9.4:
+ const Time& response_time) const {
+ // From RFC 2616 section 13.2.3:
//
- // When the must-revalidate directive is present in a response received by
- // a cache, that cache MUST NOT use the entry after it becomes stale to
- // respond to a subsequent request without first revalidating it with the
- // origin server. (I.e., the cache MUST do an end-to-end revalidation every
- // time, if, based solely on the origin server's Expires or max-age value,
- // the cached response is stale.)
+ // Summary of age calculation algorithm, when a cache receives a response:
//
- // https://datatracker.ietf.org/doc/draft-reschke-http-status-308/ is an
- // experimental RFC that adds 308 permanent redirect as well, for which "any
- // future references ... SHOULD use one of the returned URIs."
- if ((response_code_ == 200 || response_code_ == 203 ||
- response_code_ == 206) && !must_revalidate) {
- // TODO(darin): Implement a smarter heuristic.
- Time last_modified_value;
- if (GetLastModifiedValue(&last_modified_value)) {
- // The last-modified value can be a date in the future!
- if (last_modified_value <= date_value) {
- lifetimes.freshness = (date_value - last_modified_value) / 10;
- return lifetimes;
- }
- }
- }
+ // /*
+ // * age_value
+ // * is the value of Age: header received by the cache with
+ // * this response.
+ // * date_value
+ // * is the value of the origin server's Date: header
+ // * request_time
+ // * is the (local) time when the cache made the request
+ // * that resulted in this cached response
+ // * response_time
+ // * is the (local) time when the cache received the
+ // * response
+ // * now
+ // * is the current (local) time
+ // */
+ // apparent_age = max(0, response_time - date_value);
+ // corrected_received_age = max(apparent_age, age_value);
+ // response_delay = response_time - request_time;
+ // corrected_initial_age = corrected_received_age + response_delay;
+ // resident_time = now - response_time;
+ // current_age = corrected_initial_age + resident_time;
- // These responses are implicitly fresh (unless otherwise overruled):
- if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 ||
- response_code_ == 410) {
- lifetimes.freshness = TimeDelta::Max();
- lifetimes.staleness = TimeDelta(); // It should never be stale.
- return lifetimes;
- }
-
- // Our heuristic freshness estimate for this resource is 0 seconds, in
- // accordance with common browser behaviour. However, stale-while-revalidate
- // may still apply.
- DCHECK_EQ(TimeDelta(), lifetimes.freshness);
- return lifetimes;
-}
-
-// From RFC 2616 section 13.2.3:
-//
-// Summary of age calculation algorithm, when a cache receives a response:
-//
-// /*
-// * age_value
-// * is the value of Age: header received by the cache with
-// * this response.
-// * date_value
-// * is the value of the origin server's Date: header
-// * request_time
-// * is the (local) time when the cache made the request
-// * that resulted in this cached response
-// * response_time
-// * is the (local) time when the cache received the
-// * response
-// * now
-// * is the current (local) time
-// */
-// apparent_age = max(0, response_time - date_value);
-// corrected_received_age = max(apparent_age, age_value);
-// response_delay = response_time - request_time;
-// corrected_initial_age = corrected_received_age + response_delay;
-// resident_time = now - response_time;
-// current_age = corrected_initial_age + resident_time;
-//
-TimeDelta HttpResponseHeaders::GetCurrentAge(const Time& request_time,
- const Time& response_time,
- const Time& current_time) const {
// If there is no Date header, then assume that the server response was
// generated at the time when we received the response.
Time date_value;
@@ -1142,10 +1123,20 @@ TimeDelta HttpResponseHeaders::GetCurrentAge(const Time& request_time,
TimeDelta corrected_received_age = std::max(apparent_age, age_value);
TimeDelta response_delay = response_time - request_time;
TimeDelta corrected_initial_age = corrected_received_age + response_delay;
- TimeDelta resident_time = current_time - response_time;
- TimeDelta current_age = corrected_initial_age + resident_time;
- return current_age;
+ // From the age calculation algorithm above, we can derive the corrected
+ // response time, the |now| for which |current_age == 0|. Substituting into
+ // the RFC 2616 13.2.3 equations above, and simplyfing:
+ //
+ // corrected_initial_age + resident_time == 0
+ // corrected_initial_age + corrected_response_time - response_time == 0
+ // corrected_response_time == response_time - corrected_initial_age
+
+ ExpirationTimes expirations;
+ expirations.corrected_response_time = response_time - corrected_initial_age;
+ CalculateLifetimes(response_time, &expirations.freshness_lifetime,
+ &expirations.staleness_lifetime);
+ return expirations;
}
bool HttpResponseHeaders::GetMaxAgeValue(TimeDelta* result) const {

Powered by Google App Engine
This is Rietveld 408576698