1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h" 6 7 #include "chrome/browser/chrome_notification_types.h" 8 #include "chrome/browser/content_settings/host_content_settings_map.h" 9 #include "chrome/browser/content_settings/tab_specific_content_settings.h" 10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/ui/blocked_content/blocked_window_params.h" 12 #include "chrome/browser/ui/browser_navigator.h" 13 #include "chrome/browser/ui/tabs/tab_strip_model.h" 14 #include "chrome/common/render_messages.h" 15 #include "content/public/browser/navigation_controller.h" 16 #include "content/public/browser/navigation_details.h" 17 #include "content/public/browser/navigation_entry.h" 18 #include "content/public/browser/render_view_host.h" 19 #include "content/public/browser/web_contents.h" 20 #include "content/public/browser/web_contents_delegate.h" 21 #include "third_party/WebKit/public/web/WebWindowFeatures.h" 22 23 #if defined(OS_ANDROID) 24 #include "chrome/browser/ui/android/tab_model/tab_model_list.h" 25 #endif 26 27 using blink::WebWindowFeatures; 28 29 const size_t kMaximumNumberOfPopups = 25; 30 31 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PopupBlockerTabHelper); 32 33 struct PopupBlockerTabHelper::BlockedRequest { 34 BlockedRequest(const chrome::NavigateParams& params, 35 const WebWindowFeatures& window_features) 36 : params(params), window_features(window_features) {} 37 38 chrome::NavigateParams params; 39 WebWindowFeatures window_features; 40 }; 41 42 PopupBlockerTabHelper::PopupBlockerTabHelper( 43 content::WebContents* web_contents) 44 : content::WebContentsObserver(web_contents) { 45 } 46 47 PopupBlockerTabHelper::~PopupBlockerTabHelper() { 48 } 49 50 void PopupBlockerTabHelper::DidNavigateMainFrame( 51 const content::LoadCommittedDetails& details, 52 const content::FrameNavigateParams& params) { 53 // Clear all page actions, blocked content notifications and browser actions 54 // for this tab, unless this is an in-page navigation. 55 if (details.is_in_page) 56 return; 57 58 // Close blocked popups. 59 if (!blocked_popups_.IsEmpty()) { 60 blocked_popups_.Clear(); 61 PopupNotificationVisibilityChanged(false); 62 } 63 } 64 65 void PopupBlockerTabHelper::PopupNotificationVisibilityChanged( 66 bool visible) { 67 if (!web_contents()->IsBeingDestroyed()) { 68 TabSpecificContentSettings::FromWebContents(web_contents())-> 69 SetPopupsBlocked(visible); 70 } 71 } 72 73 bool PopupBlockerTabHelper::MaybeBlockPopup( 74 const chrome::NavigateParams& params, 75 const WebWindowFeatures& window_features) { 76 // A page can't spawn popups (or do anything else, either) until its load 77 // commits, so when we reach here, the popup was spawned by the 78 // NavigationController's last committed entry, not the active entry. For 79 // example, if a page opens a popup in an onunload() handler, then the active 80 // entry is the page to be loaded as we navigate away from the unloading 81 // page. For this reason, we can't use GetURL() to get the opener URL, 82 // because it returns the active entry. 83 content::NavigationEntry* entry = 84 web_contents()->GetController().GetLastCommittedEntry(); 85 GURL creator = entry ? entry->GetVirtualURL() : GURL(); 86 Profile* profile = 87 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 88 89 if (creator.is_valid() && 90 profile->GetHostContentSettingsMap()->GetContentSetting( 91 creator, creator, CONTENT_SETTINGS_TYPE_POPUPS, std::string()) == 92 CONTENT_SETTING_ALLOW) { 93 return false; 94 } else { 95 if (blocked_popups_.size() < kMaximumNumberOfPopups) { 96 blocked_popups_.Add(new BlockedRequest(params, window_features)); 97 TabSpecificContentSettings::FromWebContents(web_contents())-> 98 OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS); 99 } 100 return true; 101 } 102 } 103 104 void PopupBlockerTabHelper::AddBlockedPopup(const BlockedWindowParams& params) { 105 chrome::NavigateParams nav_params = 106 params.CreateNavigateParams(web_contents()); 107 108 if (blocked_popups_.size() < kMaximumNumberOfPopups) { 109 blocked_popups_.Add(new BlockedRequest(nav_params, params.features())); 110 TabSpecificContentSettings::FromWebContents(web_contents())-> 111 OnContentBlocked(CONTENT_SETTINGS_TYPE_POPUPS); 112 } 113 } 114 115 void PopupBlockerTabHelper::ShowBlockedPopup(int32 id) { 116 BlockedRequest* popup = blocked_popups_.Lookup(id); 117 if (!popup) 118 return; 119 // We set user_gesture to true here, so the new popup gets correctly focused. 120 popup->params.user_gesture = true; 121 #if defined(OS_ANDROID) 122 TabModelList::HandlePopupNavigation(&popup->params); 123 #else 124 chrome::Navigate(&popup->params); 125 #endif 126 if (popup->params.target_contents) { 127 popup->params.target_contents->Send(new ChromeViewMsg_SetWindowFeatures( 128 popup->params.target_contents->GetRoutingID(), popup->window_features)); 129 } 130 blocked_popups_.Remove(id); 131 if (blocked_popups_.IsEmpty()) 132 PopupNotificationVisibilityChanged(false); 133 } 134 135 size_t PopupBlockerTabHelper::GetBlockedPopupsCount() const { 136 return blocked_popups_.size(); 137 } 138 139 PopupBlockerTabHelper::PopupIdMap 140 PopupBlockerTabHelper::GetBlockedPopupRequests() { 141 PopupIdMap result; 142 for (IDMap<BlockedRequest, IDMapOwnPointer>::const_iterator iter( 143 &blocked_popups_); 144 !iter.IsAtEnd(); 145 iter.Advance()) { 146 result[iter.GetCurrentKey()] = iter.GetCurrentValue()->params.url; 147 } 148 return result; 149 } 150