diff options
author | creis@chromium.org <creis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-01 20:12:54 +0000 |
---|---|---|
committer | creis@chromium.org <creis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-01 20:12:54 +0000 |
commit | 37403f36a6984400c226fda2afd139be51043a1c (patch) | |
tree | 72b6ca06acd47399f37a784a8bb2c96d8dde44fc /content/browser/loader | |
parent | 584a1aaa6645e49fc05fb7a43c7d6693c329f01e (diff) | |
download | chromium_src-37403f36a6984400c226fda2afd139be51043a1c.zip chromium_src-37403f36a6984400c226fda2afd139be51043a1c.tar.gz chromium_src-37403f36a6984400c226fda2afd139be51043a1c.tar.bz2 |
Move TransferNavigationResourceThrottle into CrossSiteResourceHandler.
We now transfer requests to a new process when they are ready to commit, rather than each time a redirect occurs. This simplifies the ResourceDispatcherHost logic, and it prepares for a future CL to intercept all navigations in the browser process.
BUG=238331
TEST=No more than one process swap for repeated redirects.
Review URL: https://codereview.chromium.org/15476003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@226284 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/loader')
7 files changed, 217 insertions, 232 deletions
diff --git a/content/browser/loader/cross_site_resource_handler.cc b/content/browser/loader/cross_site_resource_handler.cc index 90fe84a..6bac75a 100644 --- a/content/browser/loader/cross_site_resource_handler.cc +++ b/content/browser/loader/cross_site_resource_handler.cc @@ -9,14 +9,17 @@ #include "base/bind.h" #include "base/logging.h" #include "content/browser/cross_site_request_manager.h" +#include "content/browser/loader/resource_dispatcher_host_impl.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" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/content_browser_client.h" #include "content/public/browser/global_request_id.h" #include "content/public/browser/resource_controller.h" #include "content/public/common/resource_response.h" #include "net/http/http_response_headers.h" +#include "net/url_request/url_request.h" namespace content { @@ -24,13 +27,21 @@ namespace { void OnCrossSiteResponseHelper(int render_process_id, int render_view_id, - int request_id) { + const GlobalRequestID& global_request_id, + bool is_transfer, + const GURL& transfer_url, + const Referrer& referrer, + int64 frame_id) { RenderViewHostImpl* rvh = RenderViewHostImpl::FromID(render_process_id, render_view_id); - if (rvh && rvh->GetDelegate()->GetRendererManagementDelegate()) { - rvh->GetDelegate()->GetRendererManagementDelegate()->OnCrossSiteResponse( - rvh, GlobalRequestID(render_process_id, request_id)); - } + if (!rvh) + return; + RenderViewHostDelegate* delegate = rvh->GetDelegate(); + if (!delegate || !delegate->GetRendererManagementDelegate()) + return; + + delegate->GetRendererManagementDelegate()->OnCrossSiteResponse( + rvh, global_request_id, is_transfer, transfer_url, referrer, frame_id); } } // namespace @@ -77,10 +88,16 @@ 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()); + // We will need to swap processes if either (1) a redirect that requires a + // transfer occurred before we got here, or (2) a pending cross-site request + // was already in progress. Note that a swap may no longer be needed if we + // transferred back into the original process due to a redirect. + bool should_transfer = + GetContentClient()->browser()->ShouldSwapProcessesForRedirect( + info->GetContext(), request_->original_url(), request_->url()); + bool swap_needed = should_transfer || + 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 @@ -90,8 +107,9 @@ bool CrossSiteResourceHandler::OnResponseStarted( // page. We should allow the navigation to finish without running the unload // handler or swapping in the pending RenderViewHost. // - // 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. + // In both cases, any pending RenderViewHost (if one was created for this + // navigation) will stick around until the next cross-site navigation, since + // we are unable to tell when to destroy it. // See RenderViewHostManager::RendererAbortedProvisionalLoad. if (!swap_needed || info->is_download() || (response->head.headers.get() && @@ -99,8 +117,10 @@ bool CrossSiteResourceHandler::OnResponseStarted( return next_handler_->OnResponseStarted(request_id, response, defer); } - // Tell the renderer to run the onunload event handler. - StartCrossSiteTransition(request_id, response); + // Now that we know a swap is needed and we have something to commit, we + // pause to let the UI thread run the unload handler of the previous page + // and set up a transfer if needed. + StartCrossSiteTransition(request_id, response, should_transfer); // Defer loading until after the onunload event handler has run. did_defer_ = *defer = true; @@ -119,19 +139,24 @@ bool CrossSiteResourceHandler::OnResponseCompleted( const net::URLRequestStatus& status, const std::string& security_info) { if (!in_cross_site_transition_) { + ResourceRequestInfoImpl* info = + ResourceRequestInfoImpl::ForRequest(request_); + // If we've already completed the transition, or we're canceling the + // request, or an error occurred with no cross-process navigation in + // progress, then we should just pass this through. if (has_started_response_ || - status.status() != net::URLRequestStatus::FAILED) { - // We've already completed the transition or we're canceling the request, - // so just pass it through. + status.status() != net::URLRequestStatus::FAILED || + !CrossSiteRequestManager::GetInstance()->HasPendingCrossSiteRequest( + info->GetChildID(), info->GetRouteID())) { return next_handler_->OnResponseCompleted(request_id, status, security_info); } - // An error occured, we should wait now for the cross-site transition, + // An error occurred. We should wait now for the cross-process transition, // so that the error message (e.g., 404) can be displayed to the user. // Also continue with the logic below to remember that we completed // during the cross-site transition. - StartCrossSiteTransition(request_id, NULL); + StartCrossSiteTransition(request_id, NULL, false); } // We have to buffer the call until after the transition completes. @@ -186,19 +211,35 @@ void CrossSiteResourceHandler::ResumeResponse() { // telling the old RenderViewHost to run its onunload handler. void CrossSiteResourceHandler::StartCrossSiteTransition( int request_id, - ResourceResponse* response) { + ResourceResponse* response, + bool should_transfer) { in_cross_site_transition_ = true; response_ = response; // Store this handler on the ExtraRequestInfo, so that RDH can call our - // ResumeResponse method when the close ACK is received. + // ResumeResponse method when we are ready to resume. ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_); info->set_cross_site_handler(this); + DCHECK_EQ(request_id, info->GetRequestID()); + GlobalRequestID global_id(info->GetChildID(), info->GetRequestID()); + // Tell the contents responsible for this request that a cross-site response // is starting, so that it can tell its old renderer to run its onunload - // handler now. We will wait to hear the corresponding ClosePage_ACK. + // handler now. We will wait until the unload is finished and (if a transfer + // is needed) for the new renderer's request to arrive. + GURL transfer_url; + Referrer referrer; + int frame_id = -1; + if (should_transfer) { + transfer_url = request_->url(); + referrer = Referrer(GURL(request_->referrer()), info->GetReferrerPolicy()); + frame_id = info->GetFrameID(); + + ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation( + global_id, transfer_url); + } BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, @@ -206,10 +247,11 @@ void CrossSiteResourceHandler::StartCrossSiteTransition( &OnCrossSiteResponseHelper, info->GetChildID(), info->GetRouteID(), - request_id)); - - // TODO(creis): If the above call should fail, then we need to notify the IO - // thread to proceed anyway, using ResourceDispatcherHost::OnClosePageACK. + global_id, + should_transfer, + transfer_url, + referrer, + frame_id)); } void CrossSiteResourceHandler::ResumeIfDeferred() { diff --git a/content/browser/loader/cross_site_resource_handler.h b/content/browser/loader/cross_site_resource_handler.h index 39c3a14..5c08f7e 100644 --- a/content/browser/loader/cross_site_resource_handler.h +++ b/content/browser/loader/cross_site_resource_handler.h @@ -47,9 +47,9 @@ class CrossSiteResourceHandler : public LayeredResourceHandler { private: // Prepare to render the cross-site response in a new RenderViewHost, by // telling the old RenderViewHost to run its onunload handler. - void StartCrossSiteTransition( - int request_id, - ResourceResponse* response); + void StartCrossSiteTransition(int request_id, + ResourceResponse* response, + bool should_transfer); void ResumeIfDeferred(); diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index a44715d..839678e 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc @@ -40,7 +40,6 @@ #include "content/browser/loader/stream_resource_handler.h" #include "content/browser/loader/sync_resource_handler.h" #include "content/browser/loader/throttling_resource_handler.h" -#include "content/browser/loader/transfer_navigation_resource_throttle.h" #include "content/browser/loader/upload_data_stream_builder.h" #include "content/browser/plugin_service_impl.h" #include "content/browser/renderer_host/render_view_host_delegate.h" @@ -938,6 +937,9 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer( route_id, request_id); } + + // We should have a CrossSiteResourceHandler to finish the transfer. + DCHECK(info->cross_site_handler()); } void ResourceDispatcherHostImpl::BeginRequest( @@ -1107,16 +1109,11 @@ void ResourceDispatcherHostImpl::BeginRequest( new RedirectToFileResourceHandler(handler.Pass(), request, this)); } - // Install a CrossSiteResourceHandler if this request is coming from a - // RenderViewHost with a pending cross-site request. We only check this for - // MAIN_FRAME requests. Unblock requests only come from a blocked page, do - // not count as cross-site, otherwise it gets blocked indefinitely. - if (request_data.resource_type == ResourceType::MAIN_FRAME && - process_type == PROCESS_TYPE_RENDERER && - CrossSiteRequestManager::GetInstance()-> - 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. + // Install a CrossSiteResourceHandler for all main frame requests. This will + // let us check whether a transfer is required and pause for the unload + // handler either if so or if a cross-process navigation is already under way. + if (request_data.resource_type == ResourceType::MAIN_FRAME && + process_type == PROCESS_TYPE_RENDERER) { handler.reset(new CrossSiteResourceHandler(handler.Pass(), request)); } @@ -1140,12 +1137,6 @@ void ResourceDispatcherHostImpl::BeginRequest( throttles.push_back(new PowerSaveBlockResourceThrottle()); } - if (request_data.resource_type == ResourceType::MAIN_FRAME) { - throttles.insert( - throttles.begin(), - new TransferNavigationResourceThrottle(request)); - } - throttles.push_back( scheduler_->ScheduleRequest(child_id, route_id, request).release()); diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc index 75f3c7b..4a9e275 100644 --- a/content/browser/loader/resource_dispatcher_host_unittest.cc +++ b/content/browser/loader/resource_dispatcher_host_unittest.cc @@ -9,6 +9,7 @@ #include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" #include "base/pickle.h" +#include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "content/browser/browser_thread_impl.h" @@ -1698,7 +1699,9 @@ TEST_F(ResourceDispatcherHostTest, CancelRequestsForContextTransferred) { EXPECT_EQ(0, host_.pending_requests()); } -TEST_F(ResourceDispatcherHostTest, TransferNavigation) { +// Test transferred navigations with text/html, which doesn't trigger any +// content sniffing. +TEST_F(ResourceDispatcherHostTest, TransferNavigationHtml) { EXPECT_EQ(0, host_.pending_requests()); int render_view_id = 0; @@ -1718,7 +1721,22 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigation) { MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); - // Restore. + // Now that we're blocked on the redirect, update the response and unblock by + // telling the AsyncResourceHandler to follow the redirect. + const std::string kResponseBody = "hello world"; + SetResponse("HTTP/1.1 200 OK\n" + "Content-Type: text/html\n\n", + kResponseBody); + ResourceHostMsg_FollowRedirect redirect_msg(request_id, false, GURL()); + bool msg_was_ok; + host_.OnMessageReceived(redirect_msg, filter_.get(), &msg_was_ok); + base::MessageLoop::current()->RunUntilIdle(); + + // Flush all the pending requests to get the response through the + // BufferedResourceHandler. + while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} + + // Restore, now that we've set up a transfer. SetBrowserClientForTesting(old_client); // This second filter is used to emulate a second process. @@ -1728,10 +1746,78 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigation) { int new_render_view_id = 1; int new_request_id = 2; + ResourceHostMsg_Request request = + CreateResourceRequest("GET", ResourceType::MAIN_FRAME, + GURL("http://other.com/blech")); + request.transferred_request_child_id = filter_->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); + host_.OnMessageReceived( + transfer_request_msg, second_filter.get(), &msg_was_ok); + base::MessageLoop::current()->RunUntilIdle(); + + // Check generated messages. + ResourceIPCAccumulator::ClassifiedMessages msgs; + accum_.GetClassifiedMessages(&msgs); + + ASSERT_EQ(2U, msgs.size()); + EXPECT_EQ(ResourceMsg_ReceivedRedirect::ID, msgs[0][0].type()); + CheckSuccessfulRequest(msgs[1], kResponseBody); +} + +// Test transferred navigations with text/plain, which causes +// BufferedResourceHandler to buffer the response to sniff the content +// before the transfer occurs. +TEST_F(ResourceDispatcherHostTest, TransferNavigationText) { + EXPECT_EQ(0, host_.pending_requests()); + + int render_view_id = 0; + int request_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); + + MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); + + // Now that we're blocked on the redirect, update the response and unblock by + // telling the AsyncResourceHandler to follow the redirect. Use a text/plain + // MIME type, which causes BufferedResourceHandler to buffer it before the + // transfer occurs. const std::string kResponseBody = "hello world"; SetResponse("HTTP/1.1 200 OK\n" "Content-Type: text/plain\n\n", kResponseBody); + ResourceHostMsg_FollowRedirect redirect_msg(request_id, false, GURL()); + bool msg_was_ok; + host_.OnMessageReceived(redirect_msg, filter_.get(), &msg_was_ok); + base::MessageLoop::current()->RunUntilIdle(); + + // Flush all the pending requests to get the response through the + // BufferedResourceHandler. + while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} + + // Restore, now that we've set up a transfer. + SetBrowserClientForTesting(old_client); + + // 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; ResourceHostMsg_Request request = CreateResourceRequest("GET", ResourceType::MAIN_FRAME, @@ -1743,20 +1829,17 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigation) { 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); + ASSERT_EQ(2U, msgs.size()); + EXPECT_EQ(ResourceMsg_ReceivedRedirect::ID, msgs[0][0].type()); + CheckSuccessfulRequest(msgs[1], kResponseBody); } TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) { @@ -1769,6 +1852,7 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) { // Configure initial request. SetResponse("HTTP/1.1 302 Found\n" "Location: http://other.com/blech\n\n"); + const std::string kResponseBody = "hello world"; SetResourceType(ResourceType::MAIN_FRAME); HandleScheme("http"); @@ -1796,6 +1880,19 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) { host_.OnMessageReceived( first_request_msg, first_filter.get(), &msg_was_ok); base::MessageLoop::current()->RunUntilIdle(); + + // Now that we're blocked on the redirect, update the response and unblock + // by telling the AsyncResourceHandler to follow the redirect. + SetResponse("HTTP/1.1 200 OK\n" + "Content-Type: text/html\n\n", + kResponseBody); + ResourceHostMsg_FollowRedirect redirect_msg(request_id, false, GURL()); + host_.OnMessageReceived(redirect_msg, first_filter.get(), &msg_was_ok); + base::MessageLoop::current()->RunUntilIdle(); + + // Flush all the pending requests to get the response through the + // BufferedResourceHandler. + while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} } // The first filter is now deleted, as if the child process died. @@ -1812,11 +1909,6 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) { 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")); @@ -1832,18 +1924,16 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationWithProcessCrash) { 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); + ASSERT_EQ(2U, msgs.size()); + EXPECT_EQ(ResourceMsg_ReceivedRedirect::ID, msgs[0][0].type()); + CheckSuccessfulRequest(msgs[1], kResponseBody); } -TEST_F(ResourceDispatcherHostTest, TransferNavigationAndThenRedirect) { +TEST_F(ResourceDispatcherHostTest, TransferNavigationWithTwoRedirects) { EXPECT_EQ(0, host_.pending_requests()); int render_view_id = 0; @@ -1863,6 +1953,30 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationAndThenRedirect) { MakeTestRequest(render_view_id, request_id, GURL("http://example.com/blah")); + // Now that we're blocked on the redirect, simulate hitting another redirect. + SetResponse("HTTP/1.1 302 Found\n" + "Location: http://other.com/blerg\n\n"); + ResourceHostMsg_FollowRedirect redirect_msg(request_id, false, GURL()); + bool msg_was_ok; + host_.OnMessageReceived(redirect_msg, filter_.get(), &msg_was_ok); + base::MessageLoop::current()->RunUntilIdle(); + + // Now that we're blocked on the second redirect, update the response and + // unblock by telling the AsyncResourceHandler to follow the redirect. + // Again, use text/plain to force BufferedResourceHandler to buffer before + // the transfer. + const std::string kResponseBody = "hello world"; + SetResponse("HTTP/1.1 200 OK\n" + "Content-Type: text/plain\n\n", + kResponseBody); + ResourceHostMsg_FollowRedirect redirect_msg2(request_id, false, GURL()); + host_.OnMessageReceived(redirect_msg2, filter_.get(), &msg_was_ok); + base::MessageLoop::current()->RunUntilIdle(); + + // Flush all the pending requests to get the response through the + // BufferedResourceHandler. + while (net::URLRequestTestJob::ProcessOnePendingMessage()) {} + // Restore. SetBrowserClientForTesting(old_client); @@ -1873,13 +1987,6 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationAndThenRedirect) { int new_render_view_id = 1; int new_request_id = 2; - // Delay the start of the next request so that we can setup the response for - // the next URL. - SetDelayedStartJobGeneration(true); - - SetResponse("HTTP/1.1 302 Found\n" - "Location: http://other.com/blerg\n\n"); - ResourceHostMsg_Request request = CreateResourceRequest("GET", ResourceType::MAIN_FRAME, GURL("http://other.com/blech")); @@ -1890,24 +1997,8 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationAndThenRedirect) { 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(); - - // Response data for "http://other.com/blerg": - const std::string kResponseBody = "hello world"; - SetResponse("HTTP/1.1 200 OK\n" - "Content-Type: text/plain\n\n", - kResponseBody); - - // OK, let the redirect happen. - SetDelayedStartJobGeneration(false); - CompleteStartRequest(second_filter.get(), new_request_id); - base::MessageLoop::current()->RunUntilIdle(); - - // 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); @@ -1918,25 +2009,16 @@ TEST_F(ResourceDispatcherHostTest, TransferNavigationAndThenRedirect) { 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()); - host_.OnMessageReceived(redirect_msg, second_filter.get(), &msg_was_ok); + // Let request complete. 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()); - - // We should have received a redirect followed by a "normal" payload. + ASSERT_EQ(2U, msgs.size()); EXPECT_EQ(ResourceMsg_ReceivedRedirect::ID, msgs[0][0].type()); - msgs[0].erase(msgs[0].begin()); - CheckSuccessfulRequest(msgs[0], kResponseBody); + CheckSuccessfulRequest(msgs[1], kResponseBody); } TEST_F(ResourceDispatcherHostTest, UnknownURLScheme) { diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc index c99fe5b..8f70ab5 100644 --- a/content/browser/loader/resource_loader.cc +++ b/content/browser/loader/resource_loader.cc @@ -9,6 +9,7 @@ #include "base/metrics/histogram.h" #include "base/time/time.h" #include "content/browser/child_process_security_policy_impl.h" +#include "content/browser/loader/cross_site_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" @@ -165,10 +166,10 @@ void ResourceLoader::MarkAsTransferring(const GURL& target_url) { } void ResourceLoader::CompleteTransfer() { - DCHECK_EQ(DEFERRED_REDIRECT, deferred_stage_); + DCHECK_EQ(DEFERRED_READ, deferred_stage_); is_transferring_ = false; - Resume(); + GetRequestInfo()->cross_site_handler()->ResumeResponse(); } ResourceRequestInfoImpl* ResourceLoader::GetRequestInfo() { diff --git a/content/browser/loader/transfer_navigation_resource_throttle.cc b/content/browser/loader/transfer_navigation_resource_throttle.cc deleted file mode 100644 index 8021bce..0000000 --- a/content/browser/loader/transfer_navigation_resource_throttle.cc +++ /dev/null @@ -1,93 +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/transfer_navigation_resource_throttle.h" - -#include "base/bind.h" -#include "content/browser/loader/resource_dispatcher_host_impl.h" -#include "content/browser/renderer_host/render_view_host_delegate.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/content_browser_client.h" -#include "content/public/browser/global_request_id.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/resource_request_info.h" -#include "content/public/common/referrer.h" -#include "net/url_request/url_request.h" - -namespace content { - -namespace { - -void RequestTransferURLOnUIThread(int render_process_id, - int render_view_id, - const GURL& new_url, - const Referrer& referrer, - WindowOpenDisposition window_open_disposition, - int64 frame_id, - const GlobalRequestID& global_request_id) { - RenderViewHost* rvh = - RenderViewHost::FromID(render_process_id, render_view_id); - if (!rvh) - return; - - RenderViewHostDelegate* delegate = rvh->GetDelegate(); - if (!delegate) - return; - - // We don't know whether the original request had |user_action| set to true. - // However, since we force the navigation to be in the current tab, it doesn't - // matter. - delegate->RequestTransferURL( - new_url, referrer, window_open_disposition, - frame_id, global_request_id, false, true); -} - -} // namespace - -TransferNavigationResourceThrottle::TransferNavigationResourceThrottle( - net::URLRequest* request) - : request_(request) { -} - -TransferNavigationResourceThrottle::~TransferNavigationResourceThrottle() { -} - -void TransferNavigationResourceThrottle::WillRedirectRequest( - const GURL& new_url, - bool* defer) { - const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); - - // If a toplevel request is redirecting across extension extents, we want to - // switch processes. We do this by deferring the redirect and resuming the - // request once the navigation controller properly assigns the right process - // to host the new URL. - // TODO(mpcomplete): handle for cases other than extensions (e.g. WebUI). - ResourceContext* resource_context = info->GetContext(); - if (GetContentClient()->browser()->ShouldSwapProcessesForRedirect( - resource_context, request_->url(), new_url)) { - int render_process_id, render_view_id; - if (info->GetAssociatedRenderView(&render_process_id, &render_view_id)) { - GlobalRequestID global_id(info->GetChildID(), info->GetRequestID()); - - ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(global_id, - new_url); - - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(&RequestTransferURLOnUIThread, - render_process_id, - render_view_id, - new_url, - Referrer(GURL(request_->referrer()), info->GetReferrerPolicy()), - CURRENT_TAB, - info->GetFrameID(), - global_id)); - - *defer = true; - } - } -} - -} // namespace content diff --git a/content/browser/loader/transfer_navigation_resource_throttle.h b/content/browser/loader/transfer_navigation_resource_throttle.h deleted file mode 100644 index 6d08c2a..0000000 --- a/content/browser/loader/transfer_navigation_resource_throttle.h +++ /dev/null @@ -1,38 +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_TRANSFER_NAVIGATION_RESOURCE_THROTTLE_H_ -#define CONTENT_BROWSER_LOADER_TRANSFER_NAVIGATION_RESOURCE_THROTTLE_H_ - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "content/public/browser/resource_throttle.h" - -namespace net { -class URLRequest; -} - -namespace content { - -// This ResourceThrottle checks whether a navigation redirect will cause a -// renderer process swap. When that happens, we remember the request so -// that we can transfer it to be handled by the new renderer. This fixes -// http://crbug.com/79520 -class TransferNavigationResourceThrottle : public ResourceThrottle { - public: - explicit TransferNavigationResourceThrottle(net::URLRequest* request); - virtual ~TransferNavigationResourceThrottle(); - - // ResourceThrottle implementation: - virtual void WillRedirectRequest(const GURL& new_url, bool* defer) OVERRIDE; - - private: - net::URLRequest* request_; - - DISALLOW_COPY_AND_ASSIGN(TransferNavigationResourceThrottle); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_LOADER_TRANSFER_NAVIGATION_RESOURCE_THROTTLE_H_ |