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 948 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 | 959 // From RFC 5861 section 3, a stale response may be used while revalidation is |
960 // performed in the background if | 960 // performed in the background if |
961 // | 961 // |
962 // freshness_lifetime + stale_while_revalidate > current_age | 962 // freshness_lifetime + stale_while_revalidate > current_age |
963 // | 963 // |
964 ValidationType HttpResponseHeaders::RequiresValidation( | 964 ValidationType HttpResponseHeaders::RequiresValidation( |
965 const Time& request_time, | 965 const Time& request_time, |
966 const Time& response_time, | 966 const Time& response_time, |
967 const Time& current_time) const { | 967 const Time& current_time) const { |
968 FreshnessLifetimes lifetimes = GetFreshnessLifetimes(response_time); | 968 FreshnessLifetimes lifetimes = GetFreshnessLifetimes(response_time); |
969 if (lifetimes.fresh == TimeDelta() && lifetimes.stale == TimeDelta()) | 969 if (lifetimes.freshness == TimeDelta() && lifetimes.staleness == TimeDelta()) |
970 return VALIDATION_SYNCHRONOUS; | 970 return VALIDATION_SYNCHRONOUS; |
971 | 971 |
972 TimeDelta age = GetCurrentAge(request_time, response_time, current_time); | 972 TimeDelta age = GetCurrentAge(request_time, response_time, current_time); |
973 | 973 |
974 if (lifetimes.fresh > age) | 974 if (lifetimes.freshness > age) |
975 return VALIDATION_NONE; | 975 return VALIDATION_NONE; |
976 | 976 |
977 if (lifetimes.fresh + lifetimes.stale > age) | 977 if (lifetimes.freshness + lifetimes.staleness > age) |
978 return VALIDATION_ASYNCHRONOUS; | 978 return VALIDATION_ASYNCHRONOUS; |
979 | 979 |
980 return VALIDATION_SYNCHRONOUS; | 980 return VALIDATION_SYNCHRONOUS; |
981 } | 981 } |
982 | 982 |
983 // From RFC 2616 section 13.2.4: | 983 // From RFC 2616 section 13.2.4: |
984 // | 984 // |
985 // The max-age directive takes priority over Expires, so if max-age is present | 985 // The max-age directive takes priority over Expires, so if max-age is present |
986 // in a response, the calculation is simply: | 986 // in a response, the calculation is simply: |
987 // | 987 // |
988 // freshness_lifetime = max_age_value | 988 // freshness_lifetime = max_age_value |
989 // | 989 // |
990 // Otherwise, if Expires is present in the response, the calculation is: | 990 // Otherwise, if Expires is present in the response, the calculation is: |
991 // | 991 // |
992 // freshness_lifetime = expires_value - date_value | 992 // freshness_lifetime = expires_value - date_value |
993 // | 993 // |
994 // Note that neither of these calculations is vulnerable to clock skew, since | 994 // Note that neither of these calculations is vulnerable to clock skew, since |
995 // all of the information comes from the origin server. | 995 // all of the information comes from the origin server. |
996 // | 996 // |
997 // Also, if the response does have a Last-Modified time, the heuristic | 997 // 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 | 998 // 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%: | 999 // that time. A typical setting of this fraction might be 10%: |
1000 // | 1000 // |
1001 // freshness_lifetime = (date_value - last_modified_value) * 0.10 | 1001 // freshness_lifetime = (date_value - last_modified_value) * 0.10 |
1002 // | 1002 // |
1003 // If the stale-while-revalidate directive is present, then it is used to set | 1003 // If the stale-while-revalidate directive is present, then it is used to set |
1004 // the |stale| time, unless it overridden by another directive. | 1004 // the |staleness| time, unless it overridden by another directive. |
1005 // | 1005 // |
1006 HttpResponseHeaders::FreshnessLifetimes | 1006 HttpResponseHeaders::FreshnessLifetimes |
1007 HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const { | 1007 HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const { |
1008 FreshnessLifetimes lifetimes; | 1008 FreshnessLifetimes lifetimes; |
1009 // Check for headers that force a response to never be fresh. For backwards | 1009 // 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: | 1010 // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control: |
1011 // no-cache" even though RFC 2616 does not specify it. | 1011 // no-cache" even though RFC 2616 does not specify it. |
1012 if (HasHeaderValue("cache-control", "no-cache") || | 1012 if (HasHeaderValue("cache-control", "no-cache") || |
1013 HasHeaderValue("cache-control", "no-store") || | 1013 HasHeaderValue("cache-control", "no-store") || |
1014 HasHeaderValue("pragma", "no-cache") || | 1014 HasHeaderValue("pragma", "no-cache") || |
1015 // Vary: * is never usable: see RFC 2616 section 13.6. | 1015 // Vary: * is never usable: see RFC 2616 section 13.6. |
1016 HasHeaderValue("vary", "*")) { | 1016 HasHeaderValue("vary", "*")) { |
1017 return lifetimes; | 1017 return lifetimes; |
1018 } | 1018 } |
1019 | 1019 |
1020 // Cache-Control directive must_revalidate overrides stale-while-revalidate. | 1020 // Cache-Control directive must_revalidate overrides stale-while-revalidate. |
1021 bool must_revalidate = HasHeaderValue("cache-control", "must-revalidate"); | 1021 bool must_revalidate = HasHeaderValue("cache-control", "must-revalidate"); |
1022 | 1022 |
1023 if (must_revalidate || !GetStaleWhileRevalidateValue(&lifetimes.stale)) | 1023 if (must_revalidate || !GetStaleWhileRevalidateValue(&lifetimes.staleness)) { |
1024 DCHECK(lifetimes.stale == TimeDelta()); | 1024 DCHECK(lifetimes.staleness == TimeDelta()); |
| 1025 } |
1025 | 1026 |
1026 // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the | 1027 // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the |
1027 // Expires header after checking for max-age in GetFreshnessLifetimes. This | 1028 // Expires header after checking for max-age in GetFreshnessLifetimes. This |
1028 // is important since "Expires: <date in the past>" means not fresh, but | 1029 // is important since "Expires: <date in the past>" means not fresh, but |
1029 // it should not trump a max-age value. | 1030 // it should not trump a max-age value. |
1030 if (GetMaxAgeValue(&lifetimes.fresh)) | 1031 if (GetMaxAgeValue(&lifetimes.freshness)) |
1031 return lifetimes; | 1032 return lifetimes; |
1032 | 1033 |
1033 // If there is no Date header, then assume that the server response was | 1034 // If there is no Date header, then assume that the server response was |
1034 // generated at the time when we received the response. | 1035 // generated at the time when we received the response. |
1035 Time date_value; | 1036 Time date_value; |
1036 if (!GetDateValue(&date_value)) | 1037 if (!GetDateValue(&date_value)) |
1037 date_value = response_time; | 1038 date_value = response_time; |
1038 | 1039 |
1039 Time expires_value; | 1040 Time expires_value; |
1040 if (GetExpiresValue(&expires_value)) { | 1041 if (GetExpiresValue(&expires_value)) { |
1041 // The expires value can be a date in the past! | 1042 // The expires value can be a date in the past! |
1042 if (expires_value > date_value) { | 1043 if (expires_value > date_value) { |
1043 lifetimes.fresh = expires_value - date_value; | 1044 lifetimes.freshness = expires_value - date_value; |
1044 return lifetimes; | 1045 return lifetimes; |
1045 } | 1046 } |
1046 | 1047 |
1047 DCHECK(lifetimes.fresh == TimeDelta()); | 1048 DCHECK(lifetimes.freshness == TimeDelta()); |
1048 return lifetimes; | 1049 return lifetimes; |
1049 } | 1050 } |
1050 | 1051 |
1051 // From RFC 2616 section 13.4: | 1052 // From RFC 2616 section 13.4: |
1052 // | 1053 // |
1053 // A response received with a status code of 200, 203, 206, 300, 301 or 410 | 1054 // 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, | 1055 // 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 | 1056 // subject to the expiration mechanism, unless a cache-control directive |
1056 // prohibits caching. | 1057 // prohibits caching. |
1057 // ... | 1058 // ... |
(...skipping 14 matching lines...) Expand all Loading... |
1072 // https://datatracker.ietf.org/doc/draft-reschke-http-status-308/ is an | 1073 // 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 | 1074 // experimental RFC that adds 308 permanent redirect as well, for which "any |
1074 // future references ... SHOULD use one of the returned URIs." | 1075 // future references ... SHOULD use one of the returned URIs." |
1075 if ((response_code_ == 200 || response_code_ == 203 || | 1076 if ((response_code_ == 200 || response_code_ == 203 || |
1076 response_code_ == 206) && !must_revalidate) { | 1077 response_code_ == 206) && !must_revalidate) { |
1077 // TODO(darin): Implement a smarter heuristic. | 1078 // TODO(darin): Implement a smarter heuristic. |
1078 Time last_modified_value; | 1079 Time last_modified_value; |
1079 if (GetLastModifiedValue(&last_modified_value)) { | 1080 if (GetLastModifiedValue(&last_modified_value)) { |
1080 // The last-modified value can be a date in the future! | 1081 // The last-modified value can be a date in the future! |
1081 if (last_modified_value <= date_value) { | 1082 if (last_modified_value <= date_value) { |
1082 lifetimes.fresh = (date_value - last_modified_value) / 10; | 1083 lifetimes.freshness = (date_value - last_modified_value) / 10; |
1083 return lifetimes; | 1084 return lifetimes; |
1084 } | 1085 } |
1085 } | 1086 } |
1086 } | 1087 } |
1087 | 1088 |
1088 // These responses are implicitly fresh (unless otherwise overruled): | 1089 // These responses are implicitly fresh (unless otherwise overruled): |
1089 if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 || | 1090 if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 || |
1090 response_code_ == 410) { | 1091 response_code_ == 410) { |
1091 lifetimes.fresh = TimeDelta::Max(); | 1092 lifetimes.freshness = TimeDelta::Max(); |
1092 lifetimes.stale = TimeDelta(); // It should never be stale. | 1093 lifetimes.staleness = TimeDelta(); // It should never be stale. |
1093 return lifetimes; | 1094 return lifetimes; |
1094 } | 1095 } |
1095 | 1096 |
1096 // Our heuristic freshness estimate for this resource is 0 seconds, in | 1097 // Our heuristic freshness estimate for this resource is 0 seconds, in |
1097 // accordance with common browser behaviour. However, stale-while-revalidate | 1098 // accordance with common browser behaviour. However, stale-while-revalidate |
1098 // may still apply. | 1099 // may still apply. |
1099 DCHECK(lifetimes.fresh == TimeDelta()); | 1100 DCHECK(lifetimes.freshness == TimeDelta()); |
1100 return lifetimes; | 1101 return lifetimes; |
1101 } | 1102 } |
1102 | 1103 |
1103 // From RFC 2616 section 13.2.3: | 1104 // From RFC 2616 section 13.2.3: |
1104 // | 1105 // |
1105 // Summary of age calculation algorithm, when a cache receives a response: | 1106 // Summary of age calculation algorithm, when a cache receives a response: |
1106 // | 1107 // |
1107 // /* | 1108 // /* |
1108 // * age_value | 1109 // * age_value |
1109 // * is the value of Age: header received by the cache with | 1110 // * 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; | 1443 return true; |
1443 } | 1444 } |
1444 | 1445 |
1445 bool HttpResponseHeaders::IsChunkEncoded() const { | 1446 bool HttpResponseHeaders::IsChunkEncoded() const { |
1446 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. | 1447 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. |
1447 return GetHttpVersion() >= HttpVersion(1, 1) && | 1448 return GetHttpVersion() >= HttpVersion(1, 1) && |
1448 HasHeaderValue("Transfer-Encoding", "chunked"); | 1449 HasHeaderValue("Transfer-Encoding", "chunked"); |
1449 } | 1450 } |
1450 | 1451 |
1451 } // namespace net | 1452 } // namespace net |
OLD | NEW |