From a17df45d963ff3291fd59c80c328300c0c19e593 Mon Sep 17 00:00:00 2001 From: "simonjam@chromium.org" Date: Fri, 15 Feb 2013 11:12:46 +0000 Subject: Create a ResourceMessageDelegate interface to allow ResourceLoaders to directly receive IPC messages. BUG=None Review URL: https://chromiumcodereview.appspot.com/12212059 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182668 0039d316-1c4b-4281-b951-d872f2087c98 --- content/browser/loader/async_resource_handler.cc | 24 ++++--- content/browser/loader/async_resource_handler.h | 16 +++-- .../loader/resource_dispatcher_host_impl.cc | 79 +++++++++++++--------- .../browser/loader/resource_dispatcher_host_impl.h | 18 +++-- .../browser/loader/resource_message_delegate.cc | 24 +++++++ content/browser/loader/resource_message_delegate.h | 42 ++++++++++++ .../browser/loader/resource_request_info_impl.cc | 12 ++-- .../browser/loader/resource_request_info_impl.h | 14 +--- content/common/resource_messages.h | 2 + content/content_browser.gypi | 2 + 10 files changed, 166 insertions(+), 67 deletions(-) create mode 100644 content/browser/loader/resource_message_delegate.cc create mode 100644 content/browser/loader/resource_message_delegate.h (limited to 'content') diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc index 5fa77c0..da6fa8e 100644 --- a/content/browser/loader/async_resource_handler.cc +++ b/content/browser/loader/async_resource_handler.cc @@ -83,7 +83,8 @@ AsyncResourceHandler::AsyncResourceHandler( int routing_id, net::URLRequest* request, ResourceDispatcherHostImpl* rdh) - : filter_(filter), + : ResourceMessageDelegate(request), + filter_(filter), routing_id_(routing_id), request_(request), rdh_(rdh), @@ -92,20 +93,25 @@ AsyncResourceHandler::AsyncResourceHandler( did_defer_(false), sent_received_response_msg_(false), sent_first_data_msg_(false) { - // Set a back-pointer from ResourceRequestInfoImpl to |this|, so that the - // ResourceDispatcherHostImpl can send us IPC messages. - // TODO(darin): Implement an IPC message filter instead? - ResourceRequestInfoImpl::ForRequest(request_)->set_async_handler(this); - InitializeResourceBufferConstants(); } AsyncResourceHandler::~AsyncResourceHandler() { - // Cleanup back-pointer stored on the request info. - ResourceRequestInfoImpl::ForRequest(request_)->set_async_handler(NULL); +} + +bool AsyncResourceHandler::OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP_EX(AsyncResourceHandler, message, *message_was_ok) + IPC_MESSAGE_HANDLER(ResourceHostMsg_FollowRedirect, OnFollowRedirect) + IPC_MESSAGE_HANDLER(ResourceHostMsg_DataReceived_ACK, OnDataReceivedACK) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP_EX() + return handled; } void AsyncResourceHandler::OnFollowRedirect( + int request_id, bool has_new_first_party_for_cookies, const GURL& new_first_party_for_cookies) { if (!request_->status().is_success()) { @@ -119,7 +125,7 @@ void AsyncResourceHandler::OnFollowRedirect( ResumeIfDeferred(); } -void AsyncResourceHandler::OnDataReceivedACK() { +void AsyncResourceHandler::OnDataReceivedACK(int request_id) { --pending_data_count_; buffer_->RecycleLeastRecentlyAllocated(); diff --git a/content/browser/loader/async_resource_handler.h b/content/browser/loader/async_resource_handler.h index fb4ffce..3ea9583 100644 --- a/content/browser/loader/async_resource_handler.h +++ b/content/browser/loader/async_resource_handler.h @@ -9,6 +9,7 @@ #include "base/memory/ref_counted.h" #include "content/browser/loader/resource_handler.h" +#include "content/browser/loader/resource_message_delegate.h" #include "googleurl/src/gurl.h" namespace net { @@ -23,7 +24,8 @@ class SharedIOBuffer; // Used to complete an asynchronous resource request in response to resource // load events from the resource dispatcher host. -class AsyncResourceHandler : public ResourceHandler { +class AsyncResourceHandler : public ResourceHandler, + public ResourceMessageDelegate { public: AsyncResourceHandler(ResourceMessageFilter* filter, int routing_id, @@ -31,10 +33,8 @@ class AsyncResourceHandler : public ResourceHandler { ResourceDispatcherHostImpl* rdh); virtual ~AsyncResourceHandler(); - // IPC message handlers: - void OnFollowRedirect(bool has_new_first_party_for_cookies, - const GURL& new_first_party_for_cookies); - void OnDataReceivedACK(); + virtual bool OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) OVERRIDE; // ResourceHandler implementation: virtual bool OnUploadProgress(int request_id, @@ -64,6 +64,12 @@ class AsyncResourceHandler : public ResourceHandler { int bytes_downloaded) OVERRIDE; private: + // IPC message handlers: + void OnFollowRedirect(int request_id, + bool has_new_first_party_for_cookies, + const GURL& new_first_party_for_cookies); + void OnDataReceivedACK(int request_id); + bool EnsureResourceBufferIsInitialized(); void ResumeIfDeferred(); diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index ab37db2..37891cb 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc @@ -59,6 +59,8 @@ #include "content/public/common/content_switches.h" #include "content/public/common/process_type.h" #include "content/public/common/url_constants.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_message_start.h" #include "net/base/auth.h" #include "net/base/cert_status_flags.h" #include "net/base/load_flags.h" @@ -788,17 +790,31 @@ bool ResourceDispatcherHostImpl::OnMessageReceived( IPC_MESSAGE_HANDLER_DELAY_REPLY(ResourceHostMsg_SyncLoad, OnSyncLoad) IPC_MESSAGE_HANDLER(ResourceHostMsg_ReleaseDownloadedFile, OnReleaseDownloadedFile) - IPC_MESSAGE_HANDLER(ResourceHostMsg_DataReceived_ACK, OnDataReceivedACK) IPC_MESSAGE_HANDLER(ResourceHostMsg_DataDownloaded_ACK, OnDataDownloadedACK) IPC_MESSAGE_HANDLER(ResourceHostMsg_UploadProgress_ACK, OnUploadProgressACK) IPC_MESSAGE_HANDLER(ResourceHostMsg_CancelRequest, OnCancelRequest) - IPC_MESSAGE_HANDLER(ResourceHostMsg_FollowRedirect, OnFollowRedirect) IPC_MESSAGE_HANDLER(ViewHostMsg_SwapOut_ACK, OnSwapOutACK) IPC_MESSAGE_HANDLER(ViewHostMsg_DidLoadResourceFromMemoryCache, OnDidLoadResourceFromMemoryCache) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP_EX() + if (!handled && IPC_MESSAGE_ID_CLASS(message.type()) == ResourceMsgStart) { + PickleIterator iter(message); + int request_id = -1; + bool ok = iter.ReadInt(&request_id); + DCHECK(ok); + GlobalRequestID id(filter_->child_id(), request_id); + DelegateMap::iterator it = delegate_map_.find(id); + if (it != delegate_map_.end()) { + ObserverList::Iterator del_it(*it->second); + ResourceMessageDelegate* delegate; + while (!handled && (delegate = del_it.GetNext()) != NULL) { + handled = delegate->OnMessageReceived(message, message_was_ok); + } + } + } + if (message.type() == ViewHostMsg_DidLoadResourceFromMemoryCache::ID) { // We just needed to peek at this message. We still want it to reach its // normal destination. @@ -890,8 +906,9 @@ void ResourceDispatcherHostImpl::BeginRequest( return; } + bool is_sync_load = sync_result != NULL; int load_flags = - BuildLoadFlagsForRequest(request_data, child_id, sync_result != NULL); + BuildLoadFlagsForRequest(request_data, child_id, is_sync_load); // Construct the request. scoped_ptr new_request; @@ -955,7 +972,8 @@ void ResourceDispatcherHostImpl::BeginRequest( allow_download, request_data.has_user_gesture, request_data.referrer_policy, - resource_context); + resource_context, + !is_sync_load); extra_info->AssociateWithRequest(request); // Request takes ownership. if (request->url().SchemeIs(chrome::kBlobScheme)) { @@ -1049,16 +1067,6 @@ void ResourceDispatcherHostImpl::OnReleaseDownloadedFile(int request_id) { UnregisterDownloadedTempFile(filter_->child_id(), request_id); } -void ResourceDispatcherHostImpl::OnDataReceivedACK(int request_id) { - ResourceLoader* loader = GetLoader(filter_->child_id(), request_id); - if (!loader) - return; - - ResourceRequestInfoImpl* info = loader->GetRequestInfo(); - if (info->async_handler()) - info->async_handler()->OnDataReceivedACK(); -} - void ResourceDispatcherHostImpl::OnDataDownloadedACK(int request_id) { // TODO(michaeln): maybe throttle DataDownloaded messages } @@ -1110,24 +1118,6 @@ void ResourceDispatcherHostImpl::OnCancelRequest(int request_id) { CancelRequest(filter_->child_id(), request_id, true); } -void ResourceDispatcherHostImpl::OnFollowRedirect( - int request_id, - bool has_new_first_party_for_cookies, - const GURL& new_first_party_for_cookies) { - ResourceLoader* loader = GetLoader(filter_->child_id(), request_id); - if (!loader) { - DVLOG(1) << "OnFollowRedirect for invalid request"; - return; - } - - ResourceRequestInfoImpl* info = loader->GetRequestInfo(); - if (info->async_handler()) { - info->async_handler()->OnFollowRedirect( - has_new_first_party_for_cookies, - new_first_party_for_cookies); - } -} - ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo( int child_id, int route_id, @@ -1149,7 +1139,8 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo( download, // allow_download false, // has_user_gesture WebKit::WebReferrerPolicyDefault, - context); + context, + true); // is_async } @@ -1707,4 +1698,26 @@ ResourceLoader* ResourceDispatcherHostImpl::GetLoader(int child_id, return GetLoader(GlobalRequestID(child_id, request_id)); } +void ResourceDispatcherHostImpl::RegisterResourceMessageDelegate( + const GlobalRequestID& id, ResourceMessageDelegate* delegate) { + DelegateMap::iterator it = delegate_map_.find(id); + if (it == delegate_map_.end()) { + it = delegate_map_.insert( + std::make_pair(id, new ObserverList)).first; + } + it->second->AddObserver(delegate); +} + +void ResourceDispatcherHostImpl::UnregisterResourceMessageDelegate( + const GlobalRequestID& id, ResourceMessageDelegate* delegate) { + DCHECK(ContainsKey(delegate_map_, id)); + DelegateMap::iterator it = delegate_map_.find(id); + DCHECK(it->second->HasObserver(delegate)); + it->second->RemoveObserver(delegate); + if (it->second->size() == 0) { + delete it->second; + delegate_map_.erase(it); + } +} + } // namespace content diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h index 467745a..edffcf7 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.h +++ b/content/browser/loader/resource_dispatcher_host_impl.h @@ -21,6 +21,7 @@ #include "base/gtest_prod_util.h" #include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" +#include "base/observer_list.h" #include "base/time.h" #include "base/timer.h" #include "content/browser/download/download_resource_handler.h" @@ -51,6 +52,7 @@ class ShareableFileReference; namespace content { class ResourceContext; class ResourceDispatcherHostDelegate; +class ResourceMessageDelegate; class ResourceMessageFilter; class ResourceRequestInfoImpl; class SaveFileManager; @@ -226,6 +228,7 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl class ShutdownTask; friend class ShutdownTask; + friend class ResourceMessageDelegate; // ResourceLoaderDelegate implementation: virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate( @@ -314,13 +317,9 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl const ResourceHostMsg_Request& request_data, IPC::Message* sync_result, // only valid for sync int route_id); // only valid for async - void OnDataReceivedACK(int request_id); void OnDataDownloadedACK(int request_id); void OnUploadProgressACK(int request_id); void OnCancelRequest(int request_id); - void OnFollowRedirect(int request_id, - bool has_new_first_party_for_cookies, - const GURL& new_first_party_for_cookies); void OnReleaseDownloadedFile(int request_id); // Creates ResourceRequestInfoImpl for a download or page save. @@ -352,6 +351,13 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl ResourceLoader* GetLoader(const GlobalRequestID& id) const; ResourceLoader* GetLoader(int child_id, int request_id) const; + // Registers |delegate| to receive resource IPC messages targeted to the + // specified |id|. + void RegisterResourceMessageDelegate(const GlobalRequestID& id, + ResourceMessageDelegate* delegate); + void UnregisterResourceMessageDelegate(const GlobalRequestID& id, + ResourceMessageDelegate* delegate); + LoaderMap pending_loaders_; // Collection of temp files downloaded for child processes via @@ -419,6 +425,10 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl // shutdown. std::set active_resource_contexts_; + typedef std::map*> DelegateMap; + DelegateMap delegate_map_; + DISALLOW_COPY_AND_ASSIGN(ResourceDispatcherHostImpl); }; diff --git a/content/browser/loader/resource_message_delegate.cc b/content/browser/loader/resource_message_delegate.cc new file mode 100644 index 0000000..01d3595 --- /dev/null +++ b/content/browser/loader/resource_message_delegate.cc @@ -0,0 +1,24 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/loader/resource_message_delegate.h" + +#include "content/browser/loader/resource_dispatcher_host_impl.h" +#include "content/browser/loader/resource_request_info_impl.h" +#include "net/url_request/url_request.h" + +namespace content { + +ResourceMessageDelegate::ResourceMessageDelegate(const net::URLRequest* request) + : id_(ResourceRequestInfoImpl::ForRequest(request)->GetGlobalRequestID()) { + ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get(); + rdh->RegisterResourceMessageDelegate(id_, this); +} + +ResourceMessageDelegate::~ResourceMessageDelegate() { + ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get(); + rdh->UnregisterResourceMessageDelegate(id_, this); +} + +} // namespace content diff --git a/content/browser/loader/resource_message_delegate.h b/content/browser/loader/resource_message_delegate.h new file mode 100644 index 0000000..d5716e3 --- /dev/null +++ b/content/browser/loader/resource_message_delegate.h @@ -0,0 +1,42 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_ +#define CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_ + +#include "base/basictypes.h" +#include "content/common/content_export.h" +#include "content/public/browser/global_request_id.h" + +namespace IPC { +class Message; +} + +namespace net { +class URLRequest; +} + +namespace content { + +// A ResourceMessageDelegate receives IPC ResourceMsg_* messages for a specified +// URLRequest. The delegate should implement its own IPC handler. It will +// receive the message _after_ the ResourceDispatcherHost has handled it. +class CONTENT_EXPORT ResourceMessageDelegate { + public: + ResourceMessageDelegate(const net::URLRequest* request); + virtual ~ResourceMessageDelegate(); + + // Called when the ResourceDispatcherHostImpl receives a message specifically + // for this delegate. + virtual bool OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) = 0; + + private: + GlobalRequestID id_; + DISALLOW_IMPLICIT_CONSTRUCTORS(ResourceMessageDelegate); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_LOADER_RESOURCE_MESSAGE_DELEGATE_ diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc index 3c5fc49..9920545 100644 --- a/content/browser/loader/resource_request_info_impl.cc +++ b/content/browser/loader/resource_request_info_impl.cc @@ -45,7 +45,8 @@ void ResourceRequestInfo::AllocateForTesting( true, // allow_download false, // has_user_gesture WebKit::WebReferrerPolicyDefault, // referrer_policy - context); // context + context, // context + false); // is_async info->AssociateWithRequest(request); } @@ -94,9 +95,9 @@ ResourceRequestInfoImpl::ResourceRequestInfoImpl( bool allow_download, bool has_user_gesture, WebKit::WebReferrerPolicy referrer_policy, - ResourceContext* context) + ResourceContext* context, + bool is_async) : cross_site_handler_(NULL), - async_handler_(NULL), process_type_(process_type), child_id_(child_id), route_id_(route_id), @@ -114,7 +115,8 @@ ResourceRequestInfoImpl::ResourceRequestInfoImpl( transition_type_(transition_type), memory_cost_(0), referrer_policy_(referrer_policy), - context_(context) { + context_(context), + is_async_(is_async) { } ResourceRequestInfoImpl::~ResourceRequestInfoImpl() { @@ -198,7 +200,7 @@ bool ResourceRequestInfoImpl::GetAssociatedRenderView( } bool ResourceRequestInfoImpl::IsAsync() const { - return async_handler_ != NULL; + return is_async_; } void ResourceRequestInfoImpl::AssociateWithRequest(net::URLRequest* request) { diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h index b8e505f..30532bd 100644 --- a/content/browser/loader/resource_request_info_impl.h +++ b/content/browser/loader/resource_request_info_impl.h @@ -22,7 +22,6 @@ class BlobData; } namespace content { -class AsyncResourceHandler; class CrossSiteResourceHandler; class ResourceContext; struct GlobalRequestID; @@ -56,7 +55,8 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo, bool allow_download, bool has_user_gesture, WebKit::WebReferrerPolicy referrer_policy, - ResourceContext* context); + ResourceContext* context, + bool is_async); virtual ~ResourceRequestInfoImpl(); // ResourceRequestInfo implementation: @@ -91,14 +91,6 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo, cross_site_handler_ = h; } - // AsyncResourceHandler for this request. May be null. - AsyncResourceHandler* async_handler() { - return async_handler_; - } - void set_async_handler(AsyncResourceHandler* h) { - async_handler_ = h; - } - // Identifies the type of process (renderer, plugin, etc.) making the request. ProcessType process_type() const { return process_type_; @@ -130,7 +122,6 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo, private: // Non-owning, may be NULL. CrossSiteResourceHandler* cross_site_handler_; - AsyncResourceHandler* async_handler_; ProcessType process_type_; int child_id_; @@ -151,6 +142,7 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo, scoped_refptr requested_blob_data_; WebKit::WebReferrerPolicy referrer_policy_; ResourceContext* context_; + bool is_async_; DISALLOW_COPY_AND_ASSIGN(ResourceRequestInfoImpl); }; diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h index ed53ec7..e065419 100644 --- a/content/common/resource_messages.h +++ b/content/common/resource_messages.h @@ -3,6 +3,8 @@ // found in the LICENSE file. // IPC messages for resource loading. +// +// NOTE: All messages must send an |int request_id| as their first parameter. // Multiply-included message file, hence no include guard. #include "base/process.h" diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 2893191..636b061 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -525,6 +525,8 @@ 'browser/loader/resource_loader.cc', 'browser/loader/resource_loader_delegate.h', 'browser/loader/resource_loader.h', + 'browser/loader/resource_message_delegate.cc', + 'browser/loader/resource_message_delegate.h', 'browser/loader/resource_message_filter.cc', 'browser/loader/resource_message_filter.h', 'browser/loader/resource_request_info_impl.cc', -- cgit v1.1