1 // Copyright (c) 2012 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/managed_mode/managed_mode_navigation_observer.h" 6 7 #include "base/bind.h" 8 #include "base/callback.h" 9 #include "base/metrics/histogram.h" 10 #include "base/strings/string_util.h" 11 #include "chrome/browser/history/history_service.h" 12 #include "chrome/browser/history/history_service_factory.h" 13 #include "chrome/browser/history/history_types.h" 14 #include "chrome/browser/infobars/confirm_infobar_delegate.h" 15 #include "chrome/browser/infobars/infobar_service.h" 16 #include "chrome/browser/managed_mode/managed_mode_interstitial.h" 17 #include "chrome/browser/managed_mode/managed_mode_resource_throttle.h" 18 #include "chrome/browser/managed_mode/managed_mode_url_filter.h" 19 #include "chrome/browser/managed_mode/managed_user_service.h" 20 #include "chrome/browser/managed_mode/managed_user_service_factory.h" 21 #include "chrome/browser/profiles/profile.h" 22 #include "chrome/browser/tab_contents/tab_util.h" 23 #include "chrome/browser/ui/browser.h" 24 #include "chrome/browser/ui/browser_commands.h" 25 #include "chrome/browser/ui/browser_finder.h" 26 #include "chrome/browser/ui/browser_list.h" 27 #include "chrome/browser/ui/host_desktop.h" 28 #include "chrome/browser/ui/tabs/tab_strip_model.h" 29 #include "content/public/browser/browser_thread.h" 30 #include "content/public/browser/navigation_entry.h" 31 #include "content/public/browser/render_process_host.h" 32 #include "content/public/browser/render_view_host.h" 33 #include "content/public/browser/user_metrics.h" 34 #include "content/public/browser/web_contents_view.h" 35 #include "grit/generated_resources.h" 36 #include "ui/base/l10n/l10n_util.h" 37 38 using base::Time; 39 using content::NavigationEntry; 40 41 namespace { 42 43 44 // Helpers -------------------------------------------------------------------- 45 46 void GoBackToSafety(content::WebContents* web_contents) { 47 // For now, just go back one page (the user didn't retreat from that page, 48 // so it should be okay). 49 content::NavigationController* controller = 50 &web_contents->GetController(); 51 if (controller->CanGoBack()) { 52 controller->GoBack(); 53 return; 54 } 55 56 // If we can't go back (because we opened a new tab), try to close the tab. 57 // If this is the last tab on this desktop, open a new window. 58 chrome::HostDesktopType host_desktop_type = 59 chrome::GetHostDesktopTypeForNativeView( 60 web_contents->GetView()->GetNativeView()); 61 const BrowserList* browser_list = BrowserList::GetInstance(host_desktop_type); 62 if (browser_list->size() == 1) { 63 Browser* browser = browser_list->get(0); 64 DCHECK(browser == chrome::FindBrowserWithWebContents(web_contents)); 65 if (browser->tab_strip_model()->count() == 1) 66 chrome::NewEmptyWindow(browser->profile(), browser->host_desktop_type()); 67 } 68 69 web_contents->GetDelegate()->CloseContents(web_contents); 70 } 71 72 73 // ManagedModeWarningInfoBarDelegate ------------------------------------------ 74 75 class ManagedModeWarningInfoBarDelegate : public ConfirmInfoBarDelegate { 76 public: 77 // Creates a managed mode warning infobar delegate and adds it to 78 // |infobar_service|. Returns the delegate if it was successfully added. 79 static InfoBarDelegate* Create(InfoBarService* infobar_service); 80 81 private: 82 explicit ManagedModeWarningInfoBarDelegate(InfoBarService* infobar_service); 83 virtual ~ManagedModeWarningInfoBarDelegate(); 84 85 // ConfirmInfoBarDelegate: 86 virtual bool ShouldExpire( 87 const content::LoadCommittedDetails& details) const OVERRIDE; 88 virtual void InfoBarDismissed() OVERRIDE; 89 virtual string16 GetMessageText() const OVERRIDE; 90 virtual int GetButtons() const OVERRIDE; 91 virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; 92 virtual bool Accept() OVERRIDE; 93 94 DISALLOW_COPY_AND_ASSIGN(ManagedModeWarningInfoBarDelegate); 95 }; 96 97 // static 98 InfoBarDelegate* ManagedModeWarningInfoBarDelegate::Create( 99 InfoBarService* infobar_service) { 100 return infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>( 101 new ManagedModeWarningInfoBarDelegate(infobar_service))); 102 } 103 104 ManagedModeWarningInfoBarDelegate::ManagedModeWarningInfoBarDelegate( 105 InfoBarService* infobar_service) 106 : ConfirmInfoBarDelegate(infobar_service) { 107 } 108 109 ManagedModeWarningInfoBarDelegate::~ManagedModeWarningInfoBarDelegate() { 110 } 111 112 bool ManagedModeWarningInfoBarDelegate::ShouldExpire( 113 const content::LoadCommittedDetails& details) const { 114 // ManagedModeNavigationObserver removes us below. 115 return false; 116 } 117 118 void ManagedModeWarningInfoBarDelegate::InfoBarDismissed() { 119 ManagedModeNavigationObserver::FromWebContents( 120 web_contents())->WarnInfoBarDismissed(); 121 } 122 123 string16 ManagedModeWarningInfoBarDelegate::GetMessageText() const { 124 return l10n_util::GetStringUTF16(IDS_MANAGED_USER_WARN_INFOBAR_MESSAGE); 125 } 126 127 int ManagedModeWarningInfoBarDelegate::GetButtons() const { 128 return BUTTON_OK; 129 } 130 131 string16 ManagedModeWarningInfoBarDelegate::GetButtonLabel( 132 InfoBarButton button) const { 133 DCHECK_EQ(BUTTON_OK, button); 134 return l10n_util::GetStringUTF16(IDS_MANAGED_USER_WARN_INFOBAR_GO_BACK); 135 } 136 137 bool ManagedModeWarningInfoBarDelegate::Accept() { 138 GoBackToSafety(web_contents()); 139 140 return false; 141 } 142 143 144 } // namespace 145 146 // ManagedModeNavigationObserver ---------------------------------------------- 147 148 DEFINE_WEB_CONTENTS_USER_DATA_KEY(ManagedModeNavigationObserver); 149 150 ManagedModeNavigationObserver::~ManagedModeNavigationObserver() { 151 } 152 153 ManagedModeNavigationObserver::ManagedModeNavigationObserver( 154 content::WebContents* web_contents) 155 : WebContentsObserver(web_contents), 156 warn_infobar_(NULL) { 157 Profile* profile = 158 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 159 managed_user_service_ = ManagedUserServiceFactory::GetForProfile(profile); 160 url_filter_ = managed_user_service_->GetURLFilterForUIThread(); 161 } 162 163 void ManagedModeNavigationObserver::WarnInfoBarDismissed() { 164 DCHECK(warn_infobar_); 165 warn_infobar_ = NULL; 166 } 167 168 void ManagedModeNavigationObserver::ProvisionalChangeToMainFrameUrl( 169 const GURL& url, 170 content::RenderViewHost* render_view_host) { 171 ManagedModeURLFilter::FilteringBehavior behavior = 172 url_filter_->GetFilteringBehaviorForURL(url); 173 174 if (behavior == ManagedModeURLFilter::WARN || !warn_infobar_) 175 return; 176 177 // If we shouldn't have a warn infobar remove it here. 178 InfoBarService::FromWebContents(web_contents())->RemoveInfoBar(warn_infobar_); 179 warn_infobar_ = NULL; 180 } 181 182 void ManagedModeNavigationObserver::DidCommitProvisionalLoadForFrame( 183 int64 frame_id, 184 bool is_main_frame, 185 const GURL& url, 186 content::PageTransition transition_type, 187 content::RenderViewHost* render_view_host) { 188 if (!is_main_frame) 189 return; 190 191 DVLOG(1) << "DidCommitProvisionalLoadForFrame " << url.spec(); 192 ManagedModeURLFilter::FilteringBehavior behavior = 193 url_filter_->GetFilteringBehaviorForURL(url); 194 195 if (behavior == ManagedModeURLFilter::WARN && !warn_infobar_) { 196 warn_infobar_ = ManagedModeWarningInfoBarDelegate::Create( 197 InfoBarService::FromWebContents(web_contents())); 198 } 199 } 200 201 // static 202 void ManagedModeNavigationObserver::OnRequestBlocked( 203 int render_process_host_id, 204 int render_view_id, 205 const GURL& url, 206 const base::Callback<void(bool)>& callback) { 207 content::WebContents* web_contents = 208 tab_util::GetWebContentsByID(render_process_host_id, render_view_id); 209 if (!web_contents) { 210 content::BrowserThread::PostTask( 211 content::BrowserThread::IO, FROM_HERE, base::Bind(callback, false)); 212 return; 213 } 214 215 ManagedModeNavigationObserver* navigation_observer = 216 ManagedModeNavigationObserver::FromWebContents(web_contents); 217 if (navigation_observer) 218 navigation_observer->OnRequestBlockedInternal(url); 219 220 // Show the interstitial. 221 new ManagedModeInterstitial(web_contents, url, callback); 222 } 223 224 void ManagedModeNavigationObserver::OnRequestBlockedInternal(const GURL& url) { 225 Time timestamp = Time::Now(); // TODO(bauerb): Use SaneTime when available. 226 // Create a history entry for the attempt and mark it as such. 227 history::HistoryAddPageArgs add_page_args( 228 url, timestamp, web_contents(), 0, 229 url, history::RedirectList(), 230 content::PAGE_TRANSITION_BLOCKED, history::SOURCE_BROWSED, 231 false); 232 233 // Add the entry to the history database. 234 Profile* profile = 235 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); 236 HistoryService* history_service = 237 HistoryServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS); 238 239 // |history_service| is null if saving history is disabled. 240 if (history_service) 241 history_service->AddPage(add_page_args); 242 243 scoped_ptr<NavigationEntry> entry(NavigationEntry::Create()); 244 entry->SetVirtualURL(url); 245 entry->SetTimestamp(timestamp); 246 blocked_navigations_.push_back(entry.release()); 247 ManagedUserService* managed_user_service = 248 ManagedUserServiceFactory::GetForProfile(profile); 249 managed_user_service->DidBlockNavigation(web_contents()); 250 } 251