Index: content/browser/site_per_process_browsertest.cc |
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc |
index df3ee7c607886cd4dbb2fc7f39aea1e8b8103648..18e7d33039acf82f211e25d51be02709ffceada7 100644 |
--- a/content/browser/site_per_process_browsertest.cc |
+++ b/content/browser/site_per_process_browsertest.cc |
@@ -8339,4 +8339,149 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
transfer_manager.WaitForNavigationFinished(); |
} |
+// Test that when canceling a pending RenderFrameHost in the middle of a |
+// redirect, and then killing the corresponding RenderView's renderer process, |
+// the RenderViewHost isn't reused in an improper state later. Previously this |
+// led to a crash in CreateRenderView when recreating the RenderView due to a |
+// stale main frame routing ID. See https://crbug.com/627400. |
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
+ ReuseNonLiveRenderViewAfterCancelPending) { |
+ GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
+ GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html")); |
+ GURL c_url(embedded_test_server()->GetURL("c.com", "/title3.html")); |
+ |
+ EXPECT_TRUE(NavigateToURL(shell(), a_url)); |
+ |
+ // Open a popup and navigate it to b.com. |
+ Shell* popup = OpenPopup(shell(), a_url, "popup"); |
+ EXPECT_TRUE(NavigateToURL(popup, b_url)); |
+ |
+ // Open a second popup and navigate it to b.com, which redirects to c.com. |
+ // The navigation to b.com will create a pending RenderFrameHost, which will |
+ // be canceled during the redirect to c.com. Note that NavigateToURL will |
+ // return false because the committed URL won't match the requested URL due |
+ // to the redirect. |
+ Shell* popup2 = OpenPopup(shell(), a_url, "popup2"); |
+ TestNavigationObserver observer(popup2->web_contents()); |
+ GURL redirect_url(embedded_test_server()->GetURL( |
+ "b.com", "/server-redirect?" + c_url.spec())); |
+ EXPECT_FALSE(NavigateToURL(popup2, redirect_url)); |
+ EXPECT_EQ(c_url, observer.last_navigation_url()); |
+ EXPECT_TRUE(observer.last_navigation_succeeded()); |
+ |
+ // Kill the b.com process (which currently hosts a RenderFrameProxy that |
+ // replaced the pending RenderFrame in |popup2|, as well as the RenderFrame |
+ // for |popup|). |
+ RenderProcessHost* b_process = |
+ popup->web_contents()->GetMainFrame()->GetProcess(); |
+ RenderProcessHostWatcher crash_observer( |
+ b_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
+ b_process->Shutdown(0, false); |
+ crash_observer.Wait(); |
+ |
+ // Navigate the second popup to b.com. This used to crash when creating the |
+ // RenderView, because it reused the RenderViewHost created by the canceled |
+ // navigation to b.com, and that RenderViewHost had a stale main frame |
+ // routing ID and active state. |
+ EXPECT_TRUE(NavigateToURL(popup2, b_url)); |
+} |
+ |
+// Check that after a pending RFH is canceled and replaced with a proxy (which |
+// reuses the canceled RFH's RenderView), navigating to a main frame in the |
nasko
2016/10/13 21:26:28
nit: RenderViewHost, since you mention RFH's.
alexmos
2016/10/14 17:07:38
Done.
|
+// same site as the canceled RFH doesn't lead to a renderer crash. The steps |
+// here are similar to the test above, but don't involve crashing the renderer. |
nasko
2016/10/13 21:26:28
nit: replace "test above" with the explicit name o
alexmos
2016/10/14 17:07:38
Done.
|
+// See https://crbug.com/651980. |
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
+ RecreateMainFrameAfterCancelPending) { |
+ GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
+ GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html")); |
+ GURL c_url(embedded_test_server()->GetURL("c.com", "/title3.html")); |
+ |
+ EXPECT_TRUE(NavigateToURL(shell(), a_url)); |
+ |
+ // Open a popup and navigate it to b.com. |
+ Shell* popup = OpenPopup(shell(), a_url, "popup"); |
+ EXPECT_TRUE(NavigateToURL(popup, b_url)); |
+ |
+ // Open a second popup and navigate it to b.com, which redirects to c.com. |
+ // The navigation to b.com will create a pending RenderFrameHost, which will |
+ // be canceled during the redirect to c.com. Note that NavigateToURL will |
+ // return false because the committed URL won't match the requested URL due |
+ // to the redirect. |
+ Shell* popup2 = OpenPopup(shell(), a_url, "popup2"); |
+ TestNavigationObserver observer(popup2->web_contents()); |
+ GURL redirect_url(embedded_test_server()->GetURL( |
+ "b.com", "/server-redirect?" + c_url.spec())); |
+ EXPECT_FALSE(NavigateToURL(popup2, redirect_url)); |
+ EXPECT_EQ(c_url, observer.last_navigation_url()); |
+ EXPECT_TRUE(observer.last_navigation_succeeded()); |
+ |
+ // Navigate the second popup to b.com. This used to crash the b.com renderer |
+ // because it failed to delete the canceled RFH's RenderFrame, so this caused |
+ // it to try to create a frame widget which already existed. |
+ EXPECT_TRUE(NavigateToURL(popup2, b_url)); |
+} |
+ |
+// Check that when a pending RFH is canceled and a proxy needs to be created in |
+// its place, the proxy is properly initialized on the renderer side. See |
+// https://crbug.com/653746. |
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
+ CommunicateWithProxyAfterCancelPending) { |
+ GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
+ GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html")); |
+ GURL c_url(embedded_test_server()->GetURL("c.com", "/title3.html")); |
+ |
+ EXPECT_TRUE(NavigateToURL(shell(), a_url)); |
+ |
+ // Open a popup and navigate it to b.com. |
+ Shell* popup = OpenPopup(shell(), a_url, "popup"); |
+ EXPECT_TRUE(NavigateToURL(popup, b_url)); |
+ |
+ // Open a second popup and navigate it to b.com, which redirects to c.com. |
+ // The navigation to b.com will create a pending RenderFrameHost, which will |
+ // be canceled during the redirect to c.com. Note that NavigateToURL will |
+ // return false because the committed URL won't match the requested URL due |
+ // to the redirect. |
+ Shell* popup2 = OpenPopup(shell(), a_url, "popup2"); |
+ TestNavigationObserver observer(popup2->web_contents()); |
+ GURL redirect_url(embedded_test_server()->GetURL( |
+ "b.com", "/server-redirect?" + c_url.spec())); |
+ EXPECT_FALSE(NavigateToURL(popup2, redirect_url)); |
+ EXPECT_EQ(c_url, observer.last_navigation_url()); |
+ EXPECT_TRUE(observer.last_navigation_succeeded()); |
+ |
+ // Because b.com has other active frames (namely, the frame in |popup|), |
+ // there should be a proxy created for the canceled RFH, and it should be |
+ // live. |
+ SiteInstance* b_instance = popup->web_contents()->GetSiteInstance(); |
+ FrameTreeNode* popup2_root = |
+ static_cast<WebContentsImpl*>(popup2->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ RenderFrameProxyHost* proxy = |
+ popup2_root->render_manager()->GetRenderFrameProxyHost(b_instance); |
+ EXPECT_TRUE(proxy); |
+ EXPECT_TRUE(proxy->is_render_frame_proxy_live()); |
+ |
+ // Add a postMessage listener in |popup2| (currently at a c.com URL). |
+ EXPECT_TRUE( |
+ ExecuteScript(popup2, |
+ "window.addEventListener('message', function(event) {\n" |
+ " document.title=event.data;\n" |
+ "});")); |
+ |
+ // Check that a postMessage can be sent via |proxy| above. This needs to be |
+ // done from the b.com process. |popup| is currently in b.com, but it can't |
+ // reach the window reference for |popup2| due to a security restriction in |
+ // Blink. So, navigate the main tab to b.com and then send a postMessage to |
+ // |popup2|. This is allowed since the main tab is |popup2|'s opener. |
+ EXPECT_TRUE(NavigateToURL(shell(), b_url)); |
+ |
+ base::string16 expected_title(base::UTF8ToUTF16("foo")); |
+ TitleWatcher title_watcher(popup2->web_contents(), expected_title); |
+ EXPECT_TRUE(ExecuteScript( |
+ shell(), "window.open('','popup2').postMessage('foo', '*');")); |
+ EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
+} |
+ |
} // namespace content |