blob: 9ef6e2ba389c7707d1286c65f80837d288ccf0b8 [file] [log] [blame]
// 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/macros.h"
#include "base/strings/stringprintf.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.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(base::CommandLine* command_line) override {
// Use --site-per-process to force process swaps on cross-site navigations.
IsolateAllSitesForTesting(command_line);
}
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
}
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(nullptr);
nav_observer.StartWatchingNewWebContents();
CHECK(ExecuteScript(
shell, 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(embedded_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 = embedded_test_server()->GetURL("/site_isolation/blank.html?1");
GURL url2 = embedded_test_server()->GetURL("/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(embedded_test_server()->Start());
GURL url1 = embedded_test_server()->GetURL("/site_isolation/blank.html?1");
GURL url2 = embedded_test_server()->GetURL("/site_isolation/blank.html?2");
GURL url3 = embedded_test_server()->GetURL("/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.
IN_PROC_BROWSER_TEST_F(OpenedByDOMTest, CrossProcessPopup) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL url1 = embedded_test_server()->GetURL("/site_isolation/blank.html?1");
GURL url2 = embedded_test_server()->GetURL("/site_isolation/blank.html?2");
GURL::Replacements replace_host;
replace_host.SetHostStr("foo.com");
url2 = url2.ReplaceComponents(replace_host);
GURL url3 = embedded_test_server()->GetURL("/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