diff options
Diffstat (limited to 'chrome/browser/managed_mode')
6 files changed, 207 insertions, 145 deletions
diff --git a/chrome/browser/managed_mode/managed_mode_interstitial.cc b/chrome/browser/managed_mode/managed_mode_interstitial.cc index 878d7c7..ac1f537 100644 --- a/chrome/browser/managed_mode/managed_mode_interstitial.cc +++ b/chrome/browser/managed_mode/managed_mode_interstitial.cc @@ -11,7 +11,6 @@ #include "chrome/browser/managed_mode/managed_user_service.h" #include "chrome/browser/managed_mode/managed_user_service_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/tab_contents/tab_util.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "content/public/browser/browser_thread.h" @@ -28,44 +27,6 @@ using content::BrowserThread; -namespace { - -void ShowInterstitialOnUIThread(int render_process_host_id, - int render_view_id, - const GURL& url, - const base::Callback<void(bool)>& callback) { - // The tab might have been closed. - content::WebContents* web_contents = - tab_util::GetWebContentsByID(render_process_host_id, render_view_id); - if (!web_contents) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, base::Bind(callback, true)); - return; - } - - ManagedModeNavigationObserver* navigation_observer = - ManagedModeNavigationObserver::FromWebContents(web_contents); - if (navigation_observer) - navigation_observer->SetStateToRecordingAfterPreview(); - - new ManagedModeInterstitial(web_contents, url, callback); -} - -} // namespace - -// static -void ManagedModeInterstitial::ShowInterstitial( - int render_process_host_id, - int render_view_id, - const GURL& url, - const base::Callback<void(bool)>& callback) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&ShowInterstitialOnUIThread, render_process_host_id, - render_view_id, url, callback)); -} - ManagedModeInterstitial::ManagedModeInterstitial( content::WebContents* web_contents, const GURL& url, @@ -164,20 +125,14 @@ void ManagedModeInterstitial::CommandReceived(const std::string& command) { } void ManagedModeInterstitial::OnProceed() { - DispatchContinueRequest(true); + callback_.Run(true); } void ManagedModeInterstitial::OnDontProceed() { - DispatchContinueRequest(false); + callback_.Run(false); } void ManagedModeInterstitial::OnAuthorizationResult(bool success) { if (success) interstitial_page_->Proceed(); } - -void ManagedModeInterstitial::DispatchContinueRequest(bool continue_request) { - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(callback_, continue_request)); -} - diff --git a/chrome/browser/managed_mode/managed_mode_interstitial.h b/chrome/browser/managed_mode/managed_mode_interstitial.h index 98aeaef..1bfc346d 100644 --- a/chrome/browser/managed_mode/managed_mode_interstitial.h +++ b/chrome/browser/managed_mode/managed_mode_interstitial.h @@ -28,16 +28,6 @@ class ManagedModeInterstitial : public content::InterstitialPageDelegate { const base::Callback<void(bool)>& callback); virtual ~ManagedModeInterstitial(); - // Should be called on the IO thread. - // |render_process_host_id| and |render_view_id| identify the WebContents - // where the request was blocked. |url| is the URL that was blocked. - // |callback| should be called with the result (whether to allow the request - // or not). - static void ShowInterstitial(int render_process_host_id, - int render_view_id, - const GURL& url, - const base::Callback<void(bool)>& callback); - private: void GoToNewTabPage(); @@ -50,7 +40,6 @@ class ManagedModeInterstitial : public content::InterstitialPageDelegate { // Will be called when the passphrase dialog is closed, which is shown after // clicking the preview button. void OnAuthorizationResult(bool success); - void DispatchContinueRequest(bool continue_request); // Owns the interstitial, which owns us. content::WebContents* web_contents_; diff --git a/chrome/browser/managed_mode/managed_mode_navigation_observer.cc b/chrome/browser/managed_mode/managed_mode_navigation_observer.cc index 2740d5f..3d96c3b 100644 --- a/chrome/browser/managed_mode/managed_mode_navigation_observer.cc +++ b/chrome/browser/managed_mode/managed_mode_navigation_observer.cc @@ -20,6 +20,7 @@ #include "chrome/browser/managed_mode/managed_user_service.h" #include "chrome/browser/managed_mode/managed_user_service_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/tab_contents/tab_util.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_finder.h" @@ -30,8 +31,12 @@ #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/resource_request_details.h" #include "content/public/browser/user_metrics.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_view.h" @@ -266,6 +271,7 @@ ManagedModeNavigationObserver::ManagedModeNavigationObserver( got_user_gesture_(false), state_(RECORDING_URLS_BEFORE_PREVIEW), is_elevated_(false), + ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), last_allowed_page_(-1) { Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); @@ -273,6 +279,60 @@ ManagedModeNavigationObserver::ManagedModeNavigationObserver( if (!managed_user_service_->ProfileIsManaged()) is_elevated_ = true; url_filter_ = managed_user_service_->GetURLFilterForUIThread(); + registrar_.Add(this, content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, + content::Source<content::WebContents>(web_contents)); +} + +// static +void ManagedModeNavigationObserver::DidBlockRequest( + int render_process_id, + int render_view_id, + const GURL& url, + const ManagedModeNavigationObserver::SuccessCallback& callback) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // The tab might have been closed. + content::WebContents* web_contents = + tab_util::GetWebContentsByID(render_process_id, render_view_id); + if (!web_contents) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, base::Bind(callback, false)); + return; + } + + ManagedModeNavigationObserver* navigation_observer = + ManagedModeNavigationObserver::FromWebContents(web_contents); + if (!navigation_observer) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, base::Bind(callback, false)); + return; + } + navigation_observer->AddInterstitialCallback(url, callback); +} + +void ManagedModeNavigationObserver::ShowInterstitial(const GURL& url) { + // If we already have callbacks queued up, we don't need to show the + // interstitial again. + if (!callbacks_.empty()) + return; + + new ManagedModeInterstitial( + web_contents(), url, + base::Bind(&ManagedModeNavigationObserver::OnInterstitialResult, + weak_ptr_factory_.GetWeakPtr())); +} + +void ManagedModeNavigationObserver::AddInterstitialCallback( + const GURL& url, + const ManagedModeNavigationObserver::SuccessCallback& callback) { + if (state_ == RECORDING_URLS_AFTER_PREVIEW) { + // Return immediately if we are in preview mode. + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, base::Bind(callback, true)); + return; + } + + ShowInterstitial(url); + callbacks_.push_back(callback); } void ManagedModeNavigationObserver::AddTemporaryException() { @@ -332,12 +392,12 @@ void ManagedModeNavigationObserver::AddSavedURLsToWhitelistAndClearState() { for (std::set<GURL>::const_iterator it = navigated_urls_.begin(); it != navigated_urls_.end(); ++it) { - if (it->host() != last_url_.host()) + if (!CanTemporarilyNavigateHost(*it)) urls.push_back(*it); } managed_user_service_->SetManualBehaviorForURLs( urls, ManagedUserService::MANUAL_ALLOW); - if (last_url_.is_valid()) { + if (!last_url_.is_empty()) { std::vector<std::string> hosts; hosts.push_back(last_url_.host()); managed_user_service_->SetManualBehaviorForHosts( @@ -359,10 +419,6 @@ void ManagedModeNavigationObserver::AddURLToPatternList(const GURL& url) { last_url_ = url; } -void ManagedModeNavigationObserver::SetStateToRecordingAfterPreview() { - state_ = RECORDING_URLS_AFTER_PREVIEW; -} - bool ManagedModeNavigationObserver::CanTemporarilyNavigateHost( const GURL& url) { return last_url_.host() == url.host(); @@ -400,6 +456,19 @@ void ManagedModeNavigationObserver::ClearObserverState() { RemoveTemporaryException(); } +void ManagedModeNavigationObserver::OnInterstitialResult(bool result) { + DCHECK_EQ(RECORDING_URLS_BEFORE_PREVIEW, state_); + if (result) + state_ = RECORDING_URLS_AFTER_PREVIEW; + + for (std::vector<SuccessCallback>::const_iterator it = callbacks_.begin(); + it != callbacks_.end(); ++it) { + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(*it, result)); + } + callbacks_.clear(); +} + void ManagedModeNavigationObserver::NavigateToPendingEntry( const GURL& url, content::NavigationController::ReloadType reload_type) { @@ -414,78 +483,25 @@ void ManagedModeNavigationObserver::NavigateToPendingEntry( } } -void ManagedModeNavigationObserver::DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) { - if (!ShouldStayElevatedForURL(params.url)) - is_elevated_ = false; - - content::RecordAction(UserMetricsAction("ManagedMode_MainFrameNavigation")); - - ManagedModeURLFilter::FilteringBehavior behavior = - url_filter_->GetFilteringBehaviorForURL(params.url); - - UMA_HISTOGRAM_ENUMERATION("ManagedMode.FilteringBehavior", - behavior, - ManagedModeURLFilter::HISTOGRAM_BOUNDING_VALUE); - - // The page can be redirected to a different domain, record those URLs as - // well. - if (behavior == ManagedModeURLFilter::BLOCK && - !CanTemporarilyNavigateHost(params.url)) - AddURLToPatternList(params.url); - - if (behavior == ManagedModeURLFilter::ALLOW && - state_ == RECORDING_URLS_AFTER_PREVIEW) { - // The initial page that triggered the interstitial was blocked but the - // final page is already in the whitelist so add the series of URLs - // which lead to the final page to the whitelist as well. - // Update the |last_url_| since it was not added to the list before. - last_url_ = params.url; - AddSavedURLsToWhitelistAndClearState(); - SimpleAlertInfoBarDelegate::Create( - InfoBarService::FromWebContents(web_contents()), - NULL, - l10n_util::GetStringUTF16(IDS_MANAGED_MODE_ALREADY_ADDED_MESSAGE), - true); - return; - } - - // Update the exception to the last host visited. A redirect can follow this - // so don't update the state yet. - if (state_ == RECORDING_URLS_AFTER_PREVIEW) { - AddTemporaryException(); - } - - // The navigation is complete, unless there is a redirect. So set the - // new navigation to false to detect user interaction. - got_user_gesture_ = false; -} - void ManagedModeNavigationObserver::ProvisionalChangeToMainFrameUrl( const GURL& url, content::RenderViewHost* render_view_host) { if (!ShouldStayElevatedForURL(url)) is_elevated_ = false; - // This function is the last one to be called before the resource throttle - // shows the interstitial if the URL must be blocked. - DVLOG(1) << "ProvisionalChangeToMainFrameURL " << url.spec(); ManagedModeURLFilter::FilteringBehavior behavior = url_filter_->GetFilteringBehaviorForURL(url); - if (behavior != ManagedModeURLFilter::BLOCK) return; - if (state_ == RECORDING_URLS_AFTER_PREVIEW && got_user_gesture_ && - !CanTemporarilyNavigateHost(url)) - ClearObserverState(); - - if (behavior == ManagedModeURLFilter::BLOCK && - !CanTemporarilyNavigateHost(url)) - AddURLToPatternList(url); + if (state_ == RECORDING_URLS_BEFORE_PREVIEW) { + ShowInterstitial(url); + } else { + if (got_user_gesture_ && !CanTemporarilyNavigateHost(url)) + ClearObserverState(); - got_user_gesture_ = false; + got_user_gesture_ = false; + } } void ManagedModeNavigationObserver::DidCommitProvisionalLoadForFrame( @@ -528,9 +544,72 @@ void ManagedModeNavigationObserver::DidCommitProvisionalLoadForFrame( last_allowed_page_ = web_contents()->GetController().GetCurrentEntryIndex(); } +void ManagedModeNavigationObserver::DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + if (!ShouldStayElevatedForURL(params.url)) + is_elevated_ = false; + + content::RecordAction(UserMetricsAction("ManagedMode_MainFrameNavigation")); + + ManagedModeURLFilter::FilteringBehavior behavior = + url_filter_->GetFilteringBehaviorForURL(params.url); + + UMA_HISTOGRAM_ENUMERATION("ManagedMode.FilteringBehavior", + behavior, + ManagedModeURLFilter::HISTOGRAM_BOUNDING_VALUE); + + // The page can be redirected to a different domain, record those URLs as + // well. + if (behavior == ManagedModeURLFilter::BLOCK && + !CanTemporarilyNavigateHost(params.url)) + AddURLToPatternList(params.url); + + if (behavior == ManagedModeURLFilter::ALLOW && + state_ == RECORDING_URLS_AFTER_PREVIEW) { + // The initial page that triggered the interstitial was blocked but the + // final page is already in the whitelist so add the series of URLs + // which lead to the final page to the whitelist as well. + // Update the |last_url_| since it was not added to the list before. + last_url_ = params.url; + AddSavedURLsToWhitelistAndClearState(); + SimpleAlertInfoBarDelegate::Create( + InfoBarService::FromWebContents(web_contents()), + NULL, + l10n_util::GetStringUTF16(IDS_MANAGED_MODE_ALREADY_ADDED_MESSAGE), + true); + return; + } + + // Update the exception to the last host visited. A redirect can follow this + // so don't update the state yet. + if (state_ == RECORDING_URLS_AFTER_PREVIEW) + AddTemporaryException(); + + // The navigation is complete, unless there is a redirect. So set the + // new navigation to false to detect user interaction. + got_user_gesture_ = false; +} + void ManagedModeNavigationObserver::DidGetUserGesture() { got_user_gesture_ = true; // Update the exception status so that the resource throttle knows that // there was a manual navigation. UpdateExceptionNavigationStatus(); } + +void ManagedModeNavigationObserver::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK_EQ(content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, type); + const GURL& url = + content::Details<content::ResourceRedirectDetails>(details)->url; + ManagedModeURLFilter::FilteringBehavior behavior = + url_filter_->GetFilteringBehaviorForURL(url); + if (behavior == ManagedModeURLFilter::BLOCK && + state_ == RECORDING_URLS_AFTER_PREVIEW && + !CanTemporarilyNavigateHost(url)) { + AddURLToPatternList(url); + } +} diff --git a/chrome/browser/managed_mode/managed_mode_navigation_observer.h b/chrome/browser/managed_mode/managed_mode_navigation_observer.h index 1ddd495..044f124 100644 --- a/chrome/browser/managed_mode/managed_mode_navigation_observer.h +++ b/chrome/browser/managed_mode/managed_mode_navigation_observer.h @@ -7,7 +7,10 @@ #include <set> +#include "base/memory/weak_ptr.h" #include "base/values.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" @@ -16,18 +19,26 @@ class ManagedModeURLFilter; class ManagedUserService; class ManagedModeNavigationObserver - : public content::WebContentsObserver, - public content::WebContentsUserData<ManagedModeNavigationObserver> { + : public content::WebContentsUserData<ManagedModeNavigationObserver>, + public content::WebContentsObserver, + public content::NotificationObserver { public: + typedef base::Callback<void(bool)> SuccessCallback; + virtual ~ManagedModeNavigationObserver(); + // Called when a network request was blocked. The passed in |callback| is + // called with the result of the interstitial, i.e. whether we should proceed + // with the request or not. + static void DidBlockRequest(int render_process_id, + int render_view_id, + const GURL& url, + const SuccessCallback& callback); + // Sets the specific infobar as dismissed. void WarnInfobarDismissed(); void PreviewInfobarDismissed(); - // Sets the state of the Observer from the outside. - void SetStateToRecordingAfterPreview(); - // Returns whether the user should be allowed to navigate to this URL after // he has clicked "Preview" on the interstitial. bool CanTemporarilyNavigateHost(const GURL& url); @@ -65,6 +76,16 @@ class ManagedModeNavigationObserver explicit ManagedModeNavigationObserver(content::WebContents* web_contents); + // Shows the blocking interstitial if it is not already shown. + void ShowInterstitial(const GURL& url); + + // Queues up a callback to be called with the result of the interstitial. + void AddInterstitialCallback(const GURL& url, + const SuccessCallback& callback); + + // Dispatches the result of the interstitial to all pending callbacks. + void OnInterstitialResult(bool result); + // Adding the temporary exception stops the ResourceThrottle from showing // an interstitial for this RenderView. This allows the user to navigate // around on the website after clicking preview. @@ -75,6 +96,10 @@ class ManagedModeNavigationObserver void AddURLToPatternList(const GURL& url); + // Returns whether the user would stay in elevated state if he visits this + // URL. + bool ShouldStayElevatedForURL(const GURL& url); + // content::WebContentsObserver implementation. // An example regarding the order in which these events take place for // google.com in our case is as follows: @@ -90,9 +115,6 @@ class ManagedModeNavigationObserver virtual void NavigateToPendingEntry( const GURL& url, content::NavigationController::ReloadType reload_type) OVERRIDE; - virtual void DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) OVERRIDE; virtual void ProvisionalChangeToMainFrameUrl( const GURL& url, content::RenderViewHost* render_view_host) OVERRIDE; @@ -102,11 +124,15 @@ class ManagedModeNavigationObserver const GURL& url, content::PageTransition transition_type, content::RenderViewHost* render_view_host) OVERRIDE; + virtual void DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) OVERRIDE; virtual void DidGetUserGesture() OVERRIDE; - // Returns whether the user would stay in elevated state if he visits this - // URL. - bool ShouldStayElevatedForURL(const GURL& url); + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; // Owned by the profile, so outlives us. ManagedUserService* managed_user_service_; @@ -132,6 +158,15 @@ class ManagedModeNavigationObserver // Will be set to true for non-managed users. bool is_elevated_; + base::WeakPtrFactory<ManagedModeNavigationObserver> weak_ptr_factory_; + + // These callbacks get queued up when we show the blocking interstitial and + // are posted to the IO thread with the result of the interstitial, i.e. + // whether the user successfully authenticated to continue. + std::vector<SuccessCallback> callbacks_; + + content::NotificationRegistrar registrar_; + int last_allowed_page_; DISALLOW_COPY_AND_ASSIGN(ManagedModeNavigationObserver); diff --git a/chrome/browser/managed_mode/managed_mode_resource_throttle.cc b/chrome/browser/managed_mode/managed_mode_resource_throttle.cc index 654dca8..c5fe6e1 100644 --- a/chrome/browser/managed_mode/managed_mode_resource_throttle.cc +++ b/chrome/browser/managed_mode/managed_mode_resource_throttle.cc @@ -5,12 +5,16 @@ #include "chrome/browser/managed_mode/managed_mode_resource_throttle.h" #include "base/lazy_instance.h" +#include "base/location.h" #include "chrome/browser/managed_mode/managed_mode.h" -#include "chrome/browser/managed_mode/managed_mode_interstitial.h" +#include "chrome/browser/managed_mode/managed_mode_navigation_observer.h" #include "chrome/browser/managed_mode/managed_mode_url_filter.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/resource_controller.h" #include "net/url_request/url_request.h" +using content::BrowserThread; + namespace { // Uniquely identifies a tab, used to set a temporary exception on it. @@ -44,7 +48,7 @@ struct TemporaryExceptionData { typedef std::map<WebContentsId, TemporaryExceptionData> PreviewMap; base::LazyInstance<PreviewMap> g_in_preview_mode = LAZY_INSTANCE_INITIALIZER; -} +} // namespace ManagedModeResourceThrottle::ManagedModeResourceThrottle( const net::URLRequest* request, @@ -127,10 +131,13 @@ void ManagedModeResourceThrottle::ShowInterstitialIfNeeded(bool is_redirect, } *defer = true; - ManagedModeInterstitial::ShowInterstitial( - render_process_host_id_, render_view_id_, url, - base::Bind(&ManagedModeResourceThrottle::OnInterstitialResult, - weak_ptr_factory_.GetWeakPtr())); + + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&ManagedModeNavigationObserver::DidBlockRequest, + render_process_host_id_, render_view_id_, url, + base::Bind(&ManagedModeResourceThrottle::OnInterstitialResult, + weak_ptr_factory_.GetWeakPtr()))); } void ManagedModeResourceThrottle::WillStartRequest(bool* defer) { diff --git a/chrome/browser/managed_mode/managed_mode_resource_throttle_browsertest.cc b/chrome/browser/managed_mode/managed_mode_resource_throttle_browsertest.cc index 4d5a842..4edcc0b 100644 --- a/chrome/browser/managed_mode/managed_mode_resource_throttle_browsertest.cc +++ b/chrome/browser/managed_mode/managed_mode_resource_throttle_browsertest.cc @@ -41,7 +41,7 @@ void ManagedModeResourceThrottleTest::SetUpOnMainThread() { managed_user_service_->Init(); } -// Tests that showing the blocking interstitial for a WebContents without a +// Tests that blocking a request for a WebContents without a // ManagedModeNavigationObserver doesn't crash. IN_PROC_BROWSER_TEST_F(ManagedModeResourceThrottleTest, NoNavigationObserver) { scoped_ptr<WebContents> web_contents( @@ -52,7 +52,4 @@ IN_PROC_BROWSER_TEST_F(ManagedModeResourceThrottleTest, NoNavigationObserver) { controller.LoadURL(GURL("http://www.example.com"), content::Referrer(), content::PAGE_TRANSITION_TYPED, std::string()); observer.Wait(); - content::NavigationEntry* entry = controller.GetActiveEntry(); - ASSERT_TRUE(entry); - EXPECT_EQ(content::PAGE_TYPE_INTERSTITIAL, entry->GetPageType()); } |