| Index: net/http/http_cache_transaction.cc
|
| diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
|
| index b06e8f3a272b4df533756a423f5a5fc0b321b532..5e901316f486f39bfa2fed42db3ccf33ae5192c6 100644
|
| --- a/net/http/http_cache_transaction.cc
|
| +++ b/net/http/http_cache_transaction.cc
|
| @@ -17,6 +17,7 @@
|
| #include "base/compiler_specific.h"
|
| #include "base/format_macros.h"
|
| #include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| #include "base/metrics/field_trial.h"
|
| #include "base/metrics/histogram.h"
|
| #include "base/metrics/sparse_histogram.h"
|
| @@ -26,6 +27,7 @@
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/time/time.h"
|
| +#include "base/values.h"
|
| #include "net/base/completion_callback.h"
|
| #include "net/base/io_buffer.h"
|
| #include "net/base/load_flags.h"
|
| @@ -238,6 +240,18 @@ void RecordNoStoreHeaderHistogram(int load_flags,
|
| }
|
| }
|
|
|
| +base::Value* NetLogAsyncRevalidationInfoCallback(
|
| + const net::NetLog::Source& source,
|
| + const net::HttpRequestInfo* request,
|
| + net::NetLog::LogLevel log_level) {
|
| + base::DictionaryValue* dict = new base::DictionaryValue();
|
| + source.AddToEventParameters(dict);
|
| +
|
| + dict->SetString("url", request->url.possibly_invalid_spec());
|
| + dict->SetString("method", request->method);
|
| + return dict;
|
| +}
|
| +
|
| enum ExternallyConditionalizedType {
|
| EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION,
|
| EXTERNALLY_CONDITIONALIZED_CACHE_USABLE,
|
| @@ -2110,7 +2124,16 @@ int HttpCache::Transaction::BeginCacheRead() {
|
| int HttpCache::Transaction::BeginCacheValidation() {
|
| DCHECK(mode_ == READ_WRITE);
|
|
|
| - bool skip_validation = !RequiresValidation();
|
| + ValidationType required_validation = RequiresValidation();
|
| +
|
| + bool skip_validation = (required_validation == VALIDATION_NONE);
|
| +
|
| + if (required_validation == VALIDATION_ASYNCHRONOUS &&
|
| + !(request_->method == "GET" && (truncated_ || partial_)) && cache_ &&
|
| + cache_->use_stale_while_revalidate()) {
|
| + TriggerAsyncValidation();
|
| + skip_validation = true;
|
| + }
|
|
|
| if (request_->method == "HEAD" &&
|
| (truncated_ || response_.headers->response_code() == 206)) {
|
| @@ -2140,6 +2163,7 @@ int HttpCache::Transaction::BeginCacheValidation() {
|
| }
|
|
|
| if (skip_validation) {
|
| + // TODO(ricea): Is this pattern okay for asynchronous revalidations?
|
| UpdateTransactionPattern(PATTERN_ENTRY_USED);
|
| RecordOfflineStatus(effective_load_flags_, OFFLINE_STATUS_FRESH_CACHE);
|
| return SetupEntryForRead();
|
| @@ -2295,37 +2319,42 @@ int HttpCache::Transaction::RestartNetworkRequestWithAuth(
|
| return rv;
|
| }
|
|
|
| -bool HttpCache::Transaction::RequiresValidation() {
|
| +ValidationType HttpCache::Transaction::RequiresValidation() {
|
| // TODO(darin): need to do more work here:
|
| // - make sure we have a matching request method
|
| // - watch out for cached responses that depend on authentication
|
|
|
| // In playback mode, nothing requires validation.
|
| if (cache_->mode() == net::HttpCache::PLAYBACK)
|
| - return false;
|
| + return VALIDATION_NONE;
|
|
|
| if (response_.vary_data.is_valid() &&
|
| !response_.vary_data.MatchesRequest(*request_,
|
| *response_.headers.get())) {
|
| vary_mismatch_ = true;
|
| - return true;
|
| + return VALIDATION_SYNCHRONOUS;
|
| }
|
|
|
| if (effective_load_flags_ & LOAD_PREFERRING_CACHE)
|
| - return false;
|
| + return VALIDATION_NONE;
|
|
|
| - if (effective_load_flags_ & LOAD_VALIDATE_CACHE)
|
| - return true;
|
| + if (effective_load_flags_ & (LOAD_VALIDATE_CACHE | LOAD_ASYNC_REVALIDATION))
|
| + return VALIDATION_SYNCHRONOUS;
|
|
|
| if (request_->method == "PUT" || request_->method == "DELETE")
|
| - return true;
|
| + return VALIDATION_SYNCHRONOUS;
|
|
|
| - if (response_.headers->RequiresValidation(
|
| - response_.request_time, response_.response_time, Time::Now())) {
|
| - return true;
|
| + ValidationType validation_required_by_headers =
|
| + response_.headers->RequiresValidation(
|
| + response_.request_time, response_.response_time, Time::Now());
|
| +
|
| + if (validation_required_by_headers == VALIDATION_ASYNCHRONOUS) {
|
| + // Asynchronous revalidation is only supported for GET and HEAD methods.
|
| + if (request_->method != "GET" && request_->method != "HEAD")
|
| + return VALIDATION_SYNCHRONOUS;
|
| }
|
|
|
| - return false;
|
| + return validation_required_by_headers;
|
| }
|
|
|
| bool HttpCache::Transaction::ConditionalizeRequest() {
|
| @@ -2374,12 +2403,9 @@ bool HttpCache::Transaction::ConditionalizeRequest() {
|
| if (!use_if_range) {
|
| // stale-while-revalidate is not useful when we only have a partial response
|
| // cached, so don't set the header in that case.
|
| - TimeDelta stale_while_revalidate;
|
| - if (response_.headers->GetStaleWhileRevalidateValue(
|
| - &stale_while_revalidate) &&
|
| - stale_while_revalidate > TimeDelta()) {
|
| - TimeDelta max_age =
|
| - response_.headers->GetFreshnessLifetime(response_.response_time);
|
| + HttpResponseHeaders::FreshnessLifetimes lifetime =
|
| + response_.headers->GetFreshnessLifetimes(response_.response_time);
|
| + if (lifetime.stale > TimeDelta()) {
|
| TimeDelta current_age = response_.headers->GetCurrentAge(
|
| response_.request_time, response_.response_time, Time::Now());
|
|
|
| @@ -2387,8 +2413,8 @@ bool HttpCache::Transaction::ConditionalizeRequest() {
|
| kFreshnessHeader,
|
| base::StringPrintf("max-age=%" PRId64
|
| ",stale-while-revalidate=%" PRId64 ",age=%" PRId64,
|
| - max_age.InSeconds(),
|
| - stale_while_revalidate.InSeconds(),
|
| + lifetime.fresh.InSeconds(),
|
| + lifetime.stale.InSeconds(),
|
| current_age.InSeconds()));
|
| }
|
| }
|
| @@ -2557,6 +2583,25 @@ void HttpCache::Transaction::FixHeadersForHead() {
|
| }
|
| }
|
|
|
| +void HttpCache::Transaction::TriggerAsyncValidation() {
|
| + DCHECK(!request_->upload_data_stream);
|
| + BoundNetLog async_revalidation_net_log(
|
| + BoundNetLog::Make(net_log_.net_log(), NetLog::SOURCE_ASYNC_REVALIDATION));
|
| + net_log_.AddEvent(
|
| + NetLog::TYPE_HTTP_CACHE_VALIDATE_RESOURCE_ASYNC,
|
| + async_revalidation_net_log.source().ToEventParametersCallback());
|
| + async_revalidation_net_log.BeginEvent(
|
| + NetLog::TYPE_ASYNC_REVALIDATION,
|
| + base::Bind(
|
| + &NetLogAsyncRevalidationInfoCallback, net_log_.source(), request_));
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&HttpCache::PerformAsyncValidation,
|
| + cache_, // cache_ is a weak pointer.
|
| + *request_,
|
| + async_revalidation_net_log));
|
| +}
|
| +
|
| void HttpCache::Transaction::FailRangeRequest() {
|
| response_ = *new_response_;
|
| partial_->FixResponseHeaders(response_.headers.get(), false);
|
|
|