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

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

Issue 2854433002: Combine and make const RequiresValidation() and ConditionalizeRequest().
Patch Set: Restructure code, execute todos, fix GetConnectionAttempts. Created 3 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
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>
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 new_response_(NULL), 157 new_response_(NULL),
158 mode_(NONE), 158 mode_(NONE),
159 reading_(false), 159 reading_(false),
160 invalid_range_(false), 160 invalid_range_(false),
161 truncated_(false), 161 truncated_(false),
162 is_sparse_(false), 162 is_sparse_(false),
163 range_requested_(false), 163 range_requested_(false),
164 handling_206_(false), 164 handling_206_(false),
165 cache_pending_(false), 165 cache_pending_(false),
166 done_reading_(false), 166 done_reading_(false),
167 vary_mismatch_(false),
168 couldnt_conditionalize_request_(false), 167 couldnt_conditionalize_request_(false),
169 bypass_lock_for_test_(false), 168 bypass_lock_for_test_(false),
170 fail_conditionalization_for_test_(false), 169 fail_conditionalization_for_test_(false),
171 io_buf_len_(0), 170 io_buf_len_(0),
172 read_offset_(0), 171 read_offset_(0),
173 effective_load_flags_(0), 172 effective_load_flags_(0),
174 write_len_(0), 173 write_len_(0),
175 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED), 174 cache_entry_status_(CacheEntryStatus::ENTRY_UNDEFINED),
176 validation_cause_(VALIDATION_CAUSE_UNDEFINED), 175 validation_cause_(VALIDATION_CAUSE_UNDEFINED),
177 total_received_bytes_(0), 176 total_received_bytes_(0),
(...skipping 1912 matching lines...) Expand 10 before | Expand all | Expand 10 after
2090 TransitionToState(STATE_NONE); 2089 TransitionToState(STATE_NONE);
2091 return ERR_CACHE_MISS; 2090 return ERR_CACHE_MISS;
2092 } 2091 }
2093 2092
2094 // We don't have the whole resource. 2093 // We don't have the whole resource.
2095 if (truncated_) { 2094 if (truncated_) {
2096 TransitionToState(STATE_NONE); 2095 TransitionToState(STATE_NONE);
2097 return ERR_CACHE_MISS; 2096 return ERR_CACHE_MISS;
2098 } 2097 }
2099 2098
2100 if (RequiresValidation()) { 2099 if (GetEntryValidationStatus() != USABLE) {
2101 TransitionToState(STATE_NONE); 2100 TransitionToState(STATE_NONE);
2102 return ERR_CACHE_MISS; 2101 return ERR_CACHE_MISS;
2103 } 2102 }
2104 2103
2105 if (request_->method == "HEAD") 2104 if (request_->method == "HEAD")
2106 FixHeadersForHead(); 2105 FixHeadersForHead();
2107 2106
2108 if (entry_->disk_entry->GetDataSize(kMetadataIndex)) 2107 if (entry_->disk_entry->GetDataSize(kMetadataIndex))
2109 TransitionToState(STATE_CACHE_READ_METADATA); 2108 TransitionToState(STATE_CACHE_READ_METADATA);
2110 else 2109 else
2111 TransitionToState(STATE_NONE); 2110 TransitionToState(STATE_NONE);
2112 2111
2113 return OK; 2112 return OK;
2114 } 2113 }
2115 2114
2116 int HttpCache::Transaction::BeginCacheValidation() { 2115 int HttpCache::Transaction::BeginCacheValidation() {
2117 DCHECK_EQ(mode_, READ_WRITE); 2116 DCHECK_EQ(mode_, READ_WRITE);
2118 2117
2119 bool skip_validation = !RequiresValidation(); 2118 enum EntryValidationStatus entry_validation_status =
2119 GetEntryValidationStatus();
2120 2120
2121 if (request_->method == "HEAD" && 2121 if (request_->method == "HEAD" &&
2122 (truncated_ || response_.headers->response_code() == 206)) { 2122 (truncated_ || response_.headers->response_code() == 206)) {
2123 DCHECK(!partial_); 2123 DCHECK(!partial_);
2124 if (skip_validation) 2124 if (entry_validation_status == USABLE)
2125 return SetupEntryForRead(); 2125 return SetupEntryForRead();
2126 2126
2127 // Bail out! 2127 // Bail out!
2128 TransitionToState(STATE_SEND_REQUEST); 2128 TransitionToState(STATE_SEND_REQUEST);
2129 mode_ = NONE; 2129 mode_ = NONE;
2130 return OK; 2130 return OK;
2131 } 2131 }
2132 2132
2133 if (truncated_) { 2133 if (truncated_) {
2134 // Truncated entries can cause partial gets, so we shouldn't record this 2134 // Truncated entries can cause partial gets, so we shouldn't record this
2135 // load in histograms. 2135 // load in histograms.
2136 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER); 2136 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
2137 skip_validation = !partial_->initial_validation();
2138 } 2137 }
2139 2138
2140 if (partial_ && (is_sparse_ || truncated_) && 2139 if (entry_validation_status == USABLE) {
2141 (!partial_->IsCurrentRangeCached() || invalid_range_)) { 2140 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_USED);
2142 // Force revalidation for sparse or truncated entries. Note that we don't 2141 return SetupEntryForRead();
2143 // want to ignore the regular validation logic just because a byte range was
2144 // part of the request.
2145 skip_validation = false;
2146 } 2142 }
2147 2143
2148 if (skip_validation) { 2144 // If the network request cannot be conditional, setup a normal
2149 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_USED); 2145 // fetch. The mode remains READ_WRITE for a conditional request.
2150 return SetupEntryForRead(); 2146 // Even if the conditionalization fails, don't switch to WRITE mode
2151 } else { 2147 // until it is confirmed that the transaction won't be falling back
2152 // Make the network request conditional, to see if we may reuse our cached 2148 // to using the cache entry in the LOAD_FROM_CACHE_IF_OFFLINE case.
2153 // response. If we cannot do so, then we just resort to a normal fetch. 2149 if (entry_validation_status == REQUIRES_REFETCH) {
2154 // Our mode remains READ_WRITE for a conditional request. Even if the 2150 couldnt_conditionalize_request_ = true;
shivanisha 2017/05/02 16:03:25 Can we save entry_validation_status as a member va
2155 // conditionalization fails, we don't switch to WRITE mode until we 2151 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE);
2156 // know we won't be falling back to using the cache entry in the 2152 if (partial_)
2157 // LOAD_FROM_CACHE_IF_OFFLINE case. 2153 return DoRestartPartialRequest();
2158 if (!ConditionalizeRequest()) {
2159 couldnt_conditionalize_request_ = true;
2160 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE);
2161 if (partial_)
2162 return DoRestartPartialRequest();
2163 2154
2164 DCHECK_NE(206, response_.headers->response_code()); 2155 DCHECK_NE(206, response_.headers->response_code());
2156 TransitionToState(STATE_SEND_REQUEST);
2157 return OK;
2158 }
2159
2160 // Sending a conditional request to see if the cache entry is still valid.
2161
2162 // Setup custom request if needed.
2163 if (!partial_) {
2164 custom_request_.reset(new HttpRequestInfo(*request_));
2165 request_ = custom_request_.get();
2166 }
2167 DCHECK(custom_request_.get());
2168 bool use_if_range =
2169 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_;
2170
2171 std::string etag_value;
2172 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1))
2173 response_.headers->EnumerateHeader(NULL, "etag", &etag_value);
2174
2175 std::string last_modified_value;
2176 if (entry_validation_status == REQUIRES_VALIDATION_VARY_MISMATCH) {
2177 response_.headers->EnumerateHeader(NULL, "last-modified",
2178 &last_modified_value);
shivanisha 2017/05/02 16:03:26 The above two conditions seem to be getting execut
2179 }
2180
shivanisha 2017/05/02 16:03:25 DCHECK(!etag_value.empty() || !last_modified_value
2181 if (!etag_value.empty()) {
2182 if (use_if_range) {
2183 // We don't want to switch to WRITE mode if we don't have this block of a
2184 // byte-range request because we may have other parts cached.
2185 custom_request_->extra_headers.SetHeader(HttpRequestHeaders::kIfRange,
2186 etag_value);
2187 } else {
2188 custom_request_->extra_headers.SetHeader(HttpRequestHeaders::kIfNoneMatch,
2189 etag_value);
2165 } 2190 }
2166 TransitionToState(STATE_SEND_REQUEST);
2167 } 2191 }
2192
2193 if (!last_modified_value.empty() &&
2194 // For byte-range requests, make sure that we use only one way to validate
2195 // the request.
2196 (!partial_ || partial_->IsCurrentRangeCached())) {
2197 if (use_if_range) {
2198 custom_request_->extra_headers.SetHeader(HttpRequestHeaders::kIfRange,
2199 last_modified_value);
2200 } else {
2201 custom_request_->extra_headers.SetHeader(
2202 HttpRequestHeaders::kIfModifiedSince, last_modified_value);
2203 }
2204 }
2205
2206 TransitionToState(STATE_SEND_REQUEST);
2168 return OK; 2207 return OK;
2169 } 2208 }
2170 2209
2171 int HttpCache::Transaction::BeginPartialCacheValidation() { 2210 int HttpCache::Transaction::BeginPartialCacheValidation() {
2172 DCHECK_EQ(mode_, READ_WRITE); 2211 DCHECK_EQ(mode_, READ_WRITE);
2173 2212
2174 if (response_.headers->response_code() != 206 && !partial_ && !truncated_) 2213 if (response_.headers->response_code() != 206 && !partial_ && !truncated_)
2175 return BeginCacheValidation(); 2214 return BeginCacheValidation();
2176 2215
2177 // Partial requests should not be recorded in histograms. 2216 // Partial requests should not be recorded in histograms.
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
2275 DCHECK(network_trans_.get()); 2314 DCHECK(network_trans_.get());
2276 DCHECK_EQ(STATE_NONE, next_state_); 2315 DCHECK_EQ(STATE_NONE, next_state_);
2277 2316
2278 next_state_ = STATE_SEND_REQUEST_COMPLETE; 2317 next_state_ = STATE_SEND_REQUEST_COMPLETE;
2279 int rv = network_trans_->RestartWithAuth(credentials, io_callback_); 2318 int rv = network_trans_->RestartWithAuth(credentials, io_callback_);
2280 if (rv != ERR_IO_PENDING) 2319 if (rv != ERR_IO_PENDING)
2281 return DoLoop(rv); 2320 return DoLoop(rv);
2282 return rv; 2321 return rv;
2283 } 2322 }
2284 2323
2285 bool HttpCache::Transaction::RequiresValidation() { 2324 // Helper function for GetEntryValidationStatus.
2325 bool HttpCache::Transaction::RequiresValidation(bool* vary_mismatch) const {
2326 if (partial_ && (is_sparse_ || truncated_) &&
2327 (!partial_->IsCurrentRangeCached() || invalid_range_)) {
2328 // Force revalidation for sparse or truncated entries. Note that
2329 // we don't want to ignore the regular validation logic just
2330 // because a byte range was part of the request.
2331 return true;
2332 }
2333
2334 // In the truncation case, validation status is controlled by the
2335 // partial_ state; that state either determines that it's usable, or
2336 // forces validation.
2337 if (truncated_ && request_->method != "HEAD")
2338 return partial_->initial_validation();
2339
2286 // TODO(darin): need to do more work here: 2340 // TODO(darin): need to do more work here:
2287 // - make sure we have a matching request method 2341 // - make sure we have a matching request method
2288 // - watch out for cached responses that depend on authentication 2342 // - watch out for cached responses that depend on authentication
2289
2290 if (!(effective_load_flags_ & LOAD_SKIP_VARY_CHECK) && 2343 if (!(effective_load_flags_ & LOAD_SKIP_VARY_CHECK) &&
2291 response_.vary_data.is_valid() && 2344 response_.vary_data.is_valid() &&
2292 !response_.vary_data.MatchesRequest(*request_, 2345 !response_.vary_data.MatchesRequest(*request_,
2293 *response_.headers.get())) { 2346 *response_.headers.get())) {
2294 vary_mismatch_ = true; 2347 *vary_mismatch = true;
2295 validation_cause_ = VALIDATION_CAUSE_VARY_MISMATCH; 2348 validation_cause_ = VALIDATION_CAUSE_VARY_MISMATCH;
2296 return true; 2349 return true;
2297 } 2350 }
2298 2351
2299 if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION) 2352 if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION)
2300 return false; 2353 return false;
2301 2354
2302 if (response_.unused_since_prefetch && 2355 if (response_.unused_since_prefetch &&
2303 !(effective_load_flags_ & LOAD_PREFETCH) && 2356 !(effective_load_flags_ & LOAD_PREFETCH) &&
2304 response_.headers->GetCurrentAge( 2357 (response_.headers->GetCurrentAge(response_.request_time,
2305 response_.request_time, response_.response_time, 2358 response_.response_time,
2306 cache_->clock_->Now()) < TimeDelta::FromMinutes(kPrefetchReuseMins)) { 2359 cache_->clock_->Now()) <
2360 TimeDelta::FromMinutes(kPrefetchReuseMins))) {
2307 // The first use of a resource after prefetch within a short window skips 2361 // The first use of a resource after prefetch within a short window skips
2308 // validation. 2362 // validation.
2309 return false; 2363 return false;
2310 } 2364 }
2311 2365
2312 if (effective_load_flags_ & LOAD_VALIDATE_CACHE) { 2366 if (effective_load_flags_ & LOAD_VALIDATE_CACHE) {
2313 validation_cause_ = VALIDATION_CAUSE_VALIDATE_FLAG; 2367 validation_cause_ = VALIDATION_CAUSE_VALIDATE_FLAG;
2314 return true; 2368 return true;
2315 } 2369 }
2316 2370
2317 if (request_->method == "PUT" || request_->method == "DELETE")
2318 return true;
2319
2320 bool validation_required_by_headers = response_.headers->RequiresValidation( 2371 bool validation_required_by_headers = response_.headers->RequiresValidation(
2321 response_.request_time, response_.response_time, cache_->clock_->Now()); 2372 response_.request_time, response_.response_time, cache_->clock_->Now());
2322 2373
2323 if (validation_required_by_headers) { 2374 if (validation_required_by_headers) {
2324 HttpResponseHeaders::FreshnessLifetimes lifetimes = 2375 HttpResponseHeaders::FreshnessLifetimes lifetimes =
2325 response_.headers->GetFreshnessLifetimes(response_.response_time); 2376 response_.headers->GetFreshnessLifetimes(response_.response_time);
2326 if (lifetimes.freshness == base::TimeDelta()) { 2377 if (lifetimes.freshness == base::TimeDelta()) {
2327 validation_cause_ = VALIDATION_CAUSE_ZERO_FRESHNESS; 2378 validation_cause_ = VALIDATION_CAUSE_ZERO_FRESHNESS;
2328 } else { 2379 } else {
2329 validation_cause_ = VALIDATION_CAUSE_STALE; 2380 validation_cause_ = VALIDATION_CAUSE_STALE;
2330 stale_entry_freshness_ = lifetimes.freshness; 2381 stale_entry_freshness_ = lifetimes.freshness;
2331 stale_entry_age_ = response_.headers->GetCurrentAge( 2382 stale_entry_age_ = response_.headers->GetCurrentAge(
2332 response_.request_time, response_.response_time, 2383 response_.request_time, response_.response_time,
2333 cache_->clock_->Now()); 2384 cache_->clock_->Now());
2334 } 2385 }
2335 } 2386 }
2336 2387
2337 return validation_required_by_headers; 2388 return validation_required_by_headers;
2338 } 2389 }
2339 2390
2340 bool HttpCache::Transaction::ConditionalizeRequest() { 2391 HttpCache::Transaction::EntryValidationStatus
2341 DCHECK(response_.headers.get()); 2392 HttpCache::Transaction::GetEntryValidationStatus() const {
2393 if (request_->method == "PUT" || request_->method == "DELETE")
2394 return REQUIRES_REFETCH;
shivanisha 2017/05/02 16:03:26 In the original code, this check comes after the o
2342 2395
2343 if (request_->method == "PUT" || request_->method == "DELETE") 2396 bool vary_mismatch = false;
2344 return false; 2397 if (!RequiresValidation(&vary_mismatch))
2398 return USABLE;
2345 2399
2346 // This only makes sense for cached 200 or 206 responses. 2400 // The transaction requires revalidation with the server, and may require
2401 // a re-fetch.
2347 if (response_.headers->response_code() != 200 && 2402 if (response_.headers->response_code() != 200 &&
2348 response_.headers->response_code() != 206) { 2403 response_.headers->response_code() != 206) {
2349 return false; 2404 return REQUIRES_REFETCH;
2350 } 2405 }
2351 2406
2352 if (fail_conditionalization_for_test_) 2407 if (fail_conditionalization_for_test_)
2353 return false; 2408 return REQUIRES_REFETCH;
2354 2409
2355 DCHECK(response_.headers->response_code() != 206 || 2410 DCHECK(response_.headers->response_code() != 206 ||
2356 response_.headers->HasStrongValidators()); 2411 response_.headers->HasStrongValidators());
2357 2412
2358 // Just use the first available ETag and/or Last-Modified header value. 2413 // Just use the first available ETag and/or Last-Modified header value.
2359 // TODO(darin): Or should we use the last? 2414 // TODO(darin): Or should we use the last?
2360 2415
2361 std::string etag_value; 2416 std::string etag_value;
2362 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) 2417 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1))
2363 response_.headers->EnumerateHeader(NULL, "etag", &etag_value); 2418 response_.headers->EnumerateHeader(NULL, "etag", &etag_value);
2364 2419
2365 std::string last_modified_value; 2420 std::string last_modified_value;
2366 if (!vary_mismatch_) { 2421 if (!vary_mismatch) {
2367 response_.headers->EnumerateHeader(NULL, "last-modified", 2422 response_.headers->EnumerateHeader(NULL, "last-modified",
2368 &last_modified_value); 2423 &last_modified_value);
2369 } 2424 }
2370 2425
2371 if (etag_value.empty() && last_modified_value.empty()) 2426 if (etag_value.empty() && last_modified_value.empty())
2372 return false; 2427 return REQUIRES_REFETCH;
2373 2428
2374 if (!partial_) { 2429 return vary_mismatch ? REQUIRES_VALIDATION
2375 // Need to customize the request, so this forces us to allocate :( 2430 : REQUIRES_VALIDATION_VARY_MISMATCH;
shivanisha 2017/05/02 16:03:25 Looks like it should be REQUIRES_VALIDATION_VARY_M
2376 custom_request_.reset(new HttpRequestInfo(*request_));
2377 request_ = custom_request_.get();
2378 }
2379 DCHECK(custom_request_.get());
2380
2381 bool use_if_range =
2382 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_;
2383
2384 if (!etag_value.empty()) {
2385 if (use_if_range) {
2386 // We don't want to switch to WRITE mode if we don't have this block of a
2387 // byte-range request because we may have other parts cached.
2388 custom_request_->extra_headers.SetHeader(
2389 HttpRequestHeaders::kIfRange, etag_value);
2390 } else {
2391 custom_request_->extra_headers.SetHeader(
2392 HttpRequestHeaders::kIfNoneMatch, etag_value);
2393 }
2394 // For byte-range requests, make sure that we use only one way to validate
2395 // the request.
2396 if (partial_ && !partial_->IsCurrentRangeCached())
2397 return true;
2398 }
2399
2400 if (!last_modified_value.empty()) {
2401 if (use_if_range) {
2402 custom_request_->extra_headers.SetHeader(
2403 HttpRequestHeaders::kIfRange, last_modified_value);
2404 } else {
2405 custom_request_->extra_headers.SetHeader(
2406 HttpRequestHeaders::kIfModifiedSince, last_modified_value);
2407 }
2408 }
2409
2410 return true;
2411 } 2431 }
2412 2432
2413 // We just received some headers from the server. We may have asked for a range, 2433 // We just received some headers from the server. We may have asked for a range,
2414 // in which case partial_ has an object. This could be the first network request 2434 // in which case partial_ has an object. This could be the first network request
2415 // we make to fulfill the original request, or we may be already reading (from 2435 // we make to fulfill the original request, or we may be already reading (from
2416 // the net and / or the cache). If we are not expecting a certain response, we 2436 // the net and / or the cache). If we are not expecting a certain response, we
2417 // just bypass the cache for this request (but again, maybe we are reading), and 2437 // just bypass the cache for this request (but again, maybe we are reading), and
2418 // delete partial_ (so we are not able to "fix" the headers that we return to 2438 // delete partial_ (so we are not able to "fix" the headers that we return to
2419 // the user). This results in either a weird response for the caller (we don't 2439 // the user). This results in either a weird response for the caller (we don't
2420 // expect it after all), or maybe a range that was not exactly what it was asked 2440 // expect it after all), or maybe a range that was not exactly what it was asked
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after
3017 } 3037 }
3018 3038
3019 void HttpCache::Transaction::TransitionToState(State state) { 3039 void HttpCache::Transaction::TransitionToState(State state) {
3020 // Ensure that the state is only set once per Do* state. 3040 // Ensure that the state is only set once per Do* state.
3021 DCHECK(in_do_loop_); 3041 DCHECK(in_do_loop_);
3022 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; 3042 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state;
3023 next_state_ = state; 3043 next_state_ = state;
3024 } 3044 }
3025 3045
3026 } // namespace net 3046 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698