 Chromium Code Reviews
 Chromium Code Reviews Issue 665023002:
  Post-commit fixes for "stale-while-revalidate..."  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 665023002:
  Post-commit fixes for "stale-while-revalidate..."  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 // The rules for header parsing were borrowed from Firefox: | 5 // The rules for header parsing were borrowed from Firefox: | 
| 6 // http://lxr.mozilla.org/seamonkey/source/netwerk/protocol/http/src/nsHttpRespo nseHead.cpp | 6 // http://lxr.mozilla.org/seamonkey/source/netwerk/protocol/http/src/nsHttpRespo nseHead.cpp | 
| 7 // The rules for parsing content-types were also borrowed from Firefox: | 7 // The rules for parsing content-types were also borrowed from Firefox: | 
| 8 // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 | 8 // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 | 
| 9 | 9 | 
| 10 #include "net/http/http_response_headers.h" | 10 #include "net/http/http_response_headers.h" | 
| 11 | 11 | 
| 12 #include <algorithm> | 12 #include <algorithm> | 
| 13 | 13 | 
| 14 #include "base/format_macros.h" | 14 #include "base/format_macros.h" | 
| 15 #include "base/logging.h" | 15 #include "base/logging.h" | 
| 16 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" | 
| 17 #include "base/pickle.h" | 17 #include "base/pickle.h" | 
| 18 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" | 
| 19 #include "base/strings/string_piece.h" | 19 #include "base/strings/string_piece.h" | 
| 20 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" | 
| 21 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" | 
| 22 #include "base/time/time.h" | 22 #include "base/time/time.h" | 
| 23 #include "base/time/time_logging.h" | |
| 
mmenke
2014/10/21 14:22:00
I wonder about requiring this include - I don't th
 
Adam Rice
2014/10/23 01:13:02
True. I got rid of the separate include file.
 | |
| 23 #include "base/values.h" | 24 #include "base/values.h" | 
| 24 #include "net/base/escape.h" | 25 #include "net/base/escape.h" | 
| 25 #include "net/http/http_byte_range.h" | 26 #include "net/http/http_byte_range.h" | 
| 26 #include "net/http/http_log_util.h" | 27 #include "net/http/http_log_util.h" | 
| 27 #include "net/http/http_util.h" | 28 #include "net/http/http_util.h" | 
| 28 | 29 | 
| 29 using base::StringPiece; | 30 using base::StringPiece; | 
| 30 using base::Time; | 31 using base::Time; | 
| 31 using base::TimeDelta; | 32 using base::TimeDelta; | 
| 32 | 33 | 
| (...skipping 926 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 959 // From RFC 5861 section 3, a stale response may be used while revalidation is | 960 // From RFC 5861 section 3, a stale response may be used while revalidation is | 
| 960 // performed in the background if | 961 // performed in the background if | 
| 961 // | 962 // | 
| 962 // freshness_lifetime + stale_while_revalidate > current_age | 963 // freshness_lifetime + stale_while_revalidate > current_age | 
| 963 // | 964 // | 
| 964 ValidationType HttpResponseHeaders::RequiresValidation( | 965 ValidationType HttpResponseHeaders::RequiresValidation( | 
| 965 const Time& request_time, | 966 const Time& request_time, | 
| 966 const Time& response_time, | 967 const Time& response_time, | 
| 967 const Time& current_time) const { | 968 const Time& current_time) const { | 
| 968 FreshnessLifetimes lifetimes = GetFreshnessLifetimes(response_time); | 969 FreshnessLifetimes lifetimes = GetFreshnessLifetimes(response_time); | 
| 969 if (lifetimes.fresh == TimeDelta() && lifetimes.stale == TimeDelta()) | 970 if (lifetimes.freshness == TimeDelta() && lifetimes.staleness == TimeDelta()) | 
| 970 return VALIDATION_SYNCHRONOUS; | 971 return VALIDATION_SYNCHRONOUS; | 
| 971 | 972 | 
| 972 TimeDelta age = GetCurrentAge(request_time, response_time, current_time); | 973 TimeDelta age = GetCurrentAge(request_time, response_time, current_time); | 
| 973 | 974 | 
| 974 if (lifetimes.fresh > age) | 975 if (lifetimes.freshness > age) | 
| 975 return VALIDATION_NONE; | 976 return VALIDATION_NONE; | 
| 976 | 977 | 
| 977 if (lifetimes.fresh + lifetimes.stale > age) | 978 if (lifetimes.freshness + lifetimes.staleness > age) | 
| 978 return VALIDATION_ASYNCHRONOUS; | 979 return VALIDATION_ASYNCHRONOUS; | 
| 979 | 980 | 
| 980 return VALIDATION_SYNCHRONOUS; | 981 return VALIDATION_SYNCHRONOUS; | 
| 981 } | 982 } | 
| 982 | 983 | 
| 983 // From RFC 2616 section 13.2.4: | 984 // From RFC 2616 section 13.2.4: | 
| 984 // | 985 // | 
| 985 // The max-age directive takes priority over Expires, so if max-age is present | 986 // The max-age directive takes priority over Expires, so if max-age is present | 
| 986 // in a response, the calculation is simply: | 987 // in a response, the calculation is simply: | 
| 987 // | 988 // | 
| 988 // freshness_lifetime = max_age_value | 989 // freshness_lifetime = max_age_value | 
| 989 // | 990 // | 
| 990 // Otherwise, if Expires is present in the response, the calculation is: | 991 // Otherwise, if Expires is present in the response, the calculation is: | 
| 991 // | 992 // | 
| 992 // freshness_lifetime = expires_value - date_value | 993 // freshness_lifetime = expires_value - date_value | 
| 993 // | 994 // | 
| 994 // Note that neither of these calculations is vulnerable to clock skew, since | 995 // Note that neither of these calculations is vulnerable to clock skew, since | 
| 995 // all of the information comes from the origin server. | 996 // all of the information comes from the origin server. | 
| 996 // | 997 // | 
| 997 // Also, if the response does have a Last-Modified time, the heuristic | 998 // Also, if the response does have a Last-Modified time, the heuristic | 
| 998 // expiration value SHOULD be no more than some fraction of the interval since | 999 // expiration value SHOULD be no more than some fraction of the interval since | 
| 999 // that time. A typical setting of this fraction might be 10%: | 1000 // that time. A typical setting of this fraction might be 10%: | 
| 1000 // | 1001 // | 
| 1001 // freshness_lifetime = (date_value - last_modified_value) * 0.10 | 1002 // freshness_lifetime = (date_value - last_modified_value) * 0.10 | 
| 1002 // | 1003 // | 
| 1003 // If the stale-while-revalidate directive is present, then it is used to set | 1004 // If the stale-while-revalidate directive is present, then it is used to set | 
| 1004 // the |stale| time, unless it overridden by another directive. | 1005 // the |staleness| time, unless it overridden by another directive. | 
| 1005 // | 1006 // | 
| 1006 HttpResponseHeaders::FreshnessLifetimes | 1007 HttpResponseHeaders::FreshnessLifetimes | 
| 1007 HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const { | 1008 HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const { | 
| 1008 FreshnessLifetimes lifetimes; | 1009 FreshnessLifetimes lifetimes; | 
| 1009 // Check for headers that force a response to never be fresh. For backwards | 1010 // Check for headers that force a response to never be fresh. For backwards | 
| 1010 // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control: | 1011 // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control: | 
| 1011 // no-cache" even though RFC 2616 does not specify it. | 1012 // no-cache" even though RFC 2616 does not specify it. | 
| 1012 if (HasHeaderValue("cache-control", "no-cache") || | 1013 if (HasHeaderValue("cache-control", "no-cache") || | 
| 1013 HasHeaderValue("cache-control", "no-store") || | 1014 HasHeaderValue("cache-control", "no-store") || | 
| 1014 HasHeaderValue("pragma", "no-cache") || | 1015 HasHeaderValue("pragma", "no-cache") || | 
| 1015 // Vary: * is never usable: see RFC 2616 section 13.6. | 1016 // Vary: * is never usable: see RFC 2616 section 13.6. | 
| 1016 HasHeaderValue("vary", "*")) { | 1017 HasHeaderValue("vary", "*")) { | 
| 1017 return lifetimes; | 1018 return lifetimes; | 
| 1018 } | 1019 } | 
| 1019 | 1020 | 
| 1020 // Cache-Control directive must_revalidate overrides stale-while-revalidate. | 1021 // Cache-Control directive must_revalidate overrides stale-while-revalidate. | 
| 1021 bool must_revalidate = HasHeaderValue("cache-control", "must-revalidate"); | 1022 bool must_revalidate = HasHeaderValue("cache-control", "must-revalidate"); | 
| 1022 | 1023 | 
| 1023 if (must_revalidate || !GetStaleWhileRevalidateValue(&lifetimes.stale)) | 1024 if (must_revalidate || !GetStaleWhileRevalidateValue(&lifetimes.staleness)) { | 
| 1024 DCHECK(lifetimes.stale == TimeDelta()); | 1025 DCHECK_EQ(TimeDelta(), lifetimes.staleness); | 
| 1026 } | |
| 1025 | 1027 | 
| 1026 // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the | 1028 // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the | 
| 1027 // Expires header after checking for max-age in GetFreshnessLifetimes. This | 1029 // Expires header after checking for max-age in GetFreshnessLifetimes. This | 
| 1028 // is important since "Expires: <date in the past>" means not fresh, but | 1030 // is important since "Expires: <date in the past>" means not fresh, but | 
| 1029 // it should not trump a max-age value. | 1031 // it should not trump a max-age value. | 
| 1030 if (GetMaxAgeValue(&lifetimes.fresh)) | 1032 if (GetMaxAgeValue(&lifetimes.freshness)) | 
| 1031 return lifetimes; | 1033 return lifetimes; | 
| 1032 | 1034 | 
| 1033 // If there is no Date header, then assume that the server response was | 1035 // If there is no Date header, then assume that the server response was | 
| 1034 // generated at the time when we received the response. | 1036 // generated at the time when we received the response. | 
| 1035 Time date_value; | 1037 Time date_value; | 
| 1036 if (!GetDateValue(&date_value)) | 1038 if (!GetDateValue(&date_value)) | 
| 1037 date_value = response_time; | 1039 date_value = response_time; | 
| 1038 | 1040 | 
| 1039 Time expires_value; | 1041 Time expires_value; | 
| 1040 if (GetExpiresValue(&expires_value)) { | 1042 if (GetExpiresValue(&expires_value)) { | 
| 1041 // The expires value can be a date in the past! | 1043 // The expires value can be a date in the past! | 
| 1042 if (expires_value > date_value) { | 1044 if (expires_value > date_value) { | 
| 1043 lifetimes.fresh = expires_value - date_value; | 1045 lifetimes.freshness = expires_value - date_value; | 
| 1044 return lifetimes; | 1046 return lifetimes; | 
| 1045 } | 1047 } | 
| 1046 | 1048 | 
| 1047 DCHECK(lifetimes.fresh == TimeDelta()); | 1049 DCHECK_EQ(TimeDelta(), lifetimes.freshness); | 
| 1048 return lifetimes; | 1050 return lifetimes; | 
| 1049 } | 1051 } | 
| 1050 | 1052 | 
| 1051 // From RFC 2616 section 13.4: | 1053 // From RFC 2616 section 13.4: | 
| 1052 // | 1054 // | 
| 1053 // A response received with a status code of 200, 203, 206, 300, 301 or 410 | 1055 // A response received with a status code of 200, 203, 206, 300, 301 or 410 | 
| 1054 // MAY be stored by a cache and used in reply to a subsequent request, | 1056 // MAY be stored by a cache and used in reply to a subsequent request, | 
| 1055 // subject to the expiration mechanism, unless a cache-control directive | 1057 // subject to the expiration mechanism, unless a cache-control directive | 
| 1056 // prohibits caching. | 1058 // prohibits caching. | 
| 1057 // ... | 1059 // ... | 
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1072 // https://datatracker.ietf.org/doc/draft-reschke-http-status-308/ is an | 1074 // https://datatracker.ietf.org/doc/draft-reschke-http-status-308/ is an | 
| 1073 // experimental RFC that adds 308 permanent redirect as well, for which "any | 1075 // experimental RFC that adds 308 permanent redirect as well, for which "any | 
| 1074 // future references ... SHOULD use one of the returned URIs." | 1076 // future references ... SHOULD use one of the returned URIs." | 
| 1075 if ((response_code_ == 200 || response_code_ == 203 || | 1077 if ((response_code_ == 200 || response_code_ == 203 || | 
| 1076 response_code_ == 206) && !must_revalidate) { | 1078 response_code_ == 206) && !must_revalidate) { | 
| 1077 // TODO(darin): Implement a smarter heuristic. | 1079 // TODO(darin): Implement a smarter heuristic. | 
| 1078 Time last_modified_value; | 1080 Time last_modified_value; | 
| 1079 if (GetLastModifiedValue(&last_modified_value)) { | 1081 if (GetLastModifiedValue(&last_modified_value)) { | 
| 1080 // The last-modified value can be a date in the future! | 1082 // The last-modified value can be a date in the future! | 
| 1081 if (last_modified_value <= date_value) { | 1083 if (last_modified_value <= date_value) { | 
| 1082 lifetimes.fresh = (date_value - last_modified_value) / 10; | 1084 lifetimes.freshness = (date_value - last_modified_value) / 10; | 
| 1083 return lifetimes; | 1085 return lifetimes; | 
| 1084 } | 1086 } | 
| 1085 } | 1087 } | 
| 1086 } | 1088 } | 
| 1087 | 1089 | 
| 1088 // These responses are implicitly fresh (unless otherwise overruled): | 1090 // These responses are implicitly fresh (unless otherwise overruled): | 
| 1089 if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 || | 1091 if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 || | 
| 1090 response_code_ == 410) { | 1092 response_code_ == 410) { | 
| 1091 lifetimes.fresh = TimeDelta::Max(); | 1093 lifetimes.freshness = TimeDelta::Max(); | 
| 1092 lifetimes.stale = TimeDelta(); // It should never be stale. | 1094 lifetimes.staleness = TimeDelta(); // It should never be stale. | 
| 1093 return lifetimes; | 1095 return lifetimes; | 
| 1094 } | 1096 } | 
| 1095 | 1097 | 
| 1096 // Our heuristic freshness estimate for this resource is 0 seconds, in | 1098 // Our heuristic freshness estimate for this resource is 0 seconds, in | 
| 1097 // accordance with common browser behaviour. However, stale-while-revalidate | 1099 // accordance with common browser behaviour. However, stale-while-revalidate | 
| 1098 // may still apply. | 1100 // may still apply. | 
| 1099 DCHECK(lifetimes.fresh == TimeDelta()); | 1101 DCHECK_EQ(TimeDelta(), lifetimes.freshness); | 
| 1100 return lifetimes; | 1102 return lifetimes; | 
| 1101 } | 1103 } | 
| 1102 | 1104 | 
| 1103 // From RFC 2616 section 13.2.3: | 1105 // From RFC 2616 section 13.2.3: | 
| 1104 // | 1106 // | 
| 1105 // Summary of age calculation algorithm, when a cache receives a response: | 1107 // Summary of age calculation algorithm, when a cache receives a response: | 
| 1106 // | 1108 // | 
| 1107 // /* | 1109 // /* | 
| 1108 // * age_value | 1110 // * age_value | 
| 1109 // * is the value of Age: header received by the cache with | 1111 // * is the value of Age: header received by the cache with | 
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1442 return true; | 1444 return true; | 
| 1443 } | 1445 } | 
| 1444 | 1446 | 
| 1445 bool HttpResponseHeaders::IsChunkEncoded() const { | 1447 bool HttpResponseHeaders::IsChunkEncoded() const { | 
| 1446 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. | 1448 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. | 
| 1447 return GetHttpVersion() >= HttpVersion(1, 1) && | 1449 return GetHttpVersion() >= HttpVersion(1, 1) && | 
| 1448 HasHeaderValue("Transfer-Encoding", "chunked"); | 1450 HasHeaderValue("Transfer-Encoding", "chunked"); | 
| 1449 } | 1451 } | 
| 1450 | 1452 | 
| 1451 } // namespace net | 1453 } // namespace net | 
| OLD | NEW |