| Index: net/http/http_cache_transaction.cc
|
| diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
|
| index d87bcd653353cc257da0ae8f9b12d927cd2e603d..37eb8c6d55ab646f97dca658c84570a122b44f96 100644
|
| --- a/net/http/http_cache_transaction.cc
|
| +++ b/net/http/http_cache_transaction.cc
|
| @@ -1061,6 +1061,14 @@ int HttpCache::Transaction::DoOpenEntryComplete(int result) {
|
| return OK;
|
| }
|
|
|
| + if (result == ERR_CACHE_ENTRY_NOT_SUITABLE) {
|
| + DCHECK_EQ(mode_, READ_WRITE);
|
| + // Record this as CantConditionalize, but otherwise proceed as we would
|
| + // below --- as OpenEntry has already dropped the old entry for us.
|
| + couldnt_conditionalize_request_ = true;
|
| + UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE);
|
| + }
|
| +
|
| if (method_ == "PUT" || method_ == "DELETE" ||
|
| (method_ == "HEAD" && mode_ == READ_WRITE)) {
|
| DCHECK(mode_ == READ_WRITE || mode_ == WRITE || method_ == "HEAD");
|
| @@ -2558,40 +2566,56 @@ 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 (method_ == "PUT" || 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;
|
| -
|
| - 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 (method_ == "PUT" || 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;
|
| +
|
| + DCHECK(response_.headers->response_code() != 206 ||
|
| + response_.headers->HasStrongValidators());
|
| +
|
| + 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 +2655,44 @@ bool HttpCache::Transaction::ConditionalizeRequest() {
|
| return true;
|
| }
|
|
|
| +bool HttpCache::Transaction::MaybeRejectBasedOnEntryInMemoryData(
|
| + uint8_t in_memory_info) {
|
| + // Not going to be clever with those...
|
| + if (partial_)
|
| + return false;
|
| +
|
| + // Unclear how to reconcile trying to avoid opening the entry with UPDATE's
|
| + // semantics.
|
| + if (mode_ == UPDATE)
|
| + return false;
|
| +
|
| + // If we are loading ignoring cache validity (aka back button), obviously
|
| + // can't reject things based on it.
|
| + if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION)
|
| + return false;
|
| +
|
| + // This is a prefetch resource that hasn't been used yet; those get a slight
|
| + // loosening of caching rules.
|
| + if (in_memory_info & HttpCache::HINT_UNUSED_SINCE_PREFETCH)
|
| + return false;
|
| +
|
| + // We need the entry to have zero lifetime to be able to tell it's expired
|
| + // w/o reading full headers --- an expiration date is hard to fit into a few
|
| + // bits.
|
| + if (!(in_memory_info & HttpCache::HINT_ZERO_LIFETIME))
|
| + return false;
|
| +
|
| + // We also need to know that the entry can't be used for a conditional request
|
| + // (e.g. perhaps because it has neither ETag nor Last-Modified).
|
| + //
|
| + // This could potentially be refined to look at the actual request, since
|
| + // it may be unconditionalizable for reasons not captured in the hint.
|
| + if (!(in_memory_info & HttpCache::HINT_RESPONSE_CANT_CONDITIONALIZE))
|
| + return false;
|
| +
|
| + return true;
|
| +}
|
| +
|
| // We just received some headers from the server. We may have asked for a range,
|
| // in which case partial_ has an object. This could be the first network request
|
| // we make to fulfill the original request, or we may be already reading (from
|
| @@ -2853,6 +2915,19 @@ int HttpCache::Transaction::WriteResponseInfoToEntry(bool truncated) {
|
| data->Done();
|
|
|
| io_buf_len_ = data->pickle()->size();
|
| +
|
| + // Summarize some info on cacheability in memory.
|
| + uint8_t hints = 0;
|
| + if (response_.headers->GetFreshnessLifetimes(response_.response_time)
|
| + .freshness.is_zero())
|
| + hints |= HttpCache::HINT_ZERO_LIFETIME;
|
| + std::string etag_ignored, last_modified_ignored;
|
| + if (!ResponseConditionalizable(&etag_ignored, &last_modified_ignored))
|
| + hints |= HttpCache::HINT_RESPONSE_CANT_CONDITIONALIZE;
|
| + if (response_.unused_since_prefetch)
|
| + hints |= HttpCache::HINT_UNUSED_SINCE_PREFETCH;
|
| + cache_->GetCurrentBackend()->SetEntryInMemoryData(cache_key_, hints);
|
| +
|
| return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(),
|
| io_buf_len_, io_callback_, true);
|
| }
|
|
|