| Index: net/http/http_cache_transaction.cc
|
| diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
|
| index 518944650747e6a3dc7f39c58b4b4d7cb1610758..1a0fd493a98bb22c61a9974b8e3d04331851d8c2 100644
|
| --- a/net/http/http_cache_transaction.cc
|
| +++ b/net/http/http_cache_transaction.cc
|
| @@ -69,6 +69,22 @@ void RecordNoStoreHeaderHistogram(int load_flags,
|
| }
|
| }
|
|
|
| +disk_cache::Backend::OracleJudgement CheckIfUnusable(uint8_t flags) {
|
| + // If the entry is marked as an unused prefetch, we have to open it up
|
| + // to check.
|
| + if (flags & HttpCache::OBH_UNUSED_SINCE_PREFETCH)
|
| + return disk_cache::Backend::OracleJudgement::HIT;
|
| + if ((flags & HttpCache::OBH_ZERO_LIFETIME) &&
|
| + (flags & HttpCache::OBH_RESPONSE_CANT_CONDITIONALIZE)) {
|
| + // TODO(morlovich): Just zero-lifetime is sufficient for e.g.
|
| + // PUT/DELETE, also could potentially encode vary-mismatch case.
|
| + return disk_cache::Backend::OracleJudgement::MISS_AND_DOOM;
|
| + }
|
| +
|
| + // Default
|
| + return disk_cache::Backend::OracleJudgement::HIT;
|
| +}
|
| +
|
| } // namespace
|
|
|
| #define CACHE_STATUS_HISTOGRAMS(type) \
|
| @@ -991,7 +1007,12 @@ int HttpCache::Transaction::DoOpenEntry() {
|
| cache_pending_ = true;
|
| net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_OPEN_ENTRY);
|
| first_cache_access_since_ = TimeTicks::Now();
|
| - return cache_->OpenEntry(cache_key_, &new_entry_, this);
|
| + // See if we could potentially quick reject the entry.
|
| + if (!(effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION))
|
| + return cache_->OpenEntry(cache_key_, &new_entry_,
|
| + base::Bind(&CheckIfUnusable), this);
|
| + return cache_->OpenEntry(cache_key_, &new_entry_,
|
| + disk_cache::Backend::OracleCallback(), this);
|
| }
|
|
|
| int HttpCache::Transaction::DoOpenEntryComplete(int result) {
|
| @@ -2337,40 +2358,57 @@ bool HttpCache::Transaction::RequiresValidation() {
|
| return validation_required_by_headers;
|
| }
|
|
|
| -bool HttpCache::Transaction::ConditionalizeRequest() {
|
| +bool HttpCache::Transaction::ResponseConditionalizable(
|
| + std::string* etag_value,
|
| + std::string* last_modified_value) {
|
| DCHECK(response_.headers.get());
|
|
|
| - if (request_->method == "PUT" || request_->method == "DELETE")
|
| - return false;
|
| -
|
| // This only makes sense for cached 200 or 206 responses.
|
| if (response_.headers->response_code() != 200 &&
|
| response_.headers->response_code() != 206) {
|
| return false;
|
| }
|
|
|
| - if (fail_conditionalization_for_test_)
|
| - return false;
|
| -
|
| + // ### this looks scary.
|
| DCHECK(response_.headers->response_code() != 206 ||
|
| response_.headers->HasStrongValidators());
|
|
|
| // Just use the first available ETag and/or Last-Modified header value.
|
| // TODO(darin): Or should we use the last?
|
|
|
| - std::string etag_value;
|
| if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1))
|
| - response_.headers->EnumerateHeader(NULL, "etag", &etag_value);
|
| + response_.headers->EnumerateHeader(NULL, "etag", etag_value);
|
|
|
| - std::string last_modified_value;
|
| - if (!vary_mismatch_) {
|
| - response_.headers->EnumerateHeader(NULL, "last-modified",
|
| - &last_modified_value);
|
| - }
|
| + response_.headers->EnumerateHeader(NULL, "last-modified",
|
| + last_modified_value);
|
| +
|
| + if (etag_value->empty() && last_modified_value->empty())
|
| + return false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool HttpCache::Transaction::ConditionalizeRequest() {
|
| + DCHECK(response_.headers.get());
|
|
|
| - if (etag_value.empty() && last_modified_value.empty())
|
| + if (request_->method == "PUT" || request_->method == "DELETE")
|
| + return false;
|
| +
|
| + if (fail_conditionalization_for_test_)
|
| return false;
|
|
|
| + std::string etag_value;
|
| + std::string last_modified_value;
|
| + if (!ResponseConditionalizable(&etag_value, &last_modified_value))
|
| + return false;
|
| +
|
| + if (vary_mismatch_) {
|
| + // Can't rely on last-modified if vary is different.
|
| + last_modified_value.clear();
|
| + if (etag_value.empty())
|
| + return false;
|
| + }
|
| +
|
| if (!partial_) {
|
| // Need to customize the request, so this forces us to allocate :(
|
| custom_request_.reset(new HttpRequestInfo(*request_));
|
| @@ -2631,6 +2669,19 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
|
| data->Done();
|
|
|
| io_buf_len_ = data->pickle()->size();
|
| +
|
| + uint8_t hints = 0;
|
| + // ### recomputing this too much?
|
| + if (response_.headers->GetFreshnessLifetimes(response_.response_time)
|
| + .freshness.is_zero())
|
| + hints |= HttpCache::OBH_ZERO_LIFETIME;
|
| + std::string etag_ignored, last_modified_ignored;
|
| + if (!ResponseConditionalizable(&etag_ignored, &last_modified_ignored))
|
| + hints |= HttpCache::OBH_RESPONSE_CANT_CONDITIONALIZE;
|
| + if (response_.unused_since_prefetch)
|
| + hints |= HttpCache::OBH_UNUSED_SINCE_PREFETCH;
|
| + entry_->disk_entry->SetOracleByte(hints);
|
| +
|
| return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(),
|
| io_buf_len_, io_callback_, true);
|
| }
|
|
|