opened_by_dom_browsertest.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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.
4
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"
16#include "url/gurl.h"
17
18namespace content {
19
20namespace {
21
22// A dummy WebContentsDelegate which tracks whether CloseContents() has been
23// called. It refuses the actual close but keeps track of whether the renderer
24// requested it.
25class CloseTrackingDelegate : public WebContentsDelegate {
26 public:
27  CloseTrackingDelegate() : close_contents_called_(false) {}
28
29  bool close_contents_called() const { return close_contents_called_; }
30
31  virtual void CloseContents(WebContents* source) OVERRIDE {
32    close_contents_called_ = true;
33  }
34
35 private:
36  bool close_contents_called_;
37
38  DISALLOW_COPY_AND_ASSIGN(CloseTrackingDelegate);
39};
40
41}  // namespace
42
43class OpenedByDOMTest : public ContentBrowserTest {
44 protected:
45  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
46    // Use --site-per-process to force process swaps on cross-site navigations.
47    command_line->AppendSwitch(switches::kSitePerProcess);
48  }
49
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);
54
55    const char kCloseWindowScript[] =
56        // Close the window.
57        "window.close();"
58        // Report back after an event loop iteration; the close IPC isn't sent
59        // immediately.
60        "setTimeout(function() {"
61        "window.domAutomationController.send(0);"
62        "});";
63    int dummy;
64    CHECK(ExecuteScriptAndExtractInt(web_contents, kCloseWindowScript, &dummy));
65
66    web_contents->SetDelegate(old_delegate);
67    return close_tracking_delegate.close_contents_called();
68  }
69
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();
75    CHECK(ExecuteScript(
76        shell->web_contents(),
77        base::StringPrintf("window.open('%s')", url.spec().c_str())));
78    nav_observer.Wait();
79    return new_shell_observer.GetShell();
80  }
81};
82
83// Tests that window.close() does not work on a normal window that has navigated
84// a few times.
85IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, NormalWindow) {
86  ASSERT_TRUE(test_server()->Start());
87
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);
94
95  // This window was not opened by DOM, so close does not reach the browser
96  // process.
97  EXPECT_FALSE(AttemptCloseFromJavaScript(shell()->web_contents()));
98}
99
100// Tests that window.close() works in a popup window that has navigated a few
101// times.
102IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, Popup) {
103  ASSERT_TRUE(test_server()->Start());
104
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);
109
110  Shell* popup = OpenWindowFromJavaScript(shell(), url2);
111  NavigateToURL(popup, url3);
112  EXPECT_TRUE(AttemptCloseFromJavaScript(popup->web_contents()));
113}
114
115// Tests that window.close() works in a popup window that has navigated a few
116// times and swapped processes.
117IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, CrossProcessPopup) {
118  host_resolver()->AddRule("*", "127.0.0.1");
119  ASSERT_TRUE(test_server()->Start());
120
121  GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1");
122
123  GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
124  GURL::Replacements replace_host;
125  std::string foo_com("foo.com");
126  replace_host.SetHostStr(foo_com);
127  url2 = url2.ReplaceComponents(replace_host);
128
129  GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3");
130  url3 = url3.ReplaceComponents(replace_host);
131
132  NavigateToURL(shell(), url1);
133
134  Shell* popup = OpenWindowFromJavaScript(shell(), url2);
135  NavigateToURL(popup, url3);
136  EXPECT_TRUE(AttemptCloseFromJavaScript(popup->web_contents()));
137}
138
139}  // namespace content
140