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