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

Unified Diff: net/http/http_response_headers.cc

Issue 455623003: stale-while-revalidate experimental implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: GetFreshnessLifetimes now returns two times. Duplicate AsyncValidations for the same URL are discar… Created 6 years, 3 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 3a9f7e04fe0c4bad6a232ae52270e55427532d03..7238a5734fd72b9c9f3606388fab6bccd728046f 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.cc
@@ -133,6 +133,14 @@ struct HttpResponseHeaders::ParsedHeader {
//-----------------------------------------------------------------------------
+HttpResponseHeaders::FreshnessLifetimes::FreshnessLifetimes() {}
+HttpResponseHeaders::FreshnessLifetimes::FreshnessLifetimes(
+ const TimeDelta& fresh)
+ : fresh(fresh) {}
+HttpResponseHeaders::FreshnessLifetimes::~FreshnessLifetimes() {}
+
+//-----------------------------------------------------------------------------
+
HttpResponseHeaders::HttpResponseHeaders(const std::string& raw_input)
: response_code_(-1) {
Parse(raw_input);
@@ -956,15 +964,28 @@ bool HttpResponseHeaders::IsRedirectResponseCode(int response_code) {
// Of course, there are other factors that can force a response to always be
// validated or re-fetched.
//
-bool HttpResponseHeaders::RequiresValidation(const Time& request_time,
- const Time& response_time,
- const Time& current_time) const {
- TimeDelta lifetime =
- GetFreshnessLifetime(response_time);
- if (lifetime == TimeDelta())
- return true;
+// 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(
+ const Time& request_time,
+ const Time& response_time,
+ const Time& current_time) const {
+ FreshnessLifetimes lifetimes = GetFreshnessLifetimes(response_time);
+ if (lifetimes.fresh == TimeDelta() && lifetimes.stale == TimeDelta())
+ return VALIDATION_SYNCHRONOUS;
+
+ TimeDelta age = GetCurrentAge(request_time, response_time, current_time);
+
+ if (lifetimes.fresh > age)
+ return VALIDATION_NONE;
- return lifetime <= GetCurrentAge(request_time, response_time, current_time);
+ if (lifetimes.fresh + lifetimes.stale > age)
+ return VALIDATION_ASYNCHRONOUS;
+
+ return VALIDATION_SYNCHRONOUS;
}
// From RFC 2616 section 13.2.4:
@@ -987,8 +1008,11 @@ bool HttpResponseHeaders::RequiresValidation(const Time& request_time,
//
// freshness_lifetime = (date_value - last_modified_value) * 0.10
//
-TimeDelta HttpResponseHeaders::GetFreshnessLifetime(
- const Time& response_time) const {
+// If the stale-while-revalidate directive is present, then it is used to set
+// the |stale| time, unless it overridden by another directive.
+//
+HttpResponseHeaders::FreshnessLifetimes
+HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const {
// 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.
@@ -996,16 +1020,19 @@ TimeDelta HttpResponseHeaders::GetFreshnessLifetime(
HasHeaderValue("cache-control", "no-store") ||
HasHeaderValue("pragma", "no-cache") ||
HasHeaderValue("vary", "*")) // see RFC 2616 section 13.6
rvargas (doing something else) 2014/09/11 02:33:07 nit: Add {}
Adam Rice 2014/09/12 01:46:48 Done.
- return TimeDelta(); // not fresh
+ return FreshnessLifetimes();
+
+ FreshnessLifetimes lifetimes;
+
+ if (!GetStaleWhileRevalidateValue(&lifetimes.stale))
+ DCHECK(lifetimes.stale == TimeDelta());
// NOTE: "Cache-Control: max-age" overrides Expires, so we only check the
- // Expires header after checking for max-age in GetFreshnessLifetime. This
+ // 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.
-
- TimeDelta max_age_value;
- if (GetMaxAgeValue(&max_age_value))
- return max_age_value;
+ if (GetMaxAgeValue(&lifetimes.fresh))
+ return lifetimes;
// If there is no Date header, then assume that the server response was
// generated at the time when we received the response.
@@ -1016,10 +1043,13 @@ TimeDelta HttpResponseHeaders::GetFreshnessLifetime(
Time expires_value;
if (GetExpiresValue(&expires_value)) {
// The expires value can be a date in the past!
- if (expires_value > date_value)
- return expires_value - date_value;
+ if (expires_value > date_value) {
+ lifetimes.fresh = expires_value - date_value;
+ return lifetimes;
+ }
- return TimeDelta(); // not fresh
+ DCHECK(lifetimes.fresh == TimeDelta());
+ return lifetimes;
}
// From RFC 2616 section 13.4:
@@ -1046,25 +1076,35 @@ TimeDelta HttpResponseHeaders::GetFreshnessLifetime(
// 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."
+ //
+ // TODO(ricea): RFC7234 adds extra cacheable status codes and stops
+ // "must-revalidate" from influencing heuristic expiration. This code should
rvargas (doing something else) 2014/09/11 02:33:06 I'm missing the must-revalidate part of this comme
Adam Rice 2014/09/12 01:46:49 RFC7234 is missing the "based solely on the origin
rvargas (doing something else) 2014/09/12 18:33:12 I don't see how the removal of that sentence chang
Adam Rice 2014/09/16 11:53:00 I removed the comment. If the meaning of RFC2616 a
+ // be changed to match once the RFC has had time to mature.
if ((response_code_ == 200 || response_code_ == 203 ||
response_code_ == 206) &&
!HasHeaderValue("cache-control", "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 past!
- if (last_modified_value <= date_value)
- return (date_value - last_modified_value) / 10;
+ // The last-modified value can be a date in the future!
+ if (last_modified_value <= date_value) {
+ lifetimes.fresh = (date_value - last_modified_value) / 10;
+ return lifetimes;
+ }
}
}
// These responses are implicitly fresh (unless otherwise overruled):
if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 ||
response_code_ == 410) {
- return TimeDelta::Max();
+ return FreshnessLifetimes(TimeDelta::Max());
}
- return TimeDelta(); // not fresh
+ // Our heuristic freshness estimate for this resource is 0 seconds, in
+ // accordance with common browser behaviour. However, stale-while-revalidate
+ // may still apply.
+ DCHECK(lifetimes.fresh == TimeDelta());
+ return lifetimes;
}
// From RFC 2616 section 13.2.3:

Powered by Google App Engine
This is Rietveld 408576698