summaryrefslogtreecommitdiffstats
path: root/content/browser/web_contents/opened_by_dom_browsertest.cc
blob: 0a89f7189bd49cab257b09ae3ec21a9e3ece644e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/shell/browser/shell.h"
#include "net/dns/mock_host_resolver.h"
#include "url/gurl.h"

namespace content {

namespace {

// A dummy WebContentsDelegate which tracks whether CloseContents() has been
// called. It refuses the actual close but keeps track of whether the renderer
// requested it.
class CloseTrackingDelegate : public WebContentsDelegate {
 public:
  CloseTrackingDelegate() : close_contents_called_(false) {}

  bool close_contents_called() const { return close_contents_called_; }

  void CloseContents(WebContents* source) override {
    close_contents_called_ = true;
  }

 private:
  bool close_contents_called_;

  DISALLOW_COPY_AND_ASSIGN(CloseTrackingDelegate);
};

}  // namespace

class OpenedByDOMTest : public ContentBrowserTest {
 protected:
  void SetUpCommandLine(CommandLine* command_line) override {
    // Use --site-per-process to force process swaps on cross-site navigations.
    command_line->AppendSwitch(switches::kSitePerProcess);
  }

  bool AttemptCloseFromJavaScript(WebContents* web_contents) {
    CloseTrackingDelegate close_tracking_delegate;
    WebContentsDelegate* old_delegate = web_contents->GetDelegate();
    web_contents->SetDelegate(&close_tracking_delegate);

    const char kCloseWindowScript[] =
        // Close the window.
        "window.close();"
        // Report back after an event loop iteration; the close IPC isn't sent
        // immediately.
        "setTimeout(function() {"
        "window.domAutomationController.send(0);"
        "});";
    int dummy;
    CHECK(ExecuteScriptAndExtractInt(web_contents, kCloseWindowScript, &dummy));

    web_contents->SetDelegate(old_delegate);
    return close_tracking_delegate.close_contents_called();
  }

  Shell* OpenWindowFromJavaScript(Shell* shell, const GURL& url) {
    // Wait for the popup to be created and for it to have navigated.
    ShellAddedObserver new_shell_observer;
    TestNavigationObserver nav_observer(NULL);
    nav_observer.StartWatchingNewWebContents();
    CHECK(ExecuteScript(
        shell->web_contents(),
        base::StringPrintf("window.open('%s')", url.spec().c_str())));
    nav_observer.Wait();
    return new_shell_observer.GetShell();
  }
};

// Tests that window.close() does not work on a normal window that has navigated
// a few times.
IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, NormalWindow) {
  ASSERT_TRUE(test_server()->Start());

  // window.close is allowed if the window was opened by DOM OR the back/forward
  // list has only one element. Navigate a bit so the second condition is false.
  GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1");
  GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
  NavigateToURL(shell(), url1);
  NavigateToURL(shell(), url2);

  // This window was not opened by DOM, so close does not reach the browser
  // process.
  EXPECT_FALSE(AttemptCloseFromJavaScript(shell()->web_contents()));
}

// Tests that window.close() works in a popup window that has navigated a few
// times.
IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, Popup) {
  ASSERT_TRUE(test_server()->Start());

  GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1");
  GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
  GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3");
  NavigateToURL(shell(), url1);

  Shell* popup = OpenWindowFromJavaScript(shell(), url2);
  NavigateToURL(popup, url3);
  EXPECT_TRUE(AttemptCloseFromJavaScript(popup->web_contents()));
}

// Tests that window.close() works in a popup window that has navigated a few
// times and swapped processes.
// Crashes on all platforms. http://crbug.com/399709
IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, DISABLED_CrossProcessPopup) {
  host_resolver()->AddRule("*", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  GURL url1 = test_server()->GetURL("files/site_isolation/blank.html?1");

  GURL url2 = test_server()->GetURL("files/site_isolation/blank.html?2");
  GURL::Replacements replace_host;
  std::string foo_com("foo.com");
  replace_host.SetHostStr(foo_com);
  url2 = url2.ReplaceComponents(replace_host);

  GURL url3 = test_server()->GetURL("files/site_isolation/blank.html?3");
  url3 = url3.ReplaceComponents(replace_host);

  NavigateToURL(shell(), url1);

  Shell* popup = OpenWindowFromJavaScript(shell(), url2);
  NavigateToURL(popup, url3);
  EXPECT_TRUE(AttemptCloseFromJavaScript(popup->web_contents()));
}

}  // namespace content