summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-03 02:00:48 +0000
committermpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-03 02:00:48 +0000
commit4ad5d77d96dfc6f08a845b6871ecbffa64d6f6e2 (patch)
tree269f9c3132012cea865b9630082ba9009d08f8df
parent143ee25a94004844d0edc8ab5c57913af5d2056f (diff)
downloadchromium_src-4ad5d77d96dfc6f08a845b6871ecbffa64d6f6e2.zip
chromium_src-4ad5d77d96dfc6f08a845b6871ecbffa64d6f6e2.tar.gz
chromium_src-4ad5d77d96dfc6f08a845b6871ecbffa64d6f6e2.tar.bz2
Fix a bug where redirect chain gets lost on process swap.
BUG=79520 TEST= Review URL: http://codereview.chromium.org/8669014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112847 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/app_process_apitest.cc22
-rw-r--r--chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc15
-rw-r--r--chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h3
-rw-r--r--chrome/browser/renderer_host/chrome_url_request_user_data.cc6
-rw-r--r--chrome/browser/renderer_host/chrome_url_request_user_data.h4
-rw-r--r--chrome/browser/renderer_host/transfer_navigation_resource_handler.cc169
-rw-r--r--chrome/browser/renderer_host/transfer_navigation_resource_handler.h69
-rw-r--r--chrome/browser/ui/browser.cc7
-rw-r--r--chrome/browser/ui/browser_navigator.cc36
-rw-r--r--chrome/browser/ui/browser_navigator.h6
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/test/data/extensions/api_test/webrequest/framework.js4
-rw-r--r--content/browser/renderer_host/global_request_id.h10
-rw-r--r--content/browser/renderer_host/render_view_host_delegate.h8
-rw-r--r--content/browser/renderer_host/resource_dispatcher_host.cc92
-rw-r--r--content/browser/renderer_host/resource_dispatcher_host.h11
-rw-r--r--content/browser/tab_contents/navigation_controller.cc19
-rw-r--r--content/browser/tab_contents/navigation_controller.h15
-rw-r--r--content/browser/tab_contents/navigation_entry.h19
-rw-r--r--content/browser/tab_contents/page_navigator.h6
-rw-r--r--content/browser/tab_contents/tab_contents.cc29
-rw-r--r--content/browser/tab_contents/tab_contents.h6
-rw-r--r--content/common/request_extra_data.cc8
-rw-r--r--content/common/request_extra_data.h12
-rw-r--r--content/common/resource_dispatcher.cc6
-rw-r--r--content/common/resource_dispatcher_unittest.cc2
-rw-r--r--content/common/resource_messages.h7
-rw-r--r--content/common/view_messages.h7
-rw-r--r--content/public/browser/resource_dispatcher_host_delegate.h3
-rw-r--r--content/public/renderer/navigation_state.cc4
-rw-r--r--content/public/renderer/navigation_state.h19
-rw-r--r--content/renderer/render_view_impl.cc17
32 files changed, 583 insertions, 60 deletions
diff --git a/chrome/browser/extensions/app_process_apitest.cc b/chrome/browser/extensions/app_process_apitest.cc
index 8c89736..d6bf4d6 100644
--- a/chrome/browser/extensions/app_process_apitest.cc
+++ b/chrome/browser/extensions/app_process_apitest.cc
@@ -348,9 +348,26 @@ IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessRedirectBack) {
browser()->NewTab();
ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
browser()->NewTab();
- // Wait until the second tab finishes its redirect train (2 hops).
+ // Wait until the second tab finishes its redirect train (3 hops).
+ // 1. We navigate to redirect.html
+ // 2. Renderer navigates and finishes, counting as a load stop.
+ // 3. Renderer issues the meta refresh to navigate to server-redirect.
+ // 4. Renderer is now in a "provisional load", waiting for navigation to
+ // complete.
+ // 5. Browser sees a redirect response from server-redirect to empty.html, and
+ // transfers that to a new navigation, using RequestTransferURL.
+ // 6. We navigate to empty.html.
+ // 7. Renderer is still in a provisional load to server-redirect, so that is
+ // cancelled, and counts as a load stop
+ // 8. Renderer navigates to empty.html, and finishes loading, counting as the
+ // third load stop
+#if defined(TRANSFER_REDIRECTS_BUG79520)
+ ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
+ browser(), base_url.Resolve("path1/redirect.html"), 3);
+#else
ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
browser(), base_url.Resolve("path1/redirect.html"), 2);
+#endif
// 3 tabs, including the initial about:blank. The last 2 should be the same
// process.
@@ -358,8 +375,7 @@ IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_AppProcessRedirectBack) {
EXPECT_EQ("/files/extensions/api_test/app_process/path1/empty.html",
browser()->GetTabContentsAt(2)->controller().
GetLastCommittedEntry()->url().path());
- RenderViewHost* host = browser()->GetTabContentsAt(1)->render_view_host();
- EXPECT_EQ(host->process(),
+ EXPECT_EQ(browser()->GetTabContentsAt(1)->render_view_host()->process(),
browser()->GetTabContentsAt(2)->render_view_host()->process());
}
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
index 9f9bb41f..b2f096e 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/profiles/profile_io_data.h"
#include "chrome/browser/renderer_host/chrome_url_request_user_data.h"
#include "chrome/browser/renderer_host/safe_browsing_resource_handler.h"
+#include "chrome/browser/renderer_host/transfer_navigation_resource_handler.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/ui/auto_login_prompter.h"
#include "chrome/browser/ui/login/login_prompt.h"
@@ -151,7 +152,11 @@ ResourceHandler* ChromeResourceDispatcherHostDelegate::RequestBeginning(
const content::ResourceContext& resource_context,
bool is_subresource,
int child_id,
- int route_id) {
+ int route_id,
+ bool is_continuation_of_transferred_request) {
+ if (is_continuation_of_transferred_request)
+ ChromeURLRequestUserData::Delete(request);
+
ChromeURLRequestUserData* user_data =
ChromeURLRequestUserData::Create(request);
if (prerender_tracker_->IsPrerenderingOnIOThread(child_id, route_id)) {
@@ -177,6 +182,14 @@ ResourceHandler* ChromeResourceDispatcherHostDelegate::RequestBeginning(
handler, child_id, route_id, resource_dispatcher_host_, request,
resource_context.appcache_service());
#endif
+
+ // TODO(mpcomplete): Leaving disabled for now, since I'm checking this in
+ // close to the branch point.
+#if defined(TRANSFER_REDIRECTS_BUG79520)
+ handler = new TransferNavigationResourceHandler(
+ handler, resource_dispatcher_host_, request);
+#endif
+
return handler;
}
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h
index 0fc5cb6..d8e4e28 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h
@@ -47,7 +47,8 @@ class ChromeResourceDispatcherHostDelegate
const content::ResourceContext& resource_context,
bool is_subresource,
int child_id,
- int route_id) OVERRIDE;
+ int route_id,
+ bool is_continuation_of_transferred_request) OVERRIDE;
virtual ResourceHandler* DownloadStarting(
ResourceHandler* handler,
const content::ResourceContext& resource_context,
diff --git a/chrome/browser/renderer_host/chrome_url_request_user_data.cc b/chrome/browser/renderer_host/chrome_url_request_user_data.cc
index aeabcd1..511cbf1 100644
--- a/chrome/browser/renderer_host/chrome_url_request_user_data.cc
+++ b/chrome/browser/renderer_host/chrome_url_request_user_data.cc
@@ -30,3 +30,9 @@ ChromeURLRequestUserData* ChromeURLRequestUserData::Create(
request->SetUserData(kKeyName, user_data);
return user_data;
}
+
+// static
+void ChromeURLRequestUserData::Delete(net::URLRequest* request) {
+ DCHECK(request);
+ request->SetUserData(kKeyName, NULL);
+}
diff --git a/chrome/browser/renderer_host/chrome_url_request_user_data.h b/chrome/browser/renderer_host/chrome_url_request_user_data.h
index 4f356ea..5acc9bd 100644
--- a/chrome/browser/renderer_host/chrome_url_request_user_data.h
+++ b/chrome/browser/renderer_host/chrome_url_request_user_data.h
@@ -19,6 +19,10 @@ class ChromeURLRequestUserData : public net::URLRequest::UserData {
// is owned by |request|.
static ChromeURLRequestUserData* Create(net::URLRequest* request);
+ // Delete the ChromeURLRequestUserData from a |request|. |request| must be
+ // non-NULL.
+ static void Delete(net::URLRequest* request);
+
// Gets the ChromeURLRequestUserData instance attached to |request|, or
// returns NULL if one is not attached. |request| must be non-NULL.
static ChromeURLRequestUserData* Get(const net::URLRequest* request);
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 0000000..e0e80ad
--- /dev/null
+++ b/chrome/browser/renderer_host/transfer_navigation_resource_handler.cc
@@ -0,0 +1,169 @@
+// 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.
+// TODO(mpcomplete): move to common and share with the renderer logic.
+// http://crbug.com/79520
+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();
+}
diff --git a/chrome/browser/renderer_host/transfer_navigation_resource_handler.h b/chrome/browser/renderer_host/transfer_navigation_resource_handler.h
new file mode 100644
index 0000000..2943de3
--- /dev/null
+++ b/chrome/browser/renderer_host/transfer_navigation_resource_handler.h
@@ -0,0 +1,69 @@
+// 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.
+
+#ifndef CHROME_BROWSER_RENDERER_HOST_TRANSFER_NAVIGATION_RESOURCE_HANDLER_H_
+#define CHROME_BROWSER_RENDERER_HOST_TRANSFER_NAVIGATION_RESOURCE_HANDLER_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/time.h"
+#include "base/timer.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "content/browser/renderer_host/resource_handler.h"
+
+namespace content {
+struct ResourceResponse;
+}
+
+namespace net {
+class URLRequest;
+}
+
+class ResourceDispatcherHost;
+
+// This ResourceHandler 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 TransferNavigationResourceHandler : public ResourceHandler {
+ public:
+ TransferNavigationResourceHandler(
+ ResourceHandler* handler,
+ ResourceDispatcherHost* resource_dispatcher_host,
+ net::URLRequest* request);
+
+ // ResourceHandler implementation:
+ virtual bool OnUploadProgress(
+ int request_id, uint64 position, uint64 size) OVERRIDE;
+ virtual bool OnRequestRedirected(
+ int request_id, const GURL& new_url, content::ResourceResponse* response,
+ bool* defer) OVERRIDE;
+ virtual bool OnResponseStarted(
+ int request_id, content::ResourceResponse* response) 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) OVERRIDE;
+ virtual bool OnResponseCompleted(int request_id,
+ const net::URLRequestStatus& status,
+ const std::string& security_info) OVERRIDE;
+ virtual void OnRequestClosed() OVERRIDE;
+
+ private:
+ virtual ~TransferNavigationResourceHandler();
+
+ scoped_refptr<ResourceHandler> next_handler_;
+ ResourceDispatcherHost* rdh_;
+ net::URLRequest* request_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransferNavigationResourceHandler);
+};
+
+
+#endif // CHROME_BROWSER_RENDERER_HOST_TRANSFER_NAVIGATION_RESOURCE_HANDLER_H_
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index a333ef8..cd45080 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -2969,9 +2969,8 @@ TabContents* Browser::OpenURL(const GURL& url,
content::PageTransition transition) {
// For specifying a referrer, use the version of OpenURL taking OpenURLParams.
DCHECK(referrer.is_empty());
- return OpenURLFromTab(NULL,
- OpenURLParams(url, referrer, disposition, transition,
- false));
+ return OpenURLFromTab(NULL, OpenURLParams(url, referrer, disposition,
+ transition, false));
}
TabContents* Browser::OpenURL(const OpenURLParams& params) {
@@ -3389,6 +3388,8 @@ TabContents* Browser::OpenURLFromTab(TabContents* source,
nav_params.user_gesture = true;
nav_params.override_encoding = params.override_encoding;
nav_params.is_renderer_initiated = params.is_renderer_initiated;
+ nav_params.transferred_global_request_id =
+ params.transferred_global_request_id;
browser::Navigate(&nav_params);
return nav_params.target_contents ?
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 9c92019..ac4f2ef 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -242,6 +242,24 @@ Profile* GetSourceProfile(browser::NavigateParams* params,
return params->browser->profile();
}
+void LoadURLInContents(TabContents* target_contents,
+ const GURL& url,
+ browser::NavigateParams* params,
+ const std::string& extra_headers) {
+ if (params->transferred_global_request_id != GlobalRequestID()) {
+ target_contents->controller().TransferURL(
+ url, params->referrer, params->transition, extra_headers,
+ params->transferred_global_request_id,
+ params->is_renderer_initiated);
+ } else if (params->is_renderer_initiated) {
+ target_contents->controller().LoadURLFromRenderer(
+ url, params->referrer, params->transition, extra_headers);
+ } else {
+ target_contents->controller().LoadURL(
+ url, params->referrer, params->transition, extra_headers);
+ }
+
+}
// This class makes sure the Browser object held in |params| is made visible
// by the time it goes out of scope, provided |params| wants it to be shown.
@@ -499,13 +517,9 @@ void Navigate(NavigateParams* params) {
if (!HandleNonNavigationAboutURL(url)) {
// Perform the actual navigation, tracking whether it came from the
// renderer.
- if (params->is_renderer_initiated) {
- params->target_contents->controller().LoadURLFromRenderer(
- url, params->referrer, params->transition, extra_headers);
- } else {
- params->target_contents->controller().LoadURL(
- url, params->referrer, params->transition, extra_headers);
- }
+
+ LoadURLInContents(params->target_contents->tab_contents(),
+ url, params, extra_headers);
}
} else {
// |target_contents| was specified non-NULL, and so we assume it has already
@@ -553,13 +567,7 @@ void Navigate(NavigateParams* params) {
} else if (params->path_behavior == NavigateParams::IGNORE_AND_NAVIGATE &&
target->GetURL() != params->url) {
InitializeExtraHeaders(params, NULL, &extra_headers);
- if (params->is_renderer_initiated) {
- target->controller().LoadURLFromRenderer(
- params->url, params->referrer, params->transition, extra_headers);
- } else {
- target->controller().LoadURL(
- params->url, params->referrer, params->transition, extra_headers);
- }
+ LoadURLInContents(target, params->url, params, extra_headers);
}
// If the singleton tab isn't already selected, select it.
diff --git a/chrome/browser/ui/browser_navigator.h b/chrome/browser/ui/browser_navigator.h
index da7c01c..9f40509 100644
--- a/chrome/browser/ui/browser_navigator.h
+++ b/chrome/browser/ui/browser_navigator.h
@@ -8,6 +8,7 @@
#include <string>
+#include "content/browser/renderer_host/global_request_id.h"
#include "content/public/common/page_transition_types.h"
#include "googleurl/src/gurl.h"
#include "ui/gfx/rect.h"
@@ -180,6 +181,11 @@ struct NavigateParams {
// creating a Browser.
Profile* profile;
+ // Refers to a navigation that was parked in the browser in order to be
+ // transferred to another RVH. Only used in case of a redirection of a request
+ // to a different site that created a new RVH.
+ GlobalRequestID transferred_global_request_id;
+
private:
NavigateParams();
};
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index cf42538..548183a 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2030,6 +2030,8 @@
'browser/renderer_host/plugin_info_message_filter.h',
'browser/renderer_host/safe_browsing_resource_handler.cc',
'browser/renderer_host/safe_browsing_resource_handler.h',
+ 'browser/renderer_host/transfer_navigation_resource_handler.cc',
+ 'browser/renderer_host/transfer_navigation_resource_handler.h',
'browser/renderer_host/web_cache_manager.cc',
'browser/renderer_host/web_cache_manager.h',
'browser/renderer_preferences_util.cc',
diff --git a/chrome/test/data/extensions/api_test/webrequest/framework.js b/chrome/test/data/extensions/api_test/webrequest/framework.js
index 5cbbdb7..e2a0bc1 100644
--- a/chrome/test/data/extensions/api_test/webrequest/framework.js
+++ b/chrome/test/data/extensions/api_test/webrequest/framework.js
@@ -215,8 +215,10 @@ function captureEvent(name, details, callback) {
}
});
if (!found) {
+ console.log("Expected events: " +
+ JSON.stringify(expectedEventData, null, 2));
chrome.test.fail("Received unexpected event '" + name + "':" +
- JSON.stringify(details));
+ JSON.stringify(details, null, 2));
}
capturedEventData.push({label: label, event: name, details: details});
diff --git a/content/browser/renderer_host/global_request_id.h b/content/browser/renderer_host/global_request_id.h
index 031026f..f9a87db 100644
--- a/content/browser/renderer_host/global_request_id.h
+++ b/content/browser/renderer_host/global_request_id.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -27,6 +27,14 @@ struct GlobalRequestID {
return request_id < other.request_id;
return child_id < other.child_id;
}
+ bool operator==(const GlobalRequestID& other) const {
+ return child_id == other.child_id &&
+ request_id == other.request_id;
+ }
+ bool operator!=(const GlobalRequestID& other) const {
+ return child_id != other.child_id ||
+ request_id != other.request_id;
+ }
};
#endif // CHROME_BROWSER_RENDERER_HOST_GLOBAL_REQUEST_ID_H_
diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h
index 8a4bb7f..e0faaa3 100644
--- a/content/browser/renderer_host/render_view_host_delegate.h
+++ b/content/browser/renderer_host/render_view_host_delegate.h
@@ -27,6 +27,7 @@ class SkBitmap;
class TabContents;
class WebKeyboardEvent;
struct ContextMenuParams;
+struct GlobalRequestID;
struct NativeWebKeyboardEvent;
struct ViewHostMsg_CreateWindow_Params;
struct ViewHostMsg_FrameNavigate_Params;
@@ -276,6 +277,13 @@ class CONTENT_EXPORT RenderViewHostDelegate : public IPC::Channel::Listener {
WindowOpenDisposition disposition,
int64 source_frame_id) {}
+ // The page wants to transfer the request to a new renderer.
+ virtual void RequestTransferURL(const GURL& url,
+ const GURL& referrer,
+ WindowOpenDisposition disposition,
+ int64 source_frame_id,
+ const GlobalRequestID& old_request_id) {}
+
// A javascript message, confirmation or prompt should be shown.
virtual void RunJavaScriptMessage(const RenderViewHost* rvh,
const string16& message,
diff --git a/content/browser/renderer_host/resource_dispatcher_host.cc b/content/browser/renderer_host/resource_dispatcher_host.cc
index fb0f1c3..1bd30fc 100644
--- a/content/browser/renderer_host/resource_dispatcher_host.cc
+++ b/content/browser/renderer_host/resource_dispatcher_host.cc
@@ -312,7 +312,12 @@ ResourceDispatcherHost::ResourceDispatcherHost(
ResourceDispatcherHost::~ResourceDispatcherHost() {
AsyncResourceHandler::GlobalCleanup();
+ for (PendingRequestList::const_iterator i = pending_requests_.begin();
+ i != pending_requests_.end(); ++i) {
+ transferred_navigations_.erase(i->first);
+ }
STLDeleteValues(&pending_requests_);
+ DCHECK(transferred_navigations_.empty());
}
void ResourceDispatcherHost::Initialize() {
@@ -340,6 +345,10 @@ void ResourceDispatcherHost::OnShutdown() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
is_shutdown_ = true;
resource_queue_.Shutdown();
+ for (PendingRequestList::const_iterator i = pending_requests_.begin();
+ i != pending_requests_.end(); ++i) {
+ transferred_navigations_.erase(i->first);
+ }
STLDeleteValues(&pending_requests_);
// Make sure we shutdown the timer now, otherwise by the time our destructor
// runs if the timer is still running the Task is deleted twice (once by
@@ -457,6 +466,20 @@ void ResourceDispatcherHost::BeginRequest(
base::strlcpy(url_buf, request_data.url.spec().c_str(), arraysize(url_buf));
base::debug::Alias(url_buf);
+ // If the request that's coming in is being transferred from another process,
+ // we want to reuse and resume the old request rather than start a new one.
+ net::URLRequest* deferred_request = NULL;
+
+ GlobalRequestID old_request_id(request_data.transferred_request_child_id,
+ request_data.transferred_request_request_id);
+ TransferredNavigations::iterator iter =
+ transferred_navigations_.find(old_request_id);
+ if (iter != transferred_navigations_.end()) {
+ deferred_request = iter->second;
+ pending_requests_.erase(old_request_id);
+ transferred_navigations_.erase(iter);
+ }
+
const content::ResourceContext& resource_context =
filter_->resource_context();
@@ -508,13 +531,18 @@ void ResourceDispatcherHost::BeginRequest(
}
// Construct the request.
- net::URLRequest* request = new net::URLRequest(request_data.url, this);
- request->set_method(request_data.method);
- request->set_first_party_for_cookies(request_data.first_party_for_cookies);
- request->set_referrer(referrer.spec());
- net::HttpRequestHeaders headers;
- headers.AddHeadersFromString(request_data.headers);
- request->SetExtraRequestHeaders(headers);
+ net::URLRequest* request;
+ if (deferred_request) {
+ request = deferred_request;
+ } else {
+ request = new net::URLRequest(request_data.url, this);
+ request->set_method(request_data.method);
+ request->set_first_party_for_cookies(request_data.first_party_for_cookies);
+ request->set_referrer(referrer.spec());
+ net::HttpRequestHeaders headers;
+ headers.AddHeadersFromString(request_data.headers);
+ request->SetExtraRequestHeaders(headers);
+ }
int load_flags = request_data.load_flags;
// Although EV status is irrelevant to sub-frames and sub-resources, we have
@@ -543,15 +571,16 @@ void ResourceDispatcherHost::BeginRequest(
net::LOAD_DO_NOT_SAVE_COOKIES);
}
- // Raw headers are sensitive, as they inclide Cookie/Set-Cookie, so only
- // allow requesting them if requestor has ReadRawCookies permission.
+ // Raw headers are sensitive, as they include Cookie/Set-Cookie, so only
+ // allow requesting them if requester has ReadRawCookies permission.
if ((load_flags & net::LOAD_REPORT_RAW_HEADERS)
&& !policy->CanReadRawCookies(child_id)) {
- VLOG(1) << "Denied unathorized request for raw headers";
+ VLOG(1) << "Denied unauthorized request for raw headers";
load_flags &= ~net::LOAD_REPORT_RAW_HEADERS;
}
request->set_load_flags(load_flags);
+
request->set_context(
filter_->GetURLRequestContext(request_data.resource_type));
request->set_priority(DetermineRequestPriority(request_data.resource_type));
@@ -584,8 +613,11 @@ void ResourceDispatcherHost::BeginRequest(
if (delegate_) {
bool sub = request_data.resource_type != ResourceType::MAIN_FRAME;
- handler = delegate_->RequestBeginning(handler, request, resource_context,
- sub, child_id, route_id);
+ bool is_continuation_of_transferred_request =
+ (deferred_request != NULL);
+ handler = delegate_->RequestBeginning(
+ handler, request, resource_context, sub, child_id, route_id,
+ is_continuation_of_transferred_request);
}
// Make extra info and read footer (contains request ID).
@@ -624,7 +656,16 @@ void ResourceDispatcherHost::BeginRequest(
request, resource_context.appcache_service(), child_id,
request_data.appcache_host_id, request_data.resource_type);
- BeginRequestInternal(request);
+ if (deferred_request) {
+ // This is a request that has been transferred from another process, so
+ // resume it rather than continuing the regular procedure for starting a
+ // request. Currently this is only done for redirects.
+ GlobalRequestID global_id(extra_info->child_id(), extra_info->request_id());
+ pending_requests_[global_id] = request;
+ request->FollowDeferredRedirect();
+ } else {
+ BeginRequestInternal(request);
+ }
}
void ResourceDispatcherHost::OnReleaseDownloadedFile(int request_id) {
@@ -1039,7 +1080,13 @@ void ResourceDispatcherHost::CancelRequestsForRoute(int child_id,
i != pending_requests_.end(); ++i) {
if (i->first.child_id == child_id) {
ResourceDispatcherHostRequestInfo* info = InfoForRequest(i->second);
+ GlobalRequestID id(child_id, i->first.request_id);
+ DCHECK(id == i->first);
+ // Don't cancel navigations that are transferring to another process,
+ // since they belong to another process now.
if (!info->is_download() &&
+ (transferred_navigations_.find(id) ==
+ transferred_navigations_.end()) &&
(route_id == -1 || route_id == info->route_id())) {
matching_requests.push_back(
GlobalRequestID(child_id, i->first.request_id));
@@ -1418,8 +1465,15 @@ bool ResourceDispatcherHost::CompleteResponseStarted(net::URLRequest* request) {
void ResourceDispatcherHost::CancelRequest(int child_id,
int request_id,
bool from_renderer) {
- PendingRequestList::iterator i = pending_requests_.find(
- GlobalRequestID(child_id, request_id));
+ GlobalRequestID id(child_id, request_id);
+ if (from_renderer) {
+ // When the old renderer dies, it sends a message to us to cancel its
+ // requests.
+ if (transferred_navigations_.find(id) != transferred_navigations_.end())
+ return;
+ }
+
+ PendingRequestList::iterator i = pending_requests_.find(id);
if (i == pending_requests_.end()) {
// We probably want to remove this warning eventually, but I wanted to be
// able to notice when this happens during initial development since it
@@ -1481,7 +1535,7 @@ int ResourceDispatcherHost::IncrementOutstandingRequestsMemoryCost(
new_cost += cost;
CHECK(new_cost >= 0);
if (new_cost == 0)
- outstanding_requests_memory_cost_map_.erase(prev_entry);
+ outstanding_requests_memory_cost_map_.erase(child_id);
else
outstanding_requests_memory_cost_map_[child_id] = new_cost;
@@ -2179,3 +2233,9 @@ bool ResourceDispatcherHost::allow_cross_origin_auth_prompt() {
void ResourceDispatcherHost::set_allow_cross_origin_auth_prompt(bool value) {
allow_cross_origin_auth_prompt_ = value;
}
+
+void ResourceDispatcherHost::MarkAsTransferredNavigation(
+ const GlobalRequestID& transferred_request_id,
+ net::URLRequest* ransferred_request) {
+ transferred_navigations_[transferred_request_id] = ransferred_request;
+}
diff --git a/content/browser/renderer_host/resource_dispatcher_host.h b/content/browser/renderer_host/resource_dispatcher_host.h
index 21be2a3..cdf30b3 100644
--- a/content/browser/renderer_host/resource_dispatcher_host.h
+++ b/content/browser/renderer_host/resource_dispatcher_host.h
@@ -264,6 +264,12 @@ class CONTENT_EXPORT ResourceDispatcherHost : public net::URLRequest::Delegate {
return delegate_;
}
+ // Marks the request as "parked". This happens if a request is
+ // redirected cross-site and needs to be resumed by a new render view.
+ void MarkAsTransferredNavigation(
+ const GlobalRequestID& transferred_request_id,
+ net::URLRequest* transferred_request);
+
private:
FRIEND_TEST_ALL_PREFIXES(ResourceDispatcherHostTest,
TestBlockedRequestsProcessDies);
@@ -500,6 +506,11 @@ class CONTENT_EXPORT ResourceDispatcherHost : public net::URLRequest::Delegate {
static bool is_prefetch_enabled_;
bool allow_cross_origin_auth_prompt_;
+ // Maps the request ID of request that is being transferred to a new RVH
+ // to the respective request.
+ typedef std::map<GlobalRequestID, net::URLRequest*> TransferredNavigations;
+ TransferredNavigations transferred_navigations_;
+
DISALLOW_COPY_AND_ASSIGN(ResourceDispatcherHost);
};
diff --git a/content/browser/tab_contents/navigation_controller.cc b/content/browser/tab_contents/navigation_controller.cc
index 383a1ec..21582ab 100644
--- a/content/browser/tab_contents/navigation_controller.cc
+++ b/content/browser/tab_contents/navigation_controller.cc
@@ -497,6 +497,25 @@ void NavigationController::AddTransientEntry(NavigationEntry* entry) {
tab_contents_->NotifyNavigationStateChanged(kInvalidateAll);
}
+void NavigationController::TransferURL(
+ const GURL& url,
+ const GURL& referrer,
+ content::PageTransition transition,
+ const std::string& extra_headers,
+ const GlobalRequestID& transferred_global_request_id,
+ bool is_renderer_initiated) {
+ // The user initiated a load, we don't need to reload anymore.
+ needs_reload_ = false;
+
+ NavigationEntry* entry = CreateNavigationEntry(url, referrer, transition,
+ is_renderer_initiated,
+ extra_headers,
+ browser_context_);
+ entry->set_transferred_global_request_id(transferred_global_request_id);
+
+ LoadEntry(entry);
+}
+
void NavigationController::LoadURL(
const GURL& url,
const GURL& referrer,
diff --git a/content/browser/tab_contents/navigation_controller.h b/content/browser/tab_contents/navigation_controller.h
index 5d99842..1e8096d 100644
--- a/content/browser/tab_contents/navigation_controller.h
+++ b/content/browser/tab_contents/navigation_controller.h
@@ -14,6 +14,7 @@
#include "base/memory/linked_ptr.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
+#include "content/browser/renderer_host/global_request_id.h"
#include "content/browser/ssl/ssl_manager.h"
#include "content/common/content_export.h"
#include "content/public/browser/navigation_type.h"
@@ -187,6 +188,20 @@ class CONTENT_EXPORT NavigationController {
content::PageTransition type,
const std::string& extra_headers);
+ // Behaves like LoadURL() and LoadURLFromRenderer() but marks the new
+ // navigation as being transferred from one RVH to another. In this case the
+ // browser can recycle the old request once the new renderer wants to
+ // navigate.
+ // |transferred_global_request_id| identifies the request ID of the old
+ // request.
+ void TransferURL(
+ const GURL& url,
+ const GURL& referrer,
+ content::PageTransition transition,
+ const std::string& extra_headers,
+ const GlobalRequestID& transferred_global_request_id,
+ bool is_renderer_initiated);
+
// Loads the current page if this NavigationController was restored from
// history and the current page has not loaded yet.
void LoadIfNecessary();
diff --git a/content/browser/tab_contents/navigation_entry.h b/content/browser/tab_contents/navigation_entry.h
index eea3f35..8648ebb 100644
--- a/content/browser/tab_contents/navigation_entry.h
+++ b/content/browser/tab_contents/navigation_entry.h
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
+#include "content/browser/renderer_host/global_request_id.h"
#include "content/common/content_export.h"
#include "content/public/common/page_transition_types.h"
#include "content/public/common/page_type.h"
@@ -412,6 +413,15 @@ class CONTENT_EXPORT NavigationEntry {
return restore_type_;
}
+ void set_transferred_global_request_id(
+ const GlobalRequestID& transferred_global_request_id) {
+ transferred_global_request_id_ = transferred_global_request_id;
+ }
+
+ GlobalRequestID transferred_global_request_id() const {
+ return transferred_global_request_id_;
+ }
+
private:
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
// Session/Tab restore save portions of this class so that it can be recreated
@@ -451,6 +461,15 @@ class CONTENT_EXPORT NavigationEntry {
// cleared to force a refresh.
mutable string16 cached_display_title_;
+ // In case a navigation is transferred to a new RVH but the request has
+ // been generated in the renderer already, this identifies the old request so
+ // that it can be resumed. The old request is stored until the
+ // ResourceDispatcher receives the navigation from the renderer which
+ // carries this |transferred_global_request_id_| annotation. Once the request
+ // is transferred to the new process, this is cleared and the request
+ // continues as normal.
+ GlobalRequestID transferred_global_request_id_;
+
// Copy and assignment is explicitly allowed for this class.
};
diff --git a/content/browser/tab_contents/page_navigator.h b/content/browser/tab_contents/page_navigator.h
index 9369a7a..98bafd3 100644
--- a/content/browser/tab_contents/page_navigator.h
+++ b/content/browser/tab_contents/page_navigator.h
@@ -12,6 +12,7 @@
#include <string>
+#include "content/browser/renderer_host/global_request_id.h"
#include "content/common/content_export.h"
#include "content/public/common/page_transition_types.h"
#include "googleurl/src/gurl.h"
@@ -26,7 +27,6 @@ struct CONTENT_EXPORT OpenURLParams {
content::PageTransition transition,
bool is_renderer_initiated);
~OpenURLParams();
-class TabContents;
// The URL/referrer to be opened.
GURL url;
@@ -44,6 +44,10 @@ class TabContents;
// The override encoding of the URL contents to be opened.
std::string override_encoding;
+ // Reference to the old request id in case this is a navigation that is being
+ // transferred to a new renderer.
+ GlobalRequestID transferred_global_request_id;
+
private:
OpenURLParams();
};
diff --git a/content/browser/tab_contents/tab_contents.cc b/content/browser/tab_contents/tab_contents.cc
index 284ea26..bfdbd979 100644
--- a/content/browser/tab_contents/tab_contents.cc
+++ b/content/browser/tab_contents/tab_contents.cc
@@ -167,6 +167,10 @@ void MakeNavigateParams(const NavigationEntry& entry,
GetNavigationType(controller.browser_context(), entry, reload_type);
params->request_time = base::Time::Now();
params->extra_headers = entry.extra_headers();
+ params->transferred_request_child_id =
+ entry.transferred_global_request_id().child_id;
+ params->transferred_request_request_id =
+ entry.transferred_global_request_id().request_id;
if (delegate)
delegate->AddNavigationHeaders(params->url, &params->extra_headers);
@@ -1750,6 +1754,17 @@ void TabContents::RequestOpenURL(const GURL& url,
const GURL& referrer,
WindowOpenDisposition disposition,
int64 source_frame_id) {
+ // Delegate to RequestTransferURL because this is just the generic
+ // case where |old_request_id| is empty.
+ RequestTransferURL(url, referrer, disposition, source_frame_id,
+ GlobalRequestID());
+}
+
+void TabContents::RequestTransferURL(const GURL& url,
+ const GURL& referrer,
+ WindowOpenDisposition disposition,
+ int64 source_frame_id,
+ const GlobalRequestID& old_request_id) {
TabContents* new_contents = NULL;
content::PageTransition transition_type = content::PAGE_TRANSITION_LINK;
if (render_manager_.web_ui()) {
@@ -1761,13 +1776,17 @@ void TabContents::RequestOpenURL(const GURL& url,
// want web sites to see a referrer of "chrome://blah" (and some
// chrome: URLs might have search terms or other stuff we don't want to
// send to the site), so we send no referrer.
- new_contents = OpenURL(url, GURL(), disposition,
- render_manager_.web_ui()->link_transition_type());
+ OpenURLParams params(url, GURL(), disposition,
+ render_manager_.web_ui()->link_transition_type(),
+ false /* is_renderer_initiated */);
+ params.transferred_global_request_id = old_request_id;
+ new_contents = OpenURL(params);
transition_type = render_manager_.web_ui()->link_transition_type();
} else {
- new_contents = OpenURL(OpenURLParams(
- url, referrer, disposition, content::PAGE_TRANSITION_LINK,
- true /* is_renderer_initiated */));
+ OpenURLParams params(url, referrer, disposition,
+ content::PAGE_TRANSITION_LINK, true /* is_renderer_initiated */);
+ params.transferred_global_request_id = old_request_id;
+ new_contents = OpenURL(params);
}
if (new_contents) {
// Notify observers.
diff --git a/content/browser/tab_contents/tab_contents.h b/content/browser/tab_contents/tab_contents.h
index 0473b7d..46120ed 100644
--- a/content/browser/tab_contents/tab_contents.h
+++ b/content/browser/tab_contents/tab_contents.h
@@ -513,6 +513,12 @@ class CONTENT_EXPORT TabContents : public PageNavigator,
const GURL& referrer,
WindowOpenDisposition disposition,
int64 source_frame_id) OVERRIDE;
+ virtual void RequestTransferURL(
+ const GURL& url,
+ const GURL& referrer,
+ WindowOpenDisposition disposition,
+ int64 source_frame_id,
+ const GlobalRequestID& transferred_global_request_id) OVERRIDE;
virtual void RunJavaScriptMessage(const RenderViewHost* rvh,
const string16& message,
const string16& default_prompt,
diff --git a/content/common/request_extra_data.cc b/content/common/request_extra_data.cc
index a079a39..ab9ee91 100644
--- a/content/common/request_extra_data.cc
+++ b/content/common/request_extra_data.cc
@@ -11,13 +11,17 @@ RequestExtraData::RequestExtraData(WebReferrerPolicy referrer_policy,
int64 frame_id,
bool parent_is_main_frame,
int64 parent_frame_id,
- content::PageTransition transition_type)
+ content::PageTransition transition_type,
+ int transferred_request_child_id,
+ int transferred_request_request_id)
: webkit_glue::WebURLRequestExtraDataImpl(referrer_policy),
is_main_frame_(is_main_frame),
frame_id_(frame_id),
parent_is_main_frame_(parent_is_main_frame),
parent_frame_id_(parent_frame_id),
- transition_type_(transition_type) {
+ transition_type_(transition_type),
+ transferred_request_child_id_(transferred_request_child_id),
+ transferred_request_request_id_(transferred_request_request_id) {
}
RequestExtraData::~RequestExtraData() {
diff --git a/content/common/request_extra_data.h b/content/common/request_extra_data.h
index 2dc1b2a..b7ca525 100644
--- a/content/common/request_extra_data.h
+++ b/content/common/request_extra_data.h
@@ -21,7 +21,9 @@ class CONTENT_EXPORT RequestExtraData
int64 frame_id,
bool parent_is_main_frame,
int64 parent_frame_id,
- content::PageTransition transition_type);
+ content::PageTransition transition_type,
+ int transferred_request_child_id,
+ int transferred_request_request_id);
virtual ~RequestExtraData();
bool is_main_frame() const { return is_main_frame_; }
@@ -29,6 +31,12 @@ class CONTENT_EXPORT RequestExtraData
bool parent_is_main_frame() const { return parent_is_main_frame_; }
int64 parent_frame_id() const { return parent_frame_id_; }
content::PageTransition transition_type() const { return transition_type_; }
+ int transferred_request_child_id() const {
+ return transferred_request_child_id_;
+ }
+ int transferred_request_request_id() const {
+ return transferred_request_request_id_;
+ }
private:
bool is_main_frame_;
@@ -36,6 +44,8 @@ class CONTENT_EXPORT RequestExtraData
bool parent_is_main_frame_;
int64 parent_frame_id_;
content::PageTransition transition_type_;
+ int transferred_request_child_id_;
+ int transferred_request_request_id_;
DISALLOW_COPY_AND_ASSIGN(RequestExtraData);
};
diff --git a/content/common/resource_dispatcher.cc b/content/common/resource_dispatcher.cc
index fdce5c9..2983302 100644
--- a/content/common/resource_dispatcher.cc
+++ b/content/common/resource_dispatcher.cc
@@ -106,12 +106,18 @@ IPCResourceLoaderBridge::IPCResourceLoaderBridge(
request_.parent_is_main_frame = extra_data->parent_is_main_frame();
request_.parent_frame_id = extra_data->parent_frame_id();
request_.transition_type = extra_data->transition_type();
+ request_.transferred_request_child_id =
+ extra_data->transferred_request_child_id();
+ request_.transferred_request_request_id =
+ extra_data->transferred_request_request_id();
} else {
request_.is_main_frame = false;
request_.frame_id = -1;
request_.parent_is_main_frame = false;
request_.parent_frame_id = -1;
request_.transition_type = content::PAGE_TRANSITION_LINK;
+ request_.transferred_request_child_id = -1;
+ request_.transferred_request_request_id = -1;
}
}
diff --git a/content/common/resource_dispatcher_unittest.cc b/content/common/resource_dispatcher_unittest.cc
index e5c8a08..d133bc1 100644
--- a/content/common/resource_dispatcher_unittest.cc
+++ b/content/common/resource_dispatcher_unittest.cc
@@ -173,7 +173,7 @@ class ResourceDispatcherTest : public testing::Test,
request_info.routing_id = 0;
RequestExtraData extra_data(WebKit::WebReferrerPolicyDefault,
true, 0, false, -1,
- content::PAGE_TRANSITION_LINK);
+ content::PAGE_TRANSITION_LINK, -1, -1);
request_info.extra_data = &extra_data;
return dispatcher_->CreateBridge(request_info);
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index 854290a..5230206 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -111,6 +111,13 @@ IPC_STRUCT_BEGIN(ResourceHostMsg_Request)
IPC_STRUCT_MEMBER(int64, parent_frame_id)
IPC_STRUCT_MEMBER(content::PageTransition, transition_type)
+
+ // The following two members identify a previous request that has been
+ // created before this navigation has been transferred to a new render view.
+ // This serves the purpose of recycling the old request.
+ // Unless this refers to a transferred navigation, these values are -1 and -1.
+ IPC_STRUCT_MEMBER(int, transferred_request_child_id)
+ IPC_STRUCT_MEMBER(int, transferred_request_request_id)
IPC_STRUCT_END()
// Resource messages sent from the browser to the renderer.
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 45aa69e..ff07616 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -591,6 +591,13 @@ IPC_STRUCT_BEGIN(ViewMsg_Navigate_Params)
// Extra headers (separated by \n) to send during the request.
IPC_STRUCT_MEMBER(std::string, extra_headers)
+
+ // The following two members identify a previous request that has been
+ // created before this navigation is being transferred to a new render view.
+ // This serves the purpose of recycling the old request.
+ // Unless this refers to a transferred navigation, these values are -1 and -1.
+ IPC_STRUCT_MEMBER(int, transferred_request_child_id)
+ IPC_STRUCT_MEMBER(int, transferred_request_request_id)
IPC_STRUCT_END()
IPC_STRUCT_BEGIN(ViewMsg_New_Params)
diff --git a/content/public/browser/resource_dispatcher_host_delegate.h b/content/public/browser/resource_dispatcher_host_delegate.h
index 50ed0a4..64fc497 100644
--- a/content/public/browser/resource_dispatcher_host_delegate.h
+++ b/content/public/browser/resource_dispatcher_host_delegate.h
@@ -53,7 +53,8 @@ class ResourceDispatcherHostDelegate {
const content::ResourceContext& resource_context,
bool is_subresource,
int child_id,
- int route_id) = 0;
+ int route_id,
+ bool is_continuation_of_transferred_request) = 0;
// Allows an embedder to add additional resource handlers for a download.
// |is_new_request| is true if this is a request that is just starting, i.e.
diff --git a/content/public/renderer/navigation_state.cc b/content/public/renderer/navigation_state.cc
index b69518f..2c70bb7 100644
--- a/content/public/renderer/navigation_state.cc
+++ b/content/public/renderer/navigation_state.cc
@@ -15,7 +15,9 @@ NavigationState::NavigationState(content::PageTransition transition_type,
is_content_initiated_(is_content_initiated),
pending_page_id_(pending_page_id),
pending_history_list_offset_(pending_history_list_offset),
- was_within_same_page_(false) {
+ was_within_same_page_(false),
+ transferred_request_child_id_(-1),
+ transferred_request_request_id_(-1) {
}
NavigationState::~NavigationState() {}
diff --git a/content/public/renderer/navigation_state.h b/content/public/renderer/navigation_state.h
index efdcac1..cb6bc64 100644
--- a/content/public/renderer/navigation_state.h
+++ b/content/public/renderer/navigation_state.h
@@ -57,6 +57,23 @@ class NavigationState {
void set_was_within_same_page(bool value) { was_within_same_page_ = value; }
bool was_within_same_page() const { return was_within_same_page_; }
+ // transferred_request_child_id and transferred_request_request_id identify
+ // a request that has been created before the navigation is being transferred
+ // to a new renderer. This is used to recycle the old request once the new
+ // renderer tries to pick up the navigation of the old one.
+ void set_transferred_request_child_id(int value) {
+ transferred_request_child_id_ = value;
+ }
+ int transferred_request_child_id() const {
+ return transferred_request_child_id_;
+ }
+ void set_transferred_request_request_id(int value) {
+ transferred_request_request_id_ = value;
+ }
+ int transferred_request_request_id() const {
+ return transferred_request_request_id_;
+ }
+
private:
NavigationState(content::PageTransition transition_type,
bool is_content_initiated,
@@ -70,6 +87,8 @@ class NavigationState {
int pending_history_list_offset_;
bool was_within_same_page_;
+ int transferred_request_child_id_;
+ int transferred_request_request_id_;
DISALLOW_COPY_AND_ASSIGN(NavigationState);
};
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 62e2589..12c7ead 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -2052,13 +2052,8 @@ WebNavigationPolicy RenderViewImpl::decidePolicyForNavigation(
// issue a special POST navigation in WebKit (via
// FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl
// for examples of how to send the httpBody data.
- // Note2: We normally don't do this for browser-initiated navigations, since
- // it's pointless to tell the browser about navigations it gave us. But
- // we do potentially ask the browser to handle a redirect that was originally
- // initiated by the browser. See http://crbug.com/70943
- //
- // TODO(creis): Move this redirect check to the browser process to avoid
- // ping-ponging. See http://crbug.com/72380.
+ // TODO(mpcomplete): remove is_redirect clause when http://crbug.com/79520 is
+ // fixed.
if (!frame->parent() && (is_content_initiated || is_redirect) &&
default_policy == WebKit::WebNavigationPolicyCurrentTab &&
request.httpMethod() == "GET" && !url.SchemeIs(chrome::kAboutScheme)) {
@@ -2332,6 +2327,10 @@ void RenderViewImpl::PopulateStateFromPendingNavigationParams(
params.page_id,
params.pending_history_list_offset,
params.transition);
+ navigation_state->set_transferred_request_child_id(
+ params.transferred_request_child_id);
+ navigation_state->set_transferred_request_request_id(
+ params.transferred_request_request_id);
if (params.navigation_type == ViewMsg_Navigate_Type::RESTORE) {
// We're doing a load of a page that was restored from the last session.
// By default this prefers the cache over loading (LOAD_PREFERRING_CACHE)
@@ -2732,7 +2731,9 @@ void RenderViewImpl::willSendRequest(WebFrame* frame,
frame->identifier(),
frame->parent() == top_frame,
frame->parent() ? frame->parent()->identifier() : -1,
- transition_type));
+ transition_type,
+ navigation_state->transferred_request_child_id(),
+ navigation_state->transferred_request_request_id()));
DocumentState* top_document_state =
DocumentState::FromDataSource(top_data_source);