blob: 0ad8e7aa77d4be03da637ff24eb184aebf68bc01 [file] [log] [blame]
// Copyright 2020 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 "build/build_config.h"
#include "components/blocked_content/popup_blocker_tab_helper.h"
#include "ui/base/page_transition_types.h"
#include "ui/base/window_open_disposition.h"
#include "weblayer/browser/browser_impl.h"
#include "weblayer/browser/host_content_settings_map_factory.h"
#include "weblayer/browser/profile_impl.h"
#include "weblayer/browser/tab_impl.h"
#include "weblayer/public/browser.h"
#include "weblayer/public/browser_observer.h"
#include "weblayer/public/navigation_controller.h"
#include "weblayer/public/new_tab_delegate.h"
#include "weblayer/shell/browser/shell.h"
#include "weblayer/test/test_navigation_observer.h"
#include "weblayer/test/weblayer_browser_test.h"
#include "weblayer/test/weblayer_browser_test_utils.h"
namespace weblayer {
class PopupBlockerBrowserTest : public WebLayerBrowserTest,
public NewTabDelegate,
public BrowserObserver {
public:
// WebLayerBrowserTest:
void SetUpOnMainThread() override {
ASSERT_TRUE(embedded_test_server()->Start());
original_tab_ = shell()->tab();
#if !defined(OS_ANDROID)
// Android does this in Java.
original_tab_->SetNewTabDelegate(this);
#endif
shell()->browser()->AddObserver(this);
NavigateAndWaitForCompletion(embedded_test_server()->GetURL("/echo"),
original_tab_);
}
void TearDownOnMainThread() override {
shell()->browser()->RemoveObserver(this);
}
// NewTabDelegate:
void OnNewTab(Tab* new_tab, NewTabType type) override {}
// BrowserObserver:
void OnTabAdded(Tab* tab) override {
new_tab_ = tab;
if (new_tab_run_loop_)
new_tab_run_loop_->Quit();
}
void OnTabRemoved(Tab* tab, bool active_tab_changed) override {
ASSERT_EQ(tab, new_tab_);
new_tab_ = nullptr;
if (close_tab_run_loop_)
close_tab_run_loop_->Quit();
}
size_t GetBlockedPopupCount() {
return blocked_content::PopupBlockerTabHelper::FromWebContents(
GetWebContents(original_tab_))
->GetBlockedPopupsCount();
}
content::WebContents* GetWebContents(Tab* tab) {
return static_cast<TabImpl*>(tab)->web_contents();
}
Tab* WaitForNewTab() {
if (!new_tab_) {
new_tab_run_loop_ = std::make_unique<base::RunLoop>();
new_tab_run_loop_->Run();
new_tab_run_loop_ = nullptr;
}
return new_tab_;
}
void WaitForCloseTab() {
if (new_tab_) {
close_tab_run_loop_ = std::make_unique<base::RunLoop>();
close_tab_run_loop_->Run();
close_tab_run_loop_ = nullptr;
}
ASSERT_FALSE(new_tab_);
}
void ExpectTabURL(Tab* tab, const GURL& url) {
if (tab->GetNavigationController()->GetNavigationListSize() > 0) {
EXPECT_EQ(tab->GetNavigationController()->GetNavigationEntryDisplayURL(0),
url);
} else {
TestNavigationObserver(
url, TestNavigationObserver::NavigationEvent::kCompletion, tab)
.Wait();
}
}
Tab* ShowPopup(const GURL& url) {
auto* popup_blocker =
blocked_content::PopupBlockerTabHelper::FromWebContents(
GetWebContents(original_tab_));
popup_blocker->ShowBlockedPopup(
popup_blocker->GetBlockedPopupRequests().begin()->first,
WindowOpenDisposition::NEW_FOREGROUND_TAB);
Tab* new_tab = WaitForNewTab();
ExpectTabURL(new_tab, url);
EXPECT_EQ(GetBlockedPopupCount(), 0u);
return new_tab;
}
Tab* original_tab() { return original_tab_; }
private:
std::unique_ptr<base::RunLoop> new_tab_run_loop_;
std::unique_ptr<base::RunLoop> close_tab_run_loop_;
Tab* original_tab_ = nullptr;
Tab* new_tab_ = nullptr;
};
IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, BlocksPopup) {
ExecuteScript(original_tab(), "window.open('https://google.com')", true);
EXPECT_EQ(GetBlockedPopupCount(), 1u);
}
IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, BlocksMultiplePopups) {
ExecuteScript(original_tab(), "window.open('https://google.com')", true);
ExecuteScript(original_tab(), "window.open('https://google.com')", true);
EXPECT_EQ(GetBlockedPopupCount(), 2u);
}
IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, DoesNotBlockUserGesture) {
GURL popup_url = embedded_test_server()->GetURL("/echo?popup");
ExecuteScriptWithUserGesture(
original_tab(),
base::StringPrintf("window.open('%s')", popup_url.spec().c_str()));
Tab* new_tab = WaitForNewTab();
ExpectTabURL(new_tab, popup_url);
EXPECT_EQ(GetBlockedPopupCount(), 0u);
}
IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, OpensBlockedPopup) {
GURL popup_url = embedded_test_server()->GetURL("/echo?popup");
ExecuteScript(
original_tab(),
base::StringPrintf("window.open('%s')", popup_url.spec().c_str()), true);
EXPECT_EQ(GetBlockedPopupCount(), 1u);
Tab* new_tab = ShowPopup(popup_url);
// Blocked popups should no longer have the opener set to match Chrome
// behavior.
EXPECT_FALSE(GetWebContents(new_tab)->HasOpener());
// Make sure we can cleanly close the popup, and there's no crash.
ExecuteScriptWithUserGesture(new_tab, "window.close()");
WaitForCloseTab();
}
IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
AllowsPopupThroughContentSettingException) {
GURL popup_url = embedded_test_server()->GetURL("/echo?popup");
HostContentSettingsMapFactory::GetForBrowserContext(
GetWebContents(original_tab())->GetBrowserContext())
->SetContentSettingDefaultScope(popup_url, GURL(),
ContentSettingsType::POPUPS,
CONTENT_SETTING_ALLOW);
ExecuteScript(
original_tab(),
base::StringPrintf("window.open('%s')", popup_url.spec().c_str()), true);
Tab* new_tab = WaitForNewTab();
ExpectTabURL(new_tab, popup_url);
EXPECT_EQ(GetBlockedPopupCount(), 0u);
}
IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
AllowsPopupThroughContentSettingDefaultValue) {
GURL popup_url = embedded_test_server()->GetURL("/echo?popup");
HostContentSettingsMapFactory::GetForBrowserContext(
GetWebContents(original_tab())->GetBrowserContext())
->SetDefaultContentSetting(ContentSettingsType::POPUPS,
CONTENT_SETTING_ALLOW);
ExecuteScript(
original_tab(),
base::StringPrintf("window.open('%s')", popup_url.spec().c_str()), true);
Tab* new_tab = WaitForNewTab();
ExpectTabURL(new_tab, popup_url);
EXPECT_EQ(GetBlockedPopupCount(), 0u);
}
IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
BlockPopupThroughContentSettingException) {
GURL popup_url = embedded_test_server()->GetURL("/echo?popup");
HostContentSettingsMapFactory::GetForBrowserContext(
GetWebContents(original_tab())->GetBrowserContext())
->SetDefaultContentSetting(ContentSettingsType::POPUPS,
CONTENT_SETTING_ALLOW);
HostContentSettingsMapFactory::GetForBrowserContext(
GetWebContents(original_tab())->GetBrowserContext())
->SetContentSettingDefaultScope(popup_url, GURL(),
ContentSettingsType::POPUPS,
CONTENT_SETTING_BLOCK);
ExecuteScript(
original_tab(),
base::StringPrintf("window.open('%s')", popup_url.spec().c_str()), true);
EXPECT_EQ(GetBlockedPopupCount(), 1u);
}
IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
BlocksAndOpensPopupFromOpenURL) {
GURL popup_url = embedded_test_server()->GetURL("/echo?popup");
content::OpenURLParams params(popup_url, content::Referrer(),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_LINK, true);
params.initiator_origin = url::Origin::Create(popup_url);
GetWebContents(original_tab())->OpenURL(params);
EXPECT_EQ(GetBlockedPopupCount(), 1u);
ShowPopup(popup_url);
}
IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
DoesNotOpenPopupWithoutNewTabDelegate) {
NewTabDelegate* old_delegate =
static_cast<TabImpl*>(original_tab())->new_tab_delegate();
original_tab()->SetNewTabDelegate(nullptr);
GURL popup_url = embedded_test_server()->GetURL("/echo?popup");
ExecuteScriptWithUserGesture(
original_tab(),
base::StringPrintf("window.open('%s')", popup_url.spec().c_str()));
EXPECT_EQ(GetBlockedPopupCount(), 0u);
// Navigate the original tab, then make sure we still only have a single tab.
NavigateAndWaitForCompletion(embedded_test_server()->GetURL("/echo"),
original_tab());
EXPECT_EQ(shell()->browser()->GetTabs().size(), 1u);
// Restore the old delegate to make sure it is cleaned up on Android.
original_tab()->SetNewTabDelegate(old_delegate);
}
IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
DoesNotOpenBlockedPopupWithoutNewTabDelegate) {
NewTabDelegate* old_delegate =
static_cast<TabImpl*>(original_tab())->new_tab_delegate();
original_tab()->SetNewTabDelegate(nullptr);
GURL popup_url = embedded_test_server()->GetURL("/echo?popup");
ExecuteScript(
original_tab(),
base::StringPrintf("window.open('%s')", popup_url.spec().c_str()), true);
EXPECT_EQ(GetBlockedPopupCount(), 0u);
// Navigate the original tab, then make sure we still only have a single tab.
NavigateAndWaitForCompletion(embedded_test_server()->GetURL("/echo"),
original_tab());
EXPECT_EQ(shell()->browser()->GetTabs().size(), 1u);
// Restore the old delegate to make sure it is cleaned up on Android.
original_tab()->SetNewTabDelegate(old_delegate);
}
} // namespace weblayer