| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "android_webview/browser/supervised_user/aw_supervised_user_throttle.h" |
| |
| #include "android_webview/browser/supervised_user/aw_supervised_user_blocking_page.h" |
| #include "components/security_interstitials/content/security_interstitial_tab_helper.h" |
| #include "content/public/browser/navigation_handle.h" |
| |
| namespace android_webview { |
| |
| // static |
| void AwSupervisedUserThrottle::CreateAndAdd( |
| content::NavigationThrottleRegistry& registry, |
| AwSupervisedUserUrlClassifier* url_classifier) { |
| registry.AddThrottle(base::WrapUnique<AwSupervisedUserThrottle>( |
| new AwSupervisedUserThrottle(registry, url_classifier))); |
| } |
| |
| AwSupervisedUserThrottle::AwSupervisedUserThrottle( |
| content::NavigationThrottleRegistry& registry, |
| AwSupervisedUserUrlClassifier* url_classifier) |
| : NavigationThrottle(registry), url_classifier_(url_classifier) { |
| DCHECK(url_classifier_); |
| DETACH_FROM_SEQUENCE(sequence_checker_); |
| } |
| |
| AwSupervisedUserThrottle::~AwSupervisedUserThrottle() = default; |
| |
| content::NavigationThrottle::ThrottleCheckResult |
| AwSupervisedUserThrottle::WillStartRequest() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| DCHECK_EQ(0u, pending_checks_); |
| DCHECK(!blocked_); |
| pending_checks_++; |
| return CheckShouldBlockUrl(navigation_handle()->GetURL()); |
| } |
| |
| content::NavigationThrottle::ThrottleCheckResult |
| AwSupervisedUserThrottle::WillRedirectRequest() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (blocked_) { |
| // onShouldBlockUrlResult() has set |blocked_| to true and called |
| // |CancelDeferredNavigation()|, but this method is called before the |
| // request is actually cancelled. In that case, simply defer the request. |
| return NavigationThrottle::DEFER; |
| } |
| pending_checks_++; |
| return CheckShouldBlockUrl(navigation_handle()->GetURL()); |
| } |
| |
| const char* AwSupervisedUserThrottle::GetNameForLogging() { |
| return "AwSupervisedUserThrottle"; |
| } |
| |
| content::NavigationThrottle::ThrottleCheckResult |
| AwSupervisedUserThrottle::WillProcessResponse() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (blocked_) { |
| // onShouldBlockUrlResult() has set |blocked_| to true and called |
| // |CancelDeferredNavigation()|, but this method is called before the |
| // request is actually cancelled. In that case, simply defer the request. |
| return NavigationThrottle::DEFER; |
| } |
| |
| if (pending_checks_ == 0) { |
| return NavigationThrottle::PROCEED; |
| } |
| |
| DCHECK(!deferred_); |
| deferred_ = true; |
| return NavigationThrottle::DEFER; |
| } |
| |
| content::NavigationThrottle::ThrottleCheckResult |
| AwSupervisedUserThrottle::CheckShouldBlockUrl(const GURL& url) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| DCHECK(url_classifier_); |
| |
| base::SequencedTaskRunner::GetCurrentDefault()->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| &AwSupervisedUserUrlClassifier::ShouldBlockUrl, |
| base::Unretained(url_classifier_), url, |
| base::BindOnce(&AwSupervisedUserThrottle::OnShouldBlockUrlResult, |
| weak_factory_.GetWeakPtr()))); |
| deferred_ = true; |
| return NavigationThrottle::DEFER; |
| } |
| |
| void AwSupervisedUserThrottle::OnShouldBlockUrlResult(bool shouldBlockUrl) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| DCHECK(!blocked_); |
| DCHECK_LT(0u, pending_checks_); |
| pending_checks_--; |
| |
| if (shouldBlockUrl) { |
| blocked_ = true; |
| pending_checks_ = 0; |
| |
| std::unique_ptr<security_interstitials::SecurityInterstitialPage> |
| blocking_page = AwSupervisedUserBlockingPage::CreateBlockingPage( |
| navigation_handle()->GetWebContents(), |
| navigation_handle()->GetURL()); |
| std::string error_page_content = blocking_page->GetHTMLContents(); |
| // AssociateBlockingPage takes ownership of the blocking page. |
| security_interstitials::SecurityInterstitialTabHelper:: |
| AssociateBlockingPage(navigation_handle(), std::move(blocking_page)); |
| CancelDeferredNavigation(content::NavigationThrottle::ThrottleCheckResult( |
| CANCEL, net::ERR_BLOCKED_BY_CLIENT, error_page_content)); |
| |
| } else { |
| if (pending_checks_ == 0 && deferred_) { |
| deferred_ = false; |
| Resume(); |
| } |
| } |
| } |
| |
| } // namespace android_webview |