Index: chrome/browser/ui/browser_browsertest.cc |
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc |
index 6c5135c2448d8367ed850103e17e25d313cddf3d..973584801998d7d547b85e206fd1520d03bdc6f5 100644 |
--- a/chrome/browser/ui/browser_browsertest.cc |
+++ b/chrome/browser/ui/browser_browsertest.cc |
@@ -339,6 +339,165 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, MAYBE_SingleBeforeUnloadAfterWindowClose) { |
alert->native_dialog()->AcceptAppModalDialog(); |
} |
+// Test that scripts can fork a new renderer process for a cross-site popup, |
+// based on http://www.google.com/chrome/intl/en/webmasters-faq.html#newtab. |
+// The script must open a new tab, set its window.opener to null, and navigate |
+// it to a cross-site URL. It should also work for meta-refreshes. |
+// See http://crbug.com/93517. |
+IN_PROC_BROWSER_TEST_F(BrowserTest, NullOpenerRedirectForksProcess) { |
+ CommandLine::ForCurrentProcess()->AppendSwitch( |
+ switches::kDisablePopupBlocking); |
+ |
+ // Create http and https servers for a cross-site transition. |
+ ASSERT_TRUE(test_server()->Start()); |
+ net::TestServer https_test_server(net::TestServer::TYPE_HTTPS, |
+ FilePath(kDocRoot)); |
+ ASSERT_TRUE(https_test_server.Start()); |
+ GURL http_url(test_server()->GetURL("files/title1.html")); |
+ GURL https_url(https_test_server.GetURL("")); |
+ |
+ // Start with an http URL. |
+ ui_test_utils::NavigateToURL(browser(), http_url); |
+ TabContents* oldtab = browser()->GetSelectedTabContents(); |
+ RenderProcessHost* process = oldtab->render_view_host()->process(); |
+ |
+ // Now open a tab to a blank page, set its opener to null, and redirect it |
+ // cross-site. |
+ std::string redirect_popup = "w=window.open();"; |
+ redirect_popup += "w.opener=null;"; |
+ redirect_popup += "w.document.location=\""; |
+ redirect_popup += https_url.spec(); |
+ redirect_popup += "\";"; |
+ |
+ ui_test_utils::WindowedNotificationObserver popup_observer( |
+ content::NOTIFICATION_TAB_ADDED, |
+ NotificationService::AllSources()); |
+ ui_test_utils::WindowedNotificationObserver nav_observer( |
+ content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
+ NotificationService::AllSources()); |
+ oldtab->render_view_host()-> |
+ ExecuteJavascriptInWebFrame(string16(), ASCIIToUTF16(redirect_popup)); |
+ |
+ // Wait for popup window to appear and finish navigating. |
+ popup_observer.Wait(); |
+ ASSERT_EQ(2, browser()->tab_count()); |
+ TabContents* newtab = browser()->GetSelectedTabContents(); |
+ EXPECT_TRUE(newtab); |
+ EXPECT_NE(oldtab, newtab); |
+ nav_observer.Wait(); |
+ ASSERT_TRUE(newtab->controller().GetLastCommittedEntry()); |
+ EXPECT_EQ(https_url.spec(), |
+ newtab->controller().GetLastCommittedEntry()->url().spec()); |
+ |
+ // Popup window should not be in the opener's process. |
+ RenderProcessHost* popup_process = newtab->render_view_host()->process(); |
+ EXPECT_NE(process, popup_process); |
+ |
+ // Now open a tab to a blank page, set its opener to null, and use a |
+ // meta-refresh to navigate it instead. |
+ std::string refresh_popup = "w=window.open();"; |
+ refresh_popup += "w.opener=null;"; |
+ refresh_popup += "w.document.write("; |
+ refresh_popup += "'<META HTTP-EQUIV=\"refresh\" content=\"0; url="; |
+ refresh_popup += https_url.spec(); |
+ refresh_popup += "\">');w.document.close();"; |
+ |
+ ui_test_utils::WindowedNotificationObserver popup_observer2( |
+ content::NOTIFICATION_TAB_ADDED, |
+ NotificationService::AllSources()); |
+ ui_test_utils::WindowedNotificationObserver nav_observer2( |
+ content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
+ NotificationService::AllSources()); |
+ oldtab->render_view_host()-> |
+ ExecuteJavascriptInWebFrame(string16(), ASCIIToUTF16(refresh_popup)); |
+ |
+ // Wait for popup window to appear and finish navigating. |
+ popup_observer2.Wait(); |
+ ASSERT_EQ(3, browser()->tab_count()); |
+ TabContents* newtab2 = browser()->GetSelectedTabContents(); |
+ EXPECT_TRUE(newtab2); |
+ EXPECT_NE(oldtab, newtab2); |
+ nav_observer2.Wait(); |
+ ASSERT_TRUE(newtab2->controller().GetLastCommittedEntry()); |
+ EXPECT_EQ(https_url.spec(), |
+ newtab2->controller().GetLastCommittedEntry()->url().spec()); |
+ |
+ // This popup window should also not be in the opener's process. |
+ RenderProcessHost* popup_process2 = newtab2->render_view_host()->process(); |
+ EXPECT_NE(process, popup_process2); |
+} |
+ |
+// Tests that other popup navigations that do not follow the steps at |
+// http://www.google.com/chrome/intl/en/webmasters-faq.html#newtab will not |
+// fork a new renderer process. |
+IN_PROC_BROWSER_TEST_F(BrowserTest, OtherRedirectsDontForkProcess) { |
+ CommandLine::ForCurrentProcess()->AppendSwitch( |
+ switches::kDisablePopupBlocking); |
+ |
+ // Create http and https servers for a cross-site transition. |
+ ASSERT_TRUE(test_server()->Start()); |
+ net::TestServer https_test_server(net::TestServer::TYPE_HTTPS, |
+ FilePath(kDocRoot)); |
+ ASSERT_TRUE(https_test_server.Start()); |
+ GURL http_url(test_server()->GetURL("files/title1.html")); |
+ GURL https_url(https_test_server.GetURL("")); |
+ |
+ // Start with an http URL. |
+ ui_test_utils::NavigateToURL(browser(), http_url); |
+ TabContents* oldtab = browser()->GetSelectedTabContents(); |
+ RenderProcessHost* process = oldtab->render_view_host()->process(); |
+ |
+ // Now open a tab to a blank page, set its opener to null, and redirect it |
+ // cross-site. |
+ std::string dont_fork_popup = "w=window.open();"; |
+ dont_fork_popup += "w.document.location=\""; |
+ dont_fork_popup += https_url.spec(); |
+ dont_fork_popup += "\";"; |
+ |
+ ui_test_utils::WindowedNotificationObserver popup_observer( |
+ content::NOTIFICATION_TAB_ADDED, |
+ NotificationService::AllSources()); |
+ ui_test_utils::WindowedNotificationObserver nav_observer( |
+ content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
+ NotificationService::AllSources()); |
+ oldtab->render_view_host()-> |
+ ExecuteJavascriptInWebFrame(string16(), ASCIIToUTF16(dont_fork_popup)); |
+ |
+ // Wait for popup window to appear and finish navigating. |
+ popup_observer.Wait(); |
+ ASSERT_EQ(2, browser()->tab_count()); |
+ TabContents* newtab = browser()->GetSelectedTabContents(); |
+ EXPECT_TRUE(newtab); |
+ EXPECT_NE(oldtab, newtab); |
+ nav_observer.Wait(); |
+ ASSERT_TRUE(newtab->controller().GetLastCommittedEntry()); |
+ EXPECT_EQ(https_url.spec(), |
+ newtab->controller().GetLastCommittedEntry()->url().spec()); |
+ |
+ // Popup window should still be in the opener's process. |
+ RenderProcessHost* popup_process = newtab->render_view_host()->process(); |
+ EXPECT_EQ(process, popup_process); |
+ |
+ // Same thing if the current tab tries to navigate itself. |
+ std::string navigate_str = "document.location=\""; |
+ navigate_str += https_url.spec(); |
+ navigate_str += "\";"; |
+ |
+ ui_test_utils::WindowedNotificationObserver nav_observer2( |
+ content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
+ NotificationService::AllSources()); |
+ oldtab->render_view_host()-> |
+ ExecuteJavascriptInWebFrame(string16(), ASCIIToUTF16(navigate_str)); |
+ nav_observer2.Wait(); |
+ ASSERT_TRUE(oldtab->controller().GetLastCommittedEntry()); |
+ EXPECT_EQ(https_url.spec(), |
+ oldtab->controller().GetLastCommittedEntry()->url().spec()); |
+ |
+ // Original window should still be in the original process. |
+ RenderProcessHost* new_process = newtab->render_view_host()->process(); |
+ EXPECT_EQ(process, new_process); |
+} |
+ |
// Test that get_process_idle_time() returns reasonable values when compared |
// with time deltas measured locally. |
IN_PROC_BROWSER_TEST_F(BrowserTest, RenderIdleTime) { |