blob: 8b12c7dd441f31b1247ae0a2b273b7068ac19e80 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/blocked_content/popup_blocker.h"
#include <string>
#include "base/check.h"
#include "base/command_line.h"
#include "components/blocked_content/popup_blocker_tab_helper.h"
#include "components/blocked_content/popup_navigation_delegate.h"
#include "components/blocked_content/safe_browsing_triggered_popup_blocker.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/embedder_support/switches.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/frame/frame.mojom-shared.h"
namespace blocked_content {
namespace {
content::Page& GetSourcePageForPopup(
const content::OpenURLParams* open_url_params,
content::WebContents* web_contents) {
if (open_url_params) {
content::RenderFrameHost* source = content::RenderFrameHost::FromID(
open_url_params->source_render_process_id,
open_url_params->source_render_frame_id);
if (source)
return source->GetPage();
}
// When there's no source RenderFrameHost, attribute the popup to the primary
// page.
return web_contents->GetPrimaryPage();
}
// If the popup should be blocked, returns the reason why it was blocked.
// Otherwise returns kNotBlocked.
PopupBlockType ShouldBlockPopup(content::WebContents* web_contents,
const GURL* opener_url,
bool user_gesture,
const content::OpenURLParams* open_url_params,
HostContentSettingsMap* settings_map) {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
embedder_support::kDisablePopupBlocking)) {
return PopupBlockType::kNotBlocked;
}
// If an explicit opener is not given, use the current committed load in this
// web contents. This is because A page can't spawn popups (or do anything
// else, either) until its load commits, so when we reach here, the popup was
// spawned by the NavigationController's last committed entry, not the active
// entry. For example, if a page opens a popup in an onunload() handler, then
// the active entry is the page to be loaded as we navigate away from the
// unloading page.
const GURL& url =
opener_url ? *opener_url : web_contents->GetLastCommittedURL();
ContentSetting cs;
if (url.is_valid()) {
cs = settings_map->GetContentSetting(url, url, ContentSettingsType::POPUPS);
} else {
cs = settings_map->GetDefaultContentSetting(ContentSettingsType::POPUPS,
nullptr);
}
if (cs == CONTENT_SETTING_ALLOW)
return PopupBlockType::kNotBlocked;
if (!user_gesture)
return PopupBlockType::kNoGesture;
// This is trusted user action (e.g. shift-click), so make sure it is not
// blocked.
if (open_url_params &&
open_url_params->triggering_event_info !=
blink::mojom::TriggeringEventInfo::kFromUntrustedEvent) {
return PopupBlockType::kNotBlocked;
}
auto* safe_browsing_blocker =
SafeBrowsingTriggeredPopupBlocker::FromWebContents(web_contents);
if (safe_browsing_blocker &&
safe_browsing_blocker->ShouldApplyAbusivePopupBlocker(
GetSourcePageForPopup(open_url_params, web_contents))) {
return PopupBlockType::kAbusive;
}
return PopupBlockType::kNotBlocked;
}
} // namespace
bool ConsiderForPopupBlocking(WindowOpenDisposition disposition) {
return disposition == WindowOpenDisposition::NEW_POPUP ||
disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB ||
disposition == WindowOpenDisposition::NEW_WINDOW;
}
std::unique_ptr<PopupNavigationDelegate> MaybeBlockPopup(
content::WebContents* web_contents,
const GURL* opener_url,
std::unique_ptr<PopupNavigationDelegate> delegate,
const content::OpenURLParams* open_url_params,
const blink::mojom::WindowFeatures& window_features,
HostContentSettingsMap* settings_map) {
DCHECK(web_contents);
DCHECK(!open_url_params ||
open_url_params->user_gesture == delegate->GetOriginalUserGesture());
PopupBlockerTabHelper::LogAction(PopupBlockerTabHelper::Action::kInitiated);
// Check |popup_blocker| first since it is cheaper than ShouldBlockPopup().
auto* popup_blocker = PopupBlockerTabHelper::FromWebContents(web_contents);
if (!popup_blocker)
return delegate;
PopupBlockType block_type = ShouldBlockPopup(
web_contents, opener_url, delegate->GetOriginalUserGesture(),
open_url_params, settings_map);
if (block_type == PopupBlockType::kNotBlocked)
return delegate;
popup_blocker->AddBlockedPopup(std::move(delegate), window_features,
block_type);
return nullptr;
}
} // namespace blocked_content