| 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 |