diff options
author | creis@chromium.org <creis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-21 17:10:26 +0000 |
---|---|---|
committer | creis@chromium.org <creis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-21 17:10:26 +0000 |
commit | 58436a1770176ece2c02b28a57bba2a89db5d58b (patch) | |
tree | fdc8965e47e515b0d39d98f05f0280fefc7456a3 /content | |
parent | 8f8167ed2bd7ef7c76ed7d7b5f21bae175da5953 (diff) | |
download | chromium_src-58436a1770176ece2c02b28a57bba2a89db5d58b.zip chromium_src-58436a1770176ece2c02b28a57bba2a89db5d58b.tar.gz chromium_src-58436a1770176ece2c02b28a57bba2a89db5d58b.tar.bz2 |
Use a new scheme for swapping out RenderViews.
BUG=118664
TEST=none
Review URL: http://codereview.chromium.org/9720004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127986 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/browser/renderer_host/render_view_host_manager_browsertest.cc | 78 | ||||
-rw-r--r-- | content/public/common/url_constants.cc | 6 | ||||
-rw-r--r-- | content/public/common/url_constants.h | 3 | ||||
-rw-r--r-- | content/renderer/render_thread_impl.cc | 14 | ||||
-rw-r--r-- | content/renderer/render_thread_impl.h | 4 | ||||
-rw-r--r-- | content/renderer/render_view_impl.cc | 17 | ||||
-rw-r--r-- | content/test/render_view_test.cc | 5 |
7 files changed, 119 insertions, 8 deletions
diff --git a/content/browser/renderer_host/render_view_host_manager_browsertest.cc b/content/browser/renderer_host/render_view_host_manager_browsertest.cc index 79a9032..fe220b2 100644 --- a/content/browser/renderer_host/render_view_host_manager_browsertest.cc +++ b/content/browser/renderer_host/render_view_host_manager_browsertest.cc @@ -42,6 +42,84 @@ class RenderViewHostManagerTest : public InProcessBrowserTest { } }; +// Web pages should not have script access to the swapped out page. +IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, NoScriptAccessAfterSwapOut) { + // Start two servers with different sites. + ASSERT_TRUE(test_server()->Start()); + net::TestServer https_server( + net::TestServer::TYPE_HTTPS, + net::TestServer::kLocalhost, + FilePath(FILE_PATH_LITERAL("chrome/test/data"))); + ASSERT_TRUE(https_server.Start()); + + // Load a page with links that open in a new window. + std::string replacement_path; + ASSERT_TRUE(GetFilePathWithHostAndPortReplacement( + "files/click-noreferrer-links.html", + https_server.host_port_pair(), + &replacement_path)); + ui_test_utils::NavigateToURL(browser(), + test_server()->GetURL(replacement_path)); + + // Get the original SiteInstance for later comparison. + scoped_refptr<SiteInstance> orig_site_instance( + browser()->GetSelectedWebContents()->GetSiteInstance()); + EXPECT_TRUE(orig_site_instance != NULL); + + // Open a same-site link in a new tab. + ui_test_utils::WindowedNotificationObserver new_tab_observer( + content::NOTIFICATION_TAB_ADDED, + content::Source<content::WebContentsDelegate>(browser())); + bool success = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + browser()->GetSelectedWebContents()->GetRenderViewHost(), L"", + L"window.domAutomationController.send(clickSameSiteTargetedLink());", + &success)); + EXPECT_TRUE(success); + new_tab_observer.Wait(); + + // Opens in new tab. + EXPECT_EQ(2, browser()->tab_count()); + EXPECT_EQ(1, browser()->active_index()); + + // Wait for the navigation in the new tab to finish, if it hasn't. + ui_test_utils::WaitForLoadStop(browser()->GetSelectedWebContents()); + EXPECT_EQ("/files/title2.html", + browser()->GetSelectedWebContents()->GetURL().path()); + EXPECT_EQ(1, browser()->active_index()); + + // Should have the same SiteInstance. + scoped_refptr<SiteInstance> blank_site_instance( + browser()->GetSelectedWebContents()->GetSiteInstance()); + EXPECT_EQ(orig_site_instance, blank_site_instance); + + // We should have access to the opened tab's location. + browser()->ActivateTabAt(0, true); + success = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + browser()->GetSelectedWebContents()->GetRenderViewHost(), L"", + L"window.domAutomationController.send(testScriptAccessToWindow());", + &success)); + EXPECT_TRUE(success); + + // Now navigate the new tab to a different site. + browser()->ActivateTabAt(1, true); + ui_test_utils::NavigateToURL(browser(), + https_server.GetURL("files/title1.html")); + scoped_refptr<SiteInstance> new_site_instance( + browser()->GetSelectedWebContents()->GetSiteInstance()); + EXPECT_NE(orig_site_instance, new_site_instance); + + // We should no longer have script access to the opened tab's location. + browser()->ActivateTabAt(0, true); + success = false; + EXPECT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool( + browser()->GetSelectedWebContents()->GetRenderViewHost(), L"", + L"window.domAutomationController.send(testScriptAccessToWindow());", + &success)); + EXPECT_FALSE(success); +} + // Test for crbug.com/24447. Following a cross-site link with rel=noreferrer // and target=_blank should create a new SiteInstance. IN_PROC_BROWSER_TEST_F(RenderViewHostManagerTest, diff --git a/content/public/common/url_constants.cc b/content/public/common/url_constants.cc index ee82d1e..49f9711 100644 --- a/content/public/common/url_constants.cc +++ b/content/public/common/url_constants.cc @@ -39,6 +39,7 @@ const char kHttpsScheme[] = "https"; const char kJavaScriptScheme[] = "javascript"; const char kMailToScheme[] = "mailto"; const char kMetadataScheme[] = "metadata"; +const char kSwappedOutScheme[] = "swappedout"; const char kViewSourceScheme[] = "view-source"; const char kStandardSchemeSeparator[] = "://"; @@ -57,6 +58,11 @@ const char kChromeUIShorthangURL[] = "chrome://shorthang"; // have a chrome:// scheme that might let it be confused with a WebUI page. const char kUnreachableWebDataURL[] = "data:text/html,chromewebdata"; +// This URL is loaded when a page is swapped out and replaced by a page in a +// different renderer process. It must have a unique origin that cannot be +// scripted by other pages in the process. +const char kSwappedOutURL[] = "swappedout://"; + } // namespace chrome namespace content { diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h index 0470195..2df75c8 100644 --- a/content/public/common/url_constants.h +++ b/content/public/common/url_constants.h @@ -31,6 +31,7 @@ CONTENT_EXPORT extern const char kHttpsScheme[]; CONTENT_EXPORT extern const char kJavaScriptScheme[]; CONTENT_EXPORT extern const char kMailToScheme[]; CONTENT_EXPORT extern const char kMetadataScheme[]; +CONTENT_EXPORT extern const char kSwappedOutScheme[]; CONTENT_EXPORT extern const char kViewSourceScheme[]; // Used to separate a standard scheme and the hostname: "://". @@ -50,6 +51,8 @@ CONTENT_EXPORT extern const char kChromeUIShorthangURL[]; // Special URL used to start a navigation to an error page. extern const char kUnreachableWebDataURL[]; +// Special URL used to swap out a view being rendered by another process. +extern const char kSwappedOutURL[]; } // namespace chrome diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index a7277f8..19905c6 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc @@ -20,6 +20,7 @@ #include "base/shared_memory.h" #include "base/string_number_conversions.h" // Temporary #include "base/threading/thread_local.h" +#include "base/utf_string_conversions.h" #include "base/values.h" #include "base/win/scoped_com_initializer.h" #include "content/common/appcache/appcache_dispatcher.h" @@ -41,6 +42,7 @@ #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "content/public/common/renderer_preferences.h" +#include "content/public/common/url_constants.h" #include "content/public/renderer/content_renderer_client.h" #include "content/public/renderer/render_process_observer.h" #include "content/public/renderer/render_view_visitor.h" @@ -72,6 +74,7 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupMenu.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebRuntimeFeatures.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptController.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageEventDispatcher.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" @@ -100,6 +103,7 @@ using WebKit::WebFrame; using WebKit::WebNetworkStateNotifier; using WebKit::WebRuntimeFeatures; using WebKit::WebScriptController; +using WebKit::WebSecurityPolicy; using WebKit::WebString; using WebKit::WebStorageEventDispatcher; using WebKit::WebView; @@ -470,6 +474,8 @@ void RenderThreadImpl::EnsureWebKitInitialized() { WebScriptController::enableV8SingleThreadMode(); + RenderThreadImpl::RegisterSchemes(); + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); webkit_glue::EnableWebCoreLogChannels( @@ -586,6 +592,14 @@ void RenderThreadImpl::EnsureWebKitInitialized() { } } +void RenderThreadImpl::RegisterSchemes() { + // swappedout: pages should not be accessible, and should also + // be treated as empty documents that can commit synchronously. + WebString swappedout_scheme(ASCIIToUTF16(chrome::kSwappedOutScheme)); + WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(swappedout_scheme); + WebSecurityPolicy::registerURLSchemeAsEmptyDocument(swappedout_scheme); +} + void RenderThreadImpl::RecordUserMetrics(const std::string& action) { Send(new ViewHostMsg_UserMetricsRecordAction(action)); } diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index 4b24657..df6bf55 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h @@ -86,6 +86,10 @@ class CONTENT_EXPORT RenderThreadImpl : public content::RenderThread, // execution context (corresponding to WebFrame::frameForCurrentContext). static int32 RoutingIDForCurrentContext(); + // When initializing WebKit, ensure that any schemes needed for the content + // module are registered properly. Static to allow sharing with tests. + static void RegisterSchemes(); + // content::RenderThread implementation: virtual bool Send(IPC::Message* msg) OVERRIDE; virtual MessageLoop* GetMessageLoop() OVERRIDE; diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 18c5238..7cc0a21 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -2247,10 +2247,10 @@ WebNavigationPolicy RenderViewImpl::decidePolicyForNavigation( if (is_swapped_out_) { // It is possible for in-progress navigations to arrive here just after we // are swapped out, including iframes. We should cancel them. - if (request.url() != GURL("about:swappedout")) + if (request.url() != GURL(chrome::kSwappedOutURL)) return WebKit::WebNavigationPolicyIgnore; - // Allow about:swappedout to complete. + // Allow chrome::kSwappedOutURL to complete. return default_policy; } @@ -2781,13 +2781,13 @@ void RenderViewImpl::didCommitProvisionalLoad(WebFrame* frame, // We bump our Page ID to correspond with the new session history entry. page_id_ = next_page_id_++; - // Don't update history_page_ids_ (etc) for about:swappedout, since we - // don't want to forget the entry that was there, and since we will - // never come back to about:swappedout. Note that we have to call + // Don't update history_page_ids_ (etc) for chrome::kSwappedOutURL, since + // we don't want to forget the entry that was there, and since we will + // never come back to chrome::kSwappedOutURL. Note that we have to call // UpdateSessionHistory and update page_id_ even in this case, so that // the current entry gets a state update and so that we don't send a // state update to the wrong entry when we swap back in. - if (GetLoadingUrl(frame) != GURL("about:swappedout")) { + if (GetLoadingUrl(frame) != GURL(chrome::kSwappedOutURL)) { // Advance our offset in session history, applying the length limit. // There is now no forward history. history_list_offset_++; @@ -4378,11 +4378,12 @@ void RenderViewImpl::OnSwapOut(const ViewMsg_SwapOut_Params& params) { // 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 about:swappedout. If that happens to be to the page we had been + // to chrome::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. - WebURLRequest request(GURL("about:swappedout")); + GURL swappedOutURL(chrome::kSwappedOutURL); + WebURLRequest request(swappedOutURL); webview()->mainFrame()->loadRequest(request); } diff --git a/content/test/render_view_test.cc b/content/test/render_view_test.cc index db3d3f4..e52b157 100644 --- a/content/test/render_view_test.cc +++ b/content/test/render_view_test.cc @@ -8,6 +8,7 @@ #include "content/common/view_messages.h" #include "content/public/browser/native_web_keyboard_event.h" #include "content/public/common/renderer_preferences.h" +#include "content/renderer/render_thread_impl.h" #include "content/renderer/render_view_impl.h" #include "content/renderer/renderer_main_platform_delegate.h" #include "content/test/mock_render_process.h" @@ -146,6 +147,10 @@ void RenderViewTest::SetUp() { webkit_glue::SetJavaScriptFlags(" --expose-gc"); WebKit::initialize(&webkit_platform_support_); + // Ensure that we register any necessary schemes when initializing WebKit, + // since we are using a MockRenderThread. + RenderThreadImpl::RegisterSchemes(); + mock_process_.reset(new MockRenderProcess); // This needs to pass the mock render thread to the view. |