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 |