Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1907)

Unified Diff: content/browser/site_per_process_browsertest.cc

Issue 1986643002: Track pending WebContents and widgets by (process_id, routing_id) pair. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@fullscreen-flash
Patch Set: Disable popup menu test for Mac/Android Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 bd1aceddff64296fc75fedd50454b2b78ae2beef..bae0956c29917fbee29d76ede216ca6f01017ee6 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -6932,4 +6932,190 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DetachInUnloadHandler) {
DepictFrameTree(root));
}
+// Helper filter class to wait for a ShowView or ShowWidget message, record the
+// routing ID from the message, and then drop the message.
+class PendingWidgetMessageFilter : public BrowserMessageFilter {
+ public:
+ PendingWidgetMessageFilter()
+ : BrowserMessageFilter(ViewMsgStart),
+ routing_id_(MSG_ROUTING_NONE),
+ message_loop_runner_(new MessageLoopRunner) {}
+
+ bool OnMessageReceived(const IPC::Message& message) override {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(PendingWidgetMessageFilter, message)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ShowView, OnShowView)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+ }
+
+ void Wait() {
+ message_loop_runner_->Run();
+ }
+
+ int routing_id() { return routing_id_; }
+
+ private:
+ ~PendingWidgetMessageFilter() override {}
+
+ void OnShowView(int routing_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_rect,
+ bool user_gesture) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&PendingWidgetMessageFilter::OnReceivedRoutingIDOnUI, this,
+ routing_id));
+ }
+
+ void OnShowWidget(int routing_id, const gfx::Rect& initial_rect) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&PendingWidgetMessageFilter::OnReceivedRoutingIDOnUI, this,
+ routing_id));
+ }
+
+ void OnReceivedRoutingIDOnUI(int routing_id) {
+ routing_id_ = routing_id;
+ message_loop_runner_->Quit();
+ }
+
+ int routing_id_;
+ scoped_refptr<MessageLoopRunner> message_loop_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(PendingWidgetMessageFilter);
+};
+
+// Test for https://crbug.com/612276. Simultaneously open two new windows from
+// two subframes in different processes, where each subframe process's next
+// routing ID is the same. Make sure that both windows are created properly.
+//
+// Each new window requires two IPCs to first create it (handled by
+// CreateNewWindow) and then show it (ShowCreatedWindow). In the bug, both
+// CreateNewWindow calls arrived before the ShowCreatedWindow calls, resulting
+// in the two pending windows colliding in the pending WebContents map, which
+// used to be keyed only by routing_id.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ TwoSubframesCreatePopupsSimultaneously) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b,c)"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+ FrameTreeNode* child1 = root->child_at(0);
+ FrameTreeNode* child2 = root->child_at(1);
+ RenderProcessHost* process1 = child1->current_frame_host()->GetProcess();
+ RenderProcessHost* process2 = child2->current_frame_host()->GetProcess();
+
+ // Call window.open simultaneously in both subframes to create two popups.
+ // Wait for and then drop both ViewHostMsg_ShowView messages. This will
+ // ensure that both CreateNewWindow calls happen before either
+ // ShowCreatedWindow call.
+ scoped_refptr<PendingWidgetMessageFilter> filter1 =
+ new PendingWidgetMessageFilter();
+ process1->AddFilter(filter1.get());
+ EXPECT_TRUE(ExecuteScript(child1->current_frame_host(), "window.open();"));
+ filter1->Wait();
+
+ scoped_refptr<PendingWidgetMessageFilter> filter2 =
+ new PendingWidgetMessageFilter();
+ process2->AddFilter(filter2.get());
+ EXPECT_TRUE(ExecuteScript(child2->current_frame_host(), "window.open();"));
+ filter2->Wait();
+
+ // At this point, we should have two pending WebContents.
+ EXPECT_TRUE(
+ ContainsKey(web_contents()->pending_contents_,
+ std::make_pair(process1->GetID(), filter1->routing_id())));
+ EXPECT_TRUE(
+ ContainsKey(web_contents()->pending_contents_,
+ std::make_pair(process2->GetID(), filter2->routing_id())));
+
+ // Both subframes were set up in the same way, so the next routing ID for the
+ // new popup windows should match up (this led to the collision in the
+ // pending contents map in the original bug).
+ EXPECT_EQ(filter1->routing_id(), filter2->routing_id());
+
+ // Now, simulate that both ShowView messages arrive by showing both of the
+ // pending WebContents.
+ web_contents()->ShowCreatedWindow(process1->GetID(), filter1->routing_id(),
+ NEW_FOREGROUND_TAB, gfx::Rect(), true);
+ web_contents()->ShowCreatedWindow(process2->GetID(), filter2->routing_id(),
+ NEW_FOREGROUND_TAB, gfx::Rect(), true);
+
+ // Verify that both shells were properly created.
+ EXPECT_EQ(3u, Shell::windows().size());
+}
+
+// Test for https://crbug.com/612276. Similar to
+// TwoSubframesOpenWindowsSimultaneously, but use popup menu widgets instead of
+// windows.
+//
+// The plumbing that this test is verifying is not utilized on Mac/Android,
+// where popup menus don't create a popup RenderWidget, but rather they trigger
+// a FrameHostMsg_ShowPopup to ask the browser to build and display the actual
+// popup using native controls.
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+ TwoSubframesCreatePopupMenuWidgetsSimultaneously) {
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(b,c)"));
+ EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+ FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+ FrameTreeNode* child1 = root->child_at(0);
+ FrameTreeNode* child2 = root->child_at(1);
+ RenderProcessHost* process1 = child1->current_frame_host()->GetProcess();
+ RenderProcessHost* process2 = child2->current_frame_host()->GetProcess();
+
+ // Navigate both subframes to a page with a <select> element.
+ NavigateFrameToURL(child1, embedded_test_server()->GetURL(
+ "b.com", "/site_isolation/page-with-select.html"));
+ NavigateFrameToURL(child2, embedded_test_server()->GetURL(
+ "c.com", "/site_isolation/page-with-select.html"));
+
+ // Open both <select> menus. This creates a popup widget in both processes.
+ // Wait for and then drop the ViewHostMsg_ShowWidget messages, so that both
+ // widgets are left in pending-but-not-shown state.
+ scoped_refptr<PendingWidgetMessageFilter> filter1 =
+ new PendingWidgetMessageFilter();
+ process1->AddFilter(filter1.get());
+ EXPECT_TRUE(ExecuteScript(child1->current_frame_host(), "openSelectMenu();"));
+ filter1->Wait();
+
+ scoped_refptr<PendingWidgetMessageFilter> filter2 =
+ new PendingWidgetMessageFilter();
+ process2->AddFilter(filter2.get());
+ EXPECT_TRUE(ExecuteScript(child2->current_frame_host(), "openSelectMenu();"));
+ filter2->Wait();
+
+ // At this point, we should have two pending widgets.
+ EXPECT_TRUE(
+ ContainsKey(web_contents()->pending_widget_views_,
+ std::make_pair(process1->GetID(), filter1->routing_id())));
+ EXPECT_TRUE(
+ ContainsKey(web_contents()->pending_widget_views_,
+ std::make_pair(process2->GetID(), filter2->routing_id())));
+
+ // Both subframes were set up in the same way, so the next routing ID for the
+ // new popup widgets should match up (this led to the collision in the
+ // pending widgets map in the original bug).
+ EXPECT_EQ(filter1->routing_id(), filter2->routing_id());
+
+ // Now simulate both widgets being shown.
+ web_contents()->ShowCreatedWidget(process1->GetID(), filter1->routing_id(),
+ false, gfx::Rect());
+ web_contents()->ShowCreatedWidget(process2->GetID(), filter2->routing_id(),
+ false, gfx::Rect());
+ EXPECT_FALSE(
+ ContainsKey(web_contents()->pending_widget_views_,
+ std::make_pair(process1->GetID(), filter1->routing_id())));
+ EXPECT_FALSE(
+ ContainsKey(web_contents()->pending_widget_views_,
+ std::make_pair(process2->GetID(), filter2->routing_id())));
+}
+#endif
+
} // namespace content
« no previous file with comments | « content/browser/renderer_host/render_view_host_impl.cc ('k') | content/browser/web_contents/web_contents_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698