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" // 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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |