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

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

Issue 2922973003: RFC: use some in-memory state in SimpleCache to quickly cache-miss some CantConditionalize cases
Patch Set: omewhat better take at higher-level HC::T impl, a bit lessy hacky, and actually write to cache now. Created 3 years, 6 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 1018 matching lines...) Expand 10 before | Expand all | Expand 10 after
1029 if (result == OK) { 1029 if (result == OK) {
1030 TransitionToState(STATE_ADD_TO_ENTRY); 1030 TransitionToState(STATE_ADD_TO_ENTRY);
1031 return OK; 1031 return OK;
1032 } 1032 }
1033 1033
1034 if (result == ERR_CACHE_RACE) { 1034 if (result == ERR_CACHE_RACE) {
1035 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); 1035 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
1036 return OK; 1036 return OK;
1037 } 1037 }
1038 1038
1039 if (result == ERR_CACHE_ENTRY_NOT_SUITABLE) {
1040 DCHECK_EQ(mode_, READ_WRITE);
1041 // Record this as CantConditionalize, but otherwise proceed as we would
1042 // below --- as OpenEntry has already dropped the old entry for us.
1043 couldnt_conditionalize_request_ = true;
1044 response_.was_cached = true;
1045 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE);
1046 }
1047
1039 if (method_ == "PUT" || method_ == "DELETE" || 1048 if (method_ == "PUT" || method_ == "DELETE" ||
1040 (method_ == "HEAD" && mode_ == READ_WRITE)) { 1049 (method_ == "HEAD" && mode_ == READ_WRITE)) {
1041 DCHECK(mode_ == READ_WRITE || mode_ == WRITE || method_ == "HEAD"); 1050 DCHECK(mode_ == READ_WRITE || mode_ == WRITE || method_ == "HEAD");
1042 mode_ = NONE; 1051 mode_ = NONE;
1043 TransitionToState(STATE_SEND_REQUEST); 1052 TransitionToState(STATE_SEND_REQUEST);
1044 return OK; 1053 return OK;
1045 } 1054 }
1046 1055
1047 if (mode_ == READ_WRITE) { 1056 if (mode_ == READ_WRITE) {
1048 mode_ = WRITE; 1057 mode_ = WRITE;
(...skipping 1380 matching lines...) Expand 10 before | Expand all | Expand 10 after
2429 stale_entry_freshness_ = lifetimes.freshness; 2438 stale_entry_freshness_ = lifetimes.freshness;
2430 stale_entry_age_ = response_.headers->GetCurrentAge( 2439 stale_entry_age_ = response_.headers->GetCurrentAge(
2431 response_.request_time, response_.response_time, 2440 response_.request_time, response_.response_time,
2432 cache_->clock_->Now()); 2441 cache_->clock_->Now());
2433 } 2442 }
2434 } 2443 }
2435 2444
2436 return validation_required_by_headers; 2445 return validation_required_by_headers;
2437 } 2446 }
2438 2447
2448 bool HttpCache::Transaction::ResponseConditionalizable(
2449 std::string* etag_value,
2450 std::string* last_modified_value) {
2451 DCHECK(response_.headers.get());
2452
2453 // This only makes sense for cached 200 or 206 responses.
2454 if (response_.headers->response_code() != 200 &&
2455 response_.headers->response_code() != 206) {
2456 return false;
2457 }
2458
2459 // ### this looks scary.
2460 DCHECK(response_.headers->response_code() != 206 ||
2461 response_.headers->HasStrongValidators());
2462
2463 // Just use the first available ETag and/or Last-Modified header value.
2464 // TODO(darin): Or should we use the last?
2465
2466 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1))
2467 response_.headers->EnumerateHeader(NULL, "etag", etag_value);
2468
2469 response_.headers->EnumerateHeader(NULL, "last-modified",
2470 last_modified_value);
2471
2472 if (etag_value->empty() && last_modified_value->empty())
2473 return false;
2474
2475 return true;
2476 }
2477
2439 bool HttpCache::Transaction::ConditionalizeRequest() { 2478 bool HttpCache::Transaction::ConditionalizeRequest() {
2440 DCHECK(response_.headers.get()); 2479 DCHECK(response_.headers.get());
2441 2480
2442 if (method_ == "PUT" || method_ == "DELETE") 2481 if (method_ == "PUT" || method_ == "DELETE")
2443 return false; 2482 return false;
2444 2483
2445 // This only makes sense for cached 200 or 206 responses.
2446 if (response_.headers->response_code() != 200 &&
2447 response_.headers->response_code() != 206) {
2448 return false;
2449 }
2450
2451 if (fail_conditionalization_for_test_) 2484 if (fail_conditionalization_for_test_)
2452 return false; 2485 return false;
2453 2486
2454 DCHECK(response_.headers->response_code() != 206 || 2487 std::string etag_value;
2455 response_.headers->HasStrongValidators()); 2488 std::string last_modified_value;
2489 if (!ResponseConditionalizable(&etag_value, &last_modified_value))
2490 return false;
2456 2491
2457 // Just use the first available ETag and/or Last-Modified header value. 2492 if (vary_mismatch_) {
2458 // TODO(darin): Or should we use the last? 2493 // Can't rely on last-modified if vary is different.
2459 2494 last_modified_value.clear();
2460 std::string etag_value; 2495 if (etag_value.empty())
2461 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) 2496 return false;
2462 response_.headers->EnumerateHeader(NULL, "etag", &etag_value);
2463
2464 std::string last_modified_value;
2465 if (!vary_mismatch_) {
2466 response_.headers->EnumerateHeader(NULL, "last-modified",
2467 &last_modified_value);
2468 } 2497 }
2469 2498
2470 if (etag_value.empty() && last_modified_value.empty())
2471 return false;
2472
2473 if (!partial_) { 2499 if (!partial_) {
2474 // Need to customize the request, so this forces us to allocate :( 2500 // Need to customize the request, so this forces us to allocate :(
2475 custom_request_.reset(new HttpRequestInfo(*request_)); 2501 custom_request_.reset(new HttpRequestInfo(*request_));
2476 request_ = custom_request_.get(); 2502 request_ = custom_request_.get();
2477 } 2503 }
2478 DCHECK(custom_request_.get()); 2504 DCHECK(custom_request_.get());
2479 2505
2480 bool use_if_range = 2506 bool use_if_range =
2481 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_; 2507 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_;
2482 2508
(...skipping 19 matching lines...) Expand all
2502 HttpRequestHeaders::kIfRange, last_modified_value); 2528 HttpRequestHeaders::kIfRange, last_modified_value);
2503 } else { 2529 } else {
2504 custom_request_->extra_headers.SetHeader( 2530 custom_request_->extra_headers.SetHeader(
2505 HttpRequestHeaders::kIfModifiedSince, last_modified_value); 2531 HttpRequestHeaders::kIfModifiedSince, last_modified_value);
2506 } 2532 }
2507 } 2533 }
2508 2534
2509 return true; 2535 return true;
2510 } 2536 }
2511 2537
2538 bool HttpCache::Transaction::MaybeRejectBasedOnMemoryEntryData(
2539 uint8_t in_memory_info) {
2540 // Not going to be clever with those... though is it even set here?
2541 if (partial_)
2542 return false;
2543
2544 // Unclear how to reconcile trying to avoid opening the entry with UPDATE's
2545 // semantics.
2546 if (mode_ == UPDATE)
2547 return false;
2548
2549 // We can tell that some entries in cache may be unusable under present
2550 // circumstances if:
2551 // 1) We aren't using everything because of LOAD_SKIP_CACHE_VALIDATION.
2552 // 2) We aren't holding on to results of an unused prefetch.
2553 // 3) The entry has zero freshness (so it's known to be expired!)
2554 // 4) We know the entry can't be revalidated
2555 // (we may be able to match more things here).
2556 if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION)
2557 return false;
2558
2559 if (in_memory_info & HttpCache::OBH_UNUSED_SINCE_PREFETCH)
2560 return false;
2561
2562 if (!(in_memory_info & HttpCache::OBH_ZERO_LIFETIME))
2563 return false;
2564
2565 if (!(in_memory_info & OBH_RESPONSE_CANT_CONDITIONALIZE))
2566 return false;
2567
2568 return true;
2569 }
2570
2512 // We just received some headers from the server. We may have asked for a range, 2571 // We just received some headers from the server. We may have asked for a range,
2513 // in which case partial_ has an object. This could be the first network request 2572 // in which case partial_ has an object. This could be the first network request
2514 // we make to fulfill the original request, or we may be already reading (from 2573 // we make to fulfill the original request, or we may be already reading (from
2515 // the net and / or the cache). If we are not expecting a certain response, we 2574 // the net and / or the cache). If we are not expecting a certain response, we
2516 // just bypass the cache for this request (but again, maybe we are reading), and 2575 // just bypass the cache for this request (but again, maybe we are reading), and
2517 // delete partial_ (so we are not able to "fix" the headers that we return to 2576 // delete partial_ (so we are not able to "fix" the headers that we return to
2518 // the user). This results in either a weird response for the caller (we don't 2577 // the user). This results in either a weird response for the caller (we don't
2519 // expect it after all), or maybe a range that was not exactly what it was asked 2578 // expect it after all), or maybe a range that was not exactly what it was asked
2520 // for. 2579 // for.
2521 // 2580 //
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
2724 if (truncated) 2783 if (truncated)
2725 DCHECK_EQ(200, response_.headers->response_code()); 2784 DCHECK_EQ(200, response_.headers->response_code());
2726 2785
2727 // When writing headers, we normally only write the non-transient headers. 2786 // When writing headers, we normally only write the non-transient headers.
2728 bool skip_transient_headers = true; 2787 bool skip_transient_headers = true;
2729 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); 2788 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer());
2730 response_.Persist(data->pickle(), skip_transient_headers, truncated); 2789 response_.Persist(data->pickle(), skip_transient_headers, truncated);
2731 data->Done(); 2790 data->Done();
2732 2791
2733 io_buf_len_ = data->pickle()->size(); 2792 io_buf_len_ = data->pickle()->size();
2793
2794 uint8_t hints = 0;
2795 // ### recomputing this too much?
2796 if (response_.headers->GetFreshnessLifetimes(response_.response_time)
2797 .freshness.is_zero())
2798 hints |= HttpCache::OBH_ZERO_LIFETIME;
2799 std::string etag_ignored, last_modified_ignored;
2800 if (!ResponseConditionalizable(&etag_ignored, &last_modified_ignored))
2801 hints |= HttpCache::OBH_RESPONSE_CANT_CONDITIONALIZE;
2802 if (response_.unused_since_prefetch)
2803 hints |= HttpCache::OBH_UNUSED_SINCE_PREFETCH;
2804 cache_->GetCurrentBackend()->SetMemoryEntryData(cache_key_, hints);
2734 return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(), 2805 return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(),
2735 io_buf_len_, io_callback_, true); 2806 io_buf_len_, io_callback_, true);
2736 } 2807 }
2737 2808
2738 int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) { 2809 int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) {
2739 if (!entry_) 2810 if (!entry_)
2740 return OK; 2811 return OK;
2741 if (net_log_.IsCapturing()) { 2812 if (net_log_.IsCapturing()) {
2742 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_INFO, 2813 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_INFO,
2743 result); 2814 result);
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after
3124 } 3195 }
3125 3196
3126 void HttpCache::Transaction::TransitionToState(State state) { 3197 void HttpCache::Transaction::TransitionToState(State state) {
3127 // Ensure that the state is only set once per Do* state. 3198 // Ensure that the state is only set once per Do* state.
3128 DCHECK(in_do_loop_); 3199 DCHECK(in_do_loop_);
3129 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; 3200 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state;
3130 next_state_ = state; 3201 next_state_ = state;
3131 } 3202 }
3132 3203
3133 } // namespace net 3204 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698