1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/loader/transfer_navigation_resource_throttle.h" 6 7 #include "base/bind.h" 8 #include "content/browser/loader/resource_dispatcher_host_impl.h" 9 #include "content/browser/renderer_host/render_view_host_delegate.h" 10 #include "content/public/browser/browser_thread.h" 11 #include "content/public/browser/content_browser_client.h" 12 #include "content/public/browser/global_request_id.h" 13 #include "content/public/browser/render_view_host.h" 14 #include "content/public/browser/resource_request_info.h" 15 #include "content/public/common/referrer.h" 16 #include "net/url_request/url_request.h" 17 18 namespace content { 19 20 namespace { 21 22 void RequestTransferURLOnUIThread(int render_process_id, 23 int render_view_id, 24 const GURL& new_url, 25 const Referrer& referrer, 26 WindowOpenDisposition window_open_disposition, 27 int64 frame_id, 28 const GlobalRequestID& global_request_id) { 29 RenderViewHost* rvh = 30 RenderViewHost::FromID(render_process_id, render_view_id); 31 if (!rvh) 32 return; 33 34 RenderViewHostDelegate* delegate = rvh->GetDelegate(); 35 if (!delegate) 36 return; 37 38 // We don't know whether the original request had |user_action| set to true. 39 // However, since we force the navigation to be in the current tab, it doesn't 40 // matter. 41 delegate->RequestTransferURL( 42 new_url, referrer, window_open_disposition, 43 frame_id, global_request_id, false, true); 44 } 45 46 } // namespace 47 48 TransferNavigationResourceThrottle::TransferNavigationResourceThrottle( 49 net::URLRequest* request) 50 : request_(request) { 51 } 52 53 TransferNavigationResourceThrottle::~TransferNavigationResourceThrottle() { 54 } 55 56 void TransferNavigationResourceThrottle::WillRedirectRequest( 57 const GURL& new_url, 58 bool* defer) { 59 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); 60 61 // If a toplevel request is redirecting across extension extents, we want to 62 // switch processes. We do this by deferring the redirect and resuming the 63 // request once the navigation controller properly assigns the right process 64 // to host the new URL. 65 // TODO(mpcomplete): handle for cases other than extensions (e.g. WebUI). 66 ResourceContext* resource_context = info->GetContext(); 67 if (GetContentClient()->browser()->ShouldSwapProcessesForRedirect( 68 resource_context, request_->url(), new_url)) { 69 int render_process_id, render_view_id; 70 if (info->GetAssociatedRenderView(&render_process_id, &render_view_id)) { 71 GlobalRequestID global_id(info->GetChildID(), info->GetRequestID()); 72 73 ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(global_id, 74 new_url); 75 76 BrowserThread::PostTask( 77 BrowserThread::UI, 78 FROM_HERE, 79 base::Bind(&RequestTransferURLOnUIThread, 80 render_process_id, 81 render_view_id, 82 new_url, 83 Referrer(GURL(request_->referrer()), info->GetReferrerPolicy()), 84 CURRENT_TAB, 85 info->GetFrameID(), 86 global_id)); 87 88 *defer = true; 89 } 90 } 91 } 92 93 } // namespace content 94