blob: fdd519e786fb03ec92333338297cc95747f65074 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_THROTTLE_MANAGER_H_
#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_THROTTLE_MANAGER_H_
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
#include "base/stl_util.h"
#include "components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer.h"
#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
#include "components/subresource_filter/core/common/activation_decision.h"
#include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
#include "content/public/browser/web_contents_binding_set.h"
#include "content/public/browser/web_contents_observer.h"
namespace content {
class NavigationHandle;
class NavigationThrottle;
class RenderFrameHost;
} // namespace content
namespace subresource_filter {
class AsyncDocumentSubresourceFilter;
class ActivationStateComputingNavigationThrottle;
class PageLoadStatistics;
class SubresourceFilterObserverManager;
class SubresourceFilterClient;
// The ContentSubresourceFilterThrottleManager manages NavigationThrottles in
// order to calculate frame activation states and subframe navigation filtering,
// within a given WebContents. It contains a mapping of all activated
// RenderFrameHosts, along with their associated DocumentSubresourceFilters.
//
// The class is designed to be used by a Delegate, which shares lifetime with
// this class (aka the typical lifetime of a WebContentsObserver). The delegate
// will be notified of the first disallowed subresource load for a top level
// navgation, and has veto power for frame activation.
class ContentSubresourceFilterThrottleManager
: public content::WebContentsObserver,
public mojom::SubresourceFilterHost,
public SubresourceFilterObserver,
public SubframeNavigationFilteringThrottle::Delegate {
public:
ContentSubresourceFilterThrottleManager(
SubresourceFilterClient* client,
VerifiedRulesetDealer::Handle* dealer_handle,
content::WebContents* web_contents);
~ContentSubresourceFilterThrottleManager() override;
// This method inspects |navigation_handle| and attaches navigation throttles
// appropriately, based on the current state of frame activation.
//
// 1. Subframe navigation filtering throttles are appended if the parent
// frame is activated.
// 2. Activation state computing throttles are appended if either the
// navigation is a main frame navigation, or if the parent frame is activated.
//
// Note that there is currently no constraints on the ordering of throttles.
void MaybeAppendNavigationThrottles(
content::NavigationHandle* navigation_handle,
std::vector<std::unique_ptr<content::NavigationThrottle>>* throttles);
PageLoadStatistics* page_load_statistics() const { return statistics_.get(); }
VerifiedRuleset::Handle* ruleset_handle_for_testing() {
return ruleset_handle_.get();
}
// SubframeNavigationFilteringThrottle::Delegate:
bool CalculateIsAdSubframe(content::RenderFrameHost* frame_host,
LoadPolicy load_policy) override;
bool IsFrameTaggedAsAdForTesting(content::RenderFrameHost* frame_host) const;
protected:
// content::WebContentsObserver:
void RenderFrameDeleted(content::RenderFrameHost* frame_host) override;
void ReadyToCommitNavigation(
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
void DidFinishLoad(content::RenderFrameHost* render_frame_host,
const GURL& validated_url) override;
// SubresourceFilterObserver:
void OnSubresourceFilterGoingAway() override;
void OnPageActivationComputed(
content::NavigationHandle* navigation_handle,
const mojom::ActivationState& activation_state) override;
void OnSubframeNavigationEvaluated(
content::NavigationHandle* navigation_handle,
LoadPolicy load_policy,
bool is_ad_subframe) override;
private:
FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
SubframeNavigationTaggedAsAdByRenderer);
FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
GrandchildNavigationTaggedAsAdByRenderer);
FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
AdTagCarriesAcrossProcesses);
FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
FirstDisallowedLoadCalledOutOfOrder);
std::unique_ptr<SubframeNavigationFilteringThrottle>
MaybeCreateSubframeNavigationFilteringThrottle(
content::NavigationHandle* navigation_handle);
std::unique_ptr<ActivationStateComputingNavigationThrottle>
MaybeCreateActivationStateComputingThrottle(
content::NavigationHandle* navigation_handle);
// Will return nullptr if the parent frame of this navigation is not
// activated (and therefore has no subresource filter).
AsyncDocumentSubresourceFilter* GetParentFrameFilter(
content::NavigationHandle* child_frame_navigation);
// Calls ShowNotification on |client_| at most once per committed,
// non-same-page navigation in the main frame.
void MaybeShowNotification();
VerifiedRuleset::Handle* EnsureRulesetHandle();
void DestroyRulesetHandleIfNoLongerUsed();
// Registers |render_frame_host| as an ad frame. If the frame later moves to
// a new process its RenderHost will be told that it's an ad.
void OnFrameIsAdSubframe(content::RenderFrameHost* render_frame_host);
// mojom::SubresourceFilterHost:
void DidDisallowFirstSubresource() override;
void FrameIsAdSubframe() override;
void SetDocumentLoadStatistics(
mojom::DocumentLoadStatisticsPtr statistics) override;
// Adds the navigation's RenderFrameHost to activated_frame_hosts_ if it is a
// special navigation which did not go through navigation throttles and its
// parent frame is activated as well. The filter for these frames is set
// to nullptr.
void MaybeActivateSubframeSpecialUrls(
content::NavigationHandle* navigation_handle);
// For each RenderFrameHost where the last committed load has subresource
// filtering activated, owns the corresponding AsyncDocumentSubresourceFilter.
// It is possible for a frame to have a null filter.
std::map<content::RenderFrameHost*,
std::unique_ptr<AsyncDocumentSubresourceFilter>>
activated_frame_hosts_;
// For each ongoing navigation that requires activation state computation,
// keeps track of the throttle that is carrying out that computation, so that
// the result can be retrieved when the navigation is ready to commit.
std::map<content::NavigationHandle*,
ActivationStateComputingNavigationThrottle*>
ongoing_activation_throttles_;
// Set of RenderFrameHosts that have been identified as ads. An RFH is an ad
// subframe if any of the following conditions are met:
// 1. Its navigation URL is in the filter list
// 2. Its parent is a known ad subframe
// 3. The RenderFrame declares the frame is an ad (see AdTracker in Blink)
// 4. It's the result of moving an old ad subframe RFH to a new RFH (e.g.,
// OOPIF)
std::set<content::RenderFrameHost*> ad_frames_;
content::WebContentsFrameBindingSet<mojom::SubresourceFilterHost> binding_;
ScopedObserver<SubresourceFilterObserverManager, SubresourceFilterObserver>
scoped_observer_;
// Lazily instantiated in EnsureRulesetHandle when the first page level
// activation is triggered. Will go away when there are no more activated
// RenderFrameHosts (i.e. activated_frame_hosts_ is empty).
std::unique_ptr<VerifiedRuleset::Handle> ruleset_handle_;
std::unique_ptr<PageLoadStatistics> statistics_;
// True if the current committed main frame load in this WebContents has
// notified the delegate that a subresource was disallowed. The callback
// should only be called at most once per main frame load.
bool current_committed_load_has_notified_disallowed_load_ = false;
// These members outlive this class.
VerifiedRulesetDealer::Handle* dealer_handle_;
SubresourceFilterClient* client_;
base::WeakPtrFactory<ContentSubresourceFilterThrottleManager>
weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterThrottleManager);
};
} // namespace subresource_filter
#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_THROTTLE_MANAGER_H_