| 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" |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 | 233 |
| 232 void RecordNoStoreHeaderHistogram(int load_flags, | 234 void RecordNoStoreHeaderHistogram(int load_flags, |
| 233 const net::HttpResponseInfo* response) { | 235 const net::HttpResponseInfo* response) { |
| 234 if (load_flags & net::LOAD_MAIN_FRAME) { | 236 if (load_flags & net::LOAD_MAIN_FRAME) { |
| 235 UMA_HISTOGRAM_BOOLEAN( | 237 UMA_HISTOGRAM_BOOLEAN( |
| 236 "Net.MainFrameNoStore", | 238 "Net.MainFrameNoStore", |
| 237 response->headers->HasHeaderValue("cache-control", "no-store")); | 239 response->headers->HasHeaderValue("cache-control", "no-store")); |
| 238 } | 240 } |
| 239 } | 241 } |
| 240 | 242 |
| 243 base::Value* NetLogAsyncRevalidationInfoCallback( |
| 244 const net::NetLog::Source& source, |
| 245 const net::HttpRequestInfo* request, |
| 246 net::NetLog::LogLevel log_level) { |
| 247 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 248 source.AddToEventParameters(dict); |
| 249 |
| 250 dict->SetString("url", request->url.possibly_invalid_spec()); |
| 251 dict->SetString("method", request->method); |
| 252 return dict; |
| 253 } |
| 254 |
| 241 enum ExternallyConditionalizedType { | 255 enum ExternallyConditionalizedType { |
| 242 EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION, | 256 EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION, |
| 243 EXTERNALLY_CONDITIONALIZED_CACHE_USABLE, | 257 EXTERNALLY_CONDITIONALIZED_CACHE_USABLE, |
| 244 EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS, | 258 EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS, |
| 245 EXTERNALLY_CONDITIONALIZED_MAX | 259 EXTERNALLY_CONDITIONALIZED_MAX |
| 246 }; | 260 }; |
| 247 | 261 |
| 248 } // namespace | 262 } // namespace |
| 249 | 263 |
| 250 namespace net { | 264 namespace net { |
| (...skipping 1852 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2103 | 2117 |
| 2104 if (entry_->disk_entry->GetDataSize(kMetadataIndex)) | 2118 if (entry_->disk_entry->GetDataSize(kMetadataIndex)) |
| 2105 next_state_ = STATE_CACHE_READ_METADATA; | 2119 next_state_ = STATE_CACHE_READ_METADATA; |
| 2106 | 2120 |
| 2107 return OK; | 2121 return OK; |
| 2108 } | 2122 } |
| 2109 | 2123 |
| 2110 int HttpCache::Transaction::BeginCacheValidation() { | 2124 int HttpCache::Transaction::BeginCacheValidation() { |
| 2111 DCHECK(mode_ == READ_WRITE); | 2125 DCHECK(mode_ == READ_WRITE); |
| 2112 | 2126 |
| 2113 bool skip_validation = !RequiresValidation(); | 2127 ValidationType required_validation = RequiresValidation(); |
| 2128 |
| 2129 bool skip_validation = (required_validation == VALIDATION_NONE); |
| 2130 |
| 2131 if (required_validation == VALIDATION_ASYNCHRONOUS && |
| 2132 !(request_->method == "GET" && (truncated_ || partial_)) && cache_ && |
| 2133 cache_->use_stale_while_revalidate()) { |
| 2134 TriggerAsyncValidation(); |
| 2135 skip_validation = true; |
| 2136 } |
| 2114 | 2137 |
| 2115 if (request_->method == "HEAD" && | 2138 if (request_->method == "HEAD" && |
| 2116 (truncated_ || response_.headers->response_code() == 206)) { | 2139 (truncated_ || response_.headers->response_code() == 206)) { |
| 2117 DCHECK(!partial_); | 2140 DCHECK(!partial_); |
| 2118 if (skip_validation) | 2141 if (skip_validation) |
| 2119 return SetupEntryForRead(); | 2142 return SetupEntryForRead(); |
| 2120 | 2143 |
| 2121 // Bail out! | 2144 // Bail out! |
| 2122 next_state_ = STATE_SEND_REQUEST; | 2145 next_state_ = STATE_SEND_REQUEST; |
| 2123 mode_ = NONE; | 2146 mode_ = NONE; |
| 2124 return OK; | 2147 return OK; |
| 2125 } | 2148 } |
| 2126 | 2149 |
| 2127 if (truncated_) { | 2150 if (truncated_) { |
| 2128 // Truncated entries can cause partial gets, so we shouldn't record this | 2151 // Truncated entries can cause partial gets, so we shouldn't record this |
| 2129 // load in histograms. | 2152 // load in histograms. |
| 2130 UpdateTransactionPattern(PATTERN_NOT_COVERED); | 2153 UpdateTransactionPattern(PATTERN_NOT_COVERED); |
| 2131 skip_validation = !partial_->initial_validation(); | 2154 skip_validation = !partial_->initial_validation(); |
| 2132 } | 2155 } |
| 2133 | 2156 |
| 2134 if (partial_.get() && (is_sparse_ || truncated_) && | 2157 if (partial_.get() && (is_sparse_ || truncated_) && |
| 2135 (!partial_->IsCurrentRangeCached() || invalid_range_)) { | 2158 (!partial_->IsCurrentRangeCached() || invalid_range_)) { |
| 2136 // Force revalidation for sparse or truncated entries. Note that we don't | 2159 // Force revalidation for sparse or truncated entries. Note that we don't |
| 2137 // want to ignore the regular validation logic just because a byte range was | 2160 // want to ignore the regular validation logic just because a byte range was |
| 2138 // part of the request. | 2161 // part of the request. |
| 2139 skip_validation = false; | 2162 skip_validation = false; |
| 2140 } | 2163 } |
| 2141 | 2164 |
| 2142 if (skip_validation) { | 2165 if (skip_validation) { |
| 2166 // TODO(ricea): Is this pattern okay for asynchronous revalidations? |
| 2143 UpdateTransactionPattern(PATTERN_ENTRY_USED); | 2167 UpdateTransactionPattern(PATTERN_ENTRY_USED); |
| 2144 RecordOfflineStatus(effective_load_flags_, OFFLINE_STATUS_FRESH_CACHE); | 2168 RecordOfflineStatus(effective_load_flags_, OFFLINE_STATUS_FRESH_CACHE); |
| 2145 return SetupEntryForRead(); | 2169 return SetupEntryForRead(); |
| 2146 } else { | 2170 } else { |
| 2147 // Make the network request conditional, to see if we may reuse our cached | 2171 // Make the network request conditional, to see if we may reuse our cached |
| 2148 // response. If we cannot do so, then we just resort to a normal fetch. | 2172 // response. If we cannot do so, then we just resort to a normal fetch. |
| 2149 // Our mode remains READ_WRITE for a conditional request. Even if the | 2173 // Our mode remains READ_WRITE for a conditional request. Even if the |
| 2150 // conditionalization fails, we don't switch to WRITE mode until we | 2174 // conditionalization fails, we don't switch to WRITE mode until we |
| 2151 // know we won't be falling back to using the cache entry in the | 2175 // know we won't be falling back to using the cache entry in the |
| 2152 // LOAD_FROM_CACHE_IF_OFFLINE case. | 2176 // LOAD_FROM_CACHE_IF_OFFLINE case. |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2288 DCHECK(network_trans_.get()); | 2312 DCHECK(network_trans_.get()); |
| 2289 DCHECK_EQ(STATE_NONE, next_state_); | 2313 DCHECK_EQ(STATE_NONE, next_state_); |
| 2290 | 2314 |
| 2291 next_state_ = STATE_SEND_REQUEST_COMPLETE; | 2315 next_state_ = STATE_SEND_REQUEST_COMPLETE; |
| 2292 int rv = network_trans_->RestartWithAuth(credentials, io_callback_); | 2316 int rv = network_trans_->RestartWithAuth(credentials, io_callback_); |
| 2293 if (rv != ERR_IO_PENDING) | 2317 if (rv != ERR_IO_PENDING) |
| 2294 return DoLoop(rv); | 2318 return DoLoop(rv); |
| 2295 return rv; | 2319 return rv; |
| 2296 } | 2320 } |
| 2297 | 2321 |
| 2298 bool HttpCache::Transaction::RequiresValidation() { | 2322 ValidationType HttpCache::Transaction::RequiresValidation() { |
| 2299 // TODO(darin): need to do more work here: | 2323 // TODO(darin): need to do more work here: |
| 2300 // - make sure we have a matching request method | 2324 // - make sure we have a matching request method |
| 2301 // - watch out for cached responses that depend on authentication | 2325 // - watch out for cached responses that depend on authentication |
| 2302 | 2326 |
| 2303 // In playback mode, nothing requires validation. | 2327 // In playback mode, nothing requires validation. |
| 2304 if (cache_->mode() == net::HttpCache::PLAYBACK) | 2328 if (cache_->mode() == net::HttpCache::PLAYBACK) |
| 2305 return false; | 2329 return VALIDATION_NONE; |
| 2306 | 2330 |
| 2307 if (response_.vary_data.is_valid() && | 2331 if (response_.vary_data.is_valid() && |
| 2308 !response_.vary_data.MatchesRequest(*request_, | 2332 !response_.vary_data.MatchesRequest(*request_, |
| 2309 *response_.headers.get())) { | 2333 *response_.headers.get())) { |
| 2310 vary_mismatch_ = true; | 2334 vary_mismatch_ = true; |
| 2311 return true; | 2335 return VALIDATION_SYNCHRONOUS; |
| 2312 } | 2336 } |
| 2313 | 2337 |
| 2314 if (effective_load_flags_ & LOAD_PREFERRING_CACHE) | 2338 if (effective_load_flags_ & LOAD_PREFERRING_CACHE) |
| 2315 return false; | 2339 return VALIDATION_NONE; |
| 2316 | 2340 |
| 2317 if (effective_load_flags_ & LOAD_VALIDATE_CACHE) | 2341 if (effective_load_flags_ & (LOAD_VALIDATE_CACHE | LOAD_ASYNC_REVALIDATION)) |
| 2318 return true; | 2342 return VALIDATION_SYNCHRONOUS; |
| 2319 | 2343 |
| 2320 if (request_->method == "PUT" || request_->method == "DELETE") | 2344 if (request_->method == "PUT" || request_->method == "DELETE") |
| 2321 return true; | 2345 return VALIDATION_SYNCHRONOUS; |
| 2322 | 2346 |
| 2323 if (response_.headers->RequiresValidation( | 2347 ValidationType validation_required_by_headers = |
| 2324 response_.request_time, response_.response_time, Time::Now())) { | 2348 response_.headers->RequiresValidation( |
| 2325 return true; | 2349 response_.request_time, response_.response_time, Time::Now()); |
| 2350 |
| 2351 if (validation_required_by_headers == VALIDATION_ASYNCHRONOUS) { |
| 2352 // Asynchronous revalidation is only supported for GET and HEAD methods. |
| 2353 if (request_->method != "GET" && request_->method != "HEAD") |
| 2354 return VALIDATION_SYNCHRONOUS; |
| 2326 } | 2355 } |
| 2327 | 2356 |
| 2328 return false; | 2357 return validation_required_by_headers; |
| 2329 } | 2358 } |
| 2330 | 2359 |
| 2331 bool HttpCache::Transaction::ConditionalizeRequest() { | 2360 bool HttpCache::Transaction::ConditionalizeRequest() { |
| 2332 DCHECK(response_.headers.get()); | 2361 DCHECK(response_.headers.get()); |
| 2333 | 2362 |
| 2334 if (request_->method == "PUT" || request_->method == "DELETE") | 2363 if (request_->method == "PUT" || request_->method == "DELETE") |
| 2335 return false; | 2364 return false; |
| 2336 | 2365 |
| 2337 // This only makes sense for cached 200 or 206 responses. | 2366 // This only makes sense for cached 200 or 206 responses. |
| 2338 if (response_.headers->response_code() != 200 && | 2367 if (response_.headers->response_code() != 200 && |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2367 request_ = custom_request_.get(); | 2396 request_ = custom_request_.get(); |
| 2368 } | 2397 } |
| 2369 DCHECK(custom_request_.get()); | 2398 DCHECK(custom_request_.get()); |
| 2370 | 2399 |
| 2371 bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() && | 2400 bool use_if_range = partial_.get() && !partial_->IsCurrentRangeCached() && |
| 2372 !invalid_range_; | 2401 !invalid_range_; |
| 2373 | 2402 |
| 2374 if (!use_if_range) { | 2403 if (!use_if_range) { |
| 2375 // stale-while-revalidate is not useful when we only have a partial response | 2404 // stale-while-revalidate is not useful when we only have a partial response |
| 2376 // cached, so don't set the header in that case. | 2405 // cached, so don't set the header in that case. |
| 2377 TimeDelta stale_while_revalidate; | 2406 HttpResponseHeaders::FreshnessLifetimes lifetime = |
| 2378 if (response_.headers->GetStaleWhileRevalidateValue( | 2407 response_.headers->GetFreshnessLifetimes(response_.response_time); |
| 2379 &stale_while_revalidate) && | 2408 if (lifetime.stale > TimeDelta()) { |
| 2380 stale_while_revalidate > TimeDelta()) { | |
| 2381 TimeDelta max_age = | |
| 2382 response_.headers->GetFreshnessLifetime(response_.response_time); | |
| 2383 TimeDelta current_age = response_.headers->GetCurrentAge( | 2409 TimeDelta current_age = response_.headers->GetCurrentAge( |
| 2384 response_.request_time, response_.response_time, Time::Now()); | 2410 response_.request_time, response_.response_time, Time::Now()); |
| 2385 | 2411 |
| 2386 custom_request_->extra_headers.SetHeader( | 2412 custom_request_->extra_headers.SetHeader( |
| 2387 kFreshnessHeader, | 2413 kFreshnessHeader, |
| 2388 base::StringPrintf("max-age=%" PRId64 | 2414 base::StringPrintf("max-age=%" PRId64 |
| 2389 ",stale-while-revalidate=%" PRId64 ",age=%" PRId64, | 2415 ",stale-while-revalidate=%" PRId64 ",age=%" PRId64, |
| 2390 max_age.InSeconds(), | 2416 lifetime.fresh.InSeconds(), |
| 2391 stale_while_revalidate.InSeconds(), | 2417 lifetime.stale.InSeconds(), |
| 2392 current_age.InSeconds())); | 2418 current_age.InSeconds())); |
| 2393 } | 2419 } |
| 2394 } | 2420 } |
| 2395 | 2421 |
| 2396 if (!etag_value.empty()) { | 2422 if (!etag_value.empty()) { |
| 2397 if (use_if_range) { | 2423 if (use_if_range) { |
| 2398 // We don't want to switch to WRITE mode if we don't have this block of a | 2424 // We don't want to switch to WRITE mode if we don't have this block of a |
| 2399 // byte-range request because we may have other parts cached. | 2425 // byte-range request because we may have other parts cached. |
| 2400 custom_request_->extra_headers.SetHeader( | 2426 custom_request_->extra_headers.SetHeader( |
| 2401 HttpRequestHeaders::kIfRange, etag_value); | 2427 HttpRequestHeaders::kIfRange, etag_value); |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2550 } | 2576 } |
| 2551 | 2577 |
| 2552 void HttpCache::Transaction::FixHeadersForHead() { | 2578 void HttpCache::Transaction::FixHeadersForHead() { |
| 2553 if (response_.headers->response_code() == 206) { | 2579 if (response_.headers->response_code() == 206) { |
| 2554 response_.headers->RemoveHeader("Content-Length"); | 2580 response_.headers->RemoveHeader("Content-Length"); |
| 2555 response_.headers->RemoveHeader("Content-Range"); | 2581 response_.headers->RemoveHeader("Content-Range"); |
| 2556 response_.headers->ReplaceStatusLine("HTTP/1.1 200 OK"); | 2582 response_.headers->ReplaceStatusLine("HTTP/1.1 200 OK"); |
| 2557 } | 2583 } |
| 2558 } | 2584 } |
| 2559 | 2585 |
| 2586 void HttpCache::Transaction::TriggerAsyncValidation() { |
| 2587 DCHECK(!request_->upload_data_stream); |
| 2588 BoundNetLog async_revalidation_net_log( |
| 2589 BoundNetLog::Make(net_log_.net_log(), NetLog::SOURCE_ASYNC_REVALIDATION)); |
| 2590 net_log_.AddEvent( |
| 2591 NetLog::TYPE_HTTP_CACHE_VALIDATE_RESOURCE_ASYNC, |
| 2592 async_revalidation_net_log.source().ToEventParametersCallback()); |
| 2593 async_revalidation_net_log.BeginEvent( |
| 2594 NetLog::TYPE_ASYNC_REVALIDATION, |
| 2595 base::Bind( |
| 2596 &NetLogAsyncRevalidationInfoCallback, net_log_.source(), request_)); |
| 2597 base::MessageLoop::current()->PostTask( |
| 2598 FROM_HERE, |
| 2599 base::Bind(&HttpCache::PerformAsyncValidation, |
| 2600 cache_, // cache_ is a weak pointer. |
| 2601 *request_, |
| 2602 async_revalidation_net_log)); |
| 2603 } |
| 2604 |
| 2560 void HttpCache::Transaction::FailRangeRequest() { | 2605 void HttpCache::Transaction::FailRangeRequest() { |
| 2561 response_ = *new_response_; | 2606 response_ = *new_response_; |
| 2562 partial_->FixResponseHeaders(response_.headers.get(), false); | 2607 partial_->FixResponseHeaders(response_.headers.get(), false); |
| 2563 } | 2608 } |
| 2564 | 2609 |
| 2565 int HttpCache::Transaction::SetupEntryForRead() { | 2610 int HttpCache::Transaction::SetupEntryForRead() { |
| 2566 if (network_trans_) | 2611 if (network_trans_) |
| 2567 ResetNetworkTransaction(); | 2612 ResetNetworkTransaction(); |
| 2568 if (partial_.get()) { | 2613 if (partial_.get()) { |
| 2569 if (truncated_ || is_sparse_ || !invalid_range_) { | 2614 if (truncated_ || is_sparse_ || !invalid_range_) { |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2896 default: | 2941 default: |
| 2897 NOTREACHED(); | 2942 NOTREACHED(); |
| 2898 } | 2943 } |
| 2899 } | 2944 } |
| 2900 | 2945 |
| 2901 void HttpCache::Transaction::OnIOComplete(int result) { | 2946 void HttpCache::Transaction::OnIOComplete(int result) { |
| 2902 DoLoop(result); | 2947 DoLoop(result); |
| 2903 } | 2948 } |
| 2904 | 2949 |
| 2905 } // namespace net | 2950 } // namespace net |
| OLD | NEW |