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 #include "net/http/http_cache_transaction.h" | 5 #include "net/http/http_cache_transaction.h" |
6 | 6 |
7 #include "build/build_config.h" | 7 #include "build/build_config.h" |
8 | 8 |
9 #if defined(OS_POSIX) | 9 #if defined(OS_POSIX) |
10 #include <unistd.h> | 10 #include <unistd.h> |
11 #endif | 11 #endif |
12 | 12 |
13 #include <algorithm> | 13 #include <algorithm> |
14 #include <string> | 14 #include <string> |
15 | 15 |
16 #include "base/bind.h" | 16 #include "base/bind.h" |
17 #include "base/compiler_specific.h" | 17 #include "base/compiler_specific.h" |
18 #include "base/format_macros.h" | 18 #include "base/format_macros.h" |
19 #include "base/memory/ref_counted.h" | 19 #include "base/memory/ref_counted.h" |
20 #include "base/memory/scoped_ptr.h" | |
20 #include "base/metrics/field_trial.h" | 21 #include "base/metrics/field_trial.h" |
21 #include "base/metrics/histogram.h" | 22 #include "base/metrics/histogram.h" |
22 #include "base/metrics/sparse_histogram.h" | 23 #include "base/metrics/sparse_histogram.h" |
23 #include "base/rand_util.h" | 24 #include "base/rand_util.h" |
24 #include "base/strings/string_number_conversions.h" | 25 #include "base/strings/string_number_conversions.h" |
25 #include "base/strings/string_piece.h" | 26 #include "base/strings/string_piece.h" |
26 #include "base/strings/string_util.h" | 27 #include "base/strings/string_util.h" |
27 #include "base/strings/stringprintf.h" | 28 #include "base/strings/stringprintf.h" |
28 #include "base/time/time.h" | 29 #include "base/time/time.h" |
30 #include "base/values.h" | |
29 #include "net/base/completion_callback.h" | 31 #include "net/base/completion_callback.h" |
30 #include "net/base/io_buffer.h" | 32 #include "net/base/io_buffer.h" |
31 #include "net/base/load_flags.h" | 33 #include "net/base/load_flags.h" |
32 #include "net/base/load_timing_info.h" | 34 #include "net/base/load_timing_info.h" |
33 #include "net/base/net_errors.h" | 35 #include "net/base/net_errors.h" |
34 #include "net/base/net_log.h" | 36 #include "net/base/net_log.h" |
35 #include "net/base/upload_data_stream.h" | 37 #include "net/base/upload_data_stream.h" |
36 #include "net/cert/cert_status_flags.h" | 38 #include "net/cert/cert_status_flags.h" |
37 #include "net/disk_cache/disk_cache.h" | 39 #include "net/disk_cache/disk_cache.h" |
38 #include "net/http/disk_based_cert_cache.h" | 40 #include "net/http/disk_based_cert_cache.h" |
39 #include "net/http/http_network_session.h" | 41 #include "net/http/http_network_session.h" |
40 #include "net/http/http_request_info.h" | 42 #include "net/http/http_request_info.h" |
41 #include "net/http/http_response_headers.h" | 43 #include "net/http/http_response_headers.h" |
42 #include "net/http/http_transaction.h" | 44 #include "net/http/http_transaction.h" |
43 #include "net/http/http_util.h" | 45 #include "net/http/http_util.h" |
44 #include "net/http/partial_data.h" | 46 #include "net/http/partial_data.h" |
45 #include "net/ssl/ssl_cert_request_info.h" | 47 #include "net/ssl/ssl_cert_request_info.h" |
46 #include "net/ssl/ssl_config_service.h" | 48 #include "net/ssl/ssl_config_service.h" |
47 | 49 |
48 using base::Time; | 50 using base::Time; |
49 using base::TimeDelta; | 51 using base::TimeDelta; |
50 using base::TimeTicks; | 52 using base::TimeTicks; |
51 | 53 |
52 namespace { | 54 namespace { |
53 | 55 |
56 typedef net::HttpResponseHeaders::ValidationType ValidationType; | |
57 | |
54 // TODO(ricea): Move this to HttpResponseHeaders once it is standardised. | 58 // TODO(ricea): Move this to HttpResponseHeaders once it is standardised. |
55 static const char kFreshnessHeader[] = "Resource-Freshness"; | 59 static const char kFreshnessHeader[] = "Resource-Freshness"; |
56 | 60 |
57 // Stores data relevant to the statistics of writing and reading entire | 61 // Stores data relevant to the statistics of writing and reading entire |
58 // certificate chains using DiskBasedCertCache. |num_pending_ops| is the number | 62 // certificate chains using DiskBasedCertCache. |num_pending_ops| is the number |
59 // of certificates in the chain that have pending operations in the | 63 // of certificates in the chain that have pending operations in the |
60 // DiskBasedCertCache. |start_time| is the time that the read and write | 64 // DiskBasedCertCache. |start_time| is the time that the read and write |
61 // commands began being issued to the DiskBasedCertCache. | 65 // commands began being issued to the DiskBasedCertCache. |
62 // TODO(brandonsalmon): Remove this when it is no longer necessary to | 66 // TODO(brandonsalmon): Remove this when it is no longer necessary to |
63 // collect data. | 67 // collect data. |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
231 | 235 |
232 void RecordNoStoreHeaderHistogram(int load_flags, | 236 void RecordNoStoreHeaderHistogram(int load_flags, |
233 const net::HttpResponseInfo* response) { | 237 const net::HttpResponseInfo* response) { |
234 if (load_flags & net::LOAD_MAIN_FRAME) { | 238 if (load_flags & net::LOAD_MAIN_FRAME) { |
235 UMA_HISTOGRAM_BOOLEAN( | 239 UMA_HISTOGRAM_BOOLEAN( |
236 "Net.MainFrameNoStore", | 240 "Net.MainFrameNoStore", |
237 response->headers->HasHeaderValue("cache-control", "no-store")); | 241 response->headers->HasHeaderValue("cache-control", "no-store")); |
238 } | 242 } |
239 } | 243 } |
240 | 244 |
245 base::Value* NetLogAsyncRevalidationInfoCallback( | |
246 const net::NetLog::Source& source, | |
247 const net::HttpRequestInfo* request, | |
248 net::NetLog::LogLevel log_level) { | |
249 base::DictionaryValue* dict = new base::DictionaryValue(); | |
250 source.AddToEventParameters(dict); | |
251 | |
252 dict->SetString("url", request->url.possibly_invalid_spec()); | |
253 dict->SetString("method", request->method); | |
254 return dict; | |
255 } | |
256 | |
241 } // namespace | 257 } // namespace |
242 | 258 |
243 namespace net { | 259 namespace net { |
244 | 260 |
245 struct HeaderNameAndValue { | 261 struct HeaderNameAndValue { |
246 const char* name; | 262 const char* name; |
247 const char* value; | 263 const char* value; |
248 }; | 264 }; |
249 | 265 |
250 // If the request includes one of these request headers, then avoid caching | 266 // If the request includes one of these request headers, then avoid caching |
(...skipping 1835 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2086 | 2102 |
2087 if (entry_->disk_entry->GetDataSize(kMetadataIndex)) | 2103 if (entry_->disk_entry->GetDataSize(kMetadataIndex)) |
2088 next_state_ = STATE_CACHE_READ_METADATA; | 2104 next_state_ = STATE_CACHE_READ_METADATA; |
2089 | 2105 |
2090 return OK; | 2106 return OK; |
2091 } | 2107 } |
2092 | 2108 |
2093 int HttpCache::Transaction::BeginCacheValidation() { | 2109 int HttpCache::Transaction::BeginCacheValidation() { |
2094 DCHECK(mode_ == READ_WRITE); | 2110 DCHECK(mode_ == READ_WRITE); |
2095 | 2111 |
2096 bool skip_validation = !RequiresValidation(); | 2112 ValidationType required_validation = RequiresValidation(); |
2113 | |
2114 bool skip_validation = required_validation == ValidationType::VALIDATION_NONE; | |
rvargas (doing something else)
2014/09/05 22:52:39
nit: use () around ==
Adam Rice
2014/09/09 12:36:45
Done.
| |
2115 | |
2116 if (required_validation == ValidationType::VALIDATION_ASYNCHRONOUS && | |
2117 !(request_->method == "GET" && (truncated_ || partial_)) && cache_ && | |
2118 cache_->use_stale_while_revalidate()) { | |
2119 TriggerAsyncValidation(); | |
2120 skip_validation = true; | |
2121 } | |
2097 | 2122 |
2098 if (request_->method == "HEAD" && | 2123 if (request_->method == "HEAD" && |
2099 (truncated_ || response_.headers->response_code() == 206)) { | 2124 (truncated_ || response_.headers->response_code() == 206)) { |
2100 DCHECK(!partial_); | 2125 DCHECK(!partial_); |
2101 if (skip_validation) | 2126 if (skip_validation) |
2102 return SetupEntryForRead(); | 2127 return SetupEntryForRead(); |
2103 | 2128 |
2104 // Bail out! | 2129 // Bail out! |
2105 next_state_ = STATE_SEND_REQUEST; | 2130 next_state_ = STATE_SEND_REQUEST; |
2106 mode_ = NONE; | 2131 mode_ = NONE; |
2107 return OK; | 2132 return OK; |
2108 } | 2133 } |
2109 | 2134 |
2110 if (truncated_) { | 2135 if (truncated_) { |
2111 // Truncated entries can cause partial gets, so we shouldn't record this | 2136 // Truncated entries can cause partial gets, so we shouldn't record this |
2112 // load in histograms. | 2137 // load in histograms. |
2113 UpdateTransactionPattern(PATTERN_NOT_COVERED); | 2138 UpdateTransactionPattern(PATTERN_NOT_COVERED); |
2114 skip_validation = !partial_->initial_validation(); | 2139 skip_validation = !partial_->initial_validation(); |
2115 } | 2140 } |
2116 | 2141 |
2117 if (partial_.get() && (is_sparse_ || truncated_) && | 2142 if (partial_.get() && (is_sparse_ || truncated_) && |
2118 (!partial_->IsCurrentRangeCached() || invalid_range_)) { | 2143 (!partial_->IsCurrentRangeCached() || invalid_range_)) { |
2119 // Force revalidation for sparse or truncated entries. Note that we don't | 2144 // Force revalidation for sparse or truncated entries. Note that we don't |
2120 // want to ignore the regular validation logic just because a byte range was | 2145 // want to ignore the regular validation logic just because a byte range was |
2121 // part of the request. | 2146 // part of the request. |
2122 skip_validation = false; | 2147 skip_validation = false; |
2123 } | 2148 } |
2124 | 2149 |
2125 if (skip_validation) { | 2150 if (skip_validation) { |
2151 // TODO(ricea): Is this pattern okay for asynchronous revalidations? | |
2126 UpdateTransactionPattern(PATTERN_ENTRY_USED); | 2152 UpdateTransactionPattern(PATTERN_ENTRY_USED); |
2127 RecordOfflineStatus(effective_load_flags_, OFFLINE_STATUS_FRESH_CACHE); | 2153 RecordOfflineStatus(effective_load_flags_, OFFLINE_STATUS_FRESH_CACHE); |
2128 return SetupEntryForRead(); | 2154 return SetupEntryForRead(); |
2129 } else { | 2155 } else { |
2130 // Make the network request conditional, to see if we may reuse our cached | 2156 // Make the network request conditional, to see if we may reuse our cached |
2131 // response. If we cannot do so, then we just resort to a normal fetch. | 2157 // response. If we cannot do so, then we just resort to a normal fetch. |
2132 // Our mode remains READ_WRITE for a conditional request. Even if the | 2158 // Our mode remains READ_WRITE for a conditional request. Even if the |
2133 // conditionalization fails, we don't switch to WRITE mode until we | 2159 // conditionalization fails, we don't switch to WRITE mode until we |
2134 // know we won't be falling back to using the cache entry in the | 2160 // know we won't be falling back to using the cache entry in the |
2135 // LOAD_FROM_CACHE_IF_OFFLINE case. | 2161 // LOAD_FROM_CACHE_IF_OFFLINE case. |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2255 DCHECK(network_trans_.get()); | 2281 DCHECK(network_trans_.get()); |
2256 DCHECK_EQ(STATE_NONE, next_state_); | 2282 DCHECK_EQ(STATE_NONE, next_state_); |
2257 | 2283 |
2258 next_state_ = STATE_SEND_REQUEST_COMPLETE; | 2284 next_state_ = STATE_SEND_REQUEST_COMPLETE; |
2259 int rv = network_trans_->RestartWithAuth(credentials, io_callback_); | 2285 int rv = network_trans_->RestartWithAuth(credentials, io_callback_); |
2260 if (rv != ERR_IO_PENDING) | 2286 if (rv != ERR_IO_PENDING) |
2261 return DoLoop(rv); | 2287 return DoLoop(rv); |
2262 return rv; | 2288 return rv; |
2263 } | 2289 } |
2264 | 2290 |
2265 bool HttpCache::Transaction::RequiresValidation() { | 2291 ValidationType HttpCache::Transaction::RequiresValidation() { |
2266 // TODO(darin): need to do more work here: | 2292 // TODO(darin): need to do more work here: |
2267 // - make sure we have a matching request method | 2293 // - make sure we have a matching request method |
2268 // - watch out for cached responses that depend on authentication | 2294 // - watch out for cached responses that depend on authentication |
2269 | 2295 |
2270 // In playback mode, nothing requires validation. | 2296 // In playback mode, nothing requires validation. |
2271 if (cache_->mode() == net::HttpCache::PLAYBACK) | 2297 if (cache_->mode() == net::HttpCache::PLAYBACK) |
2272 return false; | 2298 return ValidationType::VALIDATION_NONE; |
2273 | 2299 |
2274 if (response_.vary_data.is_valid() && | 2300 if (response_.vary_data.is_valid() && |
2275 !response_.vary_data.MatchesRequest(*request_, | 2301 !response_.vary_data.MatchesRequest(*request_, |
2276 *response_.headers.get())) { | 2302 *response_.headers.get())) { |
2277 vary_mismatch_ = true; | 2303 vary_mismatch_ = true; |
2278 return true; | 2304 return ValidationType::VALIDATION_SYNCHRONOUS; |
2279 } | 2305 } |
2280 | 2306 |
2281 if (effective_load_flags_ & LOAD_PREFERRING_CACHE) | 2307 if (effective_load_flags_ & LOAD_PREFERRING_CACHE) |
2282 return false; | 2308 return ValidationType::VALIDATION_NONE; |
rvargas (doing something else)
2014/09/05 22:52:40
I think we should move the enum out of ResponseHea
Adam Rice
2014/09/09 12:36:45
Done.
| |
2283 | 2309 |
2284 if (effective_load_flags_ & LOAD_VALIDATE_CACHE) | 2310 if (effective_load_flags_ & (LOAD_VALIDATE_CACHE | LOAD_ASYNC_REVALIDATION)) |
rvargas (doing something else)
2014/09/05 22:52:39
I just realized, can't we use LOAD_VALIDATE_CACHE
Adam Rice
2014/09/09 12:36:45
I tried that. It does add headers. See http_networ
| |
2285 return true; | 2311 return ValidationType::VALIDATION_SYNCHRONOUS; |
2286 | 2312 |
2287 if (request_->method == "PUT" || request_->method == "DELETE") | 2313 if (request_->method == "PUT" || request_->method == "DELETE") |
2288 return true; | 2314 return ValidationType::VALIDATION_SYNCHRONOUS; |
2289 | 2315 |
2290 if (response_.headers->RequiresValidation( | 2316 ValidationType validation_required_by_headers = |
2291 response_.request_time, response_.response_time, Time::Now())) { | 2317 response_.headers->RequiresValidation( |
2292 return true; | 2318 response_.request_time, response_.response_time, Time::Now()); |
2319 | |
2320 if (validation_required_by_headers == | |
2321 ValidationType::VALIDATION_ASYNCHRONOUS) { | |
2322 // Asynchronous revalidation is only supported for GET and HEAD methods. | |
2323 if (request_->method != "GET" && request_->method != "HEAD") | |
2324 return ValidationType::VALIDATION_SYNCHRONOUS; | |
2293 } | 2325 } |
2294 | 2326 |
2295 return false; | 2327 return validation_required_by_headers; |
2296 } | 2328 } |
2297 | 2329 |
2298 bool HttpCache::Transaction::ConditionalizeRequest() { | 2330 bool HttpCache::Transaction::ConditionalizeRequest() { |
2299 DCHECK(response_.headers.get()); | 2331 DCHECK(response_.headers.get()); |
2300 | 2332 |
2301 if (request_->method == "PUT" || request_->method == "DELETE") | 2333 if (request_->method == "PUT" || request_->method == "DELETE") |
2302 return false; | 2334 return false; |
2303 | 2335 |
2304 // This only makes sense for cached 200 or 206 responses. | 2336 // This only makes sense for cached 200 or 206 responses. |
2305 if (response_.headers->response_code() != 200 && | 2337 if (response_.headers->response_code() != 200 && |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2337 bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() && | 2369 bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() && |
2338 !invalid_range_; | 2370 !invalid_range_; |
2339 | 2371 |
2340 if (!use_if_range) { | 2372 if (!use_if_range) { |
2341 // stale-while-revalidate is not useful when we only have a partial response | 2373 // stale-while-revalidate is not useful when we only have a partial response |
2342 // cached, so don't set the header in that case. | 2374 // cached, so don't set the header in that case. |
2343 TimeDelta stale_while_revalidate; | 2375 TimeDelta stale_while_revalidate; |
2344 if (response_.headers->GetStaleWhileRevalidateValue( | 2376 if (response_.headers->GetStaleWhileRevalidateValue( |
2345 &stale_while_revalidate) && | 2377 &stale_while_revalidate) && |
2346 stale_while_revalidate > TimeDelta()) { | 2378 stale_while_revalidate > TimeDelta()) { |
2347 TimeDelta max_age = | 2379 HttpResponseHeaders::Freshness freshness = |
2348 response_.headers->GetFreshnessLifetime(response_.response_time); | 2380 response_.headers->GetFreshnessLifetime(response_.response_time); |
2349 TimeDelta current_age = response_.headers->GetCurrentAge( | 2381 TimeDelta current_age = response_.headers->GetCurrentAge( |
2350 response_.request_time, response_.response_time, Time::Now()); | 2382 response_.request_time, response_.response_time, Time::Now()); |
2351 | 2383 |
2352 custom_request_->extra_headers.SetHeader( | 2384 custom_request_->extra_headers.SetHeader( |
2353 kFreshnessHeader, | 2385 kFreshnessHeader, |
2354 base::StringPrintf("max-age=%" PRId64 | 2386 base::StringPrintf("max-age=%" PRId64 |
2355 ",stale-while-revalidate=%" PRId64 ",age=%" PRId64, | 2387 ",stale-while-revalidate=%" PRId64 ",age=%" PRId64, |
2356 max_age.InSeconds(), | 2388 freshness.lifetime.InSeconds(), |
2357 stale_while_revalidate.InSeconds(), | 2389 stale_while_revalidate.InSeconds(), |
2358 current_age.InSeconds())); | 2390 current_age.InSeconds())); |
2359 } | 2391 } |
2360 } | 2392 } |
2361 | 2393 |
2362 if (!etag_value.empty()) { | 2394 if (!etag_value.empty()) { |
2363 if (use_if_range) { | 2395 if (use_if_range) { |
2364 // We don't want to switch to WRITE mode if we don't have this block of a | 2396 // We don't want to switch to WRITE mode if we don't have this block of a |
2365 // byte-range request because we may have other parts cached. | 2397 // byte-range request because we may have other parts cached. |
2366 custom_request_->extra_headers.SetHeader( | 2398 custom_request_->extra_headers.SetHeader( |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2516 } | 2548 } |
2517 | 2549 |
2518 void HttpCache::Transaction::FixHeadersForHead() { | 2550 void HttpCache::Transaction::FixHeadersForHead() { |
2519 if (response_.headers->response_code() == 206) { | 2551 if (response_.headers->response_code() == 206) { |
2520 response_.headers->RemoveHeader("Content-Length"); | 2552 response_.headers->RemoveHeader("Content-Length"); |
2521 response_.headers->RemoveHeader("Content-Range"); | 2553 response_.headers->RemoveHeader("Content-Range"); |
2522 response_.headers->ReplaceStatusLine("HTTP/1.1 200 OK"); | 2554 response_.headers->ReplaceStatusLine("HTTP/1.1 200 OK"); |
2523 } | 2555 } |
2524 } | 2556 } |
2525 | 2557 |
2558 void HttpCache::Transaction::TriggerAsyncValidation() { | |
2559 DCHECK(!request_->upload_data_stream); | |
2560 BoundNetLog async_revalidation_net_log( | |
2561 BoundNetLog::Make(net_log_.net_log(), NetLog::SOURCE_ASYNC_REVALIDATION)); | |
2562 net_log_.AddEvent( | |
2563 NetLog::TYPE_HTTP_CACHE_VALIDATE_RESOURCE_ASYNC, | |
2564 async_revalidation_net_log.source().ToEventParametersCallback()); | |
2565 async_revalidation_net_log.BeginEvent( | |
2566 NetLog::TYPE_ASYNC_REVALIDATION, | |
2567 base::Bind( | |
2568 &NetLogAsyncRevalidationInfoCallback, net_log_.source(), request_)); | |
2569 // cache_ is a weak pointer. | |
rvargas (doing something else)
2014/09/05 22:52:40
nit: move comment inline with the argument
Adam Rice
2014/09/09 12:36:45
Done.
| |
2570 base::MessageLoop::current()->PostTask( | |
2571 FROM_HERE, | |
2572 base::Bind(&HttpCache::PerformAsyncValidation, | |
2573 cache_, | |
2574 *request_, | |
2575 async_revalidation_net_log)); | |
2576 } | |
2577 | |
2526 void HttpCache::Transaction::FailRangeRequest() { | 2578 void HttpCache::Transaction::FailRangeRequest() { |
2527 response_ = *new_response_; | 2579 response_ = *new_response_; |
2528 partial_->FixResponseHeaders(response_.headers.get(), false); | 2580 partial_->FixResponseHeaders(response_.headers.get(), false); |
2529 } | 2581 } |
2530 | 2582 |
2531 int HttpCache::Transaction::SetupEntryForRead() { | 2583 int HttpCache::Transaction::SetupEntryForRead() { |
2532 if (network_trans_) | 2584 if (network_trans_) |
2533 ResetNetworkTransaction(); | 2585 ResetNetworkTransaction(); |
2534 if (partial_.get()) { | 2586 if (partial_.get()) { |
2535 if (truncated_ || is_sparse_ || !invalid_range_) { | 2587 if (truncated_ || is_sparse_ || !invalid_range_) { |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2862 default: | 2914 default: |
2863 NOTREACHED(); | 2915 NOTREACHED(); |
2864 } | 2916 } |
2865 } | 2917 } |
2866 | 2918 |
2867 void HttpCache::Transaction::OnIOComplete(int result) { | 2919 void HttpCache::Transaction::OnIOComplete(int result) { |
2868 DoLoop(result); | 2920 DoLoop(result); |
2869 } | 2921 } |
2870 | 2922 |
2871 } // namespace net | 2923 } // namespace net |
OLD | NEW |