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