blob: 6c7a777d35902dd187096fc82266aea330ff52ea [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SUPERVISED_USER_CLASSIFY_URL_NAVIGATION_THROTTLE_H_
#define CHROME_BROWSER_SUPERVISED_USER_CLASSIFY_URL_NAVIGATION_THROTTLE_H_
#include <memory>
#include <optional>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/elapsed_timer.h"
#include "components/supervised_user/core/browser/supervised_user_service.h"
#include "components/supervised_user/core/browser/supervised_user_url_filter.h"
#include "components/supervised_user/core/browser/supervised_user_utils.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/navigation_throttle.h"
#include "url/gurl.h"
namespace supervised_user {
// LINT.IfChange(ClassifyUrlThrottleFinalStatus)
enum class ClassifyUrlThrottleFinalStatus : int {
kAllowed = 0,
kBlocked = 1,
kMaxValue = kBlocked,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/families/enums.xml:ClassifyUrlThrottleFinalStatus)
// LINT.IfChange(ClassifyUrlThrottleStatus)
enum class ClassifyUrlThrottleStatus : int {
kContinue = 0,
kProceed = 1,
kDefer = 2,
kDeferAndScheduleInterstitial = 3,
kCancel = 4,
kResume = 5,
kCancelDeferredNavigation = 6,
kMaxValue = kCancelDeferredNavigation,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/families/enums.xml:ClassifyUrlThrottleStatus)
enum class InterstitialResultCallbackActions {
kCancelNavigation = 0,
kCancelWithInterstitial = 1
};
// Navigation throttle that processes requests and redirects in parallel with
// their verification against ClassifyUrl, up until the response is ready for
// processing. Only then the navigation can be deferred.
class ClassifyUrlNavigationThrottle : public content::NavigationThrottle {
public:
// Adds a ClassifyUrlNavigationThrottle to the registry for all profiles except
// for OffTheRecord profiles.
static void MaybeCreateAndAdd(
content::NavigationThrottleRegistry& registry);
ClassifyUrlNavigationThrottle(const ClassifyUrlNavigationThrottle&) = delete;
ClassifyUrlNavigationThrottle& operator=(
const ClassifyUrlNavigationThrottle&) = delete;
~ClassifyUrlNavigationThrottle() override;
protected:
void CancelDeferredNavigation(ThrottleCheckResult result) override;
private:
// Smart container that manages list of pending checks and derives overall
// verdict for the throttle. The checks are stored in the order in which they
// were scheduled. The list can be sealed (marked that no more checks will be
// scheduled) which is important to determine the final verdict.
class ClassifyUrlCheckList {
public:
using Key = std::vector<SupervisedUserURLFilter::Result>::size_type;
ClassifyUrlCheckList();
ClassifyUrlCheckList(ClassifyUrlCheckList& other) = delete;
const ClassifyUrlCheckList& operator=(ClassifyUrlCheckList& other) = delete;
~ClassifyUrlCheckList();
// Registers new check if the list is not sealed.
Key NewCheck();
void UpdateCheck(Key key, SupervisedUserURLFilter::Result result);
// Returns blocking Filtering result if there's one or nothing.
std::optional<SupervisedUserURLFilter::Result> GetBlockingResult() const;
// Returns true if this classification allowed or blocking.
bool IsDecided() const;
// Seals this instance. After calling this method `NewCheck` cannot be
// called, but behavior of `IsDecided()` changes.
void MarkNavigationRequestsCompleted();
base::TimeDelta ElapsedSinceDecided() const;
private:
std::vector<std::optional<SupervisedUserURLFilter::Result>> results_;
// After disabling new checks can't be issued, but it enables positive
// verification of all-allow results.
bool new_checks_disabled_{false};
// Tracks time from being updated by the most recent result that had effect
// on verdict.
std::optional<base::ElapsedTimer> elapsed_;
};
explicit ClassifyUrlNavigationThrottle(content::NavigationThrottleRegistry& registry);
// content::NavigationThrottle implementation:
ThrottleCheckResult WillStartRequest() override;
ThrottleCheckResult WillRedirectRequest() override;
ThrottleCheckResult WillProcessResponse() override;
const char* GetNameForLogging() override;
// Common procedure for both initial request and redirects.
ThrottleCheckResult WillProcessRequest();
// The URL the frame is navigating to. This may change during the navigation
// when encountering a server redirect.
const GURL& currently_navigated_url() const;
// Triggers a URL check; the result might be processed either synchronously
// or asynchronously.
void CheckURL();
// The triggered callback; results will be written onto check.
void OnURLCheckDone(ClassifyUrlCheckList::Key key,
SupervisedUserURLFilter::Result result);
// Change state of the throttle and record metrics.
std::optional<ThrottleCheckResult> NextNavigationState(
ClassifyUrlThrottleStatus status);
// Defers the navigation to accommodate the interstitial and shows that
// interstitial.
ThrottleCheckResult DeferAndScheduleInterstitial(
SupervisedUserURLFilter::Result result);
// Interstitial handling
void ScheduleInterstitial(SupervisedUserURLFilter::Result result);
void ShowInterstitial(SupervisedUserURLFilter::Result result);
void OnInterstitialResult(SupervisedUserURLFilter::Result result,
InterstitialResultCallbackActions action,
bool already_sent_request,
bool is_main_frame);
// Returns the HTML to be used for the interstitial, specific for the profile
// doing the navigation.
std::string GetInterstitialHTML(SupervisedUserURLFilter::Result result,
bool already_sent_request,
bool is_main_frame) const;
// Returns the URL filter associated with the navigated under throttling.
SupervisedUserURLFilter* url_filter() const;
// Returns the supervised user service associated with the navigated under
// throttling.
SupervisedUserService* supervised_user_service() const;
// All pending and completed checks.
ClassifyUrlCheckList list_;
// True iff one of navigation events returned ::DEFER.
bool deferred_{false};
// Timers forming a continuum of time, only recorded in unblocked navigation
// (success) case.
std::optional<base::ElapsedTimer> waiting_for_decision_;
base::WeakPtrFactory<ClassifyUrlNavigationThrottle> weak_ptr_factory_{this};
};
} // namespace supervised_user
#endif // CHROME_BROWSER_SUPERVISED_USER_CLASSIFY_URL_NAVIGATION_THROTTLE_H_