Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1106)

Unified Diff: content/browser/loader/resource_dispatcher_host_impl.cc

Issue 1041993004: content::ResourceDispatcherHostImpl changes for stale-while-revalidate (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@s-w-r-yhirano-patch
Patch Set: Suppress duplicate async revalidations to the same URL. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/loader/resource_dispatcher_host_impl.cc
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index ade6e5d1648e01c3304f968789c526f469e63511..e24c17ad04ffee3e544d24aba406722a85d67cb7 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -19,6 +19,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "base/profiler/scoped_tracker.h"
@@ -41,6 +42,7 @@
#include "content/browser/loader/detachable_resource_handler.h"
#include "content/browser/loader/navigation_resource_handler.h"
#include "content/browser/loader/navigation_url_loader_impl_core.h"
+#include "content/browser/loader/null_resource_handler.h"
#include "content/browser/loader/power_save_block_resource_throttle.h"
#include "content/browser/loader/redirect_to_file_resource_handler.h"
#include "content/browser/loader/resource_message_filter.h"
@@ -89,6 +91,8 @@
#include "net/cookies/cookie_monster.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
+#include "net/http/http_transaction_factory.h"
+#include "net/http/http_util.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
@@ -416,6 +420,31 @@ void LogResourceRequestTimeOnUI(
}
}
+bool QualifiesForAsyncRevalidation(const ResourceHostMsg_Request& request) {
+ if (request.load_flags &
+ (net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE |
+ net::LOAD_VALIDATE_CACHE | net::LOAD_PREFERRING_CACHE |
+ net::LOAD_ONLY_FROM_CACHE)) {
+ return false;
+ }
+ if (request.method != "GET")
+ return false;
+ // A GET request should not have a body, but don't leave it to chance.
+ if (request.request_body.get())
+ return false;
+ if (!request.url.SchemeIsHTTPOrHTTPS())
+ return false;
+ return true;
+}
+
+std::pair<net::HttpCache*, std::string> AsyncRevalidationKey(
+ net::HttpTransactionFactory* http_transaction_factory,
+ const GURL& url) {
+ net::HttpCache* http_cache = http_transaction_factory->GetCache();
+ std::string url_key = net::HttpUtil::SpecForRequest(url);
+ return std::make_pair(http_cache, url_key);
+}
+
} // namespace
// static
@@ -429,14 +458,14 @@ ResourceDispatcherHostImpl::ResourceDispatcherHostImpl()
is_shutdown_(false),
num_in_flight_requests_(0),
max_num_in_flight_requests_(base::SharedMemory::GetHandleLimit()),
- max_num_in_flight_requests_per_process_(
- static_cast<int>(
- max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)),
+ max_num_in_flight_requests_per_process_(static_cast<int>(
+ max_num_in_flight_requests_ * kMaxRequestsPerProcessRatio)),
max_outstanding_requests_cost_per_process_(
kMaxOutstandingRequestsCostPerProcess),
filter_(NULL),
delegate_(NULL),
- allow_cross_origin_auth_prompt_(false) {
+ allow_cross_origin_auth_prompt_(false),
+ async_revalidation_enabled_(false) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!g_resource_dispatcher_host);
g_resource_dispatcher_host = this;
@@ -454,6 +483,12 @@ ResourceDispatcherHostImpl::ResourceDispatcherHostImpl()
update_load_states_timer_.reset(
new base::RepeatingTimer<ResourceDispatcherHostImpl>());
+
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (base::FieldTrialList::FindFullName("StaleWhileRevalidate") == "Enabled" ||
+ command_line->HasSwitch(switches::kEnableStaleWhileRevalidate)) {
+ async_revalidation_enabled_ = true;
+ }
}
ResourceDispatcherHostImpl::~ResourceDispatcherHostImpl() {
@@ -819,22 +854,25 @@ void ResourceDispatcherHostImpl::DidReceiveRedirect(ResourceLoader* loader,
void ResourceDispatcherHostImpl::DidReceiveResponse(ResourceLoader* loader) {
ResourceRequestInfoImpl* info = loader->GetRequestInfo();
-
- if (loader->request()->was_fetched_via_proxy() &&
- loader->request()->was_fetched_via_spdy() &&
- loader->request()->url().SchemeIs(url::kHttpScheme)) {
+ net::URLRequest* request = loader->request();
+ if (request->was_fetched_via_proxy() &&
+ request->was_fetched_via_spdy() &&
+ request->url().SchemeIs(url::kHttpScheme)) {
scheduler_->OnReceivedSpdyProxiedHttpResponse(
info->GetChildID(), info->GetRouteID());
}
+ if (request->response_info().async_revalidation_required)
+ BeginAsyncRevalidation(request);
+
int render_process_id, render_frame_host;
if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_host))
return;
// Notify the observers on the UI thread.
scoped_ptr<ResourceRequestDetails> detail(new ResourceRequestDetails(
- loader->request(),
- GetCertID(loader->request(), info->GetChildID())));
+ request,
+ GetCertID(request, info->GetChildID())));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(
@@ -1186,7 +1224,22 @@ void ResourceDispatcherHostImpl::BeginRequest(
AbortRequestBeforeItStarts(filter_, sync_result, request_id);
return;
}
+ bool is_async_revalidation = false;
+ BeginRequestFromData(request_id, request_data, sync_result, process_type,
+ child_id, route_id, is_async_revalidation,
+ request_context, resource_context);
+}
+void ResourceDispatcherHostImpl::BeginRequestFromData(
+ int request_id,
+ const ResourceHostMsg_Request& request_data,
+ IPC::Message* sync_result,
+ int process_type,
+ int child_id,
+ int route_id,
+ bool is_async_revalidation,
+ net::URLRequestContext* request_context,
+ ResourceContext* resource_context) {
// Construct the request.
scoped_ptr<net::URLRequest> new_request;
new_request = request_context->CreateRequest(
@@ -1259,6 +1312,13 @@ void ResourceDispatcherHostImpl::BeginRequest(
load_flags |= net::LOAD_DO_NOT_USE_EMBEDDED_IDENTITY;
}
+ // Check if request is eligible for async revalidation.
+ bool support_async_revalidation =
+ (async_revalidation_enabled_ && !is_sync_load && !is_async_revalidation &&
+ QualifiesForAsyncRevalidation(request_data));
+ if (support_async_revalidation)
+ load_flags |= net::LOAD_SUPPORT_ASYNC_REVALIDATION;
+
// Sync loads should have maximum priority and should be the only
// requets that have the ignore limits flag set.
if (is_sync_load) {
@@ -1292,7 +1352,9 @@ void ResourceDispatcherHostImpl::BeginRequest(
request_data.referrer_policy,
request_data.visiblity_state,
resource_context, filter_->GetWeakPtr(),
- !is_sync_load);
+ !is_sync_load,
+ is_async_revalidation,
+ support_async_revalidation ? &request_data : NULL);
// Request takes ownership.
extra_info->AssociateWithRequest(new_request.get());
@@ -1327,11 +1389,9 @@ void ResourceDispatcherHostImpl::BeginRequest(
request_data.appcache_host_id, request_data.resource_type,
request_data.should_reset_appcache);
- scoped_ptr<ResourceHandler> handler(
- CreateResourceHandler(
- new_request.get(),
- request_data, sync_result, route_id, process_type, child_id,
- resource_context));
+ scoped_ptr<ResourceHandler> handler(CreateResourceHandler(
+ new_request.get(), request_data, sync_result, route_id, process_type,
+ child_id, is_async_revalidation, resource_context));
if (handler)
BeginRequestInternal(new_request.Pass(), handler.Pass());
@@ -1344,6 +1404,7 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler(
int route_id,
int process_type,
int child_id,
+ bool is_async_revalidation,
ResourceContext* resource_context) {
// TODO(pkasting): Remove ScopedTracker below once crbug.com/456331 is fixed.
tracked_objects::ScopedTracker tracking_profile(
@@ -1360,6 +1421,10 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler(
}
handler.reset(new SyncResourceHandler(request, sync_result, this));
+ } else if (is_async_revalidation) {
+ handler.reset(new NullResourceHandler(
+ request, this, base::TimeDelta::FromSeconds(
+ kNullResourceHandlerDefaultReadTimeoutSecs)));
} else {
handler.reset(new AsyncResourceHandler(request, this));
@@ -1400,29 +1465,39 @@ scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::CreateResourceHandler(
handler.reset(new CrossSiteResourceHandler(handler.Pass(), request));
}
+ // The BufferedResourceHandler performs mime-type sniffing and redirecting of
+ // downloads and plugin-handled content. The first we don't need for an
+ // async_revalidation, and the second is dangerous.
+ if (!is_async_revalidation) {
+ handler = AddBufferedResourceHandler(request, handler.Pass());
+ }
+
return AddStandardHandlers(request, request_data.resource_type,
resource_context, filter_->appcache_service(),
child_id, route_id, handler.Pass());
}
-scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::AddStandardHandlers(
+scoped_ptr<ResourceHandler>
+ResourceDispatcherHostImpl::AddBufferedResourceHandler(
net::URLRequest* request,
- ResourceType resource_type,
- ResourceContext* resource_context,
- AppCacheService* appcache_service,
- int child_id,
- int route_id,
scoped_ptr<ResourceHandler> handler) {
-
PluginService* plugin_service = nullptr;
#if defined(ENABLE_PLUGINS)
plugin_service = PluginService::GetInstance();
#endif
// Insert a buffered event handler before the actual one.
- handler.reset(
- new BufferedResourceHandler(
- handler.Pass(), this, plugin_service, request));
+ return make_scoped_ptr(new BufferedResourceHandler(handler.Pass(), this,
+ plugin_service, request));
+}
+scoped_ptr<ResourceHandler> ResourceDispatcherHostImpl::AddStandardHandlers(
tyoshino (SeeGerritForStatus) 2015/06/12 08:20:44 now this should be called e.g. AddThrottlingResour
Adam Rice 2015/06/12 14:20:09 I tentatively renamed it AddThrottlesAndSchedule()
+ net::URLRequest* request,
+ ResourceType resource_type,
+ ResourceContext* resource_context,
+ AppCacheService* appcache_service,
+ int child_id,
+ int route_id,
+ scoped_ptr<ResourceHandler> handler) {
ScopedVector<ResourceThrottle> throttles;
if (delegate_) {
delegate_->RequestBeginning(request,
@@ -1553,7 +1628,9 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo(
blink::WebPageVisibilityStateVisible,
context,
base::WeakPtr<ResourceMessageFilter>(), // filter
- true); // is_async
+ true, // is_async
+ false, // is_async_revalidation
+ NULL); // original_message
}
void ResourceDispatcherHostImpl::OnRenderViewHostCreated(int child_id,
@@ -1704,7 +1781,8 @@ void ResourceDispatcherHostImpl::CancelRequestsForRoute(int child_id,
any_requests_transferring = true;
if (info->detachable_handler()) {
info->detachable_handler()->Detach();
- } else if (!info->IsDownload() && !info->is_stream() &&
+ } else if (!info->IsDownload() &&
+ !info->is_stream() && !info->IsAsyncRevalidation() &&
!IsTransferredNavigation(id) &&
(route_id == -1 || route_id == info->GetRouteID())) {
matching_requests.push_back(id);
@@ -1774,6 +1852,15 @@ void ResourceDispatcherHostImpl::RemovePendingRequest(int child_id,
void ResourceDispatcherHostImpl::RemovePendingLoader(
const LoaderMap::iterator& iter) {
ResourceRequestInfoImpl* info = iter->second->GetRequestInfo();
+ if (info->IsAsyncRevalidation()) {
+ net::URLRequest* request = iter->second->request();
+ auto async_revalidation_key =
+ AsyncRevalidationKey(request->context()->http_transaction_factory(),
+ request->original_url());
+ bool erased =
+ in_progress_async_revalidations_.erase(async_revalidation_key);
+ DCHECK(erased);
+ }
// Remove the memory credit that we added when pushing the request onto
// the pending list.
@@ -1999,7 +2086,9 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
blink::WebPageVisibilityStateVisible,
resource_context,
base::WeakPtr<ResourceMessageFilter>(), // filter
- true);
+ true, // is_async
+ false, // is_async_revalidation
+ NULL); // original_message
// Request takes ownership.
extra_info->AssociateWithRequest(new_request.get());
@@ -2023,12 +2112,12 @@ void ResourceDispatcherHostImpl::BeginNavigationRequest(
// TODO(davidben): Pass in the appropriate appcache_service. Also fix the
// dependency on child_id/route_id. Those are used by the ResourceScheduler;
// currently it's a no-op.
- handler = AddStandardHandlers(new_request.get(), resource_type,
- resource_context,
- nullptr, // appcache_service
- -1, // child_id
- -1, // route_id
- handler.Pass());
+ handler = AddStandardHandlers(
+ new_request.get(), resource_type, resource_context,
+ nullptr, // appcache_service
+ -1, // child_id
+ -1, // route_id
+ AddBufferedResourceHandler(new_request.get(), handler.Pass()));
BeginRequestInternal(new_request.Pass(), handler.Pass());
}
@@ -2372,4 +2461,52 @@ int ResourceDispatcherHostImpl::BuildLoadFlagsForRequest(
return load_flags;
}
+void ResourceDispatcherHostImpl::BeginAsyncRevalidation(
+ net::URLRequest* for_request) {
+ ResourceRequestInfoImpl* info =
+ ResourceRequestInfoImpl::ForRequest(for_request);
+ DCHECK(info);
+ DCHECK(!info->IsAsyncRevalidation());
+ ResourceHostMsg_Request* original_request = info->original_request();
tyoshino (SeeGerritForStatus) 2015/06/12 08:20:44 original_request_data?
Adam Rice 2015/06/12 14:20:09 Done.
+ DCHECK(original_request);
tyoshino (SeeGerritForStatus) 2015/06/12 08:20:43 blank line
Adam Rice 2015/06/12 14:20:09 Done.
+ ResourceHostMsg_Request new_request = *original_request;
tyoshino (SeeGerritForStatus) 2015/06/12 08:20:44 new_request_data?
Adam Rice 2015/06/12 14:20:09 Done.
+ new_request.do_not_prompt_for_login = true;
+ new_request.allow_download = false;
+ new_request.enable_load_timing = false;
+ new_request.download_to_file = false;
+ new_request.transferred_request_child_id = -1;
+ new_request.transferred_request_request_id = -1;
+ new_request.priority = net::MINIMUM_PRIORITY;
tyoshino (SeeGerritForStatus) 2015/06/12 08:20:44 blank line
Adam Rice 2015/06/12 14:20:09 Done.
+ int process_type = PROCESS_TYPE_BROWSER;
+ int child_id = info->GetChildID();
+ int route_id = info->GetRouteID();
+ int request_id = --request_id_;
+ bool is_async_revalidation = true;
tyoshino (SeeGerritForStatus) 2015/06/12 08:20:44 blink line
Adam Rice 2015/06/12 14:20:09 Done.
+ ResourceContext* resource_context = NULL;
+ net::URLRequestContext* request_context = NULL;
+ // TODO(ricea): How can we ensure that resource_context and request_context
+ // live long enough to service the request?
+ info->filter()->GetContexts(new_request, &resource_context, &request_context);
+ if (is_shutdown_ || (delegate_ &&
+ !delegate_->ShouldBeginRequest(
+ new_request.method, new_request.url,
+ new_request.resource_type, resource_context))) {
+ return;
+ }
tyoshino (SeeGerritForStatus) 2015/06/12 08:20:44 blank line
Adam Rice 2015/06/12 14:20:09 Done.
+ auto async_revalidation_key = AsyncRevalidationKey(
+ request_context->http_transaction_factory(), original_request->url);
+ if (!in_progress_async_revalidations_.insert(async_revalidation_key).second) {
+ // A matching async revalidation is already in progress for this cache; we
+ // don't need another one.
+ return;
+ }
+ CHECK(ContainsKey(active_resource_contexts_, resource_context));
tyoshino (SeeGerritForStatus) 2015/06/12 08:20:44 blank line
Adam Rice 2015/06/12 14:20:09 Done.
+ // TODO(ricea): Make filter_ be passed around in a sane way.
+ filter_ = info->filter();
+ BeginRequestFromData(request_id, new_request, NULL, process_type, child_id,
+ route_id, is_async_revalidation, request_context,
+ resource_context);
+ filter_ = NULL;
+}
+
} // namespace content
« no previous file with comments | « content/browser/loader/resource_dispatcher_host_impl.h ('k') | content/browser/loader/resource_dispatcher_host_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698