1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/strings/stringprintf.h"
7 #include "content/public/browser/web_contents.h"
8 #include "content/public/browser/web_contents_delegate.h"
9 #include "content/public/test/browser_test_utils.h"
10 #include "content/public/test/content_browser_test.h"
11 #include "content/public/test/content_browser_test_utils.h"
12 #include "content/public/test/test_navigation_observer.h"
13 #include "content/shell/browser/shell.h"
14 #include "net/dns/mock_host_resolver.h"
21 // A dummy WebContentsDelegate which tracks whether CloseContents() has been
22 // called. It refuses the actual close but keeps track of whether the renderer
24 class CloseTrackingDelegate
: public WebContentsDelegate
{
26 CloseTrackingDelegate() : close_contents_called_(false) {}
28 bool close_contents_called() const { return close_contents_called_
; }
30 void CloseContents(WebContents
* source
) override
{
31 close_contents_called_
= true;
35 bool close_contents_called_
;
37 DISALLOW_COPY_AND_ASSIGN(CloseTrackingDelegate
);
42 class OpenedByDOMTest
: public ContentBrowserTest
{
44 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
45 // Use --site-per-process to force process swaps on cross-site navigations.
46 IsolateAllSitesForTesting(command_line
);
49 bool AttemptCloseFromJavaScript(WebContents
* web_contents
) {
50 CloseTrackingDelegate close_tracking_delegate
;
51 WebContentsDelegate
* old_delegate
= web_contents
->GetDelegate();
52 web_contents
->SetDelegate(&close_tracking_delegate
);
54 const char kCloseWindowScript
[] =
57 // Report back after an event loop iteration; the close IPC isn't sent
59 "setTimeout(function() {"
60 "window.domAutomationController.send(0);"
63 CHECK(ExecuteScriptAndExtractInt(web_contents
, kCloseWindowScript
, &dummy
));
65 web_contents
->SetDelegate(old_delegate
);
66 return close_tracking_delegate
.close_contents_called();
69 Shell
* OpenWindowFromJavaScript(Shell
* shell
, const GURL
& url
) {
70 // Wait for the popup to be created and for it to have navigated.
71 ShellAddedObserver new_shell_observer
;
72 TestNavigationObserver
nav_observer(NULL
);
73 nav_observer
.StartWatchingNewWebContents();
75 shell
->web_contents(),
76 base::StringPrintf("window.open('%s')", url
.spec().c_str())));
78 return new_shell_observer
.GetShell();
82 // Tests that window.close() does not work on a normal window that has navigated
84 IN_PROC_BROWSER_TEST_F(OpenedByDOMTest
, NormalWindow
) {
85 ASSERT_TRUE(test_server()->Start());
87 // window.close is allowed if the window was opened by DOM OR the back/forward
88 // list has only one element. Navigate a bit so the second condition is false.
89 GURL url1
= test_server()->GetURL("files/site_isolation/blank.html?1");
90 GURL url2
= test_server()->GetURL("files/site_isolation/blank.html?2");
91 NavigateToURL(shell(), url1
);
92 NavigateToURL(shell(), url2
);
94 // This window was not opened by DOM, so close does not reach the browser
96 EXPECT_FALSE(AttemptCloseFromJavaScript(shell()->web_contents()));
99 // Tests that window.close() works in a popup window that has navigated a few
101 IN_PROC_BROWSER_TEST_F(OpenedByDOMTest
, Popup
) {
102 ASSERT_TRUE(test_server()->Start());
104 GURL url1
= test_server()->GetURL("files/site_isolation/blank.html?1");
105 GURL url2
= test_server()->GetURL("files/site_isolation/blank.html?2");
106 GURL url3
= test_server()->GetURL("files/site_isolation/blank.html?3");
107 NavigateToURL(shell(), url1
);
109 Shell
* popup
= OpenWindowFromJavaScript(shell(), url2
);
110 NavigateToURL(popup
, url3
);
111 EXPECT_TRUE(AttemptCloseFromJavaScript(popup
->web_contents()));
114 // Tests that window.close() works in a popup window that has navigated a few
115 // times and swapped processes.
116 IN_PROC_BROWSER_TEST_F(OpenedByDOMTest
, CrossProcessPopup
) {
117 host_resolver()->AddRule("*", "127.0.0.1");
118 ASSERT_TRUE(test_server()->Start());
120 GURL url1
= test_server()->GetURL("files/site_isolation/blank.html?1");
122 GURL url2
= test_server()->GetURL("files/site_isolation/blank.html?2");
123 GURL::Replacements replace_host
;
124 replace_host
.SetHostStr("foo.com");
125 url2
= url2
.ReplaceComponents(replace_host
);
127 GURL url3
= test_server()->GetURL("files/site_isolation/blank.html?3");
128 url3
= url3
.ReplaceComponents(replace_host
);
130 NavigateToURL(shell(), url1
);
132 Shell
* popup
= OpenWindowFromJavaScript(shell(), url2
);
133 NavigateToURL(popup
, url3
);
134 EXPECT_TRUE(AttemptCloseFromJavaScript(popup
->web_contents()));
137 } // namespace content