PageRenderTime 63ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h

https://github.com/chromium/chromium
C Header | 427 lines | 192 code | 68 blank | 167 comment | 0 complexity | af1bb79bf7daba9c5aaf7acb61775bbb MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
  1. // Copyright 2017 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. #ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_THROTTLE_MANAGER_H_
  5. #define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_THROTTLE_MANAGER_H_
  6. #include <map>
  7. #include <memory>
  8. #include <vector>
  9. #include "base/containers/flat_set.h"
  10. #include "base/gtest_prod_util.h"
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/memory/weak_ptr.h"
  13. #include "base/supports_user_data.h"
  14. #include "components/safe_browsing/core/browser/db/database_manager.h"
  15. #include "components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h"
  16. #include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
  17. #include "components/subresource_filter/content/common/subresource_filter_utils.h"
  18. #include "components/subresource_filter/content/mojom/subresource_filter.mojom.h"
  19. #include "components/subresource_filter/core/common/activation_decision.h"
  20. #include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
  21. #include "content/public/browser/render_frame_host_receiver_set.h"
  22. #include "third_party/abseil-cpp/absl/types/optional.h"
  23. #include "third_party/blink/public/common/frame/frame_ad_evidence.h"
  24. namespace content {
  25. class NavigationHandle;
  26. class NavigationThrottle;
  27. class Page;
  28. class RenderFrameHost;
  29. } // namespace content
  30. namespace subresource_filter {
  31. class AsyncDocumentSubresourceFilter;
  32. class ActivationStateComputingNavigationThrottle;
  33. class ContentSubresourceFilterThrottleManager;
  34. class ContentSubresourceFilterWebContentsHelper;
  35. class PageLoadStatistics;
  36. class ProfileInteractionManager;
  37. class SubresourceFilterProfileContext;
  38. // This enum backs a histogram. Make sure new elements are only added to the
  39. // end. Keep histograms.xml up to date with any changes.
  40. enum class SubresourceFilterAction {
  41. // Standard UI shown. On Desktop this is in the omnibox,
  42. // On Android, it is an infobar.
  43. kUIShown = 0,
  44. // The UI was suppressed due to "smart" logic which tries not to spam the UI
  45. // on navigations on the same origin within a certain time.
  46. kUISuppressed = 1,
  47. // On Desktop, this is a bubble. On Android it is an
  48. // expanded infobar.
  49. kDetailsShown = 2,
  50. kClickedLearnMore = 3,
  51. // Logged when the user presses "Always allow ads" scoped to a particular
  52. // site. Does not count manual changes to content settings.
  53. kAllowlistedSite = 4,
  54. // Logged when a devtools message arrives notifying us to force activation in
  55. // this web contents.
  56. kForcedActivationEnabled = 5,
  57. kMaxValue = kForcedActivationEnabled
  58. };
  59. // The ContentSubresourceFilterThrottleManager manages NavigationThrottles in
  60. // order to calculate frame activation states and subframe navigation filtering,
  61. // within a given Page. It contains a mapping of all activated
  62. // RenderFrameHosts, along with their associated DocumentSubresourceFilters.
  63. //
  64. // This class is created for each Page that is a "subresource filter root".
  65. // Most Pages are subresource filter roots so that each of (e.g. primary page,
  66. // prerender, BFCache'd page, etc.) uses its own separate and independent
  67. // subresource filter (e.g. each computes main frame activation separately).
  68. // Fenced frames are an exception. A fenced frame does create a separate Page
  69. // but is considered a "subresource filter child" of its embedder;
  70. // behaviorally, the subresource filter treats it like a regular iframe.
  71. // Portals also have their own Page but their behavior hasn't been considered
  72. // in detail yet; they are currently considered a root. See
  73. // IsInSubresourceFilterRoot in
  74. // content_subresource_filter_web_contents_helper.cc.
  75. //
  76. // Since this class is associated with a Page, cross document navigation to a
  77. // new Page will create a new instance of this class.
  78. //
  79. // Instances of this class are created by the
  80. // ContentSubresourceFilterWebContentsHelper class, of which there is 1 per
  81. // WebContents, on navigation starts that will create a new eligible Page. This
  82. // class is initially owned by the NavigationHandle that creates it. If the
  83. // navigation commits, this class will be transferred to be owned by the Page
  84. // it is associated with. Otherwise it will be destroyed with the
  85. // NavigationHandle.
  86. //
  87. // TODO(bokan): The lifetime management and observer pattern seems like it will
  88. // be common to all features that want to observe events and track state on a
  89. // per Page basis. The ContentSubresourceFilterWebContentsHelper pattern or
  90. // something like it should be wrapped up into a common and reusable //content
  91. // API. See:
  92. // https://docs.google.com/document/d/1p-IXk8hI5ucWRf5vJEi9K_YvJXsTr8kbvzGrjMcALDE/edit?usp=sharing
  93. class ContentSubresourceFilterThrottleManager
  94. : public base::SupportsUserData::Data,
  95. public mojom::SubresourceFilterHost {
  96. public:
  97. static const int kUserDataKey = 0;
  98. // Binds a remote in the given RenderFrame to the correct
  99. // ContentSubresourceFilterThrottleManager in the browser.
  100. static void BindReceiver(mojo::PendingAssociatedReceiver<
  101. mojom::SubresourceFilterHost> pending_receiver,
  102. content::RenderFrameHost* render_frame_host);
  103. // Creates a ThrottleManager instance from the given parameters.
  104. // NOTE: Short-circuits out if the kSafeBrowsingSubresourceFilter feature is
  105. // not enabled.
  106. static std::unique_ptr<ContentSubresourceFilterThrottleManager>
  107. CreateForNewPage(
  108. SubresourceFilterProfileContext* profile_context,
  109. scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
  110. database_manager,
  111. VerifiedRulesetDealer::Handle* dealer_handle,
  112. ContentSubresourceFilterWebContentsHelper& web_contents_helper,
  113. content::NavigationHandle& initiating_navigation_handle);
  114. // Since the throttle manager is created for a page-creating navigation, then
  115. // transferred onto the page once created, it is accessible in both
  116. // navigation and post-navigation contexts. Once a throttle-manager-holding
  117. // page is created, the throttle manager will be transferred into its user
  118. // data. FromPage will retrieve the throttle manager from the given `page`.
  119. // Note: a fenced frame page will not have a throttle manager so this will
  120. // return nullptr in that case.
  121. static ContentSubresourceFilterThrottleManager* FromPage(content::Page& page);
  122. // FromNavigationHandle will retrieve a throttle manager that should be used
  123. // for the given `navigation_handle`. This is a bit more subtle than FromPage
  124. // as only those navigations that create a throttle-manager-holding page
  125. // (i.e. currently all non-fenced frame pages) will store a throttle manager,
  126. // that is: main-frame, cross-document navigations that are not making an
  127. // existing page primary. In other cases, FromNavigationHandle will look up
  128. // the throttle manager from the page it is navigating in. This cannot (will
  129. // DCHECK) be used for prerendering or BFCache activating navigations because
  130. // which page to get a throttle manager from is ambiguous: the navigation
  131. // occurs in the primary frame tree but the non-primary page is the resulting
  132. // page.
  133. static ContentSubresourceFilterThrottleManager* FromNavigationHandle(
  134. content::NavigationHandle& navigation_handle);
  135. ContentSubresourceFilterThrottleManager(
  136. SubresourceFilterProfileContext* profile_context,
  137. scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
  138. database_manager,
  139. VerifiedRulesetDealer::Handle* dealer_handle,
  140. ContentSubresourceFilterWebContentsHelper& web_contents_helper,
  141. content::NavigationHandle& initiating_navigation_handle);
  142. ~ContentSubresourceFilterThrottleManager() override;
  143. // Disallow copy and assign.
  144. ContentSubresourceFilterThrottleManager(
  145. const ContentSubresourceFilterThrottleManager&) = delete;
  146. ContentSubresourceFilterThrottleManager& operator=(
  147. const ContentSubresourceFilterThrottleManager&) = delete;
  148. // This method inspects `navigation_handle` and attaches navigation throttles
  149. // appropriately, based on the current state of frame activation.
  150. //
  151. // 1. Subframe navigation filtering throttles are appended if the parent
  152. // frame is activated.
  153. // 2. Activation state computing throttles are appended if either the
  154. // navigation is a main frame navigation, or if the parent frame is activated.
  155. //
  156. // Note that there is currently no constraints on the ordering of throttles.
  157. void MaybeAppendNavigationThrottles(
  158. content::NavigationHandle* navigation_handle,
  159. std::vector<std::unique_ptr<content::NavigationThrottle>>* throttles);
  160. PageLoadStatistics* page_load_statistics() const { return statistics_.get(); }
  161. ProfileInteractionManager* profile_interaction_manager_for_testing() {
  162. return profile_interaction_manager_.get();
  163. }
  164. VerifiedRuleset::Handle* ruleset_handle_for_testing() {
  165. return ruleset_handle_.get();
  166. }
  167. // Returns whether the identified frame is considered to be an ad.
  168. bool IsFrameTaggedAsAd(int frame_tree_node_id) const;
  169. // Returns whether `frame_host` is in a frame considered to be an ad.
  170. bool IsRenderFrameHostTaggedAsAd(content::RenderFrameHost* frame_host) const;
  171. // Returns whether the last navigation resource in the given frame was
  172. // detected to be an ad. A null optional indicates there was no previous
  173. // navigation or the last navigation was not evaluated by the subresource
  174. // filter. Load policy is determined by presence of the navigation url in the
  175. // filter list.
  176. absl::optional<LoadPolicy> LoadPolicyForLastCommittedNavigation(
  177. int frame_tree_node_id) const;
  178. // Called when the user has requested a reload of a page with
  179. // blocked ads (e.g., via an infobar).
  180. void OnReloadRequested();
  181. // Invoked when an ads violation is detected in `rfh`.
  182. void OnAdsViolationTriggered(content::RenderFrameHost* rfh,
  183. mojom::AdsViolation triggered_violation);
  184. static void LogAction(SubresourceFilterAction action);
  185. void SetIsAdFrameForTesting(content::RenderFrameHost* render_frame_host,
  186. bool is_ad_frame);
  187. // Returns the matching FrameAdEvidence for the frame indicated by
  188. // `render_frame_host` or `absl::nullopt` if there is none (i.e. the frame is
  189. // a main frame, or no navigation or commit has yet occurred and no evidence
  190. // has been reported by the renderer).
  191. absl::optional<blink::FrameAdEvidence> GetAdEvidenceForFrame(
  192. content::RenderFrameHost* render_frame_host);
  193. protected:
  194. // These look like WebContentsObserver overrides but they are not, they're
  195. // called explicitly from the WebContentsHelper, which is a
  196. // WebContentsObserver, but only for the appropriate throttle manager.
  197. void RenderFrameDeleted(content::RenderFrameHost* frame_host);
  198. void FrameDeleted(int frame_tree_node_id);
  199. // "InFrame" here means that the navigation doesn't move a page between frame
  200. // trees. i.e. it is not a prerender activation.
  201. void ReadyToCommitInFrameNavigation(
  202. content::NavigationHandle* navigation_handle);
  203. void DidFinishInFrameNavigation(content::NavigationHandle* navigation_handle,
  204. bool is_initial_navigation);
  205. void DidFinishLoad(content::RenderFrameHost* render_frame_host,
  206. const GURL& validated_url);
  207. void DidBecomePrimaryPage();
  208. // Called when this manager is moved from a NavigationHandle to a Page. In
  209. // most cases this will be the Page of the RenderFrameHost the main-frame
  210. // navigation is committing into. However, for non-committing, initial
  211. // navigations this can be the initial RFH's Page. This is only called once
  212. // by the page that is associated with the throttle manager (e.g. a fenced
  213. // frame Page doesn't own a throttle manager)
  214. void OnPageCreated(content::Page& page);
  215. // Similar to above, these are called from the WebContentsHelper which is a
  216. // SubresourceFilterObserver.
  217. void OnPageActivationComputed(content::NavigationHandle* navigation_handle,
  218. const mojom::ActivationState& activation_state);
  219. void OnSubframeNavigationEvaluated(
  220. content::NavigationHandle* navigation_handle,
  221. LoadPolicy load_policy);
  222. private:
  223. friend ContentSubresourceFilterWebContentsHelper;
  224. FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
  225. SubframeNavigationTaggedAsAdByRenderer);
  226. FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
  227. GrandchildNavigationTaggedAsAdByRenderer);
  228. FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
  229. AdTagCarriesAcrossProcesses);
  230. FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
  231. FirstDisallowedLoadCalledOutOfOrder);
  232. std::unique_ptr<SubframeNavigationFilteringThrottle>
  233. MaybeCreateChildFrameNavigationFilteringThrottle(
  234. content::NavigationHandle* navigation_handle);
  235. std::unique_ptr<ActivationStateComputingNavigationThrottle>
  236. MaybeCreateActivationStateComputingThrottle(
  237. content::NavigationHandle* navigation_handle);
  238. // Will return nullptr if the parent frame of this navigation is not
  239. // activated (and therefore has no subresource filter).
  240. AsyncDocumentSubresourceFilter* GetParentFrameFilter(
  241. content::NavigationHandle* child_frame_navigation);
  242. // Returns nullptr if the frame is not activated (and therefore has no
  243. // subresource filter).
  244. AsyncDocumentSubresourceFilter* GetFrameFilter(
  245. content::RenderFrameHost* frame_host);
  246. // Returns the activation state of the frame's filter. If the frame is not
  247. // activated (and therefore has no subresource filter), returns absl::nullopt.
  248. const absl::optional<subresource_filter::mojom::ActivationState>
  249. GetFrameActivationState(content::RenderFrameHost* frame_host);
  250. // Calls MaybeShowNotification on `profile_interaction_manager_` at most once
  251. // per committed, non-same-page navigation in the main frame. `frame_host`
  252. // specifies the frame that blocked the subresource.
  253. void MaybeShowNotification(content::RenderFrameHost* frame_host);
  254. VerifiedRuleset::Handle* EnsureRulesetHandle();
  255. void DestroyRulesetHandleIfNoLongerUsed();
  256. // Prefer the NavigationHandle version where possible as there are better
  257. // guard-rails for deriving the correct frame in edge cases.
  258. blink::FrameAdEvidence& EnsureFrameAdEvidence(
  259. content::NavigationHandle* navigation_handle);
  260. blink::FrameAdEvidence& EnsureFrameAdEvidence(
  261. content::RenderFrameHost* render_frame_host);
  262. blink::FrameAdEvidence& EnsureFrameAdEvidence(int frame_tree_node_id,
  263. int parent_frame_tree_node_id);
  264. mojom::ActivationState ActivationStateForNextCommittedLoad(
  265. content::NavigationHandle* navigation_handle);
  266. // Registers `render_frame_host` as an ad frame. If the frame later moves to
  267. // a new process its RenderHost will be told that it's an ad.
  268. void OnFrameIsAdSubframe(content::RenderFrameHost* render_frame_host);
  269. // Registers `frame_host` as a frame that was created by ad script.
  270. void OnChildFrameWasCreatedByAdScript(content::RenderFrameHost* frame_host);
  271. // mojom::SubresourceFilterHost:
  272. void DidDisallowFirstSubresource() override;
  273. void FrameIsAdSubframe() override;
  274. void SubframeWasCreatedByAdScript() override;
  275. void AdScriptDidCreateFencedFrame(
  276. const blink::RemoteFrameToken& placeholder_token) override;
  277. void SetDocumentLoadStatistics(
  278. mojom::DocumentLoadStatisticsPtr statistics) override;
  279. void OnAdsViolationTriggered(mojom::AdsViolation violation) override;
  280. // Gets a filter for the navigation from `throttle`, creates and returns a new
  281. // filter, or returns `nullptr`. Also updates `frame_host_filter_map_` as
  282. // appropriate. `frame_host` is provided as `navigation_handle`'s getter
  283. // cannot be used when the navigation has not committed.
  284. // `did_inherit_opener_activation` will be set according to whether the
  285. // activation was inherited from the frame's same-origin opener.
  286. AsyncDocumentSubresourceFilter* FilterForFinishedNavigation(
  287. content::NavigationHandle* navigation_handle,
  288. ActivationStateComputingNavigationThrottle* throttle,
  289. content::RenderFrameHost* frame_host,
  290. bool& did_inherit_opener_activation);
  291. void RecordUmaHistogramsForRootNavigation(
  292. content::NavigationHandle* navigation_handle,
  293. const mojom::ActivationLevel& activation_level,
  294. bool did_inherit_opener_activation);
  295. void RecordExperimentalUmaHistogramsForNavigation(
  296. content::NavigationHandle* navigation_handle,
  297. bool passed_through_ready_to_commit);
  298. // Sets whether the frame is considered an ad subframe. If the value has
  299. // changed, we also update the replication state and inform observers.
  300. void SetIsAdFrame(content::RenderFrameHost* render_frame_host,
  301. bool is_ad_frame);
  302. // For each RenderFrameHost where the last committed load (or the initial load
  303. // if no committed load has occurred) has subresource filtering activated,
  304. // owns the corresponding AsyncDocumentSubresourceFilter.
  305. std::map<content::RenderFrameHost*,
  306. std::unique_ptr<AsyncDocumentSubresourceFilter>>
  307. frame_host_filter_map_;
  308. // For each ongoing navigation that requires activation state computation,
  309. // keeps track of the throttle that is carrying out that computation, so that
  310. // the result can be retrieved when the navigation is ready to commit. Keyed
  311. // by navigation id.
  312. std::map<int64_t, ActivationStateComputingNavigationThrottle*>
  313. ongoing_activation_throttles_;
  314. // The set of navigations that have passed through ReadyToCommitNavigation,
  315. // but haven't yet passed through DidFinishNavigation. Keyed by navigation id.
  316. base::flat_set<int64_t> ready_to_commit_navigations_;
  317. // Set of frames that have been identified as ads, identified by FrameTreeNode
  318. // ID. A RenderFrameHost is an ad subframe iff the FrameAdEvidence
  319. // corresponding to the frame indicates that it is.
  320. base::flat_set<int> ad_frames_;
  321. // Map of subframes, keyed by FrameTreeNode ID, with value being the evidence
  322. // for or against the frames being ads. This evidence is updated whenever a
  323. // navigation's LoadPolicy is calculated.
  324. std::map<int, blink::FrameAdEvidence> tracked_ad_evidence_;
  325. // Map of frames whose navigations have been identified as ads, keyed by
  326. // FrameTreeNode ID. Contains information on the most current completed
  327. // navigation for any given frames. If a frame is not present in the map, it
  328. // has not had a navigation evaluated by the filter list.
  329. std::map<int, LoadPolicy> navigation_load_policies_;
  330. // Receiver set for all RenderFrames in this throttle manager's page.
  331. content::RenderFrameHostReceiverSet<mojom::SubresourceFilterHost> receiver_;
  332. // Lazily instantiated in EnsureRulesetHandle when the first page level
  333. // activation is triggered. Will go away when there are no more activated
  334. // RenderFrameHosts (i.e. activated_frame_hosts_ is empty).
  335. std::unique_ptr<VerifiedRuleset::Handle> ruleset_handle_;
  336. std::unique_ptr<PageLoadStatistics> statistics_;
  337. // True if the current committed main frame load in this WebContents has
  338. // notified the delegate that a subresource was disallowed. The callback
  339. // should only be called at most once per main frame load.
  340. bool current_committed_load_has_notified_disallowed_load_ = false;
  341. // This member outlives this class.
  342. raw_ptr<VerifiedRulesetDealer::Handle> dealer_handle_;
  343. scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager_;
  344. std::unique_ptr<ProfileInteractionManager> profile_interaction_manager_;
  345. // Unowned since the throttle manager cannot outlive the Page that owns it.
  346. // The throttle manager is held as user data first on NavigationHandle, then
  347. // transferred to Page once it is created. Once the Page is created and this
  348. // class transferred onto it (in ContentSubresourceFilterWebContentsHelper)
  349. // we'll set this member to point to it.
  350. raw_ptr<content::Page> page_ = nullptr;
  351. // The helper class is attached to the WebContents so it is guaranteed to
  352. // outlive this class which is owned by either a Page or NavigationHandle in
  353. // the WebContents.
  354. ContentSubresourceFilterWebContentsHelper& web_contents_helper_;
  355. base::WeakPtrFactory<ContentSubresourceFilterThrottleManager>
  356. weak_ptr_factory_{this};
  357. };
  358. } // namespace subresource_filter
  359. #endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_THROTTLE_MANAGER_H_