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

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

Issue 2763393002: Remove stale-while-revalidate from net (Closed)
Patch Set: rebase Created 3 years, 9 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
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 #include "net/http/http_cache_transaction.h" 5 #include "net/http/http_cache_transaction.h"
6 6
7 #include "build/build_config.h" // For OS_POSIX 7 #include "build/build_config.h" // For OS_POSIX
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/callback_helpers.h" 17 #include "base/callback_helpers.h"
18 #include "base/compiler_specific.h" 18 #include "base/compiler_specific.h"
19 #include "base/format_macros.h"
20 #include "base/location.h" 19 #include "base/location.h"
21 #include "base/macros.h" 20 #include "base/macros.h"
22 #include "base/metrics/histogram_macros.h" 21 #include "base/metrics/histogram_macros.h"
23 #include "base/metrics/sparse_histogram.h" 22 #include "base/metrics/sparse_histogram.h"
24 #include "base/single_thread_task_runner.h" 23 #include "base/single_thread_task_runner.h"
25 #include "base/strings/string_number_conversions.h" // For HexEncode. 24 #include "base/strings/string_number_conversions.h" // For HexEncode.
26 #include "base/strings/string_piece.h"
27 #include "base/strings/string_util.h" // For LowerCaseEqualsASCII. 25 #include "base/strings/string_util.h" // For LowerCaseEqualsASCII.
28 #include "base/strings/stringprintf.h"
29 #include "base/threading/thread_task_runner_handle.h" 26 #include "base/threading/thread_task_runner_handle.h"
30 #include "base/time/clock.h" 27 #include "base/time/clock.h"
31 #include "base/trace_event/trace_event.h" 28 #include "base/trace_event/trace_event.h"
32 #include "base/values.h" 29 #include "base/values.h"
mmenke 2017/03/23 21:39:35 Tiny nit: Is this still used in this file? It wa
scottmg 2017/03/24 22:46:00 Done.
33 #include "net/base/auth.h" 30 #include "net/base/auth.h"
34 #include "net/base/load_flags.h" 31 #include "net/base/load_flags.h"
35 #include "net/base/load_timing_info.h" 32 #include "net/base/load_timing_info.h"
36 #include "net/base/trace_constants.h" 33 #include "net/base/trace_constants.h"
37 #include "net/base/upload_data_stream.h" 34 #include "net/base/upload_data_stream.h"
38 #include "net/cert/cert_status_flags.h" 35 #include "net/cert/cert_status_flags.h"
39 #include "net/cert/x509_certificate.h" 36 #include "net/cert/x509_certificate.h"
40 #include "net/disk_cache/disk_cache.h" 37 #include "net/disk_cache/disk_cache.h"
41 #include "net/http/http_network_session.h" 38 #include "net/http/http_network_session.h"
42 #include "net/http/http_request_info.h" 39 #include "net/http/http_request_info.h"
43 #include "net/http/http_util.h" 40 #include "net/http/http_util.h"
44 #include "net/log/net_log_event_type.h" 41 #include "net/log/net_log_event_type.h"
45 #include "net/ssl/ssl_cert_request_info.h" 42 #include "net/ssl/ssl_cert_request_info.h"
46 #include "net/ssl/ssl_config_service.h" 43 #include "net/ssl/ssl_config_service.h"
47 44
48 using base::Time; 45 using base::Time;
49 using base::TimeDelta; 46 using base::TimeDelta;
50 using base::TimeTicks; 47 using base::TimeTicks;
51 48
52 namespace net { 49 namespace net {
53 50
54 using CacheEntryStatus = HttpResponseInfo::CacheEntryStatus; 51 using CacheEntryStatus = HttpResponseInfo::CacheEntryStatus;
55 52
56 namespace { 53 namespace {
57 54
58 // TODO(ricea): Move this to HttpResponseHeaders once it is standardised.
59 static const char kFreshnessHeader[] = "Resource-Freshness";
60
61 // From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6 55 // From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6
62 // a "non-error response" is one with a 2xx (Successful) or 3xx 56 // a "non-error response" is one with a 2xx (Successful) or 3xx
63 // (Redirection) status code. 57 // (Redirection) status code.
64 bool NonErrorResponse(int status_code) { 58 bool NonErrorResponse(int status_code) {
65 int status_code_range = status_code / 100; 59 int status_code_range = status_code / 100;
66 return status_code_range == 2 || status_code_range == 3; 60 return status_code_range == 2 || status_code_range == 3;
67 } 61 }
68 62
69 void RecordNoStoreHeaderHistogram(int load_flags, 63 void RecordNoStoreHeaderHistogram(int load_flags,
70 const HttpResponseInfo* response) { 64 const HttpResponseInfo* response) {
71 if (load_flags & LOAD_MAIN_FRAME_DEPRECATED) { 65 if (load_flags & LOAD_MAIN_FRAME_DEPRECATED) {
72 UMA_HISTOGRAM_BOOLEAN( 66 UMA_HISTOGRAM_BOOLEAN(
73 "Net.MainFrameNoStore", 67 "Net.MainFrameNoStore",
74 response->headers->HasHeaderValue("cache-control", "no-store")); 68 response->headers->HasHeaderValue("cache-control", "no-store"));
75 } 69 }
76 } 70 }
77 71
78 enum ExternallyConditionalizedType { 72 enum ExternallyConditionalizedType {
79 EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION, 73 EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION,
80 EXTERNALLY_CONDITIONALIZED_CACHE_USABLE, 74 EXTERNALLY_CONDITIONALIZED_CACHE_USABLE,
81 EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS, 75 EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS,
82 EXTERNALLY_CONDITIONALIZED_MAX 76 EXTERNALLY_CONDITIONALIZED_MAX
83 }; 77 };
mmenke 2017/03/23 21:39:35 This enum (And the related histogram) look to have
scottmg 2017/03/24 22:45:59 Aha, good catch. Done.
84 78
85 } // namespace 79 } // namespace
86 80
87 #define CACHE_STATUS_HISTOGRAMS(type) \ 81 #define CACHE_STATUS_HISTOGRAMS(type) \
88 do { \ 82 do { \
89 UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern" type, cache_entry_status_, \ 83 UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern" type, cache_entry_status_, \
90 CacheEntryStatus::ENTRY_MAX); \ 84 CacheEntryStatus::ENTRY_MAX); \
91 if (validation_request) { \ 85 if (validation_request) { \
92 UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause" type, \ 86 UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause" type, \
93 validation_cause_, VALIDATION_CAUSE_MAX); \ 87 validation_cause_, VALIDATION_CAUSE_MAX); \
(...skipping 2000 matching lines...) Expand 10 before | Expand all | Expand 10 after
2094 next_state_ = STATE_NONE; 2088 next_state_ = STATE_NONE;
2095 return ERR_CACHE_MISS; 2089 return ERR_CACHE_MISS;
2096 } 2090 }
2097 2091
2098 // We don't have the whole resource. 2092 // We don't have the whole resource.
2099 if (truncated_) { 2093 if (truncated_) {
2100 next_state_ = STATE_NONE; 2094 next_state_ = STATE_NONE;
2101 return ERR_CACHE_MISS; 2095 return ERR_CACHE_MISS;
2102 } 2096 }
2103 2097
2104 if (RequiresValidation() != VALIDATION_NONE) { 2098 if (RequiresValidation()) {
2105 next_state_ = STATE_NONE; 2099 next_state_ = STATE_NONE;
2106 return ERR_CACHE_MISS; 2100 return ERR_CACHE_MISS;
2107 } 2101 }
2108 2102
2109 if (request_->method == "HEAD") 2103 if (request_->method == "HEAD")
2110 FixHeadersForHead(); 2104 FixHeadersForHead();
2111 2105
2112 if (entry_->disk_entry->GetDataSize(kMetadataIndex)) 2106 if (entry_->disk_entry->GetDataSize(kMetadataIndex))
2113 next_state_ = STATE_CACHE_READ_METADATA; 2107 next_state_ = STATE_CACHE_READ_METADATA;
2114 else 2108 else
2115 next_state_ = STATE_NONE; 2109 next_state_ = STATE_NONE;
2116 2110
2117 return OK; 2111 return OK;
2118 } 2112 }
2119 2113
2120 int HttpCache::Transaction::BeginCacheValidation() { 2114 int HttpCache::Transaction::BeginCacheValidation() {
2121 DCHECK_EQ(mode_, READ_WRITE); 2115 DCHECK_EQ(mode_, READ_WRITE);
2122 2116
2123 ValidationType required_validation = RequiresValidation(); 2117 bool skip_validation = !RequiresValidation();
2124
2125 bool skip_validation = (required_validation == VALIDATION_NONE);
2126
2127 if ((effective_load_flags_ & LOAD_SUPPORT_ASYNC_REVALIDATION) &&
2128 required_validation == VALIDATION_ASYNCHRONOUS) {
2129 DCHECK_EQ(request_->method, "GET");
2130 skip_validation = true;
2131 response_.async_revalidation_required = true;
2132 }
2133 2118
2134 if (request_->method == "HEAD" && 2119 if (request_->method == "HEAD" &&
2135 (truncated_ || response_.headers->response_code() == 206)) { 2120 (truncated_ || response_.headers->response_code() == 206)) {
2136 DCHECK(!partial_); 2121 DCHECK(!partial_);
2137 if (skip_validation) 2122 if (skip_validation)
2138 return SetupEntryForRead(); 2123 return SetupEntryForRead();
2139 2124
2140 // Bail out! 2125 // Bail out!
2141 next_state_ = STATE_SEND_REQUEST; 2126 next_state_ = STATE_SEND_REQUEST;
2142 mode_ = NONE; 2127 mode_ = NONE;
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
2251 } 2236 }
2252 } 2237 }
2253 2238
2254 // TODO(ricea): This calculation is expensive to perform just to collect 2239 // TODO(ricea): This calculation is expensive to perform just to collect
2255 // statistics. Either remove it or use the result, depending on the result of 2240 // statistics. Either remove it or use the result, depending on the result of
2256 // the experiment. 2241 // the experiment.
2257 ExternallyConditionalizedType type = 2242 ExternallyConditionalizedType type =
2258 EXTERNALLY_CONDITIONALIZED_CACHE_USABLE; 2243 EXTERNALLY_CONDITIONALIZED_CACHE_USABLE;
2259 if (mode_ == NONE) 2244 if (mode_ == NONE)
2260 type = EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS; 2245 type = EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS;
2261 else if (RequiresValidation() != VALIDATION_NONE) 2246 else if (RequiresValidation())
2262 type = EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION; 2247 type = EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION;
2263 2248
2264 // TODO(ricea): Add CACHE_USABLE_STALE once stale-while-revalidate CL landed.
2265 // TODO(ricea): Either remove this histogram or make it permanent by M40. 2249 // TODO(ricea): Either remove this histogram or make it permanent by M40.
2266 UMA_HISTOGRAM_ENUMERATION("HttpCache.ExternallyConditionalized", 2250 UMA_HISTOGRAM_ENUMERATION("HttpCache.ExternallyConditionalized",
2267 type, 2251 type,
2268 EXTERNALLY_CONDITIONALIZED_MAX); 2252 EXTERNALLY_CONDITIONALIZED_MAX);
2269 2253
2270 next_state_ = STATE_SEND_REQUEST; 2254 next_state_ = STATE_SEND_REQUEST;
2271 return OK; 2255 return OK;
2272 } 2256 }
2273 2257
2274 int HttpCache::Transaction::RestartNetworkRequest() { 2258 int HttpCache::Transaction::RestartNetworkRequest() {
(...skipping 29 matching lines...) Expand all
2304 DCHECK(network_trans_.get()); 2288 DCHECK(network_trans_.get());
2305 DCHECK_EQ(STATE_NONE, next_state_); 2289 DCHECK_EQ(STATE_NONE, next_state_);
2306 2290
2307 next_state_ = STATE_SEND_REQUEST_COMPLETE; 2291 next_state_ = STATE_SEND_REQUEST_COMPLETE;
2308 int rv = network_trans_->RestartWithAuth(credentials, io_callback_); 2292 int rv = network_trans_->RestartWithAuth(credentials, io_callback_);
2309 if (rv != ERR_IO_PENDING) 2293 if (rv != ERR_IO_PENDING)
2310 return DoLoop(rv); 2294 return DoLoop(rv);
2311 return rv; 2295 return rv;
2312 } 2296 }
2313 2297
2314 ValidationType HttpCache::Transaction::RequiresValidation() { 2298 bool HttpCache::Transaction::RequiresValidation() {
2315 // TODO(darin): need to do more work here: 2299 // TODO(darin): need to do more work here:
2316 // - make sure we have a matching request method 2300 // - make sure we have a matching request method
2317 // - watch out for cached responses that depend on authentication 2301 // - watch out for cached responses that depend on authentication
2318 2302
2319 if (!(effective_load_flags_ & LOAD_SKIP_VARY_CHECK) && 2303 if (!(effective_load_flags_ & LOAD_SKIP_VARY_CHECK) &&
2320 response_.vary_data.is_valid() && 2304 response_.vary_data.is_valid() &&
2321 !response_.vary_data.MatchesRequest(*request_, 2305 !response_.vary_data.MatchesRequest(*request_,
2322 *response_.headers.get())) { 2306 *response_.headers.get())) {
2323 vary_mismatch_ = true; 2307 vary_mismatch_ = true;
2324 validation_cause_ = VALIDATION_CAUSE_VARY_MISMATCH; 2308 validation_cause_ = VALIDATION_CAUSE_VARY_MISMATCH;
2325 return VALIDATION_SYNCHRONOUS; 2309 return true;
2326 } 2310 }
2327 2311
2328 if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION) 2312 if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION)
2329 return VALIDATION_NONE; 2313 return false;
2330 2314
2331 if (response_.unused_since_prefetch && 2315 if (response_.unused_since_prefetch &&
2332 !(effective_load_flags_ & LOAD_PREFETCH) && 2316 !(effective_load_flags_ & LOAD_PREFETCH) &&
2333 response_.headers->GetCurrentAge( 2317 response_.headers->GetCurrentAge(
2334 response_.request_time, response_.response_time, 2318 response_.request_time, response_.response_time,
2335 cache_->clock_->Now()) < TimeDelta::FromMinutes(kPrefetchReuseMins)) { 2319 cache_->clock_->Now()) < TimeDelta::FromMinutes(kPrefetchReuseMins)) {
2336 // The first use of a resource after prefetch within a short window skips 2320 // The first use of a resource after prefetch within a short window skips
2337 // validation. 2321 // validation.
2338 return VALIDATION_NONE; 2322 return false;
2339 } 2323 }
2340 2324
2341 if (effective_load_flags_ & LOAD_VALIDATE_CACHE) { 2325 if (effective_load_flags_ & LOAD_VALIDATE_CACHE) {
2342 validation_cause_ = VALIDATION_CAUSE_VALIDATE_FLAG; 2326 validation_cause_ = VALIDATION_CAUSE_VALIDATE_FLAG;
2343 return VALIDATION_SYNCHRONOUS; 2327 return true;
2344 } 2328 }
2345 2329
2346 if (request_->method == "PUT" || request_->method == "DELETE") 2330 if (request_->method == "PUT" || request_->method == "DELETE")
2347 return VALIDATION_SYNCHRONOUS; 2331 return true;
2348 2332
2349 ValidationType validation_required_by_headers = 2333 bool validation_required_by_headers = response_.headers->RequiresValidation(
2350 response_.headers->RequiresValidation(response_.request_time, 2334 response_.request_time, response_.response_time, cache_->clock_->Now());
2351 response_.response_time,
2352 cache_->clock_->Now());
2353 2335
2354 if (validation_required_by_headers != VALIDATION_NONE) { 2336 if (validation_required_by_headers) {
2355 HttpResponseHeaders::FreshnessLifetimes lifetimes = 2337 HttpResponseHeaders::FreshnessLifetimes lifetimes =
2356 response_.headers->GetFreshnessLifetimes(response_.response_time); 2338 response_.headers->GetFreshnessLifetimes(response_.response_time);
2357 if (lifetimes.freshness == base::TimeDelta()) { 2339 if (lifetimes.freshness == base::TimeDelta()) {
2358 validation_cause_ = VALIDATION_CAUSE_ZERO_FRESHNESS; 2340 validation_cause_ = VALIDATION_CAUSE_ZERO_FRESHNESS;
2359 } else { 2341 } else {
2360 validation_cause_ = VALIDATION_CAUSE_STALE; 2342 validation_cause_ = VALIDATION_CAUSE_STALE;
2361 stale_entry_freshness_ = lifetimes.freshness; 2343 stale_entry_freshness_ = lifetimes.freshness;
2362 stale_entry_age_ = response_.headers->GetCurrentAge( 2344 stale_entry_age_ = response_.headers->GetCurrentAge(
2363 response_.request_time, response_.response_time, 2345 response_.request_time, response_.response_time,
2364 cache_->clock_->Now()); 2346 cache_->clock_->Now());
2365 } 2347 }
2366 } 2348 }
2367 2349
2368 if (validation_required_by_headers == VALIDATION_ASYNCHRONOUS) {
2369 // Asynchronous revalidation is only supported for GET methods.
2370 if (request_->method != "GET")
2371 return VALIDATION_SYNCHRONOUS;
2372 }
2373
2374 return validation_required_by_headers; 2350 return validation_required_by_headers;
2375 } 2351 }
2376 2352
2377 bool HttpCache::Transaction::ConditionalizeRequest() { 2353 bool HttpCache::Transaction::ConditionalizeRequest() {
2378 DCHECK(response_.headers.get()); 2354 DCHECK(response_.headers.get());
2379 2355
2380 if (request_->method == "PUT" || request_->method == "DELETE") 2356 if (request_->method == "PUT" || request_->method == "DELETE")
2381 return false; 2357 return false;
2382 2358
2383 // This only makes sense for cached 200 or 206 responses. 2359 // This only makes sense for cached 200 or 206 responses.
(...skipping 27 matching lines...) Expand all
2411 if (!partial_) { 2387 if (!partial_) {
2412 // Need to customize the request, so this forces us to allocate :( 2388 // Need to customize the request, so this forces us to allocate :(
2413 custom_request_.reset(new HttpRequestInfo(*request_)); 2389 custom_request_.reset(new HttpRequestInfo(*request_));
2414 request_ = custom_request_.get(); 2390 request_ = custom_request_.get();
2415 } 2391 }
2416 DCHECK(custom_request_.get()); 2392 DCHECK(custom_request_.get());
2417 2393
2418 bool use_if_range = 2394 bool use_if_range =
2419 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_; 2395 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_;
2420 2396
2421 if (!use_if_range) {
2422 // stale-while-revalidate is not useful when we only have a partial response
2423 // cached, so don't set the header in that case.
2424 HttpResponseHeaders::FreshnessLifetimes lifetimes =
2425 response_.headers->GetFreshnessLifetimes(response_.response_time);
2426 if (lifetimes.staleness > TimeDelta()) {
2427 TimeDelta current_age = response_.headers->GetCurrentAge(
2428 response_.request_time, response_.response_time,
2429 cache_->clock_->Now());
2430
2431 custom_request_->extra_headers.SetHeader(
2432 kFreshnessHeader,
2433 base::StringPrintf("max-age=%" PRId64
2434 ",stale-while-revalidate=%" PRId64 ",age=%" PRId64,
2435 lifetimes.freshness.InSeconds(),
2436 lifetimes.staleness.InSeconds(),
2437 current_age.InSeconds()));
2438 }
2439 }
2440
2441 if (!etag_value.empty()) { 2397 if (!etag_value.empty()) {
2442 if (use_if_range) { 2398 if (use_if_range) {
2443 // We don't want to switch to WRITE mode if we don't have this block of a 2399 // We don't want to switch to WRITE mode if we don't have this block of a
2444 // byte-range request because we may have other parts cached. 2400 // byte-range request because we may have other parts cached.
2445 custom_request_->extra_headers.SetHeader( 2401 custom_request_->extra_headers.SetHeader(
2446 HttpRequestHeaders::kIfRange, etag_value); 2402 HttpRequestHeaders::kIfRange, etag_value);
2447 } else { 2403 } else {
2448 custom_request_->extra_headers.SetHeader( 2404 custom_request_->extra_headers.SetHeader(
2449 HttpRequestHeaders::kIfNoneMatch, etag_value); 2405 HttpRequestHeaders::kIfNoneMatch, etag_value);
2450 } 2406 }
(...skipping 616 matching lines...) Expand 10 before | Expand all | Expand 10 after
3067 default: 3023 default:
3068 NOTREACHED(); 3024 NOTREACHED();
3069 } 3025 }
3070 } 3026 }
3071 3027
3072 void HttpCache::Transaction::OnIOComplete(int result) { 3028 void HttpCache::Transaction::OnIOComplete(int result) {
3073 DoLoop(result); 3029 DoLoop(result);
3074 } 3030 }
3075 3031
3076 } // namespace net 3032 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698