| OLD | NEW |
| 1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2010 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 #include "net/http/http_cache_transaction.h" | 5 #include "net/http/http_cache_transaction.h" |
| 6 | 6 |
| 7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
| 8 | 8 |
| 9 #if defined(OS_POSIX) | 9 #if defined(OS_POSIX) |
| 10 #include <unistd.h> | 10 #include <unistd.h> |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 { NULL, NULL } | 71 { NULL, NULL } |
| 72 }; | 72 }; |
| 73 | 73 |
| 74 // If the request includes one of these request headers, then force our | 74 // If the request includes one of these request headers, then force our |
| 75 // cached copy (if any) to be revalidated before reusing it. | 75 // cached copy (if any) to be revalidated before reusing it. |
| 76 static const HeaderNameAndValue kForceValidateHeaders[] = { | 76 static const HeaderNameAndValue kForceValidateHeaders[] = { |
| 77 { "cache-control", "max-age=0" }, | 77 { "cache-control", "max-age=0" }, |
| 78 { NULL, NULL } | 78 { NULL, NULL } |
| 79 }; | 79 }; |
| 80 | 80 |
| 81 static bool HeaderMatches(const HttpUtil::HeadersIterator& h, | 81 static bool HeaderMatches(const HttpRequestHeaders& headers, |
| 82 const HeaderNameAndValue* search) { | 82 const HeaderNameAndValue* search) { |
| 83 for (; search->name; ++search) { | 83 for (; search->name; ++search) { |
| 84 if (!LowerCaseEqualsASCII(h.name_begin(), h.name_end(), search->name)) | 84 std::string header_value; |
| 85 if (!headers.GetHeader(search->name, &header_value)) |
| 85 continue; | 86 continue; |
| 86 | 87 |
| 87 if (!search->value) | 88 if (!search->value) |
| 88 return true; | 89 return true; |
| 89 | 90 |
| 90 HttpUtil::ValuesIterator v(h.values_begin(), h.values_end(), ','); | 91 HttpUtil::ValuesIterator v(header_value.begin(), header_value.end(), ','); |
| 91 while (v.GetNext()) { | 92 while (v.GetNext()) { |
| 92 if (LowerCaseEqualsASCII(v.value_begin(), v.value_end(), search->value)) | 93 if (LowerCaseEqualsASCII(v.value_begin(), v.value_end(), search->value)) |
| 93 return true; | 94 return true; |
| 94 } | 95 } |
| 95 } | 96 } |
| 96 return false; | 97 return false; |
| 97 } | 98 } |
| 98 | 99 |
| 99 //----------------------------------------------------------------------------- | 100 //----------------------------------------------------------------------------- |
| 100 | 101 |
| (...skipping 1077 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1178 // | 1179 // |
| 1179 static const struct { | 1180 static const struct { |
| 1180 const HeaderNameAndValue* search; | 1181 const HeaderNameAndValue* search; |
| 1181 int load_flag; | 1182 int load_flag; |
| 1182 } kSpecialHeaders[] = { | 1183 } kSpecialHeaders[] = { |
| 1183 { kPassThroughHeaders, LOAD_DISABLE_CACHE }, | 1184 { kPassThroughHeaders, LOAD_DISABLE_CACHE }, |
| 1184 { kForceFetchHeaders, LOAD_BYPASS_CACHE }, | 1185 { kForceFetchHeaders, LOAD_BYPASS_CACHE }, |
| 1185 { kForceValidateHeaders, LOAD_VALIDATE_CACHE }, | 1186 { kForceValidateHeaders, LOAD_VALIDATE_CACHE }, |
| 1186 }; | 1187 }; |
| 1187 | 1188 |
| 1188 std::string new_extra_headers; | |
| 1189 bool range_found = false; | 1189 bool range_found = false; |
| 1190 bool external_validation_error = false; | 1190 bool external_validation_error = false; |
| 1191 | 1191 |
| 1192 // scan request headers to see if we have any that would impact our load flags | 1192 if (request_->extra_headers.HasHeader(HttpRequestHeaders::kRange)) { |
| 1193 HttpUtil::HeadersIterator it(request_->extra_headers.begin(), | 1193 if (enable_range_support_) { |
| 1194 request_->extra_headers.end(), | 1194 range_found = true; |
| 1195 "\r\n"); | |
| 1196 while (it.GetNext()) { | |
| 1197 if (!LowerCaseEqualsASCII(it.name(), "range")) { | |
| 1198 new_extra_headers.append(it.name_begin(), it.values_end()); | |
| 1199 new_extra_headers.append("\r\n"); | |
| 1200 } else { | 1195 } else { |
| 1201 if (enable_range_support_) { | 1196 effective_load_flags_ |= LOAD_DISABLE_CACHE; |
| 1202 range_found = true; | |
| 1203 } else { | |
| 1204 effective_load_flags_ |= LOAD_DISABLE_CACHE; | |
| 1205 continue; | |
| 1206 } | |
| 1207 } | |
| 1208 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSpecialHeaders); ++i) { | |
| 1209 if (HeaderMatches(it, kSpecialHeaders[i].search)) { | |
| 1210 effective_load_flags_ |= kSpecialHeaders[i].load_flag; | |
| 1211 break; | |
| 1212 } | |
| 1213 } | |
| 1214 | |
| 1215 // Check for conditionalization headers which may correspond with a | |
| 1216 // cache validation request. | |
| 1217 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidationHeaders); ++i) { | |
| 1218 const ValidationHeaderInfo& info = kValidationHeaders[i]; | |
| 1219 if (LowerCaseEqualsASCII(it.name_begin(), it.name_end(), | |
| 1220 info.request_header_name)) { | |
| 1221 if (!external_validation_.values[i].empty() || it.values().empty()) | |
| 1222 external_validation_error = true; | |
| 1223 external_validation_.values[i] = it.values(); | |
| 1224 external_validation_.initialized = true; | |
| 1225 break; | |
| 1226 } | |
| 1227 } | 1197 } |
| 1228 } | 1198 } |
| 1229 | 1199 |
| 1200 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSpecialHeaders); ++i) { |
| 1201 if (HeaderMatches(request_->extra_headers, kSpecialHeaders[i].search)) { |
| 1202 effective_load_flags_ |= kSpecialHeaders[i].load_flag; |
| 1203 break; |
| 1204 } |
| 1205 } |
| 1206 |
| 1207 // Check for conditionalization headers which may correspond with a |
| 1208 // cache validation request. |
| 1209 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValidationHeaders); ++i) { |
| 1210 const ValidationHeaderInfo& info = kValidationHeaders[i]; |
| 1211 std::string validation_value; |
| 1212 if (request_->extra_headers.GetHeader( |
| 1213 info.request_header_name, &validation_value)) { |
| 1214 if (!external_validation_.values[i].empty() || |
| 1215 validation_value.empty()) |
| 1216 external_validation_error = true; |
| 1217 external_validation_.values[i] = validation_value; |
| 1218 external_validation_.initialized = true; |
| 1219 break; |
| 1220 } |
| 1221 } |
| 1222 |
| 1230 // We don't support ranges and validation headers. | 1223 // We don't support ranges and validation headers. |
| 1231 if (range_found && external_validation_.initialized) { | 1224 if (range_found && external_validation_.initialized) { |
| 1232 LOG(WARNING) << "Byte ranges AND validation headers found."; | 1225 LOG(WARNING) << "Byte ranges AND validation headers found."; |
| 1233 effective_load_flags_ |= LOAD_DISABLE_CACHE; | 1226 effective_load_flags_ |= LOAD_DISABLE_CACHE; |
| 1234 } | 1227 } |
| 1235 | 1228 |
| 1236 // If there is more than one validation header, we can't treat this request as | 1229 // If there is more than one validation header, we can't treat this request as |
| 1237 // a cache validation, since we don't know for sure which header the server | 1230 // a cache validation, since we don't know for sure which header the server |
| 1238 // will give us a response for (and they could be contradictory). | 1231 // will give us a response for (and they could be contradictory). |
| 1239 if (external_validation_error) { | 1232 if (external_validation_error) { |
| 1240 LOG(WARNING) << "Multiple or malformed validation headers found."; | 1233 LOG(WARNING) << "Multiple or malformed validation headers found."; |
| 1241 effective_load_flags_ |= LOAD_DISABLE_CACHE; | 1234 effective_load_flags_ |= LOAD_DISABLE_CACHE; |
| 1242 } | 1235 } |
| 1243 | 1236 |
| 1244 if (range_found && !(effective_load_flags_ & LOAD_DISABLE_CACHE)) { | 1237 if (range_found && !(effective_load_flags_ & LOAD_DISABLE_CACHE)) { |
| 1245 partial_.reset(new PartialData); | 1238 partial_.reset(new PartialData); |
| 1246 if (partial_->Init(request_->extra_headers)) { | 1239 if (partial_->Init(request_->extra_headers)) { |
| 1247 // We will be modifying the actual range requested to the server, so | 1240 // We will be modifying the actual range requested to the server, so |
| 1248 // let's remove the header here. | 1241 // let's remove the header here. |
| 1249 custom_request_.reset(new HttpRequestInfo(*request_)); | 1242 custom_request_.reset(new HttpRequestInfo(*request_)); |
| 1243 custom_request_->extra_headers.RemoveHeader(HttpRequestHeaders::kRange); |
| 1250 request_ = custom_request_.get(); | 1244 request_ = custom_request_.get(); |
| 1251 custom_request_->extra_headers = new_extra_headers; | 1245 partial_->SetHeaders(custom_request_->extra_headers); |
| 1252 partial_->SetHeaders(new_extra_headers); | |
| 1253 } else { | 1246 } else { |
| 1254 // The range is invalid or we cannot handle it properly. | 1247 // The range is invalid or we cannot handle it properly. |
| 1255 LOG(INFO) << "Invalid byte range found."; | 1248 LOG(INFO) << "Invalid byte range found."; |
| 1256 effective_load_flags_ |= LOAD_DISABLE_CACHE; | 1249 effective_load_flags_ |= LOAD_DISABLE_CACHE; |
| 1257 partial_.reset(NULL); | 1250 partial_.reset(NULL); |
| 1258 } | 1251 } |
| 1259 } | 1252 } |
| 1260 } | 1253 } |
| 1261 | 1254 |
| 1262 bool HttpCache::Transaction::ShouldPassThrough() { | 1255 bool HttpCache::Transaction::ShouldPassThrough() { |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1504 // Need to customize the request, so this forces us to allocate :( | 1497 // Need to customize the request, so this forces us to allocate :( |
| 1505 custom_request_.reset(new HttpRequestInfo(*request_)); | 1498 custom_request_.reset(new HttpRequestInfo(*request_)); |
| 1506 request_ = custom_request_.get(); | 1499 request_ = custom_request_.get(); |
| 1507 } | 1500 } |
| 1508 DCHECK(custom_request_.get()); | 1501 DCHECK(custom_request_.get()); |
| 1509 | 1502 |
| 1510 if (!etag_value.empty()) { | 1503 if (!etag_value.empty()) { |
| 1511 if (partial_.get() && !partial_->IsCurrentRangeCached()) { | 1504 if (partial_.get() && !partial_->IsCurrentRangeCached()) { |
| 1512 // We don't want to switch to WRITE mode if we don't have this block of a | 1505 // We don't want to switch to WRITE mode if we don't have this block of a |
| 1513 // byte-range request because we may have other parts cached. | 1506 // byte-range request because we may have other parts cached. |
| 1514 custom_request_->extra_headers.append("If-Range: "); | 1507 custom_request_->extra_headers.SetHeader( |
| 1508 HttpRequestHeaders::kIfRange, etag_value); |
| 1515 } else { | 1509 } else { |
| 1516 custom_request_->extra_headers.append("If-None-Match: "); | 1510 custom_request_->extra_headers.SetHeader( |
| 1511 HttpRequestHeaders::kIfNoneMatch, etag_value); |
| 1517 } | 1512 } |
| 1518 custom_request_->extra_headers.append(etag_value); | |
| 1519 custom_request_->extra_headers.append("\r\n"); | |
| 1520 // For byte-range requests, make sure that we use only one way to validate | 1513 // For byte-range requests, make sure that we use only one way to validate |
| 1521 // the request. | 1514 // the request. |
| 1522 if (partial_.get() && !partial_->IsCurrentRangeCached()) | 1515 if (partial_.get() && !partial_->IsCurrentRangeCached()) |
| 1523 return true; | 1516 return true; |
| 1524 } | 1517 } |
| 1525 | 1518 |
| 1526 if (!last_modified_value.empty()) { | 1519 if (!last_modified_value.empty()) { |
| 1527 if (partial_.get() && !partial_->IsCurrentRangeCached()) { | 1520 if (partial_.get() && !partial_->IsCurrentRangeCached()) { |
| 1528 custom_request_->extra_headers.append("If-Range: "); | 1521 custom_request_->extra_headers.SetHeader( |
| 1522 HttpRequestHeaders::kIfRange, last_modified_value); |
| 1529 } else { | 1523 } else { |
| 1530 custom_request_->extra_headers.append("If-Modified-Since: "); | 1524 custom_request_->extra_headers.SetHeader( |
| 1525 HttpRequestHeaders::kIfModifiedSince, last_modified_value); |
| 1531 } | 1526 } |
| 1532 custom_request_->extra_headers.append(last_modified_value); | |
| 1533 custom_request_->extra_headers.append("\r\n"); | |
| 1534 } | 1527 } |
| 1535 | 1528 |
| 1536 return true; | 1529 return true; |
| 1537 } | 1530 } |
| 1538 | 1531 |
| 1539 // We just received some headers from the server. We may have asked for a range, | 1532 // We just received some headers from the server. We may have asked for a range, |
| 1540 // in which case partial_ has an object. This could be the first network request | 1533 // in which case partial_ has an object. This could be the first network request |
| 1541 // we make to fulfill the original request, or we may be already reading (from | 1534 // we make to fulfill the original request, or we may be already reading (from |
| 1542 // the net and / or the cache). If we are not expecting a certain response, we | 1535 // the net and / or the cache). If we are not expecting a certain response, we |
| 1543 // just bypass the cache for this request (but again, maybe we are reading), and | 1536 // just bypass the cache for this request (but again, maybe we are reading), and |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1816 // |value| goes from 0 to 63. Actually, the max value should be 47 (0x2f) | 1809 // |value| goes from 0 to 63. Actually, the max value should be 47 (0x2f) |
| 1817 // but we'll see. | 1810 // but we'll see. |
| 1818 UMA_HISTOGRAM_ENUMERATION("HttpCache.ResponseHeaders", value, 65); | 1811 UMA_HISTOGRAM_ENUMERATION("HttpCache.ResponseHeaders", value, 65); |
| 1819 } | 1812 } |
| 1820 | 1813 |
| 1821 void HttpCache::Transaction::OnIOComplete(int result) { | 1814 void HttpCache::Transaction::OnIOComplete(int result) { |
| 1822 DoLoop(result); | 1815 DoLoop(result); |
| 1823 } | 1816 } |
| 1824 | 1817 |
| 1825 } // namespace net | 1818 } // namespace net |
| OLD | NEW |