summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcreis@chromium.org <creis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-02 20:28:44 +0000
committercreis@chromium.org <creis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-02 20:28:44 +0000
commit14392a5ec9b1c2679f6f58193ef6736123d4c442 (patch)
tree85eb33b09622b1ffa629e6ab361f6be861bf10de
parentadcf0f0434f7af0e399bb0a034ba706ce12f746c (diff)
downloadchromium_src-14392a5ec9b1c2679f6f58193ef6736123d4c442.zip
chromium_src-14392a5ec9b1c2679f6f58193ef6736123d4c442.tar.gz
chromium_src-14392a5ec9b1c2679f6f58193ef6736123d4c442.tar.bz2
Create swapped-out opener RVHs after a process swap.
This is required to support cross-process JavaScript calls, like postMessage. BUG=99202 TEST=window.opener present after a cross-process navigation. Review URL: https://chromiumcodereview.appspot.com/10171018 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@134981 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/visitedlink/visitedlink_unittest.cc4
-rw-r--r--content/browser/renderer_host/render_view_host_factory.cc6
-rw-r--r--content/browser/renderer_host/render_view_host_factory.h2
-rw-r--r--content/browser/renderer_host/render_view_host_impl.cc7
-rw-r--r--content/browser/renderer_host/render_view_host_impl.h19
-rw-r--r--content/browser/renderer_host/test_render_view_host.cc5
-rw-r--r--content/browser/renderer_host/test_render_view_host.h4
-rw-r--r--content/browser/site_instance_impl.cc5
-rw-r--r--content/browser/site_instance_impl.h3
-rw-r--r--content/browser/site_instance_impl_unittest.cc10
-rw-r--r--content/browser/web_contents/interstitial_page_impl.cc7
-rw-r--r--content/browser/web_contents/navigation_controller_impl_unittest.cc4
-rw-r--r--content/browser/web_contents/render_view_host_manager.cc108
-rw-r--r--content/browser/web_contents/render_view_host_manager.h30
-rw-r--r--content/browser/web_contents/render_view_host_manager_unittest.cc71
-rw-r--r--content/browser/web_contents/test_web_contents.cc18
-rw-r--r--content/browser/web_contents/test_web_contents.h5
-rw-r--r--content/browser/web_contents/web_contents_delegate_unittest.cc2
-rw-r--r--content/browser/web_contents/web_contents_impl.cc79
-rw-r--r--content/browser/web_contents/web_contents_impl.h39
-rw-r--r--content/browser/web_contents/web_contents_impl_unittest.cc2
-rw-r--r--content/browser/web_contents/web_contents_view_helper.cc42
-rw-r--r--content/browser/web_contents/web_contents_view_helper.h2
-rw-r--r--content/common/view_messages.h7
-rw-r--r--content/public/browser/site_instance.h5
-rw-r--r--content/renderer/render_thread_impl.cc4
-rw-r--r--content/renderer/render_view_impl.cc51
-rw-r--r--content/renderer/render_view_impl.h7
-rw-r--r--content/renderer/render_widget.cc7
-rw-r--r--content/renderer/render_widget.h3
-rw-r--r--content/renderer/render_widget_fullscreen.cc2
-rw-r--r--content/test/render_view_fake_resources_test.cc1
-rw-r--r--content/test/render_view_test.cc4
-rw-r--r--content/test/test_renderer_host.cc4
-rw-r--r--content/test/test_renderer_host.h1
35 files changed, 425 insertions, 145 deletions
diff --git a/chrome/browser/visitedlink/visitedlink_unittest.cc b/chrome/browser/visitedlink/visitedlink_unittest.cc
index b6ca5c0..89ccf42 100644
--- a/chrome/browser/visitedlink/visitedlink_unittest.cc
+++ b/chrome/browser/visitedlink/visitedlink_unittest.cc
@@ -652,7 +652,7 @@ TEST_F(VisitedLinkEventsTest, Coalescense) {
TEST_F(VisitedLinkEventsTest, Basics) {
VisitedLinkMaster* master = profile()->GetVisitedLinkMaster();
- rvh_tester()->CreateRenderView(string16(), -1);
+ rvh_tester()->CreateRenderView(string16(), MSG_ROUTING_NONE, -1);
// Add a few URLs.
master->AddURL(GURL("http://acidtests.org/"));
@@ -676,7 +676,7 @@ TEST_F(VisitedLinkEventsTest, Basics) {
TEST_F(VisitedLinkEventsTest, TabVisibility) {
VisitedLinkMaster* master = profile()->GetVisitedLinkMaster();
- rvh_tester()->CreateRenderView(string16(), -1);
+ rvh_tester()->CreateRenderView(string16(), MSG_ROUTING_NONE, -1);
// Simulate tab becoming inactive.
rvh_tester()->SimulateWasHidden();
diff --git a/content/browser/renderer_host/render_view_host_factory.cc b/content/browser/renderer_host/render_view_host_factory.cc
index c9f307a..7bab2d4 100644
--- a/content/browser/renderer_host/render_view_host_factory.cc
+++ b/content/browser/renderer_host/render_view_host_factory.cc
@@ -20,13 +20,15 @@ RenderViewHost* RenderViewHostFactory::Create(
SiteInstance* instance,
content::RenderViewHostDelegate* delegate,
int routing_id,
+ bool swapped_out,
SessionStorageNamespace* session_storage_namespace) {
if (factory_) {
- return factory_->CreateRenderViewHost(instance, delegate, routing_id,
+ return factory_->CreateRenderViewHost(instance, delegate,
+ routing_id, swapped_out,
session_storage_namespace);
}
return new RenderViewHostImpl(instance, delegate, routing_id,
- session_storage_namespace);
+ swapped_out, session_storage_namespace);
}
// static
diff --git a/content/browser/renderer_host/render_view_host_factory.h b/content/browser/renderer_host/render_view_host_factory.h
index fa33f07..99d7299 100644
--- a/content/browser/renderer_host/render_view_host_factory.h
+++ b/content/browser/renderer_host/render_view_host_factory.h
@@ -28,6 +28,7 @@ class RenderViewHostFactory {
content::SiteInstance* instance,
content::RenderViewHostDelegate* delegate,
int routing_id,
+ bool swapped_out,
content::SessionStorageNamespace* session_storage);
// Returns true if there is currently a globally-registered factory.
@@ -45,6 +46,7 @@ class RenderViewHostFactory {
content::SiteInstance* instance,
content::RenderViewHostDelegate* delegate,
int routing_id,
+ bool swapped_out,
content::SessionStorageNamespace* session_storage_namespace) = 0;
// Registers your factory to be called when new RenderViewHosts are created.
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 6ebe0bc..919aee0 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -135,6 +135,7 @@ RenderViewHostImpl* RenderViewHostImpl::FromID(int render_process_id,
RenderViewHostImpl::RenderViewHostImpl(SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
+ bool swapped_out,
SessionStorageNamespace* session_storage)
: RenderWidgetHostImpl(instance->GetProcess(), routing_id),
delegate_(delegate),
@@ -145,7 +146,7 @@ RenderViewHostImpl::RenderViewHostImpl(SiteInstance* instance,
pending_request_id_(-1),
navigations_suspended_(false),
suspended_nav_message_(NULL),
- is_swapped_out_(false),
+ is_swapped_out_(swapped_out),
run_modal_reply_msg_(NULL),
is_waiting_for_beforeunload_ack_(false),
is_waiting_for_unload_ack_(false),
@@ -205,6 +206,7 @@ content::SiteInstance* RenderViewHostImpl::GetSiteInstance() const {
}
bool RenderViewHostImpl::CreateRenderView(const string16& frame_name,
+ int opener_route_id,
int32 max_page_id) {
DCHECK(!IsRenderViewLive()) << "Creating view twice";
@@ -237,6 +239,9 @@ bool RenderViewHostImpl::CreateRenderView(const string16& frame_name,
params.surface_id = surface_id();
params.session_storage_namespace_id = session_storage_namespace_->id();
params.frame_name = frame_name;
+ // Ensure the RenderView sets its opener correctly.
+ params.opener_route_id = opener_route_id;
+ params.swapped_out = is_swapped_out_;
params.next_page_id = next_page_id;
#if defined(OS_POSIX) || defined(USE_AURA)
if (GetView()) {
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 19eb9a8..903027d 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -119,10 +119,12 @@ class CONTENT_EXPORT RenderViewHostImpl
// Convenience function, just like RenderViewHost::FromID.
static RenderViewHostImpl* FromID(int render_process_id, int render_view_id);
- // routing_id could be a valid route id, or it could be MSG_ROUTING_NONE, in
- // which case RenderWidgetHost will create a new one.
+ // |routing_id| could be a valid route id, or it could be MSG_ROUTING_NONE, in
+ // which case RenderWidgetHost will create a new one. |swapped_out| indicates
+ // whether the view should initially be swapped out (e.g., for an opener
+ // frame being rendered by another process).
//
- // The session storage namespace parameter allows multiple render views and
+ // The |session_storage_namespace| parameter allows multiple render views and
// WebContentses to share the same session storage (part of the WebStorage
// spec) space. This is useful when restoring contentses, but most callers
// should pass in NULL which will cause a new SessionStorageNamespace to be
@@ -131,6 +133,7 @@ class CONTENT_EXPORT RenderViewHostImpl
SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
+ bool swapped_out,
SessionStorageNamespace* session_storage_namespace);
virtual ~RenderViewHostImpl();
@@ -225,9 +228,13 @@ class CONTENT_EXPORT RenderViewHostImpl
// Set up the RenderView child process. Virtual because it is overridden by
// TestRenderViewHost. If the |frame_name| parameter is non-empty, it is used
- // as the name of the new top-level frame. If |max_page_id| is larger than
- // -1, the RenderView is told to start issuing page IDs at |max_page_id| + 1.
- virtual bool CreateRenderView(const string16& frame_name, int32 max_page_id);
+ // as the name of the new top-level frame. The |opener_route_id| parameter
+ // indicates which RenderView created this (MSG_ROUTING_NONE if none). If
+ // |max_page_id| is larger than -1, the RenderView is told to start issuing
+ // page IDs at |max_page_id| + 1.
+ virtual bool CreateRenderView(const string16& frame_name,
+ int opener_route_id,
+ int32 max_page_id);
base::TerminationStatus render_view_termination_status() const {
return render_view_termination_status_;
diff --git a/content/browser/renderer_host/test_render_view_host.cc b/content/browser/renderer_host/test_render_view_host.cc
index b8c81d8..44423f7 100644
--- a/content/browser/renderer_host/test_render_view_host.cc
+++ b/content/browser/renderer_host/test_render_view_host.cc
@@ -210,10 +210,12 @@ void TestRenderWidgetHostView::UnlockMouse() {
TestRenderViewHost::TestRenderViewHost(SiteInstance* instance,
RenderViewHostDelegate* delegate,
- int routing_id)
+ int routing_id,
+ bool swapped_out)
: RenderViewHostImpl(instance,
delegate,
routing_id,
+ swapped_out,
dom_storage::kInvalidSessionStorageNamespaceId),
render_view_created_(false),
delete_counter_(NULL),
@@ -235,6 +237,7 @@ TestRenderViewHost::~TestRenderViewHost() {
}
bool TestRenderViewHost::CreateRenderView(const string16& frame_name,
+ int opener_route_id,
int32 max_page_id) {
DCHECK(!render_view_created_);
render_view_created_ = true;
diff --git a/content/browser/renderer_host/test_render_view_host.h b/content/browser/renderer_host/test_render_view_host.h
index 966edfd..3704ddd 100644
--- a/content/browser/renderer_host/test_render_view_host.h
+++ b/content/browser/renderer_host/test_render_view_host.h
@@ -220,7 +220,8 @@ class TestRenderViewHost
public:
TestRenderViewHost(SiteInstance* instance,
RenderViewHostDelegate* delegate,
- int routing_id);
+ int routing_id,
+ bool swapped_out);
virtual ~TestRenderViewHost();
// RenderViewHostTester implementation. Note that CreateRenderView
@@ -275,6 +276,7 @@ class TestRenderViewHost
// RenderViewHost overrides --------------------------------------------------
virtual bool CreateRenderView(const string16& frame_name,
+ int opener_route_id,
int32 max_page_id) OVERRIDE;
virtual bool IsRenderViewLive() const OVERRIDE;
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 792afc5..131189e 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -142,6 +142,11 @@ SiteInstance* SiteInstanceImpl::GetRelatedSiteInstance(const GURL& url) {
return browsing_instance_->GetSiteInstanceForURL(url);
}
+bool SiteInstanceImpl::IsRelatedSiteInstance(const SiteInstance* instance) {
+ return browsing_instance_ ==
+ static_cast<const SiteInstanceImpl*>(instance)->browsing_instance_;
+}
+
bool SiteInstanceImpl::HasWrongProcessForURL(const GURL& url) const {
// Having no process isn't a problem, since we'll assign it correctly.
if (!HasProcess())
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
index bee9383..439db12 100644
--- a/content/browser/site_instance_impl.h
+++ b/content/browser/site_instance_impl.h
@@ -26,6 +26,7 @@ class CONTENT_EXPORT SiteInstanceImpl : public content::SiteInstance,
virtual content::RenderProcessHost* GetProcess() OVERRIDE;
virtual const GURL& GetSite() const OVERRIDE;
virtual SiteInstance* GetRelatedSiteInstance(const GURL& url) OVERRIDE;
+ virtual bool IsRelatedSiteInstance(const SiteInstance* instance) OVERRIDE;
virtual content::BrowserContext* GetBrowserContext() const OVERRIDE;
// Set the web site that this SiteInstance is rendering pages for.
@@ -111,8 +112,6 @@ class CONTENT_EXPORT SiteInstanceImpl : public content::SiteInstance,
// Whether SetSite has been called.
bool has_site_;
- FRIEND_TEST_ALL_PREFIXES(RenderViewHostManagerTest, NewTabPageProcesses);
-
DISALLOW_COPY_AND_ASSIGN(SiteInstanceImpl);
};
diff --git a/content/browser/site_instance_impl_unittest.cc b/content/browser/site_instance_impl_unittest.cc
index fec7c79..fcda84a 100644
--- a/content/browser/site_instance_impl_unittest.cc
+++ b/content/browser/site_instance_impl_unittest.cc
@@ -251,11 +251,8 @@ TEST_F(SiteInstanceTest, SiteInstanceDestructor) {
&site_delete_counter,
&browsing_delete_counter);
{
- WebContentsImpl web_contents(browser_context.get(),
- instance,
- MSG_ROUTING_NONE,
- NULL,
- NULL);
+ WebContentsImpl web_contents(browser_context.get(), instance,
+ MSG_ROUTING_NONE, NULL, NULL, NULL);
EXPECT_EQ(1, site_delete_counter);
EXPECT_EQ(1, browsing_delete_counter);
}
@@ -416,6 +413,7 @@ TEST_F(SiteInstanceTest, OneSiteInstancePerSite) {
static_cast<SiteInstanceImpl*>(
browsing_instance->GetSiteInstanceForURL(url_b1)));
EXPECT_NE(site_instance_a1.get(), site_instance_b1.get());
+ EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1));
// Getting the new SiteInstance from the BrowsingInstance and from another
// SiteInstance in the BrowsingInstance should give the same result.
@@ -439,6 +437,7 @@ TEST_F(SiteInstanceTest, OneSiteInstancePerSite) {
static_cast<SiteInstanceImpl*>(
browsing_instance2->GetSiteInstanceForURL(url_a2)));
EXPECT_NE(site_instance_a1.get(), site_instance_a2_2.get());
+ EXPECT_FALSE(site_instance_a1->IsRelatedSiteInstance(site_instance_a2_2));
// Should be able to see that we do have SiteInstances.
EXPECT_TRUE(browsing_instance->HasSiteInstance(
@@ -477,6 +476,7 @@ TEST_F(SiteInstanceTest, OneSiteInstancePerSiteInBrowserContext) {
static_cast<SiteInstanceImpl*>(
browsing_instance->GetSiteInstanceForURL(url_b1)));
EXPECT_NE(site_instance_a1.get(), site_instance_b1.get());
+ EXPECT_TRUE(site_instance_a1->IsRelatedSiteInstance(site_instance_b1));
// Getting the new SiteInstance from the BrowsingInstance and from another
// SiteInstance in the BrowsingInstance should give the same result.
diff --git a/content/browser/web_contents/interstitial_page_impl.cc b/content/browser/web_contents/interstitial_page_impl.cc
index 05dd03c..f7a62a6 100644
--- a/content/browser/web_contents/interstitial_page_impl.cc
+++ b/content/browser/web_contents/interstitial_page_impl.cc
@@ -489,8 +489,8 @@ WebContents* InterstitialPageImpl::web_contents() const {
RenderViewHost* InterstitialPageImpl::CreateRenderViewHost() {
RenderViewHostImpl* render_view_host = new RenderViewHostImpl(
- SiteInstance::Create(web_contents()->GetBrowserContext()),
- this, MSG_ROUTING_NONE, dom_storage::kInvalidSessionStorageNamespaceId);
+ SiteInstance::Create(web_contents()->GetBrowserContext()), this,
+ MSG_ROUTING_NONE, false, dom_storage::kInvalidSessionStorageNamespaceId);
return render_view_host;
}
@@ -505,7 +505,8 @@ WebContentsView* InterstitialPageImpl::CreateWebContentsView() {
int32 max_page_id = web_contents()->
GetMaxPageIDForSiteInstance(render_view_host_->GetSiteInstance());
- render_view_host_->CreateRenderView(string16(), max_page_id);
+ render_view_host_->CreateRenderView(string16(), MSG_ROUTING_NONE,
+ max_page_id);
view->SetSize(web_contents_view->GetContainerSize());
// Don't show the interstitial until we have navigated to it.
view->Hide();
diff --git a/content/browser/web_contents/navigation_controller_impl_unittest.cc b/content/browser/web_contents/navigation_controller_impl_unittest.cc
index 36e89daf..b0b09a5 100644
--- a/content/browser/web_contents/navigation_controller_impl_unittest.cc
+++ b/content/browser/web_contents/navigation_controller_impl_unittest.cc
@@ -1543,7 +1543,7 @@ TEST_F(NavigationControllerTest, RestoreNavigate) {
entry->SetContentState("state");
entries.push_back(entry);
WebContentsImpl our_contents(
- browser_context(), NULL, MSG_ROUTING_NONE, NULL, NULL);
+ browser_context(), NULL, MSG_ROUTING_NONE, NULL, NULL, NULL);
NavigationControllerImpl& our_controller = our_contents.GetControllerImpl();
our_controller.Restore(0, true, &entries);
ASSERT_EQ(0u, entries.size());
@@ -1610,7 +1610,7 @@ TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
entry->SetContentState("state");
entries.push_back(entry);
WebContentsImpl our_contents(
- browser_context(), NULL, MSG_ROUTING_NONE, NULL, NULL);
+ browser_context(), NULL, MSG_ROUTING_NONE, NULL, NULL, NULL);
NavigationControllerImpl& our_controller = our_contents.GetControllerImpl();
our_controller.Restore(0, true, &entries);
ASSERT_EQ(0u, entries.size());
diff --git a/content/browser/web_contents/render_view_host_manager.cc b/content/browser/web_contents/render_view_host_manager.cc
index c167333..31cb7ed 100644
--- a/content/browser/web_contents/render_view_host_manager.cc
+++ b/content/browser/web_contents/render_view_host_manager.cc
@@ -75,7 +75,7 @@ void RenderViewHostManager::Init(content::BrowserContext* browser_context,
site_instance = SiteInstance::Create(browser_context);
render_view_host_ = static_cast<RenderViewHostImpl*>(
RenderViewHostFactory::Create(
- site_instance, render_view_delegate_, routing_id, delegate_->
+ site_instance, render_view_delegate_, routing_id, false, delegate_->
GetControllerForRenderManager().GetSessionStorageNamespace()));
// Keep track of renderer processes as they start to shut down.
@@ -112,13 +112,14 @@ RenderViewHostImpl* RenderViewHostManager::Navigate(
!render_view_host_->IsRenderViewLive()) {
// Note: we don't call InitRenderView here because we are navigating away
// soon anyway, and we don't have the NavigationEntry for this host.
- delegate_->CreateRenderViewForRenderManager(render_view_host_);
+ delegate_->CreateRenderViewForRenderManager(render_view_host_,
+ MSG_ROUTING_NONE);
}
// If the renderer crashed, then try to create a new one to satisfy this
// navigation request.
if (!dest_render_view_host->IsRenderViewLive()) {
- if (!InitRenderView(dest_render_view_host, entry))
+ if (!InitRenderView(dest_render_view_host, MSG_ROUTING_NONE))
return NULL;
// Now that we've created a new renderer, be sure to hide it if it isn't
@@ -543,62 +544,64 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
// BrowsingInstance. It is important to immediately give this new
// SiteInstance to a RenderViewHost (if it is different than our current
// SiteInstance), so that it is ref counted. This will happen in
- // CreatePendingRenderView.
+ // CreateRenderView.
return curr_instance->GetRelatedSiteInstance(dest_url);
}
}
-bool RenderViewHostManager::CreatePendingRenderView(
- const NavigationEntryImpl& entry, SiteInstance* instance) {
- NavigationEntry* curr_entry =
- delegate_->GetControllerForRenderManager().GetLastCommittedEntry();
- if (curr_entry) {
- DCHECK(!curr_entry->GetContentState().empty());
- // TODO(creis): Should send a message to the RenderView to let it know
- // we're about to switch away, so that it sends an UpdateState message.
- }
-
- // Check if we've already created an RVH for this SiteInstance.
+int RenderViewHostManager::CreateRenderView(
+ SiteInstance* instance,
+ int opener_route_id,
+ bool swapped_out) {
CHECK(instance);
- RenderViewHostMap::iterator iter =
- swapped_out_hosts_.find(instance->GetId());
- if (iter != swapped_out_hosts_.end()) {
- // Re-use the existing RenderViewHost, which has already been initialized.
- // We'll remove it from the list of swapped out hosts if it commits.
- pending_render_view_host_ = iter->second;
+ // Check if we've already created an RVH for this SiteInstance. If so, try
+ // to re-use the existing one, which has already been initialized. We'll
+ // remove it from the list of swapped out hosts if it commits.
+ RenderViewHostImpl* new_render_view_host = static_cast<RenderViewHostImpl*>(
+ GetSwappedOutRenderViewHost(instance));
+ if (new_render_view_host) {
// Prevent the process from exiting while we're trying to use it.
- pending_render_view_host_->GetProcess()->AddPendingView();
-
- return true;
- }
+ new_render_view_host->GetProcess()->AddPendingView();
+ } else {
+ // Create a new RenderViewHost if we don't find an existing one.
+ new_render_view_host = static_cast<RenderViewHostImpl*>(
+ RenderViewHostFactory::Create(instance,
+ render_view_delegate_, MSG_ROUTING_NONE, swapped_out, delegate_->
+ GetControllerForRenderManager().GetSessionStorageNamespace()));
- pending_render_view_host_ = static_cast<RenderViewHostImpl*>(
- RenderViewHostFactory::Create(
- instance, render_view_delegate_, MSG_ROUTING_NONE, delegate_->
- GetControllerForRenderManager().GetSessionStorageNamespace()));
+ // Prevent the process from exiting while we're trying to use it.
+ new_render_view_host->GetProcess()->AddPendingView();
- // Prevent the process from exiting while we're trying to use it.
- pending_render_view_host_->GetProcess()->AddPendingView();
+ // Store the new RVH as swapped out if necessary.
+ if (swapped_out)
+ swapped_out_hosts_[instance->GetId()] = new_render_view_host;
- bool success = InitRenderView(pending_render_view_host_, entry);
- if (success) {
- // Don't show the view until we get a DidNavigate from it.
- pending_render_view_host_->GetView()->Hide();
- } else {
- CancelPending();
+ bool success = InitRenderView(new_render_view_host, opener_route_id);
+ if (success) {
+ // Don't show the view until we get a DidNavigate from it.
+ new_render_view_host->GetView()->Hide();
+ } else if (!swapped_out) {
+ CancelPending();
+ }
}
- return success;
+
+ // Use this as our new pending RVH if it isn't swapped out.
+ if (!swapped_out)
+ pending_render_view_host_ = new_render_view_host;
+
+ return new_render_view_host->GetRoutingID();
}
bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host,
- const NavigationEntryImpl& entry) {
+ int opener_route_id) {
// If the pending navigation is to a WebUI, tell the RenderView about any
// bindings it will need enabled.
if (pending_web_ui())
render_view_host->AllowBindings(pending_web_ui()->GetBindings());
- return delegate_->CreateRenderViewForRenderManager(render_view_host);
+ return delegate_->CreateRenderViewForRenderManager(render_view_host,
+ opener_route_id);
}
void RenderViewHostManager::CommitPending() {
@@ -737,9 +740,19 @@ RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate(
delegate_->CreateWebUIForRenderManager(entry.GetURL()));
pending_and_current_web_ui_.reset();
- // Create a pending RVH and navigate it.
- bool success = CreatePendingRenderView(entry, new_instance);
- if (!success)
+ // Ensure that we have created RVHs for the new RVH's opener chain if
+ // we are staying in the same BrowsingInstance. This allows the pending RVH
+ // to send cross-process script calls to its opener(s).
+ int opener_route_id = MSG_ROUTING_NONE;
+ if (new_instance->IsRelatedSiteInstance(curr_instance)) {
+ opener_route_id =
+ delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
+ }
+
+ // Create a non-swapped-out pending RVH with the given opener and navigate
+ // it.
+ int route_id = CreateRenderView(new_instance, opener_route_id, false);
+ if (route_id == MSG_ROUTING_NONE)
return NULL;
// Check if our current RVH is live before we set up a transition.
@@ -878,3 +891,12 @@ bool RenderViewHostManager::IsSwappedOut(RenderViewHost* rvh) {
return swapped_out_hosts_.find(rvh->GetSiteInstance()->GetId()) !=
swapped_out_hosts_.end();
}
+
+RenderViewHost* RenderViewHostManager::GetSwappedOutRenderViewHost(
+ SiteInstance* instance) {
+ RenderViewHostMap::iterator iter = swapped_out_hosts_.find(instance->GetId());
+ if (iter != swapped_out_hosts_.end())
+ return iter->second;
+
+ return NULL;
+}
diff --git a/content/browser/web_contents/render_view_host_manager.h b/content/browser/web_contents/render_view_host_manager.h
index aecc889..2d9a384 100644
--- a/content/browser/web_contents/render_view_host_manager.h
+++ b/content/browser/web_contents/render_view_host_manager.h
@@ -57,7 +57,7 @@ class CONTENT_EXPORT RenderViewHostManager
// If you are attaching to an already-existing RenderView, you should call
// InitWithExistingID.
virtual bool CreateRenderViewForRenderManager(
- content::RenderViewHost* render_view_host) = 0;
+ content::RenderViewHost* render_view_host, int opener_route_id) = 0;
virtual void BeforeUnloadFiredFromRenderManager(
bool proceed, bool* proceed_to_fire_unload) = 0;
virtual void DidStartLoadingFromRenderManager(
@@ -68,6 +68,13 @@ class CONTENT_EXPORT RenderViewHostManager
virtual void NotifySwappedFromRenderManager() = 0;
virtual NavigationControllerImpl& GetControllerForRenderManager() = 0;
+ // Create swapped out RenderViews in the given SiteInstance for each tab in
+ // the opener chain of this tab, if any. This allows the current tab to
+ // make cross-process script calls to its opener(s). Returns the route ID
+ // of the immediate opener, if one exists (otherwise MSG_ROUTING_NONE).
+ virtual int CreateOpenerRenderViewsForRenderManager(
+ content::SiteInstance* instance) = 0;
+
// Creates a WebUI object for the given URL if one applies. Ownership of the
// returned pointer will be passed to the caller. If no WebUI applies,
// returns NULL.
@@ -154,6 +161,13 @@ class CONTENT_EXPORT RenderViewHostManager
// Called when a renderer's main frame navigates.
void DidNavigateMainFrame(content::RenderViewHost* render_view_host);
+ // Helper method to create a RenderViewHost. If |swapped_out| is true, it
+ // will be initially placed on the swapped out hosts list. Otherwise, it
+ // will be used for a pending cross-site navigation.
+ int CreateRenderView(content::SiteInstance* instance,
+ int opener_route_id,
+ bool swapped_out);
+
// Set the WebUI after committing a page load. This is useful for navigations
// initiated from a renderer, where we want to give the new renderer WebUI
// privileges from the originating renderer.
@@ -204,6 +218,10 @@ class CONTENT_EXPORT RenderViewHostManager
// RenderViewHosts.
bool IsSwappedOut(content::RenderViewHost* rvh);
+ // Returns the swapped out RenderViewHost for the given SiteInstance, if any.
+ content::RenderViewHost* GetSwappedOutRenderViewHost(
+ content::SiteInstance* instance);
+
private:
friend class content::TestWebContents;
friend class RenderViewHostManagerTest;
@@ -234,15 +252,9 @@ class CONTENT_EXPORT RenderViewHostManager
const content::NavigationEntryImpl& entry,
content::SiteInstance* curr_instance);
- // Helper method to create a pending RenderViewHost for a cross-site
- // navigation.
- bool CreatePendingRenderView(const content::NavigationEntryImpl& entry,
- content::SiteInstance* instance);
-
- // Sets up the necessary state for a new RenderViewHost navigating to the
- // given entry.
+ // Sets up the necessary state for a new RenderViewHost with the given opener.
bool InitRenderView(content::RenderViewHost* render_view_host,
- const content::NavigationEntryImpl& entry);
+ int opener_route_id);
// Sets the pending RenderViewHost/WebUI to be the active one. Note that this
// doesn't require the pending render_view_host_ pointer to be non-NULL, since
diff --git a/content/browser/web_contents/render_view_host_manager_unittest.cc b/content/browser/web_contents/render_view_host_manager_unittest.cc
index fe17a0e..57b3b96 100644
--- a/content/browser/web_contents/render_view_host_manager_unittest.cc
+++ b/content/browser/web_contents/render_view_host_manager_unittest.cc
@@ -233,10 +233,8 @@ TEST_F(RenderViewHostManagerTest, NewTabPageProcesses) {
// The two RVH's should be different in every way.
EXPECT_NE(active_rvh()->GetProcess(), dest_rvh2->GetProcess());
EXPECT_NE(active_rvh()->GetSiteInstance(), dest_rvh2->GetSiteInstance());
- EXPECT_NE(static_cast<SiteInstanceImpl*>(active_rvh()->GetSiteInstance())->
- browsing_instance_,
- static_cast<SiteInstanceImpl*>(dest_rvh2->GetSiteInstance())->
- browsing_instance_);
+ EXPECT_FALSE(active_rvh()->GetSiteInstance()->IsRelatedSiteInstance(
+ dest_rvh2->GetSiteInstance()));
// Navigate both to the new tab page, and verify that they share a
// SiteInstance.
@@ -772,3 +770,68 @@ TEST_F(RenderViewHostManagerTest, NavigateAfterMissingSwapOutACK) {
EXPECT_FALSE(rvh2->is_swapped_out());
EXPECT_TRUE(rvh1->is_swapped_out());
}
+
+// Test that we create swapped out RVHs for the opener chain when navigating an
+// opened tab cross-process. This allows us to support certain cross-process
+// JavaScript calls (http://crbug.com/99202).
+TEST_F(RenderViewHostManagerTest, CreateSwappedOutOpenerRVHs) {
+ const GURL kUrl1("http://www.google.com/");
+ const GURL kUrl2("http://www.chromium.org/");
+ const GURL kNtpUrl(chrome::kTestNewTabURL);
+
+ // Navigate to an initial URL.
+ contents()->NavigateAndCommit(kUrl1);
+ RenderViewHostManager* manager = contents()->GetRenderManagerForTesting();
+
+ // Pretend the RVH is alive so it doesn't go away.
+ TestRenderViewHost* rvh1 = test_rvh();
+
+ // Create 2 new tabs and simulate them being the opener chain for the main
+ // tab. They should be in the same SiteInstance.
+ TestWebContents opener1(browser_context(), rvh1->GetSiteInstance());
+ RenderViewHostManager* opener1_manager = opener1.GetRenderManagerForTesting();
+ contents()->SetOpener(&opener1);
+
+ TestWebContents opener2(browser_context(), rvh1->GetSiteInstance());
+ RenderViewHostManager* opener2_manager = opener2.GetRenderManagerForTesting();
+ opener1.SetOpener(&opener2);
+
+ // Navigate to a cross-site URL (different SiteInstance but same
+ // BrowsingInstance).
+ contents()->NavigateAndCommit(kUrl2);
+ TestRenderViewHost* rvh2 = test_rvh();
+ EXPECT_NE(rvh1->GetSiteInstance(), rvh2->GetSiteInstance());
+ EXPECT_TRUE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
+ rvh2->GetSiteInstance()));
+
+ // Ensure rvh1 is placed on swapped out list of the current tab.
+ EXPECT_TRUE(manager->IsSwappedOut(rvh1));
+ EXPECT_EQ(rvh1,
+ manager->GetSwappedOutRenderViewHost(rvh1->GetSiteInstance()));
+
+ // Ensure a swapped out RVH is created in the first opener tab.
+ TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
+ opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
+ EXPECT_TRUE(opener1_manager->IsSwappedOut(opener1_rvh));
+ EXPECT_TRUE(opener1_rvh->is_swapped_out());
+
+ // Ensure a swapped out RVH is created in the second opener tab.
+ TestRenderViewHost* opener2_rvh = static_cast<TestRenderViewHost*>(
+ opener2_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
+ EXPECT_TRUE(opener2_manager->IsSwappedOut(opener2_rvh));
+ EXPECT_TRUE(opener2_rvh->is_swapped_out());
+
+ // Navigate to a cross-BrowsingInstance URL.
+ contents()->NavigateAndCommit(kNtpUrl);
+ TestRenderViewHost* rvh3 = test_rvh();
+ EXPECT_NE(rvh1->GetSiteInstance(), rvh3->GetSiteInstance());
+ EXPECT_FALSE(rvh1->GetSiteInstance()->IsRelatedSiteInstance(
+ rvh3->GetSiteInstance()));
+
+ // No scripting is allowed across BrowsingInstances, so we should not create
+ // swapped out RVHs for the opener chain in this case.
+ EXPECT_FALSE(opener1_manager->GetSwappedOutRenderViewHost(
+ rvh3->GetSiteInstance()));
+ EXPECT_FALSE(opener2_manager->GetSwappedOutRenderViewHost(
+ rvh3->GetSiteInstance()));
+}
diff --git a/content/browser/web_contents/test_web_contents.cc b/content/browser/web_contents/test_web_contents.cc
index 69e22e4..c5bf1fb 100644
--- a/content/browser/web_contents/test_web_contents.cc
+++ b/content/browser/web_contents/test_web_contents.cc
@@ -12,6 +12,9 @@
#include "content/browser/site_instance_impl.h"
#include "content/browser/web_contents/navigation_entry_impl.h"
#include "content/common/view_messages.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
#include "content/public/common/page_transition_types.h"
#include "content/test/mock_render_process_host.h"
#include "webkit/forms/password_form.h"
@@ -21,7 +24,8 @@ namespace content {
TestWebContents::TestWebContents(BrowserContext* browser_context,
SiteInstance* instance)
- : WebContentsImpl(browser_context, instance, MSG_ROUTING_NONE, NULL, NULL),
+ : WebContentsImpl(browser_context, instance, MSG_ROUTING_NONE, NULL, NULL,
+ NULL),
transition_cross_site(false),
delegate_view_override_(NULL),
expect_set_history_length_and_prune_(false),
@@ -83,10 +87,10 @@ WebPreferences TestWebContents::TestGetWebkitPrefs() {
}
bool TestWebContents::CreateRenderViewForRenderManager(
- RenderViewHost* render_view_host) {
+ RenderViewHost* render_view_host, int opener_route_id) {
// This will go to a TestRenderViewHost.
static_cast<RenderViewHostImpl*>(
- render_view_host)->CreateRenderView(string16(), -1);
+ render_view_host)->CreateRenderView(string16(), opener_route_id, -1);
return true;
}
@@ -156,6 +160,14 @@ RenderViewHostDelegate::View* TestWebContents::GetViewDelegate() {
return WebContentsImpl::GetViewDelegate();
}
+void TestWebContents::SetOpener(TestWebContents* opener) {
+ // This is normally only set in the WebContents constructor, which also
+ // registers an observer for when the opener gets closed.
+ opener_ = opener;
+ registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+ content::Source<WebContents>(opener_));
+}
+
void TestWebContents::ExpectSetHistoryLengthAndPrune(
const SiteInstance* site_instance,
int history_length,
diff --git a/content/browser/web_contents/test_web_contents.h b/content/browser/web_contents/test_web_contents.h
index 7267cab..c862d62 100644
--- a/content/browser/web_contents/test_web_contents.h
+++ b/content/browser/web_contents/test_web_contents.h
@@ -56,7 +56,7 @@ class TestWebContents : public WebContentsImpl, public WebContentsTester {
// Prevent interaction with views.
virtual bool CreateRenderViewForRenderManager(
- RenderViewHost* render_view_host) OVERRIDE;
+ RenderViewHost* render_view_host, int opener_route_id) OVERRIDE;
virtual void UpdateRenderViewSizeForRenderManager() OVERRIDE {}
// Returns a clone of this TestWebContents. The returned object is also a
@@ -72,6 +72,9 @@ class TestWebContents : public WebContentsImpl, public WebContentsTester {
delegate_view_override_ = view;
}
+ // Allows us to simulate this tab having an opener.
+ void SetOpener(TestWebContents* opener);
+
// Establish expected arguments for |SetHistoryLengthAndPrune()|. When
// |SetHistoryLengthAndPrune()| is called, the arguments are compared
// with the expected arguments specified here.
diff --git a/content/browser/web_contents/web_contents_delegate_unittest.cc b/content/browser/web_contents/web_contents_delegate_unittest.cc
index e147153..72cd369 100644
--- a/content/browser/web_contents/web_contents_delegate_unittest.cc
+++ b/content/browser/web_contents/web_contents_delegate_unittest.cc
@@ -25,11 +25,13 @@ TEST(WebContentsDelegateTest, UnregisterInDestructor) {
NULL,
MSG_ROUTING_NONE,
NULL,
+ NULL,
NULL));
scoped_ptr<WebContentsImpl> contents_b(new WebContentsImpl(&browser_context,
NULL,
MSG_ROUTING_NONE,
NULL,
+ NULL,
NULL));
EXPECT_TRUE(contents_a->GetDelegate() == NULL);
EXPECT_TRUE(contents_b->GetDelegate() == NULL);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 08d28b3..05dafcd 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -239,6 +239,7 @@ WebContents* WebContents::Create(
site_instance,
routing_id,
static_cast<const WebContentsImpl*>(base_web_contents),
+ NULL,
static_cast<SessionStorageNamespaceImpl*>(session_storage_namespace));
}
}
@@ -250,10 +251,12 @@ WebContentsImpl::WebContentsImpl(
SiteInstance* site_instance,
int routing_id,
const WebContentsImpl* base_web_contents,
+ WebContentsImpl* opener,
SessionStorageNamespaceImpl* session_storage_namespace)
: delegate_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(controller_(
this, browser_context, session_storage_namespace)),
+ opener_(opener),
ALLOW_THIS_IN_INITIALIZER_LIST(render_manager_(this, this)),
is_loading_(false),
crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING),
@@ -280,7 +283,6 @@ WebContentsImpl::WebContentsImpl(
temporary_zoom_settings_(false),
content_restrictions_(0),
view_type_(content::VIEW_TYPE_WEB_CONTENTS),
- has_opener_(false),
color_chooser_(NULL) {
render_manager_.Init(browser_context, site_instance, routing_id);
@@ -310,6 +312,12 @@ WebContentsImpl::WebContentsImpl(
view_->CreateView(base_web_contents ?
base_web_contents->GetView()->GetContainerSize() : gfx::Size());
+ // Listen for whether our opener gets destroyed.
+ if (opener_) {
+ registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+ content::Source<WebContents>(opener_));
+ }
+
#if defined(ENABLE_JAVA_BRIDGE)
java_bridge_dispatcher_host_manager_.reset(
new JavaBridgeDispatcherHostManager(this));
@@ -920,13 +928,12 @@ void WebContentsImpl::Stop() {
}
WebContents* WebContentsImpl::Clone() {
- // We create a new SiteInstance so that the new tab won't share processes
- // with the old one. This can be changed in the future if we need it to share
- // processes for some reason.
+ // We use our current SiteInstance since the cloned entry will use it anyway.
+ // We pass |this| for the |base_web_contents| to size the view correctly, and
+ // our own opener so that the cloned page can access it if it was before.
WebContentsImpl* tc = new WebContentsImpl(
- GetBrowserContext(),
- SiteInstance::Create(GetBrowserContext()),
- MSG_ROUTING_NONE, this, NULL);
+ GetBrowserContext(), GetSiteInstance(),
+ MSG_ROUTING_NONE, this, opener_, NULL);
tc->GetControllerImpl().CopyStateFrom(controller_);
return tc;
}
@@ -958,6 +965,28 @@ void WebContentsImpl::Focus() {
view_->Focus();
}
+void WebContentsImpl::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
+ OnWebContentsDestroyed(
+ content::Source<content::WebContents>(source).ptr());
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void WebContentsImpl::OnWebContentsDestroyed(WebContents* web_contents) {
+ // Clear the opener if it has been closed.
+ if (web_contents == opener_) {
+ registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
+ content::Source<WebContents>(opener_));
+ opener_ = NULL;
+ }
+}
+
void WebContentsImpl::AddObserver(WebContentsObserver* observer) {
observers_.AddObserver(observer);
}
@@ -1408,7 +1437,7 @@ bool WebContentsImpl::GotResponseToLockMouseRequest(bool allowed) {
}
bool WebContentsImpl::HasOpener() const {
- return has_opener_;
+ return opener_ != NULL;
}
void WebContentsImpl::DidChooseColorInColorChooser(int color_chooser_id,
@@ -2000,6 +2029,12 @@ gfx::Rect WebContentsImpl::GetRootWindowResizerRect() const {
}
void WebContentsImpl::RenderViewCreated(RenderViewHost* render_view_host) {
+ // Don't send notifications if we are just creating a swapped-out RVH for
+ // the opener chain. These won't be used for view-source or WebUI, so it's
+ // ok to return early.
+ if (static_cast<RenderViewHostImpl*>(render_view_host)->is_swapped_out())
+ return;
+
content::NotificationService::current()->Notify(
content::NOTIFICATION_RENDER_VIEW_HOST_CREATED_FOR_TAB,
content::Source<WebContents>(this),
@@ -2547,6 +2582,28 @@ void WebContentsImpl::NotifySwappedFromRenderManager() {
NotifySwapped();
}
+int WebContentsImpl::CreateOpenerRenderViewsForRenderManager(
+ SiteInstance* instance) {
+ if (!opener_)
+ return MSG_ROUTING_NONE;
+
+ // Recursively create RenderViews for anything else in the opener chain.
+ return opener_->CreateOpenerRenderViews(instance);
+}
+
+int WebContentsImpl::CreateOpenerRenderViews(SiteInstance* instance) {
+ int opener_route_id = MSG_ROUTING_NONE;
+
+ // If this tab has an opener, ensure it has a RenderView in the given
+ // SiteInstance as well.
+ if (opener_)
+ opener_route_id = opener_->CreateOpenerRenderViews(instance);
+
+ // Create a swapped out RenderView in the given SiteInstance if none exists,
+ // setting its opener to the given route_id. Return the new view's route_id.
+ return render_manager_.CreateRenderView(instance, opener_route_id, true);
+}
+
NavigationControllerImpl& WebContentsImpl::GetControllerForRenderManager() {
return GetControllerImpl();
}
@@ -2561,7 +2618,7 @@ NavigationEntry*
}
bool WebContentsImpl::CreateRenderViewForRenderManager(
- RenderViewHost* render_view_host) {
+ RenderViewHost* render_view_host, int opener_route_id) {
// Can be NULL during tests.
RenderWidgetHostView* rwh_view = view_->CreateViewForWidget(render_view_host);
@@ -2575,8 +2632,10 @@ bool WebContentsImpl::CreateRenderViewForRenderManager(
GetMaxPageIDForSiteInstance(render_view_host->GetSiteInstance());
if (!static_cast<RenderViewHostImpl*>(
- render_view_host)->CreateRenderView(string16(), max_page_id))
+ render_view_host)->CreateRenderView(string16(), opener_route_id,
+ max_page_id)) {
return false;
+ }
#if defined(OS_LINUX) || defined(OS_OPENBSD)
// Force a ViewMsg_Resize to be sent, needed to make plugins show up on
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index a2fcba7..b330375 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -19,6 +19,8 @@
#include "content/browser/web_contents/navigation_controller_impl.h"
#include "content/browser/web_contents/render_view_host_manager.h"
#include "content/common/content_export.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/render_view_host_delegate.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/renderer_preferences.h"
@@ -56,13 +58,15 @@ struct WebIntentData;
class CONTENT_EXPORT WebContentsImpl
: public NON_EXPORTED_BASE(content::WebContents),
public content::RenderViewHostDelegate,
- public RenderViewHostManager::Delegate {
+ public RenderViewHostManager::Delegate,
+ public content::NotificationObserver {
public:
// See WebContents::Create for a description of these parameters.
WebContentsImpl(content::BrowserContext* browser_context,
content::SiteInstance* site_instance,
int routing_id,
const WebContentsImpl* base_web_contents,
+ WebContentsImpl* opener,
SessionStorageNamespaceImpl* session_storage_namespace);
virtual ~WebContentsImpl();
@@ -117,10 +121,6 @@ class CONTENT_EXPORT WebContentsImpl
opener_web_ui_type_ = opener_web_ui_type;
}
- void set_has_opener(bool has_opener) {
- has_opener_ = has_opener;
- }
-
JavaBridgeDispatcherHostManager* java_bridge_dispatcher_host_manager() const {
return java_bridge_dispatcher_host_manager_.get();
}
@@ -340,7 +340,7 @@ class CONTENT_EXPORT WebContentsImpl
// RenderViewHostManager::Delegate -------------------------------------------
virtual bool CreateRenderViewForRenderManager(
- content::RenderViewHost* render_view_host) OVERRIDE;
+ content::RenderViewHost* render_view_host, int opener_route_id) OVERRIDE;
virtual void BeforeUnloadFiredFromRenderManager(
bool proceed,
bool* proceed_to_fire_unload) OVERRIDE;
@@ -350,6 +350,8 @@ class CONTENT_EXPORT WebContentsImpl
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void UpdateRenderViewSizeForRenderManager() OVERRIDE;
virtual void NotifySwappedFromRenderManager() OVERRIDE;
+ virtual int CreateOpenerRenderViewsForRenderManager(
+ content::SiteInstance* instance) OVERRIDE;
virtual NavigationControllerImpl& GetControllerForRenderManager() OVERRIDE;
virtual WebUIImpl* CreateWebUIForRenderManager(const GURL& url) OVERRIDE;
virtual content::NavigationEntry*
@@ -359,6 +361,12 @@ class CONTENT_EXPORT WebContentsImpl
virtual void CreateViewAndSetSizeForRVH(
content::RenderViewHost* rvh) OVERRIDE;
+ // content::NotificationObserver ---------------------------------------------
+
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
protected:
friend class content::WebContentsObserver;
@@ -386,6 +394,9 @@ class CONTENT_EXPORT WebContentsImpl
// TODO(brettw) TestWebContents shouldn't exist!
friend class content::TestWebContents;
+ // Clears this tab's opener if it has been closed.
+ void OnWebContentsDestroyed(content::WebContents* web_contents);
+
// Callback function when showing JS dialogs.
void OnDialogClosed(content::RenderViewHost* rvh,
IPC::Message* reply_msg,
@@ -512,6 +523,12 @@ class CONTENT_EXPORT WebContentsImpl
int merge_history_length,
int32 minimum_page_id);
+ // Recursively creates swapped out RenderViews for this tab's opener chain
+ // (including this tab) in the given SiteInstance, allowing other tabs to send
+ // cross-process JavaScript calls to their opener(s). Returns the route ID of
+ // this tab's RenderView for |instance|.
+ int CreateOpenerRenderViews(content::SiteInstance* instance);
+
// Misc non-view stuff -------------------------------------------------------
// Helper functions for sending notifications.
@@ -530,6 +547,9 @@ class CONTENT_EXPORT WebContentsImpl
// WARNING: this needs to be deleted after NavigationController.
base::PropertyBag property_bag_;
+ // Listen for notifications as well.
+ content::NotificationRegistrar registrar_;
+
// Data for core operation ---------------------------------------------------
// Delegate for notifying our owner about stuff. Not owned by us.
@@ -547,6 +567,10 @@ class CONTENT_EXPORT WebContentsImpl
// the observer list then.
ObserverList<content::WebContentsObserver> observers_;
+ // The tab that opened this tab, if any. Will be set to null if the opener
+ // is closed.
+ WebContentsImpl* opener_;
+
// Helper classes ------------------------------------------------------------
// Manages creation and swapping of render views.
@@ -674,9 +698,6 @@ class CONTENT_EXPORT WebContentsImpl
// Our view type. Default is VIEW_TYPE_WEB_CONTENTS.
content::ViewType view_type_;
- // Is there an opener associated with this?
- bool has_opener_;
-
// Color chooser that was opened by this tab.
content::ColorChooser* color_chooser_;
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index ea9ae58..4d726be 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -221,7 +221,7 @@ class TestInterstitialPage : public InterstitialPageImpl {
virtual content::RenderViewHost* CreateRenderViewHost() OVERRIDE {
return new TestRenderViewHost(
SiteInstance::Create(web_contents()->GetBrowserContext()),
- this, MSG_ROUTING_NONE);
+ this, MSG_ROUTING_NONE, false);
}
virtual content::WebContentsView* CreateWebContentsView() OVERRIDE {
diff --git a/content/browser/web_contents/web_contents_view_helper.cc b/content/browser/web_contents/web_contents_view_helper.cc
index b3bf9be..a79f8d0 100644
--- a/content/browser/web_contents/web_contents_view_helper.cc
+++ b/content/browser/web_contents/web_contents_view_helper.cc
@@ -21,6 +21,7 @@ using content::RenderWidgetHost;
using content::RenderWidgetHostImpl;
using content::RenderWidgetHostView;
using content::RenderWidgetHostViewPort;
+using content::SiteInstance;
WebContentsViewHelper::WebContentsViewHelper() {
registrar_.Add(this,
@@ -46,13 +47,13 @@ void WebContentsViewHelper::Observe(
}
WebContentsImpl* WebContentsViewHelper::CreateNewWindow(
- WebContentsImpl* web_contents,
+ WebContentsImpl* opener,
int route_id,
const ViewHostMsg_CreateWindow_Params& params) {
bool should_create = true;
- if (web_contents->GetDelegate()) {
- should_create = web_contents->GetDelegate()->ShouldCreateWebContents(
- web_contents,
+ if (opener->GetDelegate()) {
+ should_create = opener->GetDelegate()->ShouldCreateWebContents(
+ opener,
route_id,
params.window_container_type,
params.frame_name,
@@ -66,22 +67,22 @@ WebContentsImpl* WebContentsViewHelper::CreateNewWindow(
// script-related windows), by passing in the current SiteInstance. However,
// if the opener is being suppressed, we create a new SiteInstance in its own
// BrowsingInstance.
- scoped_refptr<content::SiteInstance> site_instance =
+ scoped_refptr<SiteInstance> site_instance =
params.opener_suppressed ?
- content::SiteInstance::Create(web_contents->GetBrowserContext()) :
- web_contents->GetSiteInstance();
+ SiteInstance::Create(opener->GetBrowserContext()) :
+ opener->GetSiteInstance();
// Create the new web contents. This will automatically create the new
// WebContentsView. In the future, we may want to create the view separately.
WebContentsImpl* new_contents =
- new WebContentsImpl(web_contents->GetBrowserContext(),
+ new WebContentsImpl(opener->GetBrowserContext(),
site_instance,
route_id,
- web_contents,
+ opener,
+ params.opener_suppressed ? NULL : opener,
NULL);
new_contents->set_opener_web_ui_type(
- web_contents->GetWebUITypeForCurrentState());
- new_contents->set_has_opener(!params.opener_url.is_empty());
+ opener->GetWebUITypeForCurrentState());
if (!params.opener_suppressed) {
content::WebContentsView* new_view = new_contents->GetView();
@@ -96,20 +97,21 @@ WebContentsImpl* WebContentsViewHelper::CreateNewWindow(
pending_contents_[route_id] = new_contents;
}
- if (web_contents->GetDelegate())
- web_contents->GetDelegate()->WebContentsCreated(web_contents,
- params.opener_frame_id,
- params.target_url,
- new_contents);
+ if (opener->GetDelegate()) {
+ opener->GetDelegate()->WebContentsCreated(opener,
+ params.opener_frame_id,
+ params.target_url,
+ new_contents);
+ }
if (params.opener_suppressed) {
// When the opener is suppressed, the original renderer cannot access the
// new window. As a result, we need to show and navigate the window here.
gfx::Rect initial_pos;
- web_contents->AddNewContents(new_contents,
- params.disposition,
- initial_pos,
- params.user_gesture);
+ opener->AddNewContents(new_contents,
+ params.disposition,
+ initial_pos,
+ params.user_gesture);
content::OpenURLParams open_params(params.target_url, content::Referrer(),
CURRENT_TAB,
diff --git a/content/browser/web_contents/web_contents_view_helper.h b/content/browser/web_contents/web_contents_view_helper.h
index e39755a..46d58de 100644
--- a/content/browser/web_contents/web_contents_view_helper.h
+++ b/content/browser/web_contents/web_contents_view_helper.h
@@ -37,7 +37,7 @@ class CONTENT_EXPORT WebContentsViewHelper
// Creates a new window; call |ShowCreatedWindow| below to show it.
WebContentsImpl* CreateNewWindow(
- WebContentsImpl* web_contents,
+ WebContentsImpl* opener,
int route_id,
const ViewHostMsg_CreateWindow_Params& params);
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 8edcf91..0c7bd54 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -632,6 +632,13 @@ IPC_STRUCT_BEGIN(ViewMsg_New_Params)
// The name of the frame associated with this view (or empty if none).
IPC_STRUCT_MEMBER(string16, frame_name)
+ // The route ID of the opener RenderView if we need to set one
+ // (MSG_ROUTING_NONE otherwise).
+ IPC_STRUCT_MEMBER(int, opener_route_id)
+
+ // Whether the RenderView should initially be swapped out.
+ IPC_STRUCT_MEMBER(bool, swapped_out)
+
// The initial page ID to use for this view, which must be larger than any
// existing navigation that might be loaded in the view. Page IDs are unique
// to a view and are only updated by the renderer after this initial value.
diff --git a/content/public/browser/site_instance.h b/content/public/browser/site_instance.h
index 66081ec..d68989e 100644
--- a/content/public/browser/site_instance.h
+++ b/content/public/browser/site_instance.h
@@ -82,6 +82,11 @@ class CONTENT_EXPORT SiteInstance : public base::RefCounted<SiteInstance> {
// Darin suggests.
virtual SiteInstance* GetRelatedSiteInstance(const GURL& url) = 0;
+ // Returns whether the given SiteInstance is in the same BrowsingInstance as
+ // this one. If so, JavaScript interactions that are permitted across
+ // origins (e.g., postMessage) should be supported.
+ virtual bool IsRelatedSiteInstance(const SiteInstance* instance) = 0;
+
// Factory method to create a new SiteInstance. This will create a new
// new BrowsingInstance, so it should only be used when creating a new tab
// from scratch (or similar circumstances). Callers should ensure that
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index aa3c988..b4c2b68 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -899,7 +899,7 @@ void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) {
// When bringing in render_view, also bring in webkit's glue and jsbindings.
RenderViewImpl::Create(
params.parent_window,
- MSG_ROUTING_NONE,
+ params.opener_route_id,
params.renderer_preferences,
params.web_preferences,
new SharedRenderViewCounter(0),
@@ -907,6 +907,8 @@ void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) {
params.surface_id,
params.session_storage_namespace_id,
params.frame_name,
+ false,
+ params.swapped_out,
params.next_page_id,
params.screen_info,
params.guest,
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 8ad9470..d3b95b0 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -26,6 +26,7 @@
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "content/common/appcache/appcache_dispatcher.h"
+#include "content/common/child_thread.h"
#include "content/common/clipboard_messages.h"
#include "content/common/database_messages.h"
#include "content/common/drag_messages.h"
@@ -436,11 +437,13 @@ RenderViewImpl::RenderViewImpl(
int32 surface_id,
int64 session_storage_namespace_id,
const string16& frame_name,
+ bool is_renderer_created,
+ bool swapped_out,
int32 next_page_id,
const WebKit::WebScreenInfo& screen_info,
bool guest,
AccessibilityMode accessibility_mode)
- : RenderWidget(WebKit::WebPopupTypeNone, screen_info),
+ : RenderWidget(WebKit::WebPopupTypeNone, screen_info, swapped_out),
webkit_preferences_(webkit_prefs),
send_content_state_immediately_(false),
enabled_bindings_(0),
@@ -483,7 +486,7 @@ RenderViewImpl::RenderViewImpl(
ALLOW_THIS_IN_INITIALIZER_LIST(pepper_delegate_(this)) {
routing_id_ = routing_id;
surface_id_ = surface_id;
- if (opener_id != MSG_ROUTING_NONE)
+ if (opener_id != MSG_ROUTING_NONE && is_renderer_created)
opener_id_ = opener_id;
// Ensure we start with a valid next_page_id_ from the browser.
@@ -500,7 +503,9 @@ RenderViewImpl::RenderViewImpl(
if (counter) {
shared_popup_counter_ = counter;
- shared_popup_counter_->data++;
+ // Only count this if it isn't swapped out upon creation.
+ if (!swapped_out)
+ shared_popup_counter_->data++;
decrement_shared_popup_at_destruction_ = true;
} else {
shared_popup_counter_ = new SharedRenderViewCounter(0);
@@ -514,7 +519,7 @@ RenderViewImpl::RenderViewImpl(
// If this is a popup, we must wait for the CreatingNew_ACK message before
// completing initialization. Otherwise, we can finish it now.
- if (opener_id == MSG_ROUTING_NONE) {
+ if (opener_id_ == MSG_ROUTING_NONE) {
did_show_ = true;
CompleteInit(parent_hwnd);
}
@@ -563,6 +568,20 @@ RenderViewImpl::RenderViewImpl(
ProcessViewLayoutFlags(command_line);
content::GetContentClient()->renderer()->RenderViewCreated(this);
+
+ // If we have an opener_id but we weren't created by a renderer, then
+ // it's the browser asking us to set our opener to another RenderView.
+ // TODO(creis): This doesn't yet handle openers that are subframes.
+ if (opener_id != MSG_ROUTING_NONE && !is_renderer_created) {
+ RenderViewImpl* opener_view = static_cast<RenderViewImpl*>(
+ ChildThread::current()->ResolveRoute(opener_id));
+ webview()->mainFrame()->setOpener(opener_view->webview()->mainFrame());
+ }
+
+ // If we are initially swapped out, navigate to kSwappedOutURL.
+ // This ensures we are in a unique origin that others cannot script.
+ if (is_swapped_out_)
+ NavigateToSwappedOutURL();
}
RenderViewImpl::~RenderViewImpl() {
@@ -634,6 +653,8 @@ RenderViewImpl* RenderViewImpl::Create(
int32 surface_id,
int64 session_storage_namespace_id,
const string16& frame_name,
+ bool is_renderer_created,
+ bool swapped_out,
int32 next_page_id,
const WebKit::WebScreenInfo& screen_info,
bool guest,
@@ -649,6 +670,8 @@ RenderViewImpl* RenderViewImpl::Create(
surface_id,
session_storage_namespace_id,
frame_name,
+ is_renderer_created,
+ swapped_out,
next_page_id,
screen_info,
guest,
@@ -1514,6 +1537,8 @@ WebView* RenderViewImpl::createView(
surface_id,
cloned_session_storage_namespace_id,
frame_name,
+ true,
+ false,
1,
screen_info_,
guest_,
@@ -4472,21 +4497,25 @@ void RenderViewImpl::OnSwapOut(const ViewMsg_SwapOut_Params& params) {
// Replace the page with a blank dummy URL. The unload handler will not be
// run a second time, thanks to a check in FrameLoader::stopLoading.
- // We use loadRequest instead of loadHTMLString because the former commits
- // synchronously. Otherwise a new navigation can interrupt the navigation
- // to content::kSwappedOutURL. If that happens to be to the page we had been
- // showing, then WebKit will never send a commit and we'll be left spinning.
// TODO(creis): Need to add a better way to do this that avoids running the
// beforeunload handler. For now, we just run it a second time silently.
- GURL swappedOutURL(content::kSwappedOutURL);
- WebURLRequest request(swappedOutURL);
- webview()->mainFrame()->loadRequest(request);
+ NavigateToSwappedOutURL();
}
// Just echo back the params in the ACK.
Send(new ViewHostMsg_SwapOut_ACK(routing_id_, params));
}
+void RenderViewImpl::NavigateToSwappedOutURL() {
+ // We use loadRequest instead of loadHTMLString because the former commits
+ // synchronously. Otherwise a new navigation can interrupt the navigation
+ // to content::kSwappedOutURL. If that happens to be to the page we had been
+ // showing, then WebKit will never send a commit and we'll be left spinning.
+ GURL swappedOutURL(content::kSwappedOutURL);
+ WebURLRequest request(swappedOutURL);
+ webview()->mainFrame()->loadRequest(request);
+}
+
void RenderViewImpl::OnClosePage() {
FOR_EACH_OBSERVER(RenderViewObserver, observers_, ClosePage());
// TODO(creis): We'd rather use webview()->Close() here, but that currently
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 77264de..8030060 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -193,6 +193,8 @@ class RenderViewImpl : public RenderWidget,
int32 surface_id,
int64 session_storage_namespace_id,
const string16& frame_name,
+ bool is_renderer_created,
+ bool swapped_out,
int32 next_page_id,
const WebKit::WebScreenInfo& screen_info,
bool guest,
@@ -747,6 +749,8 @@ class RenderViewImpl : public RenderWidget,
int32 surface_id,
int64 session_storage_namespace_id,
const string16& frame_name,
+ bool is_renderer_created,
+ bool swapped_out,
int32 next_page_id,
const WebKit::WebScreenInfo& screen_info,
bool guest,
@@ -984,6 +988,9 @@ class RenderViewImpl : public RenderWidget,
const WebKit::WebURLError& error,
bool replace);
+ // Make this RenderView show an empty, unscriptable page.
+ void NavigateToSwappedOutURL();
+
// If we initiated a navigation, this function will populate |document_state|
// with the navigation information saved in OnNavigate().
void PopulateDocumentStateFromPending(content::DocumentState* document_state);
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index dae7853..eb78d81 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -93,7 +93,8 @@ bool CanSendMessageWhileClosing(const IPC::Message* msg) {
} // namespace
RenderWidget::RenderWidget(WebKit::WebPopupType popup_type,
- const WebKit::WebScreenInfo& screen_info)
+ const WebKit::WebScreenInfo& screen_info,
+ bool swapped_out)
: routing_id_(MSG_ROUTING_NONE),
surface_id_(0),
webwidget_(NULL),
@@ -113,7 +114,7 @@ RenderWidget::RenderWidget(WebKit::WebPopupType popup_type,
has_focus_(false),
handling_input_event_(false),
closing_(false),
- is_swapped_out_(false),
+ is_swapped_out_(swapped_out),
input_method_is_active_(false),
text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
can_compose_inline_(true),
@@ -149,7 +150,7 @@ RenderWidget* RenderWidget::Create(int32 opener_id,
const WebKit::WebScreenInfo& screen_info) {
DCHECK(opener_id != MSG_ROUTING_NONE);
scoped_refptr<RenderWidget> widget(
- new RenderWidget(popup_type, screen_info));
+ new RenderWidget(popup_type, screen_info, false));
widget->Init(opener_id); // adds reference
return widget;
}
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index c6257bb..ffc0b8b 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -167,7 +167,8 @@ class CONTENT_EXPORT RenderWidget
};
RenderWidget(WebKit::WebPopupType popup_type,
- const WebKit::WebScreenInfo& screen_info);
+ const WebKit::WebScreenInfo& screen_info,
+ bool swapped_out);
virtual ~RenderWidget();
// Initializes this view with the given opener. CompleteInit must be called
diff --git a/content/renderer/render_widget_fullscreen.cc b/content/renderer/render_widget_fullscreen.cc
index 7030e5d..dfb5c13 100644
--- a/content/renderer/render_widget_fullscreen.cc
+++ b/content/renderer/render_widget_fullscreen.cc
@@ -31,7 +31,7 @@ void RenderWidgetFullscreen::show(WebKit::WebNavigationPolicy) {
}
RenderWidgetFullscreen::RenderWidgetFullscreen()
- : RenderWidget(WebKit::WebPopupTypeNone, WebKit::WebScreenInfo()) {
+ : RenderWidget(WebKit::WebPopupTypeNone, WebKit::WebScreenInfo(), false) {
}
RenderWidgetFullscreen::~RenderWidgetFullscreen() {}
diff --git a/content/test/render_view_fake_resources_test.cc b/content/test/render_view_fake_resources_test.cc
index d922307..807a4e1 100644
--- a/content/test/render_view_fake_resources_test.cc
+++ b/content/test/render_view_fake_resources_test.cc
@@ -72,6 +72,7 @@ void RenderViewFakeResourcesTest::SetUp() {
ViewMsg_New_Params params;
params.parent_window = 0;
params.view_id = kViewId;
+ params.opener_route_id = MSG_ROUTING_NONE;
params.session_storage_namespace_id =
dom_storage::kInvalidSessionStorageNamespaceId;
ASSERT_TRUE(channel_->Send(new ViewMsg_New(params)));
diff --git a/content/test/render_view_test.cc b/content/test/render_view_test.cc
index 25e5488..9454109 100644
--- a/content/test/render_view_test.cc
+++ b/content/test/render_view_test.cc
@@ -46,7 +46,7 @@ using WebKit::WebString;
using WebKit::WebURLRequest;
namespace {
-const int32 kOpenerId = 7;
+const int32 kOpenerId = -2;
const int32 kRouteId = 5;
const int32 kNewWindowRouteId = 6;
const int32 kSurfaceId = 42;
@@ -164,6 +164,8 @@ void RenderViewTest::SetUp() {
kSurfaceId,
dom_storage::kInvalidSessionStorageNamespaceId,
string16(),
+ false,
+ false,
1,
WebKit::WebScreenInfo(),
false,
diff --git a/content/test/test_renderer_host.cc b/content/test/test_renderer_host.cc
index cd9aa34..58d3ac9 100644
--- a/content/test/test_renderer_host.cc
+++ b/content/test/test_renderer_host.cc
@@ -44,6 +44,7 @@ class TestRenderViewHostFactory : public RenderViewHostFactory {
content::SiteInstance* instance,
content::RenderViewHostDelegate* delegate,
int routing_id,
+ bool swapped_out,
content::SessionStorageNamespace* session_storage) OVERRIDE;
private:
@@ -78,11 +79,12 @@ content::RenderViewHost* TestRenderViewHostFactory::CreateRenderViewHost(
SiteInstance* instance,
RenderViewHostDelegate* delegate,
int routing_id,
+ bool swapped_out,
SessionStorageNamespace* session_storage) {
// See declaration of render_process_host_factory_ below.
static_cast<SiteInstanceImpl*>(instance)->
set_render_process_host_factory(render_process_host_factory_);
- return new TestRenderViewHost(instance, delegate, routing_id);
+ return new TestRenderViewHost(instance, delegate, routing_id, swapped_out);
}
// static
diff --git a/content/test/test_renderer_host.h b/content/test/test_renderer_host.h
index 76ffdff..367fbea 100644
--- a/content/test/test_renderer_host.h
+++ b/content/test/test_renderer_host.h
@@ -66,6 +66,7 @@ class RenderViewHostTester {
// Gives tests access to RenderViewHostImpl::CreateRenderView.
virtual bool CreateRenderView(const string16& frame_name,
+ int opener_route_id,
int32 max_page_id) = 0;
// Calls OnMsgNavigate on the RenderViewHost with the given information,