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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 | 62 |
63 void RecordNoStoreHeaderHistogram(int load_flags, | 63 void RecordNoStoreHeaderHistogram(int load_flags, |
64 const HttpResponseInfo* response) { | 64 const HttpResponseInfo* response) { |
65 if (load_flags & LOAD_MAIN_FRAME_DEPRECATED) { | 65 if (load_flags & LOAD_MAIN_FRAME_DEPRECATED) { |
66 UMA_HISTOGRAM_BOOLEAN( | 66 UMA_HISTOGRAM_BOOLEAN( |
67 "Net.MainFrameNoStore", | 67 "Net.MainFrameNoStore", |
68 response->headers->HasHeaderValue("cache-control", "no-store")); | 68 response->headers->HasHeaderValue("cache-control", "no-store")); |
69 } | 69 } |
70 } | 70 } |
71 | 71 |
| 72 disk_cache::Backend::OracleJudgement CheckIfUnusable(uint8_t flags) { |
| 73 // If the entry is marked as an unused prefetch, we have to open it up |
| 74 // to check. |
| 75 if (flags & HttpCache::OBH_UNUSED_SINCE_PREFETCH) |
| 76 return disk_cache::Backend::OracleJudgement::HIT; |
| 77 if ((flags & HttpCache::OBH_ZERO_LIFETIME) && |
| 78 (flags & HttpCache::OBH_RESPONSE_CANT_CONDITIONALIZE)) { |
| 79 // TODO(morlovich): Just zero-lifetime is sufficient for e.g. |
| 80 // PUT/DELETE, also could potentially encode vary-mismatch case. |
| 81 return disk_cache::Backend::OracleJudgement::MISS_AND_DOOM; |
| 82 } |
| 83 |
| 84 // Default |
| 85 return disk_cache::Backend::OracleJudgement::HIT; |
| 86 } |
| 87 |
72 } // namespace | 88 } // namespace |
73 | 89 |
74 #define CACHE_STATUS_HISTOGRAMS(type) \ | 90 #define CACHE_STATUS_HISTOGRAMS(type) \ |
75 do { \ | 91 do { \ |
76 UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern" type, cache_entry_status_, \ | 92 UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern" type, cache_entry_status_, \ |
77 CacheEntryStatus::ENTRY_MAX); \ | 93 CacheEntryStatus::ENTRY_MAX); \ |
78 if (validation_request) { \ | 94 if (validation_request) { \ |
79 UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause" type, \ | 95 UMA_HISTOGRAM_ENUMERATION("HttpCache.ValidationCause" type, \ |
80 validation_cause_, VALIDATION_CAUSE_MAX); \ | 96 validation_cause_, VALIDATION_CAUSE_MAX); \ |
81 } \ | 97 } \ |
(...skipping 902 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
984 return OK; | 1000 return OK; |
985 } | 1001 } |
986 | 1002 |
987 int HttpCache::Transaction::DoOpenEntry() { | 1003 int HttpCache::Transaction::DoOpenEntry() { |
988 TRACE_EVENT0("io", "HttpCacheTransaction::DoOpenEntry"); | 1004 TRACE_EVENT0("io", "HttpCacheTransaction::DoOpenEntry"); |
989 DCHECK(!new_entry_); | 1005 DCHECK(!new_entry_); |
990 TransitionToState(STATE_OPEN_ENTRY_COMPLETE); | 1006 TransitionToState(STATE_OPEN_ENTRY_COMPLETE); |
991 cache_pending_ = true; | 1007 cache_pending_ = true; |
992 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_OPEN_ENTRY); | 1008 net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_OPEN_ENTRY); |
993 first_cache_access_since_ = TimeTicks::Now(); | 1009 first_cache_access_since_ = TimeTicks::Now(); |
994 return cache_->OpenEntry(cache_key_, &new_entry_, this); | 1010 // See if we could potentially quick reject the entry. |
| 1011 if (!(effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION)) |
| 1012 return cache_->OpenEntry(cache_key_, &new_entry_, |
| 1013 base::Bind(&CheckIfUnusable), this); |
| 1014 return cache_->OpenEntry(cache_key_, &new_entry_, |
| 1015 disk_cache::Backend::OracleCallback(), this); |
995 } | 1016 } |
996 | 1017 |
997 int HttpCache::Transaction::DoOpenEntryComplete(int result) { | 1018 int HttpCache::Transaction::DoOpenEntryComplete(int result) { |
998 TRACE_EVENT0("io", "HttpCacheTransaction::DoOpenEntryComplete"); | 1019 TRACE_EVENT0("io", "HttpCacheTransaction::DoOpenEntryComplete"); |
999 // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is | 1020 // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is |
1000 // OK, otherwise the cache will end up with an active entry without any | 1021 // OK, otherwise the cache will end up with an active entry without any |
1001 // transaction attached. | 1022 // transaction attached. |
1002 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_OPEN_ENTRY, | 1023 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_OPEN_ENTRY, |
1003 result); | 1024 result); |
1004 cache_pending_ = false; | 1025 cache_pending_ = false; |
(...skipping 1325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2330 stale_entry_freshness_ = lifetimes.freshness; | 2351 stale_entry_freshness_ = lifetimes.freshness; |
2331 stale_entry_age_ = response_.headers->GetCurrentAge( | 2352 stale_entry_age_ = response_.headers->GetCurrentAge( |
2332 response_.request_time, response_.response_time, | 2353 response_.request_time, response_.response_time, |
2333 cache_->clock_->Now()); | 2354 cache_->clock_->Now()); |
2334 } | 2355 } |
2335 } | 2356 } |
2336 | 2357 |
2337 return validation_required_by_headers; | 2358 return validation_required_by_headers; |
2338 } | 2359 } |
2339 | 2360 |
| 2361 bool HttpCache::Transaction::ResponseConditionalizable( |
| 2362 std::string* etag_value, |
| 2363 std::string* last_modified_value) { |
| 2364 DCHECK(response_.headers.get()); |
| 2365 |
| 2366 // This only makes sense for cached 200 or 206 responses. |
| 2367 if (response_.headers->response_code() != 200 && |
| 2368 response_.headers->response_code() != 206) { |
| 2369 return false; |
| 2370 } |
| 2371 |
| 2372 // ### this looks scary. |
| 2373 DCHECK(response_.headers->response_code() != 206 || |
| 2374 response_.headers->HasStrongValidators()); |
| 2375 |
| 2376 // Just use the first available ETag and/or Last-Modified header value. |
| 2377 // TODO(darin): Or should we use the last? |
| 2378 |
| 2379 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) |
| 2380 response_.headers->EnumerateHeader(NULL, "etag", etag_value); |
| 2381 |
| 2382 response_.headers->EnumerateHeader(NULL, "last-modified", |
| 2383 last_modified_value); |
| 2384 |
| 2385 if (etag_value->empty() && last_modified_value->empty()) |
| 2386 return false; |
| 2387 |
| 2388 return true; |
| 2389 } |
| 2390 |
2340 bool HttpCache::Transaction::ConditionalizeRequest() { | 2391 bool HttpCache::Transaction::ConditionalizeRequest() { |
2341 DCHECK(response_.headers.get()); | 2392 DCHECK(response_.headers.get()); |
2342 | 2393 |
2343 if (request_->method == "PUT" || request_->method == "DELETE") | 2394 if (request_->method == "PUT" || request_->method == "DELETE") |
2344 return false; | 2395 return false; |
2345 | 2396 |
2346 // This only makes sense for cached 200 or 206 responses. | |
2347 if (response_.headers->response_code() != 200 && | |
2348 response_.headers->response_code() != 206) { | |
2349 return false; | |
2350 } | |
2351 | |
2352 if (fail_conditionalization_for_test_) | 2397 if (fail_conditionalization_for_test_) |
2353 return false; | 2398 return false; |
2354 | 2399 |
2355 DCHECK(response_.headers->response_code() != 206 || | 2400 std::string etag_value; |
2356 response_.headers->HasStrongValidators()); | 2401 std::string last_modified_value; |
| 2402 if (!ResponseConditionalizable(&etag_value, &last_modified_value)) |
| 2403 return false; |
2357 | 2404 |
2358 // Just use the first available ETag and/or Last-Modified header value. | 2405 if (vary_mismatch_) { |
2359 // TODO(darin): Or should we use the last? | 2406 // Can't rely on last-modified if vary is different. |
2360 | 2407 last_modified_value.clear(); |
2361 std::string etag_value; | 2408 if (etag_value.empty()) |
2362 if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1)) | 2409 return false; |
2363 response_.headers->EnumerateHeader(NULL, "etag", &etag_value); | |
2364 | |
2365 std::string last_modified_value; | |
2366 if (!vary_mismatch_) { | |
2367 response_.headers->EnumerateHeader(NULL, "last-modified", | |
2368 &last_modified_value); | |
2369 } | 2410 } |
2370 | 2411 |
2371 if (etag_value.empty() && last_modified_value.empty()) | |
2372 return false; | |
2373 | |
2374 if (!partial_) { | 2412 if (!partial_) { |
2375 // Need to customize the request, so this forces us to allocate :( | 2413 // Need to customize the request, so this forces us to allocate :( |
2376 custom_request_.reset(new HttpRequestInfo(*request_)); | 2414 custom_request_.reset(new HttpRequestInfo(*request_)); |
2377 request_ = custom_request_.get(); | 2415 request_ = custom_request_.get(); |
2378 } | 2416 } |
2379 DCHECK(custom_request_.get()); | 2417 DCHECK(custom_request_.get()); |
2380 | 2418 |
2381 bool use_if_range = | 2419 bool use_if_range = |
2382 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_; | 2420 partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_; |
2383 | 2421 |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2624 if (truncated) | 2662 if (truncated) |
2625 DCHECK_EQ(200, response_.headers->response_code()); | 2663 DCHECK_EQ(200, response_.headers->response_code()); |
2626 | 2664 |
2627 // When writing headers, we normally only write the non-transient headers. | 2665 // When writing headers, we normally only write the non-transient headers. |
2628 bool skip_transient_headers = true; | 2666 bool skip_transient_headers = true; |
2629 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); | 2667 scoped_refptr<PickledIOBuffer> data(new PickledIOBuffer()); |
2630 response_.Persist(data->pickle(), skip_transient_headers, truncated); | 2668 response_.Persist(data->pickle(), skip_transient_headers, truncated); |
2631 data->Done(); | 2669 data->Done(); |
2632 | 2670 |
2633 io_buf_len_ = data->pickle()->size(); | 2671 io_buf_len_ = data->pickle()->size(); |
| 2672 |
| 2673 uint8_t hints = 0; |
| 2674 // ### recomputing this too much? |
| 2675 if (response_.headers->GetFreshnessLifetimes(response_.response_time) |
| 2676 .freshness.is_zero()) |
| 2677 hints |= HttpCache::OBH_ZERO_LIFETIME; |
| 2678 std::string etag_ignored, last_modified_ignored; |
| 2679 if (!ResponseConditionalizable(&etag_ignored, &last_modified_ignored)) |
| 2680 hints |= HttpCache::OBH_RESPONSE_CANT_CONDITIONALIZE; |
| 2681 if (response_.unused_since_prefetch) |
| 2682 hints |= HttpCache::OBH_UNUSED_SINCE_PREFETCH; |
| 2683 entry_->disk_entry->SetOracleByte(hints); |
| 2684 |
2634 return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(), | 2685 return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(), |
2635 io_buf_len_, io_callback_, true); | 2686 io_buf_len_, io_callback_, true); |
2636 } | 2687 } |
2637 | 2688 |
2638 int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) { | 2689 int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) { |
2639 if (!entry_) | 2690 if (!entry_) |
2640 return OK; | 2691 return OK; |
2641 if (net_log_.IsCapturing()) { | 2692 if (net_log_.IsCapturing()) { |
2642 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_INFO, | 2693 net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_INFO, |
2643 result); | 2694 result); |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3017 } | 3068 } |
3018 | 3069 |
3019 void HttpCache::Transaction::TransitionToState(State state) { | 3070 void HttpCache::Transaction::TransitionToState(State state) { |
3020 // Ensure that the state is only set once per Do* state. | 3071 // Ensure that the state is only set once per Do* state. |
3021 DCHECK(in_do_loop_); | 3072 DCHECK(in_do_loop_); |
3022 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; | 3073 DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state; |
3023 next_state_ = state; | 3074 next_state_ = state; |
3024 } | 3075 } |
3025 | 3076 |
3026 } // namespace net | 3077 } // namespace net |
OLD | NEW |