blob: 950bc0dbafaf036c844c9893cb4729758e0a3fa8 [file] [log] [blame]
// Copyright 2018 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 "chrome/browser/ui/blocked_content/popup_blocker.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
#include "chrome/browser/ui/blocked_content/safe_browsing_triggered_popup_blocker.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/common/chrome_switches.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/safe_browsing/triggers/ad_popup_trigger.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/web_contents.h"
namespace {
// If the popup should be blocked, returns the reason why it was blocked.
// Otherwise returns kNotBlocked.
PopupBlockType ShouldBlockPopup(content::WebContents* web_contents,
const base::Optional<GURL>& opener_url,
bool user_gesture,
const content::OpenURLParams* open_url_params) {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::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.value() : web_contents->GetLastCommittedURL();
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
if (url.is_valid() &&
HostContentSettingsMapFactory::GetForProfile(profile)->GetContentSetting(
url, url, CONTENT_SETTINGS_TYPE_POPUPS, std::string()) ==
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::WebTriggeringEventInfo::kFromUntrustedEvent) {
return PopupBlockType::kNotBlocked;
}
auto* safe_browsing_blocker =
SafeBrowsingTriggeredPopupBlocker::FromWebContents(web_contents);
if (safe_browsing_blocker &&
safe_browsing_blocker->ShouldApplyAbusivePopupBlocker()) {
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;
}
bool MaybeBlockPopup(content::WebContents* web_contents,
const base::Optional<GURL>& opener_url,
NavigateParams* params,
const content::OpenURLParams* open_url_params,
const blink::mojom::WindowFeatures& window_features) {
DCHECK(web_contents);
DCHECK(!open_url_params ||
open_url_params->user_gesture == params->user_gesture);
PopupBlockerTabHelper::LogAction(PopupBlockerTabHelper::Action::kInitiated);
PopupBlockType block_type = ShouldBlockPopup(
web_contents, opener_url, params->user_gesture, open_url_params);
auto* popup_blocker = PopupBlockerTabHelper::FromWebContents(web_contents);
if (popup_blocker && block_type != PopupBlockType::kNotBlocked) {
popup_blocker->AddBlockedPopup(params, window_features, block_type);
if (safe_browsing::AdPopupTrigger::FromWebContents(web_contents)) {
content::RenderFrameHost* source_frame =
GetSourceFrameForPopup(params, open_url_params, web_contents);
safe_browsing::AdPopupTrigger::FromWebContents(web_contents)
->PopupWasBlocked(source_frame);
}
return true;
}
return false;
}
content::RenderFrameHost* GetSourceFrameForPopup(
NavigateParams* params,
const content::OpenURLParams* open_url_params,
content::WebContents* web_contents) {
if (params->opener)
return params->opener;
// Make sure the source render frame host is alive before we attempt to
// retrieve it from |open_url_params|.
if (open_url_params) {
content::RenderFrameHost* source = content::RenderFrameHost::FromID(
open_url_params->source_render_frame_id,
open_url_params->source_render_process_id);
if (source)
return source;
}
// The focused frame is not always the frame initiating the popup navigation
// and is used as a fallback in case opener information is not available.
return web_contents->GetFocusedFrame();
}