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/common/content_switches.h"
10 #include "content/public/test/browser_test_utils.h"
11 #include "content/public/test/content_browser_test.h"
12 #include "content/public/test/content_browser_test_utils.h"
13 #include "content/public/test/test_navigation_observer.h"
14 #include "content/shell/browser/shell.h"
15 #include "net/dns/mock_host_resolver.h"
22 // A dummy WebContentsDelegate which tracks whether CloseContents() has been
23 // called. It refuses the actual close but keeps track of whether the renderer
25 class CloseTrackingDelegate
: public WebContentsDelegate
{
27 CloseTrackingDelegate() : close_contents_called_(false) {}
29 bool close_contents_called() const { return close_contents_called_
; }
31 void CloseContents(WebContents
* source
) override
{
32 close_contents_called_
= true;
36 bool close_contents_called_
;
38 DISALLOW_COPY_AND_ASSIGN(CloseTrackingDelegate
);
43 class OpenedByDOMTest
: public ContentBrowserTest
{
45 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
46 // Use --site-per-process to force process swaps on cross-site navigations.
47 command_line
->AppendSwitch(switches::kSitePerProcess
);
50 bool AttemptCloseFromJavaScript(WebContents
* web_contents
) {
51 CloseTrackingDelegate close_tracking_delegate
;
52 WebContentsDelegate
* old_delegate
= web_contents
->GetDelegate();
53 web_contents
->SetDelegate(&close_tracking_delegate
);
55 const char kCloseWindowScript
[] =
58 // Report back after an event loop iteration; the close IPC isn't sent
60 "setTimeout(function() {"
61 "window.domAutomationController.send(0);"
64 CHECK(ExecuteScriptAndExtractInt(web_contents
, kCloseWindowScript
, &dummy
));
66 web_contents
->SetDelegate(old_delegate
);
67 return close_tracking_delegate
.close_contents_called();
70 Shell
* OpenWindowFromJavaScript(Shell
* shell
, const GURL
& url
) {
71 // Wait for the popup to be created and for it to have navigated.
72 ShellAddedObserver new_shell_observer
;
73 TestNavigationObserver
nav_observer(NULL
);
74 nav_observer
.StartWatchingNewWebContents();
76 shell
->web_contents(),
77 base::StringPrintf("window.open('%s')", url
.spec().c_str())));
79 return new_shell_observer
.GetShell();
83 // Tests that window.close() does not work on a normal window that has navigated
85 IN_PROC_BROWSER_TEST_F(OpenedByDOMTest
, NormalWindow
) {
86 ASSERT_TRUE(test_server()->Start());
88 // window.close is allowed if the window was opened by DOM OR the back/forward
89 // list has only one element. Navigate a bit so the second condition is false.
90 GURL url1
= test_server()->GetURL("files/site_isolation/blank.html?1");
91 GURL url2
= test_server()->GetURL("files/site_isolation/blank.html?2");
92 NavigateToURL(shell(), url1
);
93 NavigateToURL(shell(), url2
);
95 // This window was not opened by DOM, so close does not reach the browser
97 EXPECT_FALSE(AttemptCloseFromJavaScript(shell()->web_contents()));
100 // Tests that window.close() works in a popup window that has navigated a few
102 IN_PROC_BROWSER_TEST_F(OpenedByDOMTest
, Popup
) {
103 ASSERT_TRUE(test_server()->Start());
105 GURL url1
= test_server()->GetURL("files/site_isolation/blank.html?1");
106 GURL url2
= test_server()->GetURL("files/site_isolation/blank.html?2");
107 GURL url3
= test_server()->GetURL("files/site_isolation/blank.html?3");
108 NavigateToURL(shell(), url1
);
110 Shell
* popup
= OpenWindowFromJavaScript(shell(), url2
);
111 NavigateToURL(popup
, url3
);
112 EXPECT_TRUE(AttemptCloseFromJavaScript(popup
->web_contents()));
115 // Tests that window.close() works in a popup window that has navigated a few
116 // times and swapped processes.
117 // Crashes on all platforms. http://crbug.com/399709
118 IN_PROC_BROWSER_TEST_F(OpenedByDOMTest
, DISABLED_CrossProcessPopup
) {
119 host_resolver()->AddRule("*", "127.0.0.1");
120 ASSERT_TRUE(test_server()->Start());
122 GURL url1
= test_server()->GetURL("files/site_isolation/blank.html?1");
124 GURL url2
= test_server()->GetURL("files/site_isolation/blank.html?2");
125 GURL::Replacements replace_host
;
126 std::string
foo_com("foo.com");
127 replace_host
.SetHostStr(foo_com
);
128 url2
= url2
.ReplaceComponents(replace_host
);
130 GURL url3
= test_server()->GetURL("files/site_isolation/blank.html?3");
131 url3
= url3
.ReplaceComponents(replace_host
);
133 NavigateToURL(shell(), url1
);
135 Shell
* popup
= OpenWindowFromJavaScript(shell(), url2
);
136 NavigateToURL(popup
, url3
);
137 EXPECT_TRUE(AttemptCloseFromJavaScript(popup
->web_contents()));
140 } // namespace content