| 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 1043 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1054 if (result == OK) { | 1054 if (result == OK) { |
| 1055 TransitionToState(STATE_ADD_TO_ENTRY); | 1055 TransitionToState(STATE_ADD_TO_ENTRY); |
| 1056 return OK; | 1056 return OK; |
| 1057 } | 1057 } |
| 1058 | 1058 |
| 1059 if (result == ERR_CACHE_RACE) { | 1059 if (result == ERR_CACHE_RACE) { |
| 1060 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); | 1060 TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED); |
| 1061 return OK; | 1061 return OK; |
| 1062 } | 1062 } |
| 1063 | 1063 |
| 1064 if (result == ERR_CACHE_ENTRY_NOT_SUITABLE) { |
| 1065 DCHECK_EQ(mode_, READ_WRITE); |
| 1066 // Record this as CantConditionalize, but otherwise proceed as we would |
| 1067 // below --- as OpenEntry has already dropped the old entry for us. |
| 1068 couldnt_conditionalize_request_ = true; |
| 1069 UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE); |
| 1070 } |
| 1071 |
| 1064 if (method_ == "PUT" || method_ == "DELETE" || | 1072 if (method_ == "PUT" || method_ == "DELETE" || |
| 1065 (method_ == "HEAD" && mode_ == READ_WRITE)) { | 1073 (method_ == "HEAD" && mode_ == READ_WRITE)) { |
| 1066 DCHECK(mode_ == READ_WRITE || mode_ == WRITE || method_ == "HEAD"); | 1074 DCHECK(mode_ == READ_WRITE || mode_ == WRITE || method_ == "HEAD"); |
| 1067 mode_ = NONE; | 1075 mode_ = NONE; |
| 1068 TransitionToState(STATE_SEND_REQUEST); | 1076 TransitionToState(STATE_SEND_REQUEST); |
| 1069 return OK; | 1077 return OK; |
| 1070 } | 1078 } |
| 1071 | 1079 |
| 1072 if (mode_ == READ_WRITE) { | 1080 if (mode_ == READ_WRITE) { |
| 1073 mode_ = WRITE; | 1081 mode_ = WRITE; |
| (...skipping 1477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2551 stale_entry_freshness_ = lifetimes.freshness; | 2559 stale_entry_freshness_ = lifetimes.freshness; |
| 2552 stale_entry_age_ = response_.headers->GetCurrentAge( | 2560 stale_entry_age_ = response_.headers->GetCurrentAge( |
| 2553 response_.request_time, response_.response_time, | 2561 response_.request_time, response_.response_time, |
| 2554 cache_->clock_->Now()); | 2562 cache_->clock_->Now()); |
| 2555 } | 2563 } |
| 2556 } | 2564 } |
| 2557 | 2565 |
| 2558 return validation_required_by_headers; | 2566 return validation_required_by_headers; |
| 2559 } | 2567 } |
| 2560 | 2568 |
| 2569 bool HttpCache::Transaction::ResponseConditionalizable( |
| 2570 std::string* etag_value, |
| 2571 std::string* last_modified_value) { |
| 2572 DCHECK(response_.headers.get()); |
| 2573 |
| 2574 // This only makes sense for cached 200 or 206 responses. |
| 2575 if (response_.headers->response_code() != 200 && |
| 2576 response_.headers->response_code() != 206) { |
| 2577 return false; |
| 2578 } |
| 2579 |
| 2580 // Just use the first available ETag and/or Last-Modified header value. |
| 2581 // TODO(darin): Or should we use the last? |
| 2582 |
| 2583 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) |
| 2584 response_.headers->EnumerateHeader(NULL, "etag", etag_value); |
| 2585 |
| 2586 response_.headers->EnumerateHeader(NULL, "last-modified", |
| 2587 last_modified_value); |
| 2588 |
| 2589 if (etag_value->empty() && last_modified_value->empty()) |
| 2590 return false; |
| 2591 |
| 2592 return true; |
| 2593 } |
| 2594 |
| 2561 bool HttpCache::Transaction::ConditionalizeRequest() { | 2595 bool HttpCache::Transaction::ConditionalizeRequest() { |
| 2562 DCHECK(response_.headers.get()); | 2596 DCHECK(response_.headers.get()); |
| 2563 | 2597 |
| 2564 if (method_ == "PUT" || method_ == "DELETE") | 2598 if (method_ == "PUT" || method_ == "DELETE") |
| 2565 return false; | 2599 return false; |
| 2566 | 2600 |
| 2567 // This only makes sense for cached 200 or 206 responses. | 2601 if (fail_conditionalization_for_test_) |
| 2568 if (response_.headers->response_code() != 200 && | |
| 2569 response_.headers->response_code() != 206) { | |
| 2570 return false; | 2602 return false; |
| 2571 } | |
| 2572 | 2603 |
| 2573 if (fail_conditionalization_for_test_) | 2604 std::string etag_value; |
| 2605 std::string last_modified_value; |
| 2606 if (!ResponseConditionalizable(&etag_value, &last_modified_value)) |
| 2574 return false; | 2607 return false; |
| 2575 | 2608 |
| 2576 DCHECK(response_.headers->response_code() != 206 || | 2609 DCHECK(response_.headers->response_code() != 206 || |
| 2577 response_.headers->HasStrongValidators()); | 2610 response_.headers->HasStrongValidators()); |
| 2578 | 2611 |
| 2579 // Just use the first available ETag and/or Last-Modified header value. | 2612 if (vary_mismatch_) { |
| 2580 // TODO(darin): Or should we use the last? | 2613 // Can't rely on last-modified if vary is different. |
| 2581 | 2614 last_modified_value.clear(); |
| 2582 std::string etag_value; | 2615 if (etag_value.empty()) |
| 2583 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) | 2616 return false; |
| 2584 response_.headers->EnumerateHeader(NULL, "etag", &etag_value); | |
| 2585 | |
| 2586 std::string last_modified_value; | |
| 2587 if (!vary_mismatch_) { | |
| 2588 response_.headers->EnumerateHeader(NULL, "last-modified", | |
| 2589 &last_modified_value); | |
| 2590 } | 2617 } |
| 2591 | 2618 |
| 2592 if (etag_value.empty() && last_modified_value.empty()) | |
| 2593 return false; | |
| 2594 | |
| 2595 if (!partial_) { | 2619 if (!partial_) { |
| 2596 // Need to customize the request, so this forces us to allocate :( | 2620 // Need to customize the request, so this forces us to allocate :( |
| 2597 custom_request_.reset(new HttpRequestInfo(*request_)); | 2621 custom_request_.reset(new HttpRequestInfo(*request_)); |
| 2598 request_ = custom_request_.get(); | 2622 request_ = custom_request_.get(); |
| 2599 } | 2623 } |
| 2600 DCHECK(custom_request_.get()); | 2624 DCHECK(custom_request_.get()); |
| 2601 | 2625 |
| 2602 bool use_if_range = | 2626 bool use_if_range = |
| 2603 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_; | 2627 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_; |
| 2604 | 2628 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2624 HttpRequestHeaders::kIfRange, last_modified_value); | 2648 HttpRequestHeaders::kIfRange, last_modified_value); |
| 2625 } else { | 2649 } else { |
| 2626 custom_request_->extra_headers.SetHeader( | 2650 custom_request_->extra_headers.SetHeader( |
| 2627 HttpRequestHeaders::kIfModifiedSince, last_modified_value); | 2651 HttpRequestHeaders::kIfModifiedSince, last_modified_value); |
| 2628 } | 2652 } |
| 2629 } | 2653 } |
| 2630 | 2654 |
| 2631 return true; | 2655 return true; |
| 2632 } | 2656 } |
| 2633 | 2657 |
| 2658 bool HttpCache::Transaction::MaybeRejectBasedOnEntryInMemoryData( |
| 2659 uint8_t in_memory_info) { |
| 2660 // Not going to be clever with those... |
| 2661 if (partial_) |
| 2662 return false; |
| 2663 |
| 2664 // Unclear how to reconcile trying to avoid opening the entry with UPDATE's |
| 2665 // semantics. |
| 2666 if (mode_ == UPDATE) |
| 2667 return false; |
| 2668 |
| 2669 // If we are loading ignoring cache validity (aka back button), obviously |
| 2670 // can't reject things based on it. |
| 2671 if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION) |
| 2672 return false; |
| 2673 |
| 2674 // This is a prefetch resource that hasn't been used yet; those get a slight |
| 2675 // loosening of caching rules. |
| 2676 if (in_memory_info & HttpCache::HINT_UNUSED_SINCE_PREFETCH) |
| 2677 return false; |
| 2678 |
| 2679 // We need the entry to have zero lifetime to be able to tell it's expired |
| 2680 // w/o reading full headers --- an expiration date is hard to fit into a few |
| 2681 // bits. |
| 2682 if (!(in_memory_info & HttpCache::HINT_ZERO_LIFETIME)) |
| 2683 return false; |
| 2684 |
| 2685 // We also need to know that the entry can't be used for a conditional request |
| 2686 // (e.g. perhaps because it has neither ETag nor Last-Modified). |
| 2687 // |
| 2688 // This could potentially be refined to look at the actual request, since |
| 2689 // it may be unconditionalizable for reasons not captured in the hint. |
| 2690 if (!(in_memory_info & HttpCache::HINT_RESPONSE_CANT_CONDITIONALIZE)) |
| 2691 return false; |
| 2692 |
| 2693 return true; |
| 2694 } |
| 2695 |
| 2634 // We just received some headers from the server. We may have asked for a range, | 2696 // We just received some headers from the server. We may have asked for a range, |
| 2635 // in which case partial_ has an object. This could be the first network request | 2697 // in which case partial_ has an object. This could be the first network request |
| 2636 // we make to fulfill the original request, or we may be already reading (from | 2698 // we make to fulfill the original request, or we may be already reading (from |
| 2637 // the net and / or the cache). If we are not expecting a certain response, we | 2699 // the net and / or the cache). If we are not expecting a certain response, we |
| 2638 // just bypass the cache for this request (but again, maybe we are reading), and | 2700 // just bypass the cache for this request (but again, maybe we are reading), and |
| 2639 // delete partial_ (so we are not able to "fix" the headers that we return to | 2701 // delete partial_ (so we are not able to "fix" the headers that we return to |
| 2640 // the user). This results in either a weird response for the caller (we don't | 2702 // the user). This results in either a weird response for the caller (we don't |
| 2641 // expect it after all), or maybe a range that was not exactly what it was asked | 2703 // expect it after all), or maybe a range that was not exactly what it was asked |
| 2642 // for. | 2704 // for. |
| 2643 // | 2705 // |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2846 if (truncated) | 2908 if (truncated) |
| 2847 DCHECK_EQ(200, response_.headers->response_code()); | 2909 DCHECK_EQ(200, response_.headers->response_code()); |
| 2848 | 2910 |
| 2849 // When writing headers, we normally only write the non-transient headers. | 2911 // When writing headers, we normally only write the non-transient headers. |
| 2850 bool skip_transient_headers = true; | 2912 bool skip_transient_headers = true; |
| 2851 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); | 2913 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); |
| 2852 response_.Persist(data->pickle(), skip_transient_headers, truncated); | 2914 response_.Persist(data->pickle(), skip_transient_headers, truncated); |
| 2853 data->Done(); | 2915 data->Done(); |
| 2854 | 2916 |
| 2855 io_buf_len_ = data->pickle()->size(); | 2917 io_buf_len_ = data->pickle()->size(); |
| 2918 |
| 2919 // Summarize some info on cacheability in memory. |
| 2920 uint8_t hints = 0; |
| 2921 if (response_.headers->GetFreshnessLifetimes(response_.response_time) |
| 2922 .freshness.is_zero()) |
| 2923 hints |= HttpCache::HINT_ZERO_LIFETIME; |
| 2924 std::string etag_ignored, last_modified_ignored; |
| 2925 if (!ResponseConditionalizable(&etag_ignored, &last_modified_ignored)) |
| 2926 hints |= HttpCache::HINT_RESPONSE_CANT_CONDITIONALIZE; |
| 2927 if (response_.unused_since_prefetch) |
| 2928 hints |= HttpCache::HINT_UNUSED_SINCE_PREFETCH; |
| 2929 cache_->GetCurrentBackend()->SetEntryInMemoryData(cache_key_, hints); |
| 2930 |
| 2856 return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(), | 2931 return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(), |
| 2857 io_buf_len_, io_callback_, true); | 2932 io_buf_len_, io_callback_, true); |
| 2858 } | 2933 } |
| 2859 | 2934 |
| 2860 int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) { | 2935 int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) { |
| 2861 if (!entry_) | 2936 if (!entry_) |
| 2862 return OK; | 2937 return OK; |
| 2863 if (net_log_.IsCapturing()) { | 2938 if (net_log_.IsCapturing()) { |
| 2864 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_INFO, | 2939 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_INFO, |
| 2865 result); | 2940 result); |
| (...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3252 } | 3327 } |
| 3253 | 3328 |
| 3254 void HttpCache::Transaction::TransitionToState(State state) { | 3329 void HttpCache::Transaction::TransitionToState(State state) { |
| 3255 // Ensure that the state is only set once per Do* state. | 3330 // Ensure that the state is only set once per Do* state. |
| 3256 DCHECK(in_do_loop_); | 3331 DCHECK(in_do_loop_); |
| 3257 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; | 3332 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; |
| 3258 next_state_ = state; | 3333 next_state_ = state; |
| 3259 } | 3334 } |
| 3260 | 3335 |
| 3261 } // namespace net | 3336 } // namespace net |
| OLD | NEW |