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" |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 bool is_continuation() const { return name_begin == name_end; } | 126 bool is_continuation() const { return name_begin == name_end; } |
127 | 127 |
128 std::string::const_iterator name_begin; | 128 std::string::const_iterator name_begin; |
129 std::string::const_iterator name_end; | 129 std::string::const_iterator name_end; |
130 std::string::const_iterator value_begin; | 130 std::string::const_iterator value_begin; |
131 std::string::const_iterator value_end; | 131 std::string::const_iterator value_end; |
132 }; | 132 }; |
133 | 133 |
134 //----------------------------------------------------------------------------- | 134 //----------------------------------------------------------------------------- |
135 | 135 |
136 HttpResponseHeaders::Freshness::Freshness() : usable(false) {} | |
137 HttpResponseHeaders::Freshness::Freshness(const TimeDelta& lifetime) | |
138 : usable(true), lifetime(lifetime) {} | |
139 HttpResponseHeaders::Freshness::~Freshness() {} | |
140 | |
141 //----------------------------------------------------------------------------- | |
142 | |
136 HttpResponseHeaders::HttpResponseHeaders(const std::string& raw_input) | 143 HttpResponseHeaders::HttpResponseHeaders(const std::string& raw_input) |
137 : response_code_(-1) { | 144 : response_code_(-1) { |
138 Parse(raw_input); | 145 Parse(raw_input); |
139 | 146 |
140 // The most important thing to do with this histogram is find out | 147 // The most important thing to do with this histogram is find out |
141 // the existence of unusual HTTP status codes. As it happens | 148 // the existence of unusual HTTP status codes. As it happens |
142 // right now, there aren't double-constructions of response headers | 149 // right now, there aren't double-constructions of response headers |
143 // using this constructor, so our counts should also be accurate, | 150 // using this constructor, so our counts should also be accurate, |
144 // without instantiating the histogram in two places. It is also | 151 // without instantiating the histogram in two places. It is also |
145 // important that this histogram not collect data in the other | 152 // important that this histogram not collect data in the other |
(...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
949 | 956 |
950 // From RFC 2616 section 13.2.4: | 957 // From RFC 2616 section 13.2.4: |
951 // | 958 // |
952 // The calculation to determine if a response has expired is quite simple: | 959 // The calculation to determine if a response has expired is quite simple: |
953 // | 960 // |
954 // response_is_fresh = (freshness_lifetime > current_age) | 961 // response_is_fresh = (freshness_lifetime > current_age) |
955 // | 962 // |
956 // Of course, there are other factors that can force a response to always be | 963 // Of course, there are other factors that can force a response to always be |
957 // validated or re-fetched. | 964 // validated or re-fetched. |
958 // | 965 // |
959 bool HttpResponseHeaders::RequiresValidation(const Time& request_time, | 966 // From RFC 5861 section 3, a stale response may be used while revalidation is |
960 const Time& response_time, | 967 // performed in the background if |
961 const Time& current_time) const { | 968 // |
962 TimeDelta lifetime = | 969 // freshness_lifetime + stale_while_revalidate > current_age |
963 GetFreshnessLifetime(response_time); | 970 // |
964 if (lifetime == TimeDelta()) | 971 HttpResponseHeaders::ValidationType HttpResponseHeaders::RequiresValidation( |
965 return true; | 972 const Time& request_time, |
973 const Time& response_time, | |
974 const Time& current_time) const { | |
975 Freshness freshness = GetFreshnessLifetime(response_time); | |
976 if (!freshness.usable) | |
977 return VALIDATION_SYNCHRONOUS; | |
978 TimeDelta age = GetCurrentAge(request_time, response_time, current_time); | |
966 | 979 |
967 return lifetime <= GetCurrentAge(request_time, response_time, current_time); | 980 if (freshness.lifetime > age) |
981 return VALIDATION_NONE; | |
982 | |
983 TimeDelta stale_while_revalidate; | |
984 if (GetStaleWhileRevalidateValue(&stale_while_revalidate) && | |
985 freshness.lifetime + stale_while_revalidate > age) | |
986 return VALIDATION_ASYNCHRONOUS; | |
987 | |
988 return VALIDATION_SYNCHRONOUS; | |
968 } | 989 } |
969 | 990 |
970 // From RFC 2616 section 13.2.4: | 991 // From RFC 2616 section 13.2.4: |
971 // | 992 // |
972 // The max-age directive takes priority over Expires, so if max-age is present | 993 // The max-age directive takes priority over Expires, so if max-age is present |
973 // in a response, the calculation is simply: | 994 // in a response, the calculation is simply: |
974 // | 995 // |
975 // freshness_lifetime = max_age_value | 996 // freshness_lifetime = max_age_value |
976 // | 997 // |
977 // Otherwise, if Expires is present in the response, the calculation is: | 998 // Otherwise, if Expires is present in the response, the calculation is: |
978 // | 999 // |
979 // freshness_lifetime = expires_value - date_value | 1000 // freshness_lifetime = expires_value - date_value |
980 // | 1001 // |
981 // Note that neither of these calculations is vulnerable to clock skew, since | 1002 // Note that neither of these calculations is vulnerable to clock skew, since |
982 // all of the information comes from the origin server. | 1003 // all of the information comes from the origin server. |
983 // | 1004 // |
984 // Also, if the response does have a Last-Modified time, the heuristic | 1005 // Also, if the response does have a Last-Modified time, the heuristic |
985 // expiration value SHOULD be no more than some fraction of the interval since | 1006 // expiration value SHOULD be no more than some fraction of the interval since |
986 // that time. A typical setting of this fraction might be 10%: | 1007 // that time. A typical setting of this fraction might be 10%: |
987 // | 1008 // |
988 // freshness_lifetime = (date_value - last_modified_value) * 0.10 | 1009 // freshness_lifetime = (date_value - last_modified_value) * 0.10 |
989 // | 1010 // |
990 TimeDelta HttpResponseHeaders::GetFreshnessLifetime( | 1011 HttpResponseHeaders::Freshness HttpResponseHeaders::GetFreshnessLifetime( |
991 const Time& response_time) const { | 1012 const Time& response_time) const { |
992 // Check for headers that force a response to never be fresh. For backwards | 1013 // Check for headers that force a response to never be fresh. For backwards |
993 // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control: | 1014 // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control: |
994 // no-cache" even though RFC 2616 does not specify it. | 1015 // no-cache" even though RFC 2616 does not specify it. |
995 if (HasHeaderValue("cache-control", "no-cache") || | 1016 if (HasHeaderValue("cache-control", "no-cache") || |
996 HasHeaderValue("cache-control", "no-store") || | 1017 HasHeaderValue("cache-control", "no-store") || |
997 HasHeaderValue("pragma", "no-cache") || | 1018 HasHeaderValue("pragma", "no-cache") || |
998 HasHeaderValue("vary", "*")) // see RFC 2616 section 13.6 | 1019 HasHeaderValue("vary", "*")) // see RFC 2616 section 13.6 |
999 return TimeDelta(); // not fresh | 1020 return Freshness(); |
1000 | 1021 |
1001 // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the | 1022 // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the |
1002 // Expires header after checking for max-age in GetFreshnessLifetime. This | 1023 // Expires header after checking for max-age in GetFreshnessLifetime. This |
1003 // is important since "Expires: <date in the past>" means not fresh, but | 1024 // is important since "Expires: <date in the past>" means not fresh, but |
1004 // it should not trump a max-age value. | 1025 // it should not trump a max-age value. |
1005 | 1026 TimeDelta lifetime; |
1006 TimeDelta max_age_value; | 1027 if (GetMaxAgeValue(&lifetime)) |
1007 if (GetMaxAgeValue(&max_age_value)) | 1028 return Freshness(lifetime); |
rvargas (doing something else)
2014/09/05 22:52:40
We have to look at must-revalidate before deciding
rvargas (doing something else)
2014/09/11 02:33:06
?
Adam Rice
2014/09/12 01:46:48
The existing code doesn't look at must-revalidate
rvargas (doing something else)
2014/09/12 18:33:12
must-revalidate doesn't matter for the current cod
Adam Rice
2014/09/16 11:53:00
Done.
| |
1008 return max_age_value; | |
1009 | 1029 |
1010 // If there is no Date header, then assume that the server response was | 1030 // If there is no Date header, then assume that the server response was |
1011 // generated at the time when we received the response. | 1031 // generated at the time when we received the response. |
1012 Time date_value; | 1032 Time date_value; |
1013 if (!GetDateValue(&date_value)) | 1033 if (!GetDateValue(&date_value)) |
1014 date_value = response_time; | 1034 date_value = response_time; |
1015 | 1035 |
1016 Time expires_value; | 1036 Time expires_value; |
1017 if (GetExpiresValue(&expires_value)) { | 1037 if (GetExpiresValue(&expires_value)) { |
1018 // The expires value can be a date in the past! | 1038 // The expires value can be a date in the past! |
1019 if (expires_value > date_value) | 1039 if (expires_value > date_value) { |
1020 return expires_value - date_value; | 1040 return Freshness(expires_value - date_value); |
1041 } | |
1021 | 1042 |
1022 return TimeDelta(); // not fresh | 1043 return Freshness(); |
rvargas (doing something else)
2014/09/05 22:52:40
This may be usable
Adam Rice
2014/09/09 12:36:45
Acknowledged.
| |
1023 } | 1044 } |
1024 | 1045 |
1025 // From RFC 2616 section 13.4: | 1046 // From RFC 2616 section 13.4: |
1026 // | 1047 // |
1027 // A response received with a status code of 200, 203, 206, 300, 301 or 410 | 1048 // A response received with a status code of 200, 203, 206, 300, 301 or 410 |
1028 // MAY be stored by a cache and used in reply to a subsequent request, | 1049 // MAY be stored by a cache and used in reply to a subsequent request, |
1029 // subject to the expiration mechanism, unless a cache-control directive | 1050 // subject to the expiration mechanism, unless a cache-control directive |
1030 // prohibits caching. | 1051 // prohibits caching. |
1031 // ... | 1052 // ... |
1032 // A response received with any other status code (e.g. status codes 302 | 1053 // A response received with any other status code (e.g. status codes 302 |
(...skipping 12 matching lines...) Expand all Loading... | |
1045 // | 1066 // |
1046 // https://datatracker.ietf.org/doc/draft-reschke-http-status-308/ is an | 1067 // https://datatracker.ietf.org/doc/draft-reschke-http-status-308/ is an |
1047 // experimental RFC that adds 308 permanent redirect as well, for which "any | 1068 // experimental RFC that adds 308 permanent redirect as well, for which "any |
1048 // future references ... SHOULD use one of the returned URIs." | 1069 // future references ... SHOULD use one of the returned URIs." |
1049 if ((response_code_ == 200 || response_code_ == 203 || | 1070 if ((response_code_ == 200 || response_code_ == 203 || |
1050 response_code_ == 206) && | 1071 response_code_ == 206) && |
1051 !HasHeaderValue("cache-control", "must-revalidate")) { | 1072 !HasHeaderValue("cache-control", "must-revalidate")) { |
1052 // TODO(darin): Implement a smarter heuristic. | 1073 // TODO(darin): Implement a smarter heuristic. |
1053 Time last_modified_value; | 1074 Time last_modified_value; |
1054 if (GetLastModifiedValue(&last_modified_value)) { | 1075 if (GetLastModifiedValue(&last_modified_value)) { |
1055 // The last-modified value can be a date in the past! | 1076 // The last-modified value can be a date in the future! |
1056 if (last_modified_value <= date_value) | 1077 if (last_modified_value <= date_value) { |
1057 return (date_value - last_modified_value) / 10; | 1078 return Freshness((date_value - last_modified_value) / 10); |
1079 } | |
1058 } | 1080 } |
1059 } | 1081 } |
1060 | 1082 |
1061 // These responses are implicitly fresh (unless otherwise overruled): | 1083 // These responses are implicitly fresh (unless otherwise overruled): |
1062 if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 || | 1084 if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 || |
1063 response_code_ == 410) { | 1085 response_code_ == 410) { |
1064 return TimeDelta::Max(); | 1086 return Freshness(TimeDelta::Max()); |
rvargas (doing something else)
2014/09/05 22:52:40
must-revalidate again
Adam Rice
2014/09/09 12:36:46
This never becomes stale, so must-revalidate is a
rvargas (doing something else)
2014/09/11 02:33:05
doh!
| |
1065 } | 1087 } |
1066 | 1088 |
1067 return TimeDelta(); // not fresh | 1089 return Freshness(); |
rvargas (doing something else)
2014/09/05 22:52:40
may be usable.
I think things are simpler if this
Adam Rice
2014/09/09 12:36:46
Done.
| |
1068 } | 1090 } |
1069 | 1091 |
1070 // From RFC 2616 section 13.2.3: | 1092 // From RFC 2616 section 13.2.3: |
1071 // | 1093 // |
1072 // Summary of age calculation algorithm, when a cache receives a response: | 1094 // Summary of age calculation algorithm, when a cache receives a response: |
1073 // | 1095 // |
1074 // /* | 1096 // /* |
1075 // * age_value | 1097 // * age_value |
1076 // * is the value of Age: header received by the cache with | 1098 // * is the value of Age: header received by the cache with |
1077 // * this response. | 1099 // * this response. |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1397 return true; | 1419 return true; |
1398 } | 1420 } |
1399 | 1421 |
1400 bool HttpResponseHeaders::IsChunkEncoded() const { | 1422 bool HttpResponseHeaders::IsChunkEncoded() const { |
1401 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. | 1423 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. |
1402 return GetHttpVersion() >= HttpVersion(1, 1) && | 1424 return GetHttpVersion() >= HttpVersion(1, 1) && |
1403 HasHeaderValue("Transfer-Encoding", "chunked"); | 1425 HasHeaderValue("Transfer-Encoding", "chunked"); |
1404 } | 1426 } |
1405 | 1427 |
1406 } // namespace net | 1428 } // namespace net |
OLD | NEW |