19ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
29ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
39ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch// found in the LICENSE file.
49ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
59ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
69ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
79ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
89ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/browser/content_settings/host_content_settings_map.h"
99ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/browser/content_settings/tab_specific_content_settings.h"
109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/browser/profiles/profile.h"
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/ui/blocked_content/blocked_window_params.h"
129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "chrome/browser/ui/browser_navigator.h"
13558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chrome/browser/ui/tabs/tab_strip_model.h"
1458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "chrome/common/render_messages.h"
159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "content/public/browser/navigation_controller.h"
169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "content/public/browser/navigation_details.h"
179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "content/public/browser/navigation_entry.h"
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "content/public/browser/web_contents.h"
209ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "content/public/browser/web_contents_delegate.h"
2158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "third_party/WebKit/public/web/WebWindowFeatures.h"
2258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
23424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#if defined(OS_ANDROID)
24424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
25424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#endif
26424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebWindowFeatures;
289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const size_t kMaximumNumberOfPopups = 25;
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochDEFINE_WEB_CONTENTS_USER_DATA_KEY(PopupBlockerTabHelper);
329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
3358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochstruct PopupBlockerTabHelper::BlockedRequest {
3458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  BlockedRequest(const chrome::NavigateParams& params,
3558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                 const WebWindowFeatures& window_features)
3658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch      : params(params), window_features(window_features) {}
3758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
3858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  chrome::NavigateParams params;
3958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  WebWindowFeatures window_features;
4058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch};
4158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochPopupBlockerTabHelper::PopupBlockerTabHelper(
439ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    content::WebContents* web_contents)
449ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    : content::WebContentsObserver(web_contents) {
459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochPopupBlockerTabHelper::~PopupBlockerTabHelper() {
489ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochvoid PopupBlockerTabHelper::DidNavigateMainFrame(
519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    const content::LoadCommittedDetails& details,
529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    const content::FrameNavigateParams& params) {
539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Clear all page actions, blocked content notifications and browser actions
549ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // for this tab, unless this is an in-page navigation.
559ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  if (details.is_in_page)
569ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return;
579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // Close blocked popups.
599ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  if (!blocked_popups_.IsEmpty()) {
609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    blocked_popups_.Clear();
619ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    PopupNotificationVisibilityChanged(false);
629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
649ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
659ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochvoid PopupBlockerTabHelper::PopupNotificationVisibilityChanged(
669ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    bool visible) {
679ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  if (!web_contents()->IsBeingDestroyed()) {
689ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    TabSpecificContentSettings::FromWebContents(web_contents())->
699ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        SetPopupsBlocked(visible);
709ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
719ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
729ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
739ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochbool PopupBlockerTabHelper::MaybeBlockPopup(
7458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    const chrome::NavigateParams& params,
7558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    const WebWindowFeatures& window_features) {
769ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // A page can't spawn popups (or do anything else, either) until its load
779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // commits, so when we reach here, the popup was spawned by the
789ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // NavigationController's last committed entry, not the active entry.  For
799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // example, if a page opens a popup in an onunload() handler, then the active
809ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // entry is the page to be loaded as we navigate away from the unloading
819ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // page.  For this reason, we can't use GetURL() to get the opener URL,
829ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  // because it returns the active entry.
839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  content::NavigationEntry* entry =
849ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      web_contents()->GetController().GetLastCommittedEntry();
859ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  GURL creator = entry ? entry->GetVirtualURL() : GURL();
869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  Profile* profile =
879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
889ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
899ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  if (creator.is_valid() &&
909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      profile->GetHostContentSettingsMap()->GetContentSetting(
919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch          creator, creator, CONTENT_SETTINGS_TYPE_POPUPS, std::string()) ==
929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch          CONTENT_SETTING_ALLOW) {
939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return false;
949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  } else {
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (blocked_popups_.size() < kMaximumNumberOfPopups) {
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      blocked_popups_.Add(new BlockedRequest(params, window_features));
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      TabSpecificContentSettings::FromWebContents(web_contents())->
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS);
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
1009ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return true;
1019ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
1029ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
1039ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void PopupBlockerTabHelper::AddBlockedPopup(const BlockedWindowParams& params) {
10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  chrome::NavigateParams nav_params =
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      params.CreateNavigateParams(web_contents());
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (blocked_popups_.size() < kMaximumNumberOfPopups) {
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    blocked_popups_.Add(new BlockedRequest(nav_params, params.features()));
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    TabSpecificContentSettings::FromWebContents(web_contents())->
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS);
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
113558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
114558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
1159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochvoid PopupBlockerTabHelper::ShowBlockedPopup(int32 id) {
11658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  BlockedRequest* popup = blocked_popups_.Lookup(id);
11758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (!popup)
1189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return;
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // We set user_gesture to true here, so the new popup gets correctly focused.
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  popup->params.user_gesture = true;
121424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#if defined(OS_ANDROID)
122424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  TabModelList::HandlePopupNavigation(&popup->params);
123424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#else
12458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  chrome::Navigate(&popup->params);
125424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#endif
12658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (popup->params.target_contents) {
12758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    popup->params.target_contents->Send(new ChromeViewMsg_SetWindowFeatures(
12858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch        popup->params.target_contents->GetRoutingID(), popup->window_features));
12958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  }
1309ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  blocked_popups_.Remove(id);
1319ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  if (blocked_popups_.IsEmpty())
1329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    PopupNotificationVisibilityChanged(false);
1339ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
1349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1359ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochsize_t PopupBlockerTabHelper::GetBlockedPopupsCount() const {
1369ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  return blocked_popups_.size();
1379ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
1389ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)PopupBlockerTabHelper::PopupIdMap
140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PopupBlockerTabHelper::GetBlockedPopupRequests() {
141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  PopupIdMap result;
14258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  for (IDMap<BlockedRequest, IDMapOwnPointer>::const_iterator iter(
14358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch           &blocked_popups_);
14458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch       !iter.IsAtEnd();
14558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch       iter.Advance()) {
14658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    result[iter.GetCurrentKey()] = iter.GetCurrentValue()->params.url;
14758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  }
14858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  return result;
1499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
150