Index: chrome/browser/renderer_host/transfer_navigation_resource_handler.cc |
diff --git a/chrome/browser/renderer_host/transfer_navigation_resource_handler.cc b/chrome/browser/renderer_host/transfer_navigation_resource_handler.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f678ad2e2d434dc7d6c91fcee2df206575fab771 |
--- /dev/null |
+++ b/chrome/browser/renderer_host/transfer_navigation_resource_handler.cc |
@@ -0,0 +1,167 @@ |
+// Copyright (c) 2011 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 "chrome/browser/renderer_host/transfer_navigation_resource_handler.h" |
+ |
+#include "base/bind.h" |
+#include "chrome/browser/profiles/profile_io_data.h" |
+#include "chrome/browser/extensions/extension_info_map.h" |
+#include "content/browser/renderer_host/render_view_host.h" |
+#include "content/browser/renderer_host/render_view_host_delegate.h" |
+#include "content/browser/renderer_host/resource_dispatcher_host.h" |
+#include "content/browser/renderer_host/resource_dispatcher_host_request_info.h" |
+ |
+namespace { |
+ |
+// This code is borrowed from ChromeContentRendererClient. We want to mimic |
+// the logic used by the renderer. |
+const Extension* GetNonBookmarkAppExtension( |
+ const ExtensionSet& extensions, const GURL& url) { |
+ // Exclude bookmark apps, which do not use the app process model. |
+ const Extension* extension = extensions.GetByURL(ExtensionURLInfo(url)); |
+ if (extension && extension->from_bookmark()) |
+ extension = NULL; |
+ return extension; |
+} |
+ |
+bool CrossesExtensionExtents( |
+ const ExtensionSet& extensions, |
+ const GURL& old_url, |
+ const GURL& new_url) { |
+ const Extension* new_url_extension = GetNonBookmarkAppExtension(extensions, |
+ new_url); |
+ const Extension* old_url_extension = GetNonBookmarkAppExtension(extensions, |
+ old_url); |
+ |
+ // TODO(creis): Temporary workaround for crbug.com/59285: Only return true if |
+ // we would enter an extension app's extent from a non-app, or if we leave an |
+ // extension with no web extent. We avoid swapping processes to exit a hosted |
+ // app for now, since we do not yet support postMessage calls from outside the |
+ // app back into it (e.g., as in Facebook OAuth 2.0). |
+ bool old_url_is_hosted_app = old_url_extension && |
+ !old_url_extension->web_extent().is_empty(); |
+ if (old_url_is_hosted_app) |
+ return false; |
+ |
+ return old_url_extension != new_url_extension; |
+} |
+ |
+void RequestTransferURLOnUIThread(int render_process_id, |
+ int render_view_id, |
+ GURL new_url, |
+ GURL referrer, |
+ WindowOpenDisposition window_open_disposition, |
+ int64 frame_id, |
+ const GlobalRequestID& request_id) { |
+ RenderViewHost* rvh = RenderViewHost::FromID(render_process_id, |
+ render_view_id); |
+ if (!rvh) |
+ return; |
+ |
+ RenderViewHostDelegate* delegate = rvh->delegate(); |
+ if (!delegate) |
+ return; |
+ |
+ delegate->RequestTransferURL(new_url, referrer, window_open_disposition, |
+ frame_id, request_id); |
+} |
+ |
+} // namespace |
+ |
+TransferNavigationResourceHandler::TransferNavigationResourceHandler( |
+ ResourceHandler* handler, |
+ ResourceDispatcherHost* resource_dispatcher_host, |
+ net::URLRequest* request) |
+ : next_handler_(handler), |
+ rdh_(resource_dispatcher_host), |
+ request_(request) { |
+} |
+ |
+TransferNavigationResourceHandler::~TransferNavigationResourceHandler() { |
+} |
+ |
+bool TransferNavigationResourceHandler::OnUploadProgress(int request_id, |
+ uint64 position, |
+ uint64 size) { |
+ return next_handler_->OnUploadProgress(request_id, position, size); |
+} |
+ |
+bool TransferNavigationResourceHandler::OnRequestRedirected( |
+ int request_id, |
+ const GURL& new_url, |
+ content::ResourceResponse* response, |
+ bool* defer) { |
+ |
+ ResourceDispatcherHostRequestInfo* info = |
+ ResourceDispatcherHost::InfoForRequest(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). |
+ const content::ResourceContext& resource_context = *info->context(); |
+ ProfileIOData* io_data = |
+ reinterpret_cast<ProfileIOData*>(resource_context.GetUserData(NULL)); |
+ |
+ if (info->resource_type() == ResourceType::MAIN_FRAME && |
+ CrossesExtensionExtents(io_data->GetExtensionInfoMap()->extensions(), |
+ request_->url(), new_url)) { |
+ int render_process_id, render_view_id; |
+ if (ResourceDispatcherHost::RenderViewForRequest( |
+ request_, &render_process_id, &render_view_id)) { |
+ |
+ GlobalRequestID global_id(info->child_id(), info->request_id()); |
+ rdh_->MarkAsTransferredNavigation(global_id, request_); |
+ |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(&RequestTransferURLOnUIThread, |
+ render_process_id, render_view_id, |
+ new_url, GURL(request_->referrer()), CURRENT_TAB, |
+ info->frame_id(), global_id)); |
+ |
+ *defer = true; |
+ return true; |
+ } |
+ } |
+ |
+ return next_handler_->OnRequestRedirected( |
+ request_id, new_url, response, defer); |
+} |
+ |
+bool TransferNavigationResourceHandler::OnResponseStarted( |
+ int request_id, content::ResourceResponse* response) { |
+ return next_handler_->OnResponseStarted(request_id, response); |
+} |
+ |
+bool TransferNavigationResourceHandler::OnWillStart(int request_id, |
+ const GURL& url, |
+ bool* defer) { |
+ return next_handler_->OnWillStart(request_id, url, defer); |
+} |
+ |
+bool TransferNavigationResourceHandler::OnWillRead(int request_id, |
+ net::IOBuffer** buf, |
+ int* buf_size, |
+ int min_size) { |
+ return next_handler_->OnWillRead(request_id, buf, buf_size, min_size); |
+} |
+ |
+bool TransferNavigationResourceHandler::OnReadCompleted(int request_id, |
+ int* bytes_read) { |
+ return next_handler_->OnReadCompleted(request_id, bytes_read); |
+} |
+ |
+bool TransferNavigationResourceHandler::OnResponseCompleted( |
+ int request_id, |
+ const net::URLRequestStatus& status, |
+ const std::string& security_info) { |
+ return next_handler_->OnResponseCompleted(request_id, status, security_info); |
+} |
+ |
+void TransferNavigationResourceHandler::OnRequestClosed() { |
+ next_handler_->OnRequestClosed(); |
+} |