summaryrefslogtreecommitdiffstats
path: root/content/browser
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 /content/browser
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
Diffstat (limited to 'content/browser')
-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
10 files changed, 192 insertions, 23 deletions
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,