diff options
author | creis@chromium.org <creis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-25 22:05:14 +0000 |
---|---|---|
committer | creis@chromium.org <creis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-25 22:05:14 +0000 |
commit | 1f291cd57a56e70369dc2e47e3d4be6102254102 (patch) | |
tree | 39f02a836e501f01967e46917303af0fbe785ae0 /content/browser/loader | |
parent | 0cb485cc68f91d337534372ebfd5d3a6b24ce7c3 (diff) | |
download | chromium_src-1f291cd57a56e70369dc2e47e3d4be6102254102.zip chromium_src-1f291cd57a56e70369dc2e47e3d4be6102254102.tar.gz chromium_src-1f291cd57a56e70369dc2e47e3d4be6102254102.tar.bz2 |
Make ResourceHandlers stateless with respect to child/routing/request IDs.
This lets us transfer an existing handler chain to a new process.
BUG=238331
TEST=Follow a link that redirects to the Chrome Web Store.
R=ajwong@chromium.org, darin@chromium.org, mpcomplete@chromium.org
Review URL: https://codereview.chromium.org/23180005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@225263 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/loader')
26 files changed, 404 insertions, 308 deletions
diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc index c7d7f49..f007a41 100644 --- a/content/browser/loader/async_resource_handler.cc +++ b/content/browser/loader/async_resource_handler.cc @@ -77,13 +77,9 @@ class DependentIOBuffer : public net::WrappedIOBuffer { }; AsyncResourceHandler::AsyncResourceHandler( - ResourceMessageFilter* filter, - ResourceContext* resource_context, net::URLRequest* request, ResourceDispatcherHostImpl* rdh) : ResourceMessageDelegate(request), - filter_(filter), - resource_context_(resource_context), request_(request), rdh_(rdh), pending_data_count_(0), @@ -139,25 +135,34 @@ void AsyncResourceHandler::OnDataReceivedACK(int request_id) { bool AsyncResourceHandler::OnUploadProgress(int request_id, uint64 position, uint64 size) { - return filter_->Send(new ResourceMsg_UploadProgress(request_id, position, - size)); + const ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); + if (!info->filter()) + return false; + return info->filter()->Send( + new ResourceMsg_UploadProgress(request_id, position, size)); } bool AsyncResourceHandler::OnRequestRedirected(int request_id, const GURL& new_url, ResourceResponse* response, bool* defer) { + const ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); + if (!info->filter()) + return false; + *defer = did_defer_ = true; if (rdh_->delegate()) { rdh_->delegate()->OnRequestRedirected( - new_url, request_, resource_context_, response); + new_url, request_, info->GetContext(), response); } DevToolsNetLogObserver::PopulateResponseInfo(request_, response); response->head.request_start = request_->creation_time(); response->head.response_start = TimeTicks::Now(); - return filter_->Send(new ResourceMsg_ReceivedRedirect( + return info->filter()->Send(new ResourceMsg_ReceivedRedirect( request_id, new_url, response->head)); } @@ -170,20 +175,24 @@ bool AsyncResourceHandler::OnResponseStarted(int request_id, // request commits, avoiding the possibility of e.g. zooming the old content // or of having to layout the new content twice. + const ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); + if (!info->filter()) + return false; + if (rdh_->delegate()) { rdh_->delegate()->OnResponseStarted( - request_, resource_context_, response, filter_.get()); + request_, info->GetContext(), response, info->filter()); } DevToolsNetLogObserver::PopulateResponseInfo(request_, response); HostZoomMap* host_zoom_map = - GetHostZoomMapForResourceContext(resource_context_); + GetHostZoomMapForResourceContext(info->GetContext()); - const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); if (info->GetResourceType() == ResourceType::MAIN_FRAME && host_zoom_map) { const GURL& request_url = request_->url(); - filter_->Send(new ViewMsg_SetZoomLevelForLoadingURL( + info->filter()->Send(new ViewMsg_SetZoomLevelForLoadingURL( info->GetRouteID(), request_url, host_zoom_map->GetZoomLevelForHostAndScheme( request_url.scheme(), @@ -192,14 +201,16 @@ bool AsyncResourceHandler::OnResponseStarted(int request_id, response->head.request_start = request_->creation_time(); response->head.response_start = TimeTicks::Now(); - filter_->Send(new ResourceMsg_ReceivedResponse(request_id, response->head)); + info->filter()->Send(new ResourceMsg_ReceivedResponse(request_id, + response->head)); sent_received_response_msg_ = true; if (request_->response_info().metadata.get()) { std::vector<char> copy(request_->response_info().metadata->data(), request_->response_info().metadata->data() + request_->response_info().metadata->size()); - filter_->Send(new ResourceMsg_ReceivedCachedMetadata(request_id, copy)); + info->filter()->Send(new ResourceMsg_ReceivedCachedMetadata(request_id, + copy)); } return true; @@ -236,6 +247,11 @@ bool AsyncResourceHandler::OnReadCompleted(int request_id, int bytes_read, if (!bytes_read) return true; + const ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); + if (!info->filter()) + return false; + buffer_->ShrinkLastAllocation(bytes_read); UMA_HISTOGRAM_CUSTOM_COUNTS( @@ -248,10 +264,10 @@ bool AsyncResourceHandler::OnReadCompleted(int request_id, int bytes_read, if (!sent_first_data_msg_) { base::SharedMemoryHandle handle; int size; - if (!buffer_->ShareToProcess(filter_->PeerHandle(), &handle, &size)) + if (!buffer_->ShareToProcess(info->filter()->PeerHandle(), &handle, &size)) return false; - filter_->Send(new ResourceMsg_SetDataBuffer( - request_id, handle, size, filter_->peer_pid())); + info->filter()->Send(new ResourceMsg_SetDataBuffer( + request_id, handle, size, info->filter()->peer_pid())); sent_first_data_msg_ = true; } @@ -259,7 +275,7 @@ bool AsyncResourceHandler::OnReadCompleted(int request_id, int bytes_read, int encoded_data_length = DevToolsNetLogObserver::GetAndResetEncodedDataLength(request_); - filter_->Send(new ResourceMsg_DataReceived( + info->filter()->Send(new ResourceMsg_DataReceived( request_id, data_offset, bytes_read, encoded_data_length)); ++pending_data_count_; UMA_HISTOGRAM_CUSTOM_COUNTS( @@ -281,14 +297,23 @@ void AsyncResourceHandler::OnDataDownloaded( int encoded_data_length = DevToolsNetLogObserver::GetAndResetEncodedDataLength(request_); - filter_->Send(new ResourceMsg_DataDownloaded( - request_id, bytes_downloaded, encoded_data_length)); + const ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); + if (info->filter()) { + info->filter()->Send(new ResourceMsg_DataDownloaded( + request_id, bytes_downloaded, encoded_data_length)); + } } bool AsyncResourceHandler::OnResponseCompleted( int request_id, const net::URLRequestStatus& status, const std::string& security_info) { + const ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); + if (!info->filter()) + return false; + // If we crash here, figure out what URL the renderer was requesting. // http://crbug.com/107692 char url_buf[128]; @@ -325,11 +350,12 @@ bool AsyncResourceHandler::OnResponseCompleted( error_code = net::ERR_FAILED; } - filter_->Send(new ResourceMsg_RequestComplete(request_id, - error_code, - was_ignored_by_handler, - security_info, - completion_time)); + info->filter()->Send( + new ResourceMsg_RequestComplete(request_id, + error_code, + was_ignored_by_handler, + security_info, + completion_time)); return true; } diff --git a/content/browser/loader/async_resource_handler.h b/content/browser/loader/async_resource_handler.h index b43e0ef..0992841 100644 --- a/content/browser/loader/async_resource_handler.h +++ b/content/browser/loader/async_resource_handler.h @@ -28,9 +28,7 @@ class SharedIOBuffer; class AsyncResourceHandler : public ResourceHandler, public ResourceMessageDelegate { public: - AsyncResourceHandler(ResourceMessageFilter* filter, - ResourceContext* resource_context, - net::URLRequest* request, + AsyncResourceHandler(net::URLRequest* request, ResourceDispatcherHostImpl* rdh); virtual ~AsyncResourceHandler(); @@ -75,8 +73,6 @@ class AsyncResourceHandler : public ResourceHandler, void ResumeIfDeferred(); scoped_refptr<ResourceBuffer> buffer_; - scoped_refptr<ResourceMessageFilter> filter_; - ResourceContext* resource_context_; net::URLRequest* request_; ResourceDispatcherHostImpl* rdh_; diff --git a/content/browser/loader/buffered_resource_handler.cc b/content/browser/loader/buffered_resource_handler.cc index a3afb3f..beb3228 100644 --- a/content/browser/loader/buffered_resource_handler.cc +++ b/content/browser/loader/buffered_resource_handler.cc @@ -307,9 +307,7 @@ bool BufferedResourceHandler::SelectNextHandler(bool* defer) { if (net::IsSupportedCertificateMimeType(mime_type)) { // Install certificate file. scoped_ptr<ResourceHandler> handler( - new CertificateResourceHandler(request_, - info->GetChildID(), - info->GetRouteID())); + new CertificateResourceHandler(request_)); return UseAlternateNextHandler(handler.Pass()); } diff --git a/content/browser/loader/certificate_resource_handler.cc b/content/browser/loader/certificate_resource_handler.cc index 9d99542..d850b19 100644 --- a/content/browser/loader/certificate_resource_handler.cc +++ b/content/browser/loader/certificate_resource_handler.cc @@ -18,15 +18,11 @@ namespace content { CertificateResourceHandler::CertificateResourceHandler( - net::URLRequest* request, - int render_process_host_id, - int render_view_id) + net::URLRequest* request) : request_(request), content_length_(0), read_buffer_(NULL), resource_buffer_(NULL), - render_process_host_id_(render_process_host_id), - render_view_id_(render_view_id), cert_type_(net::CERTIFICATE_MIME_TYPE_UNKNOWN) { } @@ -112,9 +108,10 @@ bool CertificateResourceHandler::OnResponseCompleted( // Note that it's up to the browser to verify that the certificate // data is well-formed. + const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); GetContentClient()->browser()->AddCertificate( request_, cert_type_, content_bytes, content_length_, - render_process_host_id_, render_view_id_); + info->GetChildID(), info->GetRouteID()); return true; } diff --git a/content/browser/loader/certificate_resource_handler.h b/content/browser/loader/certificate_resource_handler.h index b1bd8f4..12a7f67 100644 --- a/content/browser/loader/certificate_resource_handler.h +++ b/content/browser/loader/certificate_resource_handler.h @@ -31,9 +31,7 @@ namespace content { // class CertificateResourceHandler : public ResourceHandler { public: - CertificateResourceHandler(net::URLRequest* request, - int render_process_host_id, - int render_view_id); + explicit CertificateResourceHandler(net::URLRequest* request); virtual ~CertificateResourceHandler(); virtual bool OnUploadProgress(int request_id, @@ -87,10 +85,6 @@ class CertificateResourceHandler : public ResourceHandler { ContentVector buffer_; scoped_refptr<net::IOBuffer> read_buffer_; scoped_refptr<net::IOBuffer> resource_buffer_; // Downloaded certificate. - // The id of the |RenderProcessHost| which started the download. - int render_process_host_id_; - // The id of the |RenderView| which started the download. - int render_view_id_; net::CertificateMimeType cert_type_; DISALLOW_COPY_AND_ASSIGN(CertificateResourceHandler); }; diff --git a/content/browser/loader/cross_site_resource_handler.cc b/content/browser/loader/cross_site_resource_handler.cc index 6b735f6..90fe84a 100644 --- a/content/browser/loader/cross_site_resource_handler.cc +++ b/content/browser/loader/cross_site_resource_handler.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/logging.h" +#include "content/browser/cross_site_request_manager.h" #include "content/browser/loader/resource_request_info_impl.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_view_host_impl.h" @@ -36,16 +37,11 @@ void OnCrossSiteResponseHelper(int render_process_id, CrossSiteResourceHandler::CrossSiteResourceHandler( scoped_ptr<ResourceHandler> next_handler, - int render_process_host_id, - int render_view_id, net::URLRequest* request) : LayeredResourceHandler(next_handler.Pass()), - render_process_host_id_(render_process_host_id), - render_view_id_(render_view_id), request_(request), has_started_response_(false), in_cross_site_transition_(false), - request_id_(-1), completed_during_transition_(false), did_defer_(false), completed_status_(), @@ -81,6 +77,11 @@ bool CrossSiteResourceHandler::OnResponseStarted( ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_); + // A swap may no longer be needed if we transferred back into the original + // process due to a redirect. + bool swap_needed = CrossSiteRequestManager::GetInstance()-> + HasPendingCrossSiteRequest(info->GetChildID(), info->GetRouteID()); + // If this is a download, just pass the response through without doing a // cross-site check. The renderer will see it is a download and abort the // request. @@ -92,8 +93,9 @@ bool CrossSiteResourceHandler::OnResponseStarted( // In both cases, the pending RenderViewHost will stick around until the next // cross-site navigation, since we are unable to tell when to destroy it. // See RenderViewHostManager::RendererAbortedProvisionalLoad. - if (info->is_download() || (response->head.headers.get() && - response->head.headers->response_code() == 204)) { + if (!swap_needed || info->is_download() || + (response->head.headers.get() && + response->head.headers->response_code() == 204)) { return next_handler_->OnResponseStarted(request_id, response, defer); } @@ -146,15 +148,18 @@ bool CrossSiteResourceHandler::OnResponseCompleted( // We can now send the response to the new renderer, which will cause // WebContentsImpl to swap in the new renderer and destroy the old one. void CrossSiteResourceHandler::ResumeResponse() { - DCHECK(request_id_ != -1); + DCHECK(request_); DCHECK(in_cross_site_transition_); in_cross_site_transition_ = false; + ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); if (has_started_response_) { // Send OnResponseStarted to the new renderer. DCHECK(response_); bool defer = false; - if (!next_handler_->OnResponseStarted(request_id_, response_, &defer)) { + if (!next_handler_->OnResponseStarted(info->GetRequestID(), response_, + &defer)) { controller()->Cancel(); } else if (!defer) { // Unpause the request to resume reading. Any further reads will be @@ -164,14 +169,13 @@ void CrossSiteResourceHandler::ResumeResponse() { } // Remove ourselves from the ExtraRequestInfo. - ResourceRequestInfoImpl* info = - ResourceRequestInfoImpl::ForRequest(request_); info->set_cross_site_handler(NULL); // If the response completed during the transition, notify the next // event handler. if (completed_during_transition_) { - if (next_handler_->OnResponseCompleted(request_id_, completed_status_, + if (next_handler_->OnResponseCompleted(info->GetRequestID(), + completed_status_, completed_security_info_)) { ResumeIfDeferred(); } @@ -184,7 +188,6 @@ void CrossSiteResourceHandler::StartCrossSiteTransition( int request_id, ResourceResponse* response) { in_cross_site_transition_ = true; - request_id_ = request_id; response_ = response; // Store this handler on the ExtraRequestInfo, so that RDH can call our @@ -201,8 +204,8 @@ void CrossSiteResourceHandler::StartCrossSiteTransition( FROM_HERE, base::Bind( &OnCrossSiteResponseHelper, - render_process_host_id_, - render_view_id_, + info->GetChildID(), + info->GetRouteID(), request_id)); // TODO(creis): If the above call should fail, then we need to notify the IO diff --git a/content/browser/loader/cross_site_resource_handler.h b/content/browser/loader/cross_site_resource_handler.h index 378a206..39c3a14 100644 --- a/content/browser/loader/cross_site_resource_handler.h +++ b/content/browser/loader/cross_site_resource_handler.h @@ -22,8 +22,6 @@ namespace content { class CrossSiteResourceHandler : public LayeredResourceHandler { public: CrossSiteResourceHandler(scoped_ptr<ResourceHandler> next_handler, - int render_process_host_id, - int render_view_id, net::URLRequest* request); virtual ~CrossSiteResourceHandler(); @@ -55,12 +53,9 @@ class CrossSiteResourceHandler : public LayeredResourceHandler { void ResumeIfDeferred(); - int render_process_host_id_; - int render_view_id_; net::URLRequest* request_; bool has_started_response_; bool in_cross_site_transition_; - int request_id_; bool completed_during_transition_; bool did_defer_; net::URLRequestStatus completed_status_; diff --git a/content/browser/loader/doomed_resource_handler.cc b/content/browser/loader/doomed_resource_handler.cc deleted file mode 100644 index d9f2f58..0000000 --- a/content/browser/loader/doomed_resource_handler.cc +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2012 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/doomed_resource_handler.h" - -#include "base/logging.h" -#include "net/url_request/url_request_status.h" - -namespace content { - -DoomedResourceHandler::DoomedResourceHandler( - scoped_ptr<ResourceHandler> old_handler) - : old_handler_(old_handler.Pass()) { -} - -DoomedResourceHandler::~DoomedResourceHandler() { -} - -bool DoomedResourceHandler::OnUploadProgress(int request_id, - uint64 position, - uint64 size) { - NOTREACHED(); - return true; -} - -bool DoomedResourceHandler::OnRequestRedirected(int request_id, - const GURL& new_url, - ResourceResponse* response, - bool* defer) { - NOTREACHED(); - return true; -} - -bool DoomedResourceHandler::OnResponseStarted(int request_id, - ResourceResponse* response, - bool* defer) { - NOTREACHED(); - return true; -} - -bool DoomedResourceHandler::OnWillStart(int request_id, - const GURL& url, - bool* defer) { - NOTREACHED(); - return true; -} - -bool DoomedResourceHandler::OnWillRead(int request_id, - net::IOBuffer** buf, - int* buf_size, - int min_size) { - NOTREACHED(); - return true; -} - -bool DoomedResourceHandler::OnReadCompleted(int request_id, - int bytes_read, - bool* defer) { - NOTREACHED(); - return true; -} - -bool DoomedResourceHandler::OnResponseCompleted( - int request_id, - const net::URLRequestStatus& status, - const std::string& security_info) { - DCHECK(status.status() == net::URLRequestStatus::CANCELED || - status.status() == net::URLRequestStatus::FAILED); - return true; -} - -void DoomedResourceHandler::OnDataDownloaded(int request_id, - int bytes_downloaded) { - NOTREACHED(); -} - -} // namespace content diff --git a/content/browser/loader/doomed_resource_handler.h b/content/browser/loader/doomed_resource_handler.h deleted file mode 100644 index 9533ef1c..0000000 --- a/content/browser/loader/doomed_resource_handler.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2012 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_DOOMED_RESOURCE_HANDLER_H_ -#define CONTENT_BROWSER_LOADER_DOOMED_RESOURCE_HANDLER_H_ - -#include "base/memory/scoped_ptr.h" -#include "content/browser/loader/resource_handler.h" - -namespace content { - -// ResourceHandler that DCHECKs on all events but canceling and failing of -// requests while activated for a URLRequest. -class DoomedResourceHandler : public ResourceHandler { - public: - // As the DoomedResourceHandler is constructed and substituted from code - // of another ResourceHandler, we need to make sure that this other handler - // does not lose its last reference and gets destroyed by being substituted. - // Therefore, we retain a reference to |old_handler| that prevents the - // destruction. - explicit DoomedResourceHandler(scoped_ptr<ResourceHandler> old_handler); - virtual ~DoomedResourceHandler(); - - // ResourceHandler implementation: - virtual bool OnUploadProgress(int request_id, - uint64 position, - uint64 size) OVERRIDE; - virtual bool OnRequestRedirected(int request_id, - const GURL& new_url, - ResourceResponse* response, - bool* defer) OVERRIDE; - virtual bool OnResponseStarted(int request_id, - ResourceResponse* response, - bool* defer) OVERRIDE; - virtual bool OnWillStart(int request_id, - const GURL& url, - bool* defer) OVERRIDE; - virtual bool OnWillRead(int request_id, - net::IOBuffer** buf, - int* buf_size, - int min_size) OVERRIDE; - virtual bool OnReadCompleted(int request_id, - int bytes_read, - bool* defer) OVERRIDE; - virtual bool OnResponseCompleted(int request_id, - const net::URLRequestStatus& status, - const std::string& security_info) OVERRIDE; - virtual void OnDataDownloaded(int request_id, - int bytes_downloaded) OVERRIDE; - - private: - scoped_ptr<ResourceHandler> old_handler_; - - DISALLOW_COPY_AND_ASSIGN(DoomedResourceHandler); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_LOADER_DOOMED_RESOURCE_HANDLER_H_ diff --git a/content/browser/loader/redirect_to_file_resource_handler.cc b/content/browser/loader/redirect_to_file_resource_handler.cc index 9d996dc..74dc08a 100644 --- a/content/browser/loader/redirect_to_file_resource_handler.cc +++ b/content/browser/loader/redirect_to_file_resource_handler.cc @@ -12,6 +12,7 @@ #include "base/threading/thread_restrictions.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/resource_request_info.h" #include "content/public/common/resource_response.h" #include "net/base/file_stream.h" #include "net/base/io_buffer.h" @@ -54,13 +55,12 @@ static const int kMaxReadBufSize = 524288; RedirectToFileResourceHandler::RedirectToFileResourceHandler( scoped_ptr<ResourceHandler> next_handler, - int process_id, + net::URLRequest* request, ResourceDispatcherHostImpl* host) : LayeredResourceHandler(next_handler.Pass()), weak_factory_(this), host_(host), - process_id_(process_id), - request_id_(-1), + request_(request), buf_(new net::GrowableIOBuffer()), buf_write_pending_(false), write_cursor_(0), @@ -88,7 +88,6 @@ bool RedirectToFileResourceHandler::OnResponseStarted( bool RedirectToFileResourceHandler::OnWillStart(int request_id, const GURL& url, bool* defer) { - request_id_ = request_id; if (!deletable_file_.get()) { // Defer starting the request until we have created the temporary file. // TODO(darin): This is sub-optimal. We should not delay starting the @@ -172,17 +171,19 @@ void RedirectToFileResourceHandler::DidCreateTemporaryFile( new net::FileStream(file_handle.ReleaseValue(), base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_ASYNC, NULL)); + const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); host_->RegisterDownloadedTempFile( - process_id_, request_id_, deletable_file_.get()); + info->GetChildID(), info->GetRequestID(), deletable_file_.get()); ResumeIfDeferred(); } void RedirectToFileResourceHandler::DidWriteToFile(int result) { write_callback_pending_ = false; + const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); bool failed = false; if (result > 0) { - next_handler_->OnDataDownloaded(request_id_, result); + next_handler_->OnDataDownloaded(info->GetRequestID(), result); write_cursor_ += result; failed = !WriteMore(); } else { @@ -192,7 +193,8 @@ void RedirectToFileResourceHandler::DidWriteToFile(int result) { if (failed) { ResumeIfDeferred(); } else if (completed_during_write_) { - if (next_handler_->OnResponseCompleted(request_id_, completed_status_, + if (next_handler_->OnResponseCompleted(info->GetRequestID(), + completed_status_, completed_security_info_)) { ResumeIfDeferred(); } @@ -246,7 +248,8 @@ bool RedirectToFileResourceHandler::WriteMore() { } if (rv <= 0) return false; - next_handler_->OnDataDownloaded(request_id_, rv); + const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); + next_handler_->OnDataDownloaded(info->GetRequestID(), rv); write_cursor_ += rv; } } diff --git a/content/browser/loader/redirect_to_file_resource_handler.h b/content/browser/loader/redirect_to_file_resource_handler.h index 459b982..1af25df 100644 --- a/content/browser/loader/redirect_to_file_resource_handler.h +++ b/content/browser/loader/redirect_to_file_resource_handler.h @@ -11,6 +11,7 @@ #include "base/memory/weak_ptr.h" #include "base/platform_file.h" #include "content/browser/loader/layered_resource_handler.h" +#include "net/url_request/url_request.h" #include "net/url_request/url_request_status.h" namespace net { @@ -31,7 +32,7 @@ class RedirectToFileResourceHandler : public LayeredResourceHandler { public: RedirectToFileResourceHandler( scoped_ptr<ResourceHandler> next_handler, - int process_id, + net::URLRequest* request, ResourceDispatcherHostImpl* resource_dispatcher_host); virtual ~RedirectToFileResourceHandler(); @@ -65,8 +66,7 @@ class RedirectToFileResourceHandler : public LayeredResourceHandler { base::WeakPtrFactory<RedirectToFileResourceHandler> weak_factory_; ResourceDispatcherHostImpl* host_; - int process_id_; - int request_id_; + net::URLRequest* request_; // We allocate a single, fixed-size IO buffer (buf_) used to read from the // network (buf_write_pending_ is true while the system is copying data into diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index 9c29a28..0402e98 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc @@ -571,8 +571,7 @@ ResourceDispatcherHostImpl::CreateResourceHandlerForDownload( if (!throttles.empty()) { handler.reset( new ThrottlingResourceHandler( - handler.Pass(), request_info->GetChildID(), - request_info->GetRequestID(), throttles.Pass())); + handler.Pass(), request, throttles.Pass())); } } return handler.Pass(); @@ -878,6 +877,77 @@ void ResourceDispatcherHostImpl::OnSyncLoad( sync_result->routing_id()); } +void ResourceDispatcherHostImpl::UpdateRequestForTransfer( + int child_id, + int route_id, + int request_id, + const ResourceHostMsg_Request& request_data, + const linked_ptr<ResourceLoader>& loader) { + ResourceRequestInfoImpl* info = loader->GetRequestInfo(); + GlobalRoutingID old_routing_id( + request_data.transferred_request_child_id, info->GetRouteID()); + GlobalRequestID old_request_id(request_data.transferred_request_child_id, + request_data.transferred_request_request_id); + GlobalRoutingID new_routing_id(child_id, route_id); + GlobalRequestID new_request_id(child_id, request_id); + + // Clear out data that depends on |info| before updating it. + IncrementOutstandingRequestsMemory(-1, *info); + OustandingRequestsStats empty_stats = { 0, 0 }; + OustandingRequestsStats old_stats = GetOutstandingRequestsStats(*info); + UpdateOutstandingRequestsStats(*info, empty_stats); + pending_loaders_.erase(old_request_id); + + // ResourceHandlers should always get state related to the request from the + // ResourceRequestInfo rather than caching it locally. This lets us update + // the info object when a transfer occurs. + info->UpdateForTransfer(child_id, route_id, request_data.origin_pid, + request_id, request_data.frame_id, + request_data.parent_frame_id, filter_->GetWeakPtr()); + + // Update maps that used the old IDs, if necessary. Some transfers in tests + // do not actually use a different ID, so not all maps need to be updated. + pending_loaders_[new_request_id] = loader; + UpdateOutstandingRequestsStats(*info, old_stats); + IncrementOutstandingRequestsMemory(1, *info); + if (old_routing_id != new_routing_id) { + if (offline_policy_map_.find(old_routing_id) != offline_policy_map_.end()) { + offline_policy_map_[new_routing_id] = offline_policy_map_[old_routing_id]; + offline_policy_map_.erase(old_routing_id); + } + if (blocked_loaders_map_.find(old_routing_id) != + blocked_loaders_map_.end()) { + blocked_loaders_map_[new_routing_id] = + blocked_loaders_map_[old_routing_id]; + blocked_loaders_map_.erase(old_routing_id); + } + } + if (old_request_id != new_request_id) { + DelegateMap::iterator it = delegate_map_.find(old_request_id); + if (it != delegate_map_.end()) { + // Tell each delegate that the request ID has changed. + ObserverList<ResourceMessageDelegate>::Iterator del_it(*it->second); + ResourceMessageDelegate* delegate; + while ((delegate = del_it.GetNext()) != NULL) { + delegate->set_request_id(new_request_id); + } + // Now store the observer list under the new request ID. + delegate_map_[new_request_id] = delegate_map_[old_request_id]; + delegate_map_.erase(old_request_id); + } + } + + // Notify the delegate to allow it to update state as well. + if (delegate_) { + delegate_->WillTransferRequestToNewProcess(old_routing_id.child_id, + old_routing_id.route_id, + old_request_id.request_id, + child_id, + route_id, + request_id); + } +} + void ResourceDispatcherHostImpl::BeginRequest( int request_id, const ResourceHostMsg_Request& request_data, @@ -908,16 +978,19 @@ void ResourceDispatcherHostImpl::BeginRequest( GlobalRequestID(request_data.transferred_request_child_id, request_data.transferred_request_request_id)); if (it != pending_loaders_.end()) { + // If the request is transferring to a new process, we can update our + // state and let it resume with its existing ResourceHandlers. if (it->second->is_transferring()) { deferred_loader = it->second; - IncrementOutstandingRequestsMemory(-1, - *deferred_loader->GetRequestInfo()); - pending_loaders_.erase(it); + UpdateRequestForTransfer(child_id, route_id, request_id, + request_data, deferred_loader); + + deferred_loader->CompleteTransfer(); } else { RecordAction(UserMetricsAction("BadMessageTerminate_RDH")); filter_->BadMessageReceived(); - return; } + return; } } @@ -960,27 +1033,16 @@ void ResourceDispatcherHostImpl::BeginRequest( // Construct the request. scoped_ptr<net::URLRequest> new_request; net::URLRequest* request; - if (deferred_loader.get()) { - request = deferred_loader->request(); - - // Give the ResourceLoader (or any of the ResourceHandlers held by it) a - // chance to reset some state before we complete the transfer. - deferred_loader->WillCompleteTransfer(); - } else { - new_request.reset(request_context->CreateRequest(request_data.url, NULL)); - request = new_request.get(); - - request->set_method(request_data.method); - request->set_first_party_for_cookies(request_data.first_party_for_cookies); - SetReferrerForRequest(request, referrer); + new_request.reset(request_context->CreateRequest(request_data.url, NULL)); + request = new_request.get(); - net::HttpRequestHeaders headers; - headers.AddHeadersFromString(request_data.headers); - request->SetExtraRequestHeaders(headers); - } + request->set_method(request_data.method); + request->set_first_party_for_cookies(request_data.first_party_for_cookies); + SetReferrerForRequest(request, referrer); - // TODO(darin): Do we really need all of these URLRequest setters in the - // transferred navigation case? + net::HttpRequestHeaders headers; + headers.AddHeadersFromString(request_data.headers); + request->SetExtraRequestHeaders(headers); request->set_load_flags(load_flags); request->SetPriority(request_data.priority); @@ -1021,6 +1083,7 @@ void ResourceDispatcherHostImpl::BeginRequest( request_data.has_user_gesture, request_data.referrer_policy, resource_context, + filter_->GetWeakPtr(), !is_sync_load); extra_info->AssociateWithRequest(request); // Request takes ownership. @@ -1041,17 +1104,15 @@ void ResourceDispatcherHostImpl::BeginRequest( // Construct the IPC resource handler. scoped_ptr<ResourceHandler> handler; if (sync_result) { - handler.reset(new SyncResourceHandler( - filter_, resource_context, request, sync_result, this)); + handler.reset(new SyncResourceHandler(request, sync_result, this)); } else { - handler.reset(new AsyncResourceHandler( - filter_, resource_context, request, this)); + handler.reset(new AsyncResourceHandler(request, this)); } // The RedirectToFileResourceHandler depends on being next in the chain. if (request_data.download_to_file) { handler.reset( - new RedirectToFileResourceHandler(handler.Pass(), child_id, this)); + new RedirectToFileResourceHandler(handler.Pass(), request, this)); } // Install a CrossSiteResourceHandler if this request is coming from a @@ -1064,8 +1125,7 @@ void ResourceDispatcherHostImpl::BeginRequest( HasPendingCrossSiteRequest(child_id, route_id)) { // Wrap the event handler to be sure the current page's onunload handler // has a chance to run before we render the new page. - handler.reset(new CrossSiteResourceHandler(handler.Pass(), child_id, - route_id, request)); + handler.reset(new CrossSiteResourceHandler(handler.Pass(), request)); } // Insert a buffered event handler before the actual one. @@ -1074,16 +1134,12 @@ void ResourceDispatcherHostImpl::BeginRequest( ScopedVector<ResourceThrottle> throttles; if (delegate_) { - bool is_continuation_of_transferred_request = - (deferred_loader.get() != NULL); - delegate_->RequestBeginning(request, resource_context, filter_->appcache_service(), request_data.resource_type, child_id, route_id, - is_continuation_of_transferred_request, &throttles); } @@ -1102,16 +1158,9 @@ void ResourceDispatcherHostImpl::BeginRequest( scheduler_->ScheduleRequest(child_id, route_id, request).release()); handler.reset( - new ThrottlingResourceHandler(handler.Pass(), child_id, request_id, - throttles.Pass())); + new ThrottlingResourceHandler(handler.Pass(), request, throttles.Pass())); - if (deferred_loader.get()) { - pending_loaders_[extra_info->GetGlobalRequestID()] = deferred_loader; - IncrementOutstandingRequestsMemory(1, *extra_info); - deferred_loader->CompleteTransfer(handler.Pass()); - } else { - BeginRequestInternal(new_request.Pass(), handler.Pass()); - } + BeginRequestInternal(new_request.Pass(), handler.Pass()); } void ResourceDispatcherHostImpl::OnReleaseDownloadedFile(int request_id) { @@ -1192,6 +1241,7 @@ ResourceRequestInfoImpl* ResourceDispatcherHostImpl::CreateRequestInfo( false, // has_user_gesture WebKit::WebReferrerPolicyDefault, context, + base::WeakPtr<ResourceMessageFilter>(), // filter true); // is_async } @@ -1297,6 +1347,7 @@ void ResourceDispatcherHostImpl::CancelRequestsForRoute(int child_id, // iterators found in the first loop. // Find the global ID of all matching elements. + bool any_requests_transferring = false; std::vector<GlobalRequestID> matching_requests; for (LoaderMap::const_iterator i = pending_loaders_.begin(); i != pending_loaders_.end(); ++i) { @@ -1310,6 +1361,8 @@ void ResourceDispatcherHostImpl::CancelRequestsForRoute(int child_id, // Don't cancel navigations that are transferring to another process, // since they belong to another process now. + if (IsTransferredNavigation(id)) + any_requests_transferring = true; if (!info->is_download() && !info->is_stream() && !IsTransferredNavigation(id) && (route_id == -1 || route_id == info->GetRouteID())) { @@ -1333,6 +1386,14 @@ void ResourceDispatcherHostImpl::CancelRequestsForRoute(int child_id, RemovePendingLoader(iter); } + // Don't clear the blocked loaders or offline policy maps if any of the + // requests in route_id are being transferred to a new process, since those + // maps will be updated with the new route_id after the transfer. Otherwise + // we will lose track of this info when the old route goes away, before the + // new one is created. + if (any_requests_transferring) + return; + // Now deal with blocked requests if any. if (route_id != -1) { if (blocked_loaders_map_.find(GlobalRoutingID(child_id, route_id)) != diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h index e6f2241..f10b3f7 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.h +++ b/content/browser/loader/resource_dispatcher_host_impl.h @@ -356,6 +356,15 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl void OnSyncLoad(int request_id, const ResourceHostMsg_Request& request_data, IPC::Message* sync_result); + + // Update the ResourceRequestInfo and internal maps when a request is + // transferred from one process to another. + void UpdateRequestForTransfer(int child_id, + int route_id, + int request_id, + const ResourceHostMsg_Request& request_data, + const linked_ptr<ResourceLoader>& loader); + void BeginRequest(int request_id, const ResourceHostMsg_Request& request_data, IPC::Message* sync_result, // only valid for sync diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc index 89b17c4..449b515 100644 --- a/content/browser/loader/resource_dispatcher_host_unittest.cc +++ b/content/browser/loader/resource_dispatcher_host_unittest.cc @@ -15,6 +15,7 @@ #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" #include "content/browser/loader/resource_message_filter.h" +#include "content/browser/loader/resource_request_info_impl.h" #include "content/browser/worker_host/worker_service_impl.h" #include "content/common/child_process_host_impl.h" #include "content/common/resource_messages.h" @@ -22,6 +23,7 @@ #include "content/public/browser/global_request_id.h" #include "content/public/browser/resource_context.h" #include "content/public/browser/resource_dispatcher_host_delegate.h" +#include "content/public/browser/resource_request_info.h" #include "content/public/browser/resource_throttle.h" #include "content/public/common/process_type.h" #include "content/public/common/resource_response.h" @@ -489,7 +491,6 @@ class TestResourceDispatcherHostDelegate ResourceType::Type resource_type, int child_id, int route_id, - bool is_continuation_of_transferred_request, ScopedVector<ResourceThrottle>* throttles) OVERRIDE { if (user_data_) { const void* key = user_data_.get(); @@ -1758,6 +1759,93 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigation) { CheckSuccessfulRequest(msgs[0], kResponseBody); } +TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) { + EXPECT_EQ(0, host_.pending_requests()); + + int render_view_id = 0; + int request_id = 1; + int first_child_id = -1; + + // Configure initial request. + SetResponse("HTTP/1.1 302 Found\n" + "Location: http://other.com/blech\n\n"); + + SetResourceType(ResourceType::MAIN_FRAME); + HandleScheme("http"); + + // Temporarily replace ContentBrowserClient with one that will trigger the + // transfer navigation code paths. + TransfersAllNavigationsContentBrowserClient new_client; + ContentBrowserClient* old_client = SetBrowserClientForTesting(&new_client); + + // Create a first filter that can be deleted before the second one starts. + { + scoped_refptr<ForwardingFilter> first_filter = new ForwardingFilter( + this, browser_context_->GetResourceContext()); + first_child_id = first_filter->child_id(); + + ResourceHostMsg_Request first_request = + CreateResourceRequest("GET", ResourceType::MAIN_FRAME, + GURL("http://example.com/blah")); + + // For cleanup. + child_ids_.insert(first_child_id); + ResourceHostMsg_RequestResource first_request_msg( + render_view_id, request_id, first_request); + bool msg_was_ok; + host_.OnMessageReceived( + first_request_msg, first_filter.get(), &msg_was_ok); + base::MessageLoop::current()->RunUntilIdle(); + } + // The first filter is now deleted, as if the child process died. + + // Restore. + SetBrowserClientForTesting(old_client); + + // Make sure we don't hold onto the ResourceMessageFilter after it is deleted. + GlobalRequestID first_global_request_id(first_child_id, request_id); + const ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest( + host_.GetURLRequest(first_global_request_id)); + EXPECT_FALSE(info->filter()); + + // This second filter is used to emulate a second process. + scoped_refptr<ForwardingFilter> second_filter = new ForwardingFilter( + this, browser_context_->GetResourceContext()); + + int new_render_view_id = 1; + int new_request_id = 2; + + const std::string kResponseBody = "hello world"; + SetResponse("HTTP/1.1 200 OK\n" + "Content-Type: text/plain\n\n", + kResponseBody); + + ResourceHostMsg_Request request = + CreateResourceRequest("GET", ResourceType::MAIN_FRAME, + GURL("http://other.com/blech")); + request.transferred_request_child_id = first_child_id; + request.transferred_request_request_id = request_id; + + // For cleanup. + child_ids_.insert(second_filter->child_id()); + ResourceHostMsg_RequestResource transfer_request_msg( + new_render_view_id, new_request_id, request); + bool msg_was_ok; + host_.OnMessageReceived( + transfer_request_msg, second_filter.get(), &msg_was_ok); + base::MessageLoop::current()->RunUntilIdle(); + + // Flush all the pending requests. + while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} + + // Check generated messages. + ResourceIPCAccumulator::ClassifiedMessages msgs; + accum_.GetClassifiedMessages(&msgs); + + ASSERT_EQ(1U, msgs.size()); + CheckSuccessfulRequest(msgs[0], kResponseBody); +} + TEST_F(ResourceDispatcherHostTest, TransferNavigationAndThenRedirect) { EXPECT_EQ(0, host_.pending_requests()); @@ -1824,6 +1912,15 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationAndThenRedirect) { // Flush all the pending requests. while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} + // Verify that we update the ResourceRequestInfo. + GlobalRequestID global_request_id(second_filter->child_id(), new_request_id); + const ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest( + host_.GetURLRequest(global_request_id)); + EXPECT_EQ(second_filter->child_id(), info->GetChildID()); + EXPECT_EQ(new_render_view_id, info->GetRouteID()); + EXPECT_EQ(new_request_id, info->GetRequestID()); + EXPECT_EQ(second_filter, info->filter()); + // Now, simulate the renderer choosing to follow the redirect. ResourceHostMsg_FollowRedirect redirect_msg( new_request_id, false, GURL()); diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc index 5b0a9f4..c99fe5b 100644 --- a/content/browser/loader/resource_loader.cc +++ b/content/browser/loader/resource_loader.cc @@ -9,7 +9,6 @@ #include "base/metrics/histogram.h" #include "base/time/time.h" #include "content/browser/child_process_security_policy_impl.h" -#include "content/browser/loader/doomed_resource_handler.h" #include "content/browser/loader/resource_loader_delegate.h" #include "content/browser/loader/resource_request_info_impl.h" #include "content/browser/ssl/ssl_client_auth_handler.h" @@ -163,29 +162,12 @@ void ResourceLoader::MarkAsTransferring(const GURL& target_url) { // When transferring a request to another process, the renderer doesn't get // a chance to update the cookie policy URL. Do it here instead. request()->set_first_party_for_cookies(target_url); - - // When an URLRequest is transferred to a new RenderViewHost, its - // ResourceHandler should not receive any notifications because it may depend - // on the state of the old RVH. We set a ResourceHandler that only allows - // canceling requests, because on shutdown of the RDH all pending requests - // are canceled. The RVH of requests that are being transferred may be gone - // by that time. In CompleteTransfer, the ResoureHandlers are substituted - // again. - handler_.reset(new DoomedResourceHandler(handler_.Pass())); -} - -void ResourceLoader::WillCompleteTransfer() { - handler_.reset(); } -void ResourceLoader::CompleteTransfer(scoped_ptr<ResourceHandler> new_handler) { +void ResourceLoader::CompleteTransfer() { DCHECK_EQ(DEFERRED_REDIRECT, deferred_stage_); - DCHECK(!handler_.get()); - handler_ = new_handler.Pass(); - handler_->SetController(this); is_transferring_ = false; - Resume(); } diff --git a/content/browser/loader/resource_loader.h b/content/browser/loader/resource_loader.h index 76f72e2..6a611a7 100644 --- a/content/browser/loader/resource_loader.h +++ b/content/browser/loader/resource_loader.h @@ -43,8 +43,7 @@ class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate, bool is_transferring() const { return is_transferring_; } void MarkAsTransferring(const GURL& target_url); - void WillCompleteTransfer(); - void CompleteTransfer(scoped_ptr<ResourceHandler> new_handler); + void CompleteTransfer(); net::URLRequest* request() { return request_.get(); } ResourceRequestInfoImpl* GetRequestInfo(); diff --git a/content/browser/loader/resource_message_delegate.h b/content/browser/loader/resource_message_delegate.h index d5716e3..f447808 100644 --- a/content/browser/loader/resource_message_delegate.h +++ b/content/browser/loader/resource_message_delegate.h @@ -32,6 +32,10 @@ class CONTENT_EXPORT ResourceMessageDelegate { virtual bool OnMessageReceived(const IPC::Message& message, bool* message_was_ok) = 0; + void set_request_id(const GlobalRequestID& new_request_id) { + id_ = new_request_id; + } + private: GlobalRequestID id_; DISALLOW_IMPLICIT_CONSTRUCTORS(ResourceMessageDelegate); diff --git a/content/browser/loader/resource_message_filter.cc b/content/browser/loader/resource_message_filter.cc index 26ba80f..c55f2d1 100644 --- a/content/browser/loader/resource_message_filter.cc +++ b/content/browser/loader/resource_message_filter.cc @@ -24,7 +24,8 @@ ResourceMessageFilter::ResourceMessageFilter( appcache_service_(appcache_service), blob_storage_context_(blob_storage_context), file_system_context_(file_system_context), - get_contexts_callback_(get_contexts_callback) { + get_contexts_callback_(get_contexts_callback), + weak_ptr_factory_(this) { } ResourceMessageFilter::~ResourceMessageFilter() { @@ -51,4 +52,8 @@ void ResourceMessageFilter::GetContexts( return get_contexts_callback_.Run(request, resource_context, request_context); } +base::WeakPtr<ResourceMessageFilter> ResourceMessageFilter::GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); +} + } // namespace content diff --git a/content/browser/loader/resource_message_filter.h b/content/browser/loader/resource_message_filter.h index 925e452..a2fb2e3 100644 --- a/content/browser/loader/resource_message_filter.h +++ b/content/browser/loader/resource_message_filter.h @@ -7,6 +7,7 @@ #include "base/callback_forward.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "content/common/content_export.h" #include "content/public/browser/browser_message_filter.h" #include "webkit/common/resource_type.h" @@ -76,6 +77,8 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter { int child_id() const { return child_id_; } int process_type() const { return process_type_; } + base::WeakPtr<ResourceMessageFilter> GetWeakPtr(); + protected: // Protected destructor so that we can be overriden in tests. virtual ~ResourceMessageFilter(); @@ -92,6 +95,9 @@ class CONTENT_EXPORT ResourceMessageFilter : public BrowserMessageFilter { GetContextsCallback get_contexts_callback_; + // This must come last to make sure weak pointers are invalidated first. + base::WeakPtrFactory<ResourceMessageFilter> weak_ptr_factory_; + DISALLOW_IMPLICIT_CONSTRUCTORS(ResourceMessageFilter); }; diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc index c41fe39..04d4f2a 100644 --- a/content/browser/loader/resource_request_info_impl.cc +++ b/content/browser/loader/resource_request_info_impl.cc @@ -5,6 +5,7 @@ #include "content/browser/loader/resource_request_info_impl.h" #include "content/browser/loader/global_routing_id.h" +#include "content/browser/loader/resource_message_filter.h" #include "content/browser/worker_host/worker_service_impl.h" #include "content/common/net/url_request_user_data.h" #include "content/public/browser/global_request_id.h" @@ -47,6 +48,7 @@ void ResourceRequestInfo::AllocateForTesting( false, // has_user_gesture WebKit::WebReferrerPolicyDefault, // referrer_policy context, // context + base::WeakPtr<ResourceMessageFilter>(), // filter false); // is_async info->AssociateWithRequest(request); } @@ -98,6 +100,7 @@ ResourceRequestInfoImpl::ResourceRequestInfoImpl( bool has_user_gesture, WebKit::WebReferrerPolicy referrer_policy, ResourceContext* context, + base::WeakPtr<ResourceMessageFilter> filter, bool is_async) : cross_site_handler_(NULL), process_type_(process_type), @@ -119,6 +122,7 @@ ResourceRequestInfoImpl::ResourceRequestInfoImpl( memory_cost_(0), referrer_policy_(referrer_policy), context_(context), + filter_(filter), is_async_(is_async) { } @@ -228,4 +232,20 @@ GlobalRoutingID ResourceRequestInfoImpl::GetGlobalRoutingID() const { return GlobalRoutingID(child_id_, route_id_); } +void ResourceRequestInfoImpl::UpdateForTransfer( + int child_id, + int route_id, + int origin_pid, + int request_id, + int64 frame_id, + int64 parent_frame_id, + base::WeakPtr<ResourceMessageFilter> filter) { + child_id_ = child_id; + route_id_ = route_id; + origin_pid_ = origin_pid; + request_id_ = request_id; + frame_id_ = frame_id; + filter_ = filter; +} + } // namespace content diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h index e615116..6947315a 100644 --- a/content/browser/loader/resource_request_info_impl.h +++ b/content/browser/loader/resource_request_info_impl.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/supports_user_data.h" #include "content/public/browser/resource_request_info.h" #include "content/public/common/referrer.h" @@ -19,6 +20,7 @@ namespace content { class CrossSiteResourceHandler; class ResourceContext; +class ResourceMessageFilter; struct GlobalRequestID; struct GlobalRoutingID; @@ -53,6 +55,7 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo, bool has_user_gesture, WebKit::WebReferrerPolicy referrer_policy, ResourceContext* context, + base::WeakPtr<ResourceMessageFilter> filter, bool is_async); virtual ~ResourceRequestInfoImpl(); @@ -81,6 +84,23 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo, CONTENT_EXPORT GlobalRequestID GetGlobalRequestID() const; GlobalRoutingID GetGlobalRoutingID() const; + // May be NULL (e.g., if process dies during a transfer). + ResourceMessageFilter* filter() const { + return filter_.get(); + } + + // Updates the data associated with this request after it is is transferred + // to a new renderer process. Not all data will change during a transfer. + // We do not expect the ResourceContext to change during navigation, so that + // does not need to be updated. + void UpdateForTransfer(int child_id, + int route_id, + int origin_pid, + int request_id, + int64 frame_id, + int64 parent_frame_id, + base::WeakPtr<ResourceMessageFilter> filter); + // CrossSiteResourceHandler for this request. May be null. CrossSiteResourceHandler* cross_site_handler() { return cross_site_handler_; @@ -135,6 +155,9 @@ class ResourceRequestInfoImpl : public ResourceRequestInfo, int memory_cost_; WebKit::WebReferrerPolicy referrer_policy_; ResourceContext* context_; + // The filter might be deleted without deleting this object if the process + // exits during a transfer. + base::WeakPtr<ResourceMessageFilter> filter_; bool is_async_; DISALLOW_COPY_AND_ASSIGN(ResourceRequestInfoImpl); diff --git a/content/browser/loader/resource_scheduler_unittest.cc b/content/browser/loader/resource_scheduler_unittest.cc index 2c4c110..6a0bd28 100644 --- a/content/browser/loader/resource_scheduler_unittest.cc +++ b/content/browser/loader/resource_scheduler_unittest.cc @@ -159,6 +159,7 @@ class ResourceSchedulerTest : public testing::Test { false, // has_user_gesture WebKit::WebReferrerPolicyDefault, // referrer_policy NULL, // context + base::WeakPtr<ResourceMessageFilter>(), // filter true); // is_async info->AssociateWithRequest(url_request.get()); return url_request.Pass(); diff --git a/content/browser/loader/sync_resource_handler.cc b/content/browser/loader/sync_resource_handler.cc index b1a7162..1608fc4 100644 --- a/content/browser/loader/sync_resource_handler.cc +++ b/content/browser/loader/sync_resource_handler.cc @@ -8,23 +8,21 @@ #include "content/browser/devtools/devtools_netlog_observer.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" #include "content/browser/loader/resource_message_filter.h" +#include "content/browser/loader/resource_request_info_impl.h" #include "content/common/resource_messages.h" #include "content/public/browser/global_request_id.h" #include "content/public/browser/resource_dispatcher_host_delegate.h" +#include "content/public/browser/resource_request_info.h" #include "net/base/io_buffer.h" #include "net/http/http_response_headers.h" namespace content { SyncResourceHandler::SyncResourceHandler( - ResourceMessageFilter* filter, - ResourceContext* resource_context, net::URLRequest* request, IPC::Message* result_message, ResourceDispatcherHostImpl* resource_dispatcher_host) : read_buffer_(new net::IOBuffer(kReadBufSize)), - filter_(filter), - resource_context_(resource_context), request_(request), result_message_(result_message), rdh_(resource_dispatcher_host) { @@ -34,7 +32,12 @@ SyncResourceHandler::SyncResourceHandler( SyncResourceHandler::~SyncResourceHandler() { if (result_message_) { result_message_->set_reply_error(); - filter_->Send(result_message_); + const ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); + // If the filter doesn't exist at this point, the process has died and isn't + // waiting for the result message anymore. + if (info->filter()) + info->filter()->Send(result_message_); } } @@ -50,8 +53,10 @@ bool SyncResourceHandler::OnRequestRedirected( ResourceResponse* response, bool* defer) { if (rdh_->delegate()) { + const ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); rdh_->delegate()->OnRequestRedirected( - new_url, request_, resource_context_, response); + new_url, request_, info->GetContext(), response); } DevToolsNetLogObserver::PopulateResponseInfo(request_, response); @@ -70,9 +75,14 @@ bool SyncResourceHandler::OnResponseStarted( int request_id, ResourceResponse* response, bool* defer) { + const ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); + if (!info->filter()) + return false; + if (rdh_->delegate()) { rdh_->delegate()->OnResponseStarted( - request_, resource_context_, response, filter_.get()); + request_, info->GetContext(), response, info->filter()); } DevToolsNetLogObserver::PopulateResponseInfo(request_, response); @@ -115,13 +125,18 @@ bool SyncResourceHandler::OnResponseCompleted( int request_id, const net::URLRequestStatus& status, const std::string& security_info) { + const ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); + if (!info->filter()) + return false; + result_.error_code = status.error(); result_.encoded_data_length = DevToolsNetLogObserver::GetAndResetEncodedDataLength(request_); ResourceHostMsg_SyncLoad::WriteReplyParams(result_message_, result_); - filter_->Send(result_message_); + info->filter()->Send(result_message_); result_message_ = NULL; return true; } diff --git a/content/browser/loader/sync_resource_handler.h b/content/browser/loader/sync_resource_handler.h index 838a05a..358d92a 100644 --- a/content/browser/loader/sync_resource_handler.h +++ b/content/browser/loader/sync_resource_handler.h @@ -28,9 +28,7 @@ class ResourceMessageFilter; // events from the resource dispatcher host. class SyncResourceHandler : public ResourceHandler { public: - SyncResourceHandler(ResourceMessageFilter* filter, - ResourceContext* resource_context, - net::URLRequest* request, + SyncResourceHandler(net::URLRequest* request, IPC::Message* result_message, ResourceDispatcherHostImpl* resource_dispatcher_host); virtual ~SyncResourceHandler(); @@ -66,8 +64,6 @@ class SyncResourceHandler : public ResourceHandler { scoped_refptr<net::IOBuffer> read_buffer_; SyncLoadResult result_; - scoped_refptr<ResourceMessageFilter> filter_; - ResourceContext* resource_context_; net::URLRequest* request_; IPC::Message* result_message_; ResourceDispatcherHostImpl* rdh_; diff --git a/content/browser/loader/throttling_resource_handler.cc b/content/browser/loader/throttling_resource_handler.cc index 5725e03..8bb5446 100644 --- a/content/browser/loader/throttling_resource_handler.cc +++ b/content/browser/loader/throttling_resource_handler.cc @@ -4,6 +4,7 @@ #include "content/browser/loader/throttling_resource_handler.h" +#include "content/public/browser/resource_request_info.h" #include "content/public/browser/resource_throttle.h" #include "content/public/common/resource_response.h" @@ -11,12 +12,11 @@ namespace content { ThrottlingResourceHandler::ThrottlingResourceHandler( scoped_ptr<ResourceHandler> next_handler, - int child_id, - int request_id, + net::URLRequest* request, ScopedVector<ResourceThrottle> throttles) : LayeredResourceHandler(next_handler.Pass()), deferred_stage_(DEFERRED_NONE), - request_id_(request_id), + request_(request), throttles_(throttles.Pass()), index_(0), cancelled_by_resource_throttle_(false) { @@ -31,7 +31,6 @@ bool ThrottlingResourceHandler::OnRequestRedirected(int request_id, const GURL& new_url, ResourceResponse* response, bool* defer) { - DCHECK_EQ(request_id_, request_id); DCHECK(!cancelled_by_resource_throttle_); *defer = false; @@ -57,7 +56,6 @@ bool ThrottlingResourceHandler::OnRequestRedirected(int request_id, bool ThrottlingResourceHandler::OnWillStart(int request_id, const GURL& url, bool* defer) { - DCHECK_EQ(request_id_, request_id); DCHECK(!cancelled_by_resource_throttle_); *defer = false; @@ -81,7 +79,6 @@ bool ThrottlingResourceHandler::OnWillStart(int request_id, bool ThrottlingResourceHandler::OnResponseStarted(int request_id, ResourceResponse* response, bool* defer) { - DCHECK_EQ(request_id_, request_id); DCHECK(!cancelled_by_resource_throttle_); while (index_ < throttles_.size()) { @@ -144,7 +141,8 @@ void ThrottlingResourceHandler::ResumeStart() { deferred_url_ = GURL(); bool defer = false; - if (!OnWillStart(request_id_, url, &defer)) { + const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); + if (!OnWillStart(info->GetRequestID(), url, &defer)) { controller()->Cancel(); } else if (!defer) { controller()->Resume(); @@ -160,7 +158,9 @@ void ThrottlingResourceHandler::ResumeRedirect() { deferred_response_.swap(response); bool defer = false; - if (!OnRequestRedirected(request_id_, new_url, response.get(), &defer)) { + const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); + if (!OnRequestRedirected(info->GetRequestID(), new_url, response.get(), + &defer)) { controller()->Cancel(); } else if (!defer) { controller()->Resume(); @@ -174,7 +174,8 @@ void ThrottlingResourceHandler::ResumeResponse() { deferred_response_.swap(response); bool defer = false; - if (!OnResponseStarted(request_id_, response.get(), &defer)) { + const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); + if (!OnResponseStarted(info->GetRequestID(), response.get(), &defer)) { controller()->Cancel(); } else if (!defer) { controller()->Resume(); diff --git a/content/browser/loader/throttling_resource_handler.h b/content/browser/loader/throttling_resource_handler.h index 2661cdd..168dc56 100644 --- a/content/browser/loader/throttling_resource_handler.h +++ b/content/browser/loader/throttling_resource_handler.h @@ -11,6 +11,10 @@ #include "content/public/browser/resource_controller.h" #include "url/gurl.h" +namespace net { +class URLRequest; +} + namespace content { class ResourceThrottle; @@ -22,8 +26,7 @@ class ThrottlingResourceHandler : public LayeredResourceHandler, public: // Takes ownership of the ResourceThrottle instances. ThrottlingResourceHandler(scoped_ptr<ResourceHandler> next_handler, - int child_id, - int request_id, + net::URLRequest* request, ScopedVector<ResourceThrottle> throttles); virtual ~ThrottlingResourceHandler(); @@ -56,7 +59,7 @@ class ThrottlingResourceHandler : public LayeredResourceHandler, }; DeferredStage deferred_stage_; - int request_id_; + net::URLRequest* request_; ScopedVector<ResourceThrottle> throttles_; size_t index_; |