Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(260)

Side by Side Diff: net/http/http_response_headers.cc

Issue 154243006: Add GetExpirationTimes() to HttpResponseHeader. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: catch some users Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 926 matching lines...) Expand 10 before | Expand all | Expand 10 after
937 bool HttpResponseHeaders::IsRedirectResponseCode(int response_code) { 937 bool HttpResponseHeaders::IsRedirectResponseCode(int response_code) {
938 // Users probably want to see 300 (multiple choice) pages, so we don't count 938 // Users probably want to see 300 (multiple choice) pages, so we don't count
939 // them as redirects that need to be followed. 939 // them as redirects that need to be followed.
940 return (response_code == 301 || 940 return (response_code == 301 ||
941 response_code == 302 || 941 response_code == 302 ||
942 response_code == 303 || 942 response_code == 303 ||
943 response_code == 307 || 943 response_code == 307 ||
944 response_code == 308); 944 response_code == 308);
945 } 945 }
946 946
947 // From RFC 2616 section 13.2.4: 947 // We calculate and return |corrected_response_time|, defined by:
948 // 948 //
949 // The calculation to determine if a response has expired is quite simple: 949 // current_age = now - corrected_response_time
950 // 950 //
951 // response_is_fresh = (freshness_lifetime > current_age) 951 // So a caller can store an ExpirationTimes object and use it to determine
952 // freshness throughout the objects lifetime.
952 // 953 //
953 // Of course, there are other factors that can force a response to always be 954 // Of course, there are other factors that can force a response to always be
954 // validated or re-fetched. 955 // validated or re-fetched.
955 // 956 HttpResponseHeaders::ExpirationTimes HttpResponseHeaders::GetExpirationTimes(
956 // From RFC 5861 section 3, a stale response may be used while revalidation is
957 // performed in the background if
958 //
959 // freshness_lifetime + stale_while_revalidate > current_age
960 //
961 ValidationType HttpResponseHeaders::RequiresValidation(
962 const Time& request_time, 957 const Time& request_time,
963 const Time& response_time, 958 const Time& response_time) const {
964 const Time& current_time) const { 959 // From RFC 2616 section 13.2.3:
965 FreshnessLifetimes lifetimes = GetFreshnessLifetimes(response_time); 960 //
966 if (lifetimes.freshness.is_zero() && lifetimes.staleness.is_zero()) 961 // Summary of age calculation algorithm, when a cache receives a response:
967 return VALIDATION_SYNCHRONOUS; 962 //
963 // /*
964 // * age_value
965 // * is the value of Age: header received by the cache with
966 // * this response.
967 // * date_value
968 // * is the value of the origin server's Date: header
969 // * request_time
970 // * is the (local) time when the cache made the request
971 // * that resulted in this cached response
972 // * response_time
973 // * is the (local) time when the cache received the
974 // * response
975 // * now
976 // * is the current (local) time
977 // */
978 // apparent_age = max(0, response_time - date_value);
979 // corrected_received_age = max(apparent_age, age_value);
980 // response_delay = response_time - request_time;
981 // corrected_initial_age = corrected_received_age + response_delay;
982 // resident_time = now - response_time;
983 // current_age = corrected_initial_age + resident_time;
968 984
969 TimeDelta age = GetCurrentAge(request_time, response_time, current_time); 985 // If there is no Date header, then assume that the server response was
986 // generated at the time when we received the response.
987 Time date_value;
988 if (!GetDateValue(&date_value))
989 date_value = response_time;
970 990
971 if (lifetimes.freshness > age) 991 // If there is no Age header, then assume age is zero. GetAgeValue does not
972 return VALIDATION_NONE; 992 // modify its out param if the value does not exist.
993 TimeDelta age_value;
994 GetAgeValue(&age_value);
973 995
974 if (lifetimes.freshness + lifetimes.staleness > age) 996 TimeDelta apparent_age = std::max(TimeDelta(), response_time - date_value);
975 return VALIDATION_ASYNCHRONOUS; 997 TimeDelta corrected_received_age = std::max(apparent_age, age_value);
998 TimeDelta response_delay = response_time - request_time;
999 TimeDelta corrected_initial_age = corrected_received_age + response_delay;
976 1000
977 return VALIDATION_SYNCHRONOUS; 1001 // From the age calculation algorithm above, we can derive the corrected
1002 // response time, the |now| for which |current_age == 0|. Substituting into
1003 // the RFC 2616 13.2.3 equations above, and simplyfing:
1004 //
1005 // corrected_initial_age + resident_time == 0
1006 // corrected_initial_age + corrected_response_time - response_time == 0
1007 // corrected_response_time == response_time - corrected_initial_age
1008
1009 ExpirationTimes expirations;
1010 expirations.corrected_response_time = response_time - corrected_initial_age;
1011 CalculateLifetimes(response_time, &expirations.freshness_lifetime,
1012 &expirations.staleness_lifetime);
1013 return expirations;
978 } 1014 }
979 1015
980 // From RFC 2616 section 13.2.4: 1016 // From RFC 2616 section 13.2.4:
981 // 1017 //
982 // The max-age directive takes priority over Expires, so if max-age is present 1018 // The max-age directive takes priority over Expires, so if max-age is present
983 // in a response, the calculation is simply: 1019 // in a response, the calculation is simply:
984 // 1020 //
985 // freshness_lifetime = max_age_value 1021 // freshness_lifetime = max_age_value
986 // 1022 //
987 // Otherwise, if Expires is present in the response, the calculation is: 1023 // Otherwise, if Expires is present in the response, the calculation is:
988 // 1024 //
989 // freshness_lifetime = expires_value - date_value 1025 // freshness_lifetime = expires_value - date_value
990 // 1026 //
991 // Note that neither of these calculations is vulnerable to clock skew, since 1027 // Note that neither of these calculations is vulnerable to clock skew, since
992 // all of the information comes from the origin server. 1028 // all of the information comes from the origin server.
993 // 1029 //
994 // Also, if the response does have a Last-Modified time, the heuristic 1030 // Also, if the response does have a Last-Modified time, the heuristic
995 // expiration value SHOULD be no more than some fraction of the interval since 1031 // expiration value SHOULD be no more than some fraction of the interval since
996 // that time. A typical setting of this fraction might be 10%: 1032 // that time. A typical setting of this fraction might be 10%:
997 // 1033 //
998 // freshness_lifetime = (date_value - last_modified_value) * 0.10 1034 // freshness_lifetime = (date_value - last_modified_value) * 0.10
999 // 1035 //
1000 // If the stale-while-revalidate directive is present, then it is used to set 1036 // If the stale-while-revalidate directive is present, then it is used to set
1001 // the |staleness| time, unless it overridden by another directive. 1037 // the |staleness| time, unless it overridden by another directive.
1002 // 1038 //
1003 HttpResponseHeaders::FreshnessLifetimes 1039 void HttpResponseHeaders::CalculateLifetimes(
1004 HttpResponseHeaders::GetFreshnessLifetimes(const Time& response_time) const { 1040 const Time& response_time,
1005 FreshnessLifetimes lifetimes; 1041 TimeDelta* out_freshness_lifetime,
1042 TimeDelta* out_staleness_lifetime) const {
1043 *out_freshness_lifetime = TimeDelta();
1044 *out_staleness_lifetime = TimeDelta();
1045
1006 // Check for headers that force a response to never be fresh. For backwards 1046 // Check for headers that force a response to never be fresh. For backwards
1007 // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control: 1047 // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control:
1008 // no-cache" even though RFC 2616 does not specify it. 1048 // no-cache" even though RFC 2616 does not specify it.
1009 if (HasHeaderValue("cache-control", "no-cache") || 1049 if (HasHeaderValue("cache-control", "no-cache") ||
1010 HasHeaderValue("cache-control", "no-store") || 1050 HasHeaderValue("cache-control", "no-store") ||
1011 HasHeaderValue("pragma", "no-cache") || 1051 HasHeaderValue("pragma", "no-cache") ||
1012 // Vary: * is never usable: see RFC 2616 section 13.6. 1052 // Vary: * is never usable: see RFC 2616 section 13.6.
1013 HasHeaderValue("vary", "*")) { 1053 HasHeaderValue("vary", "*")) {
1014 return lifetimes; 1054 return;
1015 } 1055 }
1016 1056
1017 // Cache-Control directive must_revalidate overrides stale-while-revalidate. 1057 // Cache-Control directive must_revalidate overrides stale-while-revalidate.
1018 bool must_revalidate = HasHeaderValue("cache-control", "must-revalidate"); 1058 bool must_revalidate = HasHeaderValue("cache-control", "must-revalidate");
1019 1059
1020 if (must_revalidate || !GetStaleWhileRevalidateValue(&lifetimes.staleness)) { 1060 if (must_revalidate ||
1021 DCHECK_EQ(TimeDelta(), lifetimes.staleness); 1061 !GetStaleWhileRevalidateValue(out_staleness_lifetime)) {
1062 DCHECK_EQ(TimeDelta(), *out_staleness_lifetime);
1022 } 1063 }
1023 1064
1024 // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the 1065 // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the
1025 // Expires header after checking for max-age in GetFreshnessLifetimes. This 1066 // Expires header after checking for max-age in GetFreshnessLifetimes. This
1026 // is important since "Expires: <date in the past>" means not fresh, but 1067 // is important since "Expires: <date in the past>" means not fresh, but
1027 // it should not trump a max-age value. 1068 // it should not trump a max-age value.
1028 if (GetMaxAgeValue(&lifetimes.freshness)) 1069 if (GetMaxAgeValue(out_freshness_lifetime))
1029 return lifetimes; 1070 return;
1030 1071
1031 // If there is no Date header, then assume that the server response was 1072 // If there is no Date header, then assume that the server response was
1032 // generated at the time when we received the response. 1073 // generated at the time when we received the response.
1033 Time date_value; 1074 Time date_value;
1034 if (!GetDateValue(&date_value)) 1075 if (!GetDateValue(&date_value))
1035 date_value = response_time; 1076 date_value = response_time;
1036 1077
1037 Time expires_value; 1078 Time expires_value;
1038 if (GetExpiresValue(&expires_value)) { 1079 if (GetExpiresValue(&expires_value)) {
1039 // The expires value can be a date in the past! 1080 // The expires value can be a date in the past!
1040 if (expires_value > date_value) { 1081 if (expires_value > date_value) {
1041 lifetimes.freshness = expires_value - date_value; 1082 *out_freshness_lifetime = expires_value - date_value;
1042 return lifetimes; 1083 return;
1043 } 1084 }
1044 1085
1045 DCHECK_EQ(TimeDelta(), lifetimes.freshness); 1086 DCHECK_EQ(TimeDelta(), *out_freshness_lifetime);
1046 return lifetimes; 1087 return;
1047 } 1088 }
1048 1089
1049 // From RFC 2616 section 13.4: 1090 // From RFC 2616 section 13.4:
1050 // 1091 //
1051 // A response received with a status code of 200, 203, 206, 300, 301 or 410 1092 // A response received with a status code of 200, 203, 206, 300, 301 or 410
1052 // MAY be stored by a cache and used in reply to a subsequent request, 1093 // MAY be stored by a cache and used in reply to a subsequent request,
1053 // subject to the expiration mechanism, unless a cache-control directive 1094 // subject to the expiration mechanism, unless a cache-control directive
1054 // prohibits caching. 1095 // prohibits caching.
1055 // ... 1096 // ...
1056 // A response received with any other status code (e.g. status codes 302 1097 // A response received with any other status code (e.g. status codes 302
(...skipping 13 matching lines...) Expand all
1070 // https://datatracker.ietf.org/doc/draft-reschke-http-status-308/ is an 1111 // https://datatracker.ietf.org/doc/draft-reschke-http-status-308/ is an
1071 // experimental RFC that adds 308 permanent redirect as well, for which "any 1112 // experimental RFC that adds 308 permanent redirect as well, for which "any
1072 // future references ... SHOULD use one of the returned URIs." 1113 // future references ... SHOULD use one of the returned URIs."
1073 if ((response_code_ == 200 || response_code_ == 203 || 1114 if ((response_code_ == 200 || response_code_ == 203 ||
1074 response_code_ == 206) && !must_revalidate) { 1115 response_code_ == 206) && !must_revalidate) {
1075 // TODO(darin): Implement a smarter heuristic. 1116 // TODO(darin): Implement a smarter heuristic.
1076 Time last_modified_value; 1117 Time last_modified_value;
1077 if (GetLastModifiedValue(&last_modified_value)) { 1118 if (GetLastModifiedValue(&last_modified_value)) {
1078 // The last-modified value can be a date in the future! 1119 // The last-modified value can be a date in the future!
1079 if (last_modified_value <= date_value) { 1120 if (last_modified_value <= date_value) {
1080 lifetimes.freshness = (date_value - last_modified_value) / 10; 1121 *out_freshness_lifetime = (date_value - last_modified_value) / 10;
1081 return lifetimes; 1122 return;
1082 } 1123 }
1083 } 1124 }
1084 } 1125 }
1085 1126
1086 // These responses are implicitly fresh (unless otherwise overruled): 1127 // These responses are implicitly fresh (unless otherwise overruled):
1087 if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 || 1128 if (response_code_ == 300 || response_code_ == 301 || response_code_ == 308 ||
1088 response_code_ == 410) { 1129 response_code_ == 410) {
1089 lifetimes.freshness = TimeDelta::Max(); 1130 *out_freshness_lifetime = TimeDelta::Max();
1090 lifetimes.staleness = TimeDelta(); // It should never be stale. 1131 *out_staleness_lifetime = TimeDelta(); // It should never be stale.
1091 return lifetimes; 1132 return;
1092 } 1133 }
1093 1134
1094 // Our heuristic freshness estimate for this resource is 0 seconds, in 1135 // Our heuristic freshness estimate for this resource is 0 seconds, in
1095 // accordance with common browser behaviour. However, stale-while-revalidate 1136 // accordance with common browser behaviour. However, stale-while-revalidate
1096 // may still apply. 1137 // may still apply.
1097 DCHECK_EQ(TimeDelta(), lifetimes.freshness); 1138 DCHECK_EQ(TimeDelta(), *out_freshness_lifetime);
1098 return lifetimes; 1139 return;
1099 }
1100
1101 // From RFC 2616 section 13.2.3:
1102 //
1103 // Summary of age calculation algorithm, when a cache receives a response:
1104 //
1105 // /*
1106 // * age_value
1107 // * is the value of Age: header received by the cache with
1108 // * this response.
1109 // * date_value
1110 // * is the value of the origin server's Date: header
1111 // * request_time
1112 // * is the (local) time when the cache made the request
1113 // * that resulted in this cached response
1114 // * response_time
1115 // * is the (local) time when the cache received the
1116 // * response
1117 // * now
1118 // * is the current (local) time
1119 // */
1120 // apparent_age = max(0, response_time - date_value);
1121 // corrected_received_age = max(apparent_age, age_value);
1122 // response_delay = response_time - request_time;
1123 // corrected_initial_age = corrected_received_age + response_delay;
1124 // resident_time = now - response_time;
1125 // current_age = corrected_initial_age + resident_time;
1126 //
1127 TimeDelta HttpResponseHeaders::GetCurrentAge(const Time& request_time,
1128 const Time& response_time,
1129 const Time& current_time) const {
1130 // If there is no Date header, then assume that the server response was
1131 // generated at the time when we received the response.
1132 Time date_value;
1133 if (!GetDateValue(&date_value))
1134 date_value = response_time;
1135
1136 // If there is no Age header, then assume age is zero. GetAgeValue does not
1137 // modify its out param if the value does not exist.
1138 TimeDelta age_value;
1139 GetAgeValue(&age_value);
1140
1141 TimeDelta apparent_age = std::max(TimeDelta(), response_time - date_value);
1142 TimeDelta corrected_received_age = std::max(apparent_age, age_value);
1143 TimeDelta response_delay = response_time - request_time;
1144 TimeDelta corrected_initial_age = corrected_received_age + response_delay;
1145 TimeDelta resident_time = current_time - response_time;
1146 TimeDelta current_age = corrected_initial_age + resident_time;
1147
1148 return current_age;
1149 } 1140 }
1150 1141
1151 bool HttpResponseHeaders::GetMaxAgeValue(TimeDelta* result) const { 1142 bool HttpResponseHeaders::GetMaxAgeValue(TimeDelta* result) const {
1152 return GetCacheControlDirective("max-age", result); 1143 return GetCacheControlDirective("max-age", result);
1153 } 1144 }
1154 1145
1155 bool HttpResponseHeaders::GetAgeValue(TimeDelta* result) const { 1146 bool HttpResponseHeaders::GetAgeValue(TimeDelta* result) const {
1156 std::string value; 1147 std::string value;
1157 if (!EnumerateHeader(nullptr, "Age", &value)) 1148 if (!EnumerateHeader(nullptr, "Age", &value))
1158 return false; 1149 return false;
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after
1465 return true; 1456 return true;
1466 } 1457 }
1467 1458
1468 bool HttpResponseHeaders::IsChunkEncoded() const { 1459 bool HttpResponseHeaders::IsChunkEncoded() const {
1469 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. 1460 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
1470 return GetHttpVersion() >= HttpVersion(1, 1) && 1461 return GetHttpVersion() >= HttpVersion(1, 1) &&
1471 HasHeaderValue("Transfer-Encoding", "chunked"); 1462 HasHeaderValue("Transfer-Encoding", "chunked");
1472 } 1463 }
1473 1464
1474 } // namespace net 1465 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698