subresource_filter_browsertest.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. // Copyright 2020 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. #include "base/json/json_reader.h"
  5. #include "base/test/scoped_feature_list.h"
  6. #include "base/test/simple_test_clock.h"
  7. #include "build/build_config.h"
  8. #include "components/content_settings/core/browser/host_content_settings_map.h"
  9. #include "components/subresource_filter/content/browser/ads_intervention_manager.h"
  10. #include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
  11. #include "components/subresource_filter/content/browser/ruleset_service.h"
  12. #include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h"
  13. #include "components/subresource_filter/content/browser/subresource_filter_profile_context.h"
  14. #include "components/subresource_filter/core/browser/subresource_filter_constants.h"
  15. #include "components/subresource_filter/core/browser/subresource_filter_features.h"
  16. #include "components/ukm/test_ukm_recorder.h"
  17. #include "content/public/test/browser_test_utils.h"
  18. #include "content/public/test/test_navigation_observer.h"
  19. #include "services/metrics/public/cpp/ukm_builders.h"
  20. #include "testing/gtest/include/gtest/gtest.h"
  21. #include "ui/base/resource/resource_bundle.h"
  22. #include "weblayer/browser/browser_process.h"
  23. #include "weblayer/browser/host_content_settings_map_factory.h"
  24. #include "weblayer/browser/subresource_filter_profile_context_factory.h"
  25. #include "weblayer/browser/tab_impl.h"
  26. #include "weblayer/grit/weblayer_resources.h"
  27. #include "weblayer/shell/browser/shell.h"
  28. #include "weblayer/test/subresource_filter_browser_test_harness.h"
  29. #include "weblayer/test/weblayer_browser_test_utils.h"
  30. #if BUILDFLAG(IS_ANDROID)
  31. #include "components/infobars/android/infobar_android.h" // nogncheck
  32. #include "components/infobars/content/content_infobar_manager.h"
  33. #include "components/infobars/core/infobar_manager.h" // nogncheck
  34. #endif
  35. namespace weblayer {
  36. namespace {
  37. const char kAdsInterventionRecordedHistogram[] =
  38. "SubresourceFilter.PageLoad.AdsInterventionTriggered";
  39. const char kTimeSinceAdsInterventionTriggeredHistogram[] =
  40. "SubresourceFilter.PageLoad."
  41. "TimeSinceLastActiveAdsIntervention";
  42. const char kSubresourceFilterActionsHistogram[] = "SubresourceFilter.Actions2";
  43. #if BUILDFLAG(IS_ANDROID)
  44. class TestInfoBarManagerObserver : public infobars::InfoBarManager::Observer {
  45. public:
  46. TestInfoBarManagerObserver() = default;
  47. ~TestInfoBarManagerObserver() override = default;
  48. void OnInfoBarAdded(infobars::InfoBar* infobar) override {
  49. if (on_infobar_added_callback_)
  50. std::move(on_infobar_added_callback_).Run();
  51. }
  52. void OnInfoBarRemoved(infobars::InfoBar* infobar, bool animate) override {
  53. if (on_infobar_removed_callback_)
  54. std::move(on_infobar_removed_callback_).Run();
  55. }
  56. void set_on_infobar_added_callback(base::OnceClosure callback) {
  57. on_infobar_added_callback_ = std::move(callback);
  58. }
  59. void set_on_infobar_removed_callback(base::OnceClosure callback) {
  60. on_infobar_removed_callback_ = std::move(callback);
  61. }
  62. private:
  63. base::OnceClosure on_infobar_added_callback_;
  64. base::OnceClosure on_infobar_removed_callback_;
  65. };
  66. #endif // if BUILDFLAG(IS_ANDROID)
  67. } // namespace
  68. // Tests that the ruleset service is available.
  69. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, RulesetService) {
  70. EXPECT_NE(BrowserProcess::GetInstance()->subresource_filter_ruleset_service(),
  71. nullptr);
  72. }
  73. // Tests that the expected ruleset data was published as part of startup.
  74. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, RulesArePublished) {
  75. auto* ruleset_service =
  76. BrowserProcess::GetInstance()->subresource_filter_ruleset_service();
  77. auto ruleset_version = ruleset_service->GetMostRecentlyIndexedVersion();
  78. EXPECT_TRUE(ruleset_version.IsValid());
  79. std::string most_recently_indexed_content_version =
  80. ruleset_version.content_version;
  81. std::string packaged_ruleset_manifest_string =
  82. ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
  83. IDR_SUBRESOURCE_FILTER_UNINDEXED_RULESET_MANIFEST_JSON);
  84. auto packaged_ruleset_manifest =
  85. base::JSONReader::Read(packaged_ruleset_manifest_string);
  86. std::string* packaged_content_version =
  87. packaged_ruleset_manifest->FindStringKey("version");
  88. EXPECT_EQ(most_recently_indexed_content_version, *packaged_content_version);
  89. }
  90. // The below test is restricted to Android as it tests activation of the
  91. // subresource filter in its default production configuration and WebLayer
  92. // currently has a safe browsing database available in production only on
  93. // Android; the safe browsing database being non-null is a prerequisite for
  94. // subresource filter operation.
  95. #if BUILDFLAG(IS_ANDROID)
  96. // Tests that page activation state is computed as part of a pageload.
  97. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
  98. PageActivationStateComputed) {
  99. // Set up prereqs.
  100. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  101. content::WebContentsConsoleObserver console_observer(web_contents);
  102. console_observer.SetPattern(subresource_filter::kActivationConsoleMessage);
  103. GURL test_url(embedded_test_server()->GetURL("/simple_page.html"));
  104. subresource_filter::TestSubresourceFilterObserver observer(web_contents);
  105. absl::optional<subresource_filter::mojom::ActivationLevel> page_activation =
  106. observer.GetPageActivation(test_url);
  107. EXPECT_FALSE(page_activation);
  108. // Verify that a navigation results in both (a) the page activation level
  109. // being computed, and (b) the result of that computation being the default
  110. // level of "dry run" due to AdTagging.
  111. NavigateAndWaitForCompletion(test_url, shell());
  112. page_activation = observer.GetPageActivation(test_url);
  113. EXPECT_TRUE(page_activation);
  114. EXPECT_EQ(subresource_filter::mojom::ActivationLevel::kDryRun,
  115. page_activation.value());
  116. EXPECT_TRUE(console_observer.messages().empty());
  117. }
  118. #endif // (OS_ANDROID)
  119. // Verifies that subframes that are flagged by the subresource filter ruleset
  120. // are blocked from loading on activated URLs.
  121. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
  122. DisallowedSubframeURLBlockedOnActivatedURL) {
  123. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  124. content::WebContentsConsoleObserver console_observer(web_contents);
  125. console_observer.SetPattern(subresource_filter::kActivationConsoleMessage);
  126. GURL test_url(embedded_test_server()->GetURL(
  127. "/subresource_filter/frame_with_included_script.html"));
  128. subresource_filter::TestSubresourceFilterObserver observer(web_contents);
  129. absl::optional<subresource_filter::mojom::ActivationLevel> page_activation =
  130. observer.GetPageActivation(test_url);
  131. EXPECT_FALSE(page_activation);
  132. ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
  133. // Verify that the "ad" subframe is loaded if it is not flagged by the
  134. // ruleset.
  135. ASSERT_NO_FATAL_FAILURE(SetRulesetToDisallowURLsWithPathSuffix(
  136. "suffix-that-does-not-match-anything"));
  137. NavigateAndWaitForCompletion(test_url, shell());
  138. // The subresource filter should have been activated on this navigation...
  139. page_activation = observer.GetPageActivation(test_url);
  140. EXPECT_TRUE(page_activation);
  141. EXPECT_EQ(subresource_filter::mojom::ActivationLevel::kEnabled,
  142. page_activation.value());
  143. console_observer.Wait();
  144. // ... but it should not have blocked the subframe from being loaded.
  145. EXPECT_TRUE(
  146. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  147. // Do a different-document navigation to ensure that that the next navigation
  148. // to |test_url| executes as desired (e.g., to avoid any optimizations from
  149. // being made due to it being a same-document navigation that would interfere
  150. // with the logic of the test). Without this intervening navigation, we have
  151. // seen flake on the Windows trybot that indicates that such optimizations are
  152. // occurring.
  153. NavigateAndWaitForCompletion(GURL("about:blank"), shell());
  154. EXPECT_FALSE(
  155. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  156. // Verify that the "ad" subframe is blocked if it is flagged by the
  157. // ruleset.
  158. ASSERT_NO_FATAL_FAILURE(
  159. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  160. NavigateAndWaitForCompletion(test_url, shell());
  161. EXPECT_FALSE(
  162. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  163. // Do a different-document navigation to ensure that that the next navigation
  164. // to |test_url| executes as desired (e.g., to avoid any optimizations from
  165. // being made due to it being a same-document navigation that would interfere
  166. // with the logic of the test). Without this intervening navigation, we have
  167. // seen flake on the Windows trybot that indicates that such optimizations are
  168. // occurring.
  169. NavigateAndWaitForCompletion(GURL("about:blank"), shell());
  170. EXPECT_FALSE(
  171. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  172. // The main frame document should never be filtered.
  173. SetRulesetToDisallowURLsWithPathSuffix("frame_with_included_script.html");
  174. NavigateAndWaitForCompletion(test_url, shell());
  175. EXPECT_TRUE(
  176. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  177. }
  178. // Verifies that subframes are not blocked on non-activated URLs.
  179. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
  180. DisallowedSubframeURLNotBlockedOnNonActivatedURL) {
  181. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  182. GURL test_url(embedded_test_server()->GetURL(
  183. "/subresource_filter/frame_with_included_script.html"));
  184. // Verify that the "ad" subframe is loaded if it is not flagged by the
  185. // ruleset.
  186. ASSERT_NO_FATAL_FAILURE(SetRulesetToDisallowURLsWithPathSuffix(
  187. "suffix-that-does-not-match-anything"));
  188. NavigateAndWaitForCompletion(test_url, shell());
  189. EXPECT_TRUE(
  190. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  191. // Verify that the "ad" subframe is loaded if even it is flagged by the
  192. // ruleset as the URL is not activated.
  193. ASSERT_NO_FATAL_FAILURE(
  194. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  195. NavigateAndWaitForCompletion(test_url, shell());
  196. EXPECT_TRUE(
  197. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  198. }
  199. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
  200. ContentSettingsAllowlist_DoNotActivate) {
  201. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  202. GURL test_url(embedded_test_server()->GetURL(
  203. "/subresource_filter/frame_with_included_script.html"));
  204. ASSERT_NO_FATAL_FAILURE(
  205. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  206. ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
  207. NavigateAndWaitForCompletion(test_url, shell());
  208. EXPECT_FALSE(
  209. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  210. content::WebContentsConsoleObserver console_observer(web_contents);
  211. console_observer.SetPattern(subresource_filter::kActivationConsoleMessage);
  212. // Simulate explicitly allowlisting via content settings.
  213. HostContentSettingsMap* settings_map =
  214. HostContentSettingsMapFactory::GetForBrowserContext(
  215. web_contents->GetBrowserContext());
  216. settings_map->SetContentSettingDefaultScope(
  217. test_url, test_url, ContentSettingsType::ADS, CONTENT_SETTING_ALLOW);
  218. NavigateAndWaitForCompletion(test_url, shell());
  219. EXPECT_TRUE(
  220. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  221. // No message for allowlisted url.
  222. EXPECT_TRUE(console_observer.messages().empty());
  223. }
  224. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
  225. ContentSettingsAllowlistGlobal_DoNotActivate) {
  226. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  227. GURL test_url(embedded_test_server()->GetURL(
  228. "/subresource_filter/frame_with_included_script.html"));
  229. ASSERT_NO_FATAL_FAILURE(
  230. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  231. ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
  232. NavigateAndWaitForCompletion(test_url, shell());
  233. EXPECT_FALSE(
  234. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  235. content::WebContentsConsoleObserver console_observer(web_contents);
  236. console_observer.SetPattern(subresource_filter::kActivationConsoleMessage);
  237. // Simulate globally allowing ads via content settings.
  238. HostContentSettingsMap* settings_map =
  239. HostContentSettingsMapFactory::GetForBrowserContext(
  240. web_contents->GetBrowserContext());
  241. settings_map->SetDefaultContentSetting(ContentSettingsType::ADS,
  242. CONTENT_SETTING_ALLOW);
  243. NavigateAndWaitForCompletion(test_url, shell());
  244. EXPECT_TRUE(
  245. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  246. // No message for loads that are not activated.
  247. EXPECT_TRUE(console_observer.messages().empty());
  248. }
  249. #if BUILDFLAG(IS_ANDROID)
  250. // Test that the ads blocked infobar is presented when visiting a page where the
  251. // subresource filter blocks resources from being loaded and is removed when
  252. // navigating away.
  253. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, InfoBarPresentation) {
  254. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  255. auto* infobar_manager =
  256. infobars::ContentInfoBarManager::FromWebContents(web_contents);
  257. // Configure the subresource filter to activate on the test URL and to block
  258. // its script from loading.
  259. GURL test_url(embedded_test_server()->GetURL(
  260. "/subresource_filter/frame_with_included_script.html"));
  261. ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
  262. ASSERT_NO_FATAL_FAILURE(
  263. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  264. TestInfoBarManagerObserver infobar_observer;
  265. infobar_manager->AddObserver(&infobar_observer);
  266. base::RunLoop run_loop;
  267. infobar_observer.set_on_infobar_added_callback(run_loop.QuitClosure());
  268. EXPECT_EQ(0u, infobar_manager->infobar_count());
  269. // Navigate such that the script is blocked and verify that the ads blocked
  270. // infobar is presented.
  271. NavigateAndWaitForCompletion(test_url, shell());
  272. run_loop.Run();
  273. EXPECT_EQ(1u, infobar_manager->infobar_count());
  274. auto* infobar =
  275. static_cast<infobars::InfoBarAndroid*>(infobar_manager->infobar_at(0));
  276. EXPECT_TRUE(infobar->HasSetJavaInfoBar());
  277. EXPECT_EQ(infobar->delegate()->GetIdentifier(),
  278. infobars::InfoBarDelegate::ADS_BLOCKED_INFOBAR_DELEGATE_ANDROID);
  279. // Navigate away and verify that the infobar is removed.
  280. base::RunLoop run_loop2;
  281. infobar_observer.set_on_infobar_removed_callback(run_loop2.QuitClosure());
  282. NavigateAndWaitForCompletion(GURL("about:blank"), shell());
  283. run_loop2.Run();
  284. EXPECT_EQ(0u, infobar_manager->infobar_count());
  285. infobar_manager->RemoveObserver(&infobar_observer);
  286. }
  287. #endif
  288. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
  289. ContentSettingsAllowlistViaReload_DoNotActivate) {
  290. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  291. ASSERT_NO_FATAL_FAILURE(
  292. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  293. GURL test_url(embedded_test_server()->GetURL(
  294. "/subresource_filter/frame_with_included_script.html"));
  295. ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
  296. NavigateAndWaitForCompletion(test_url, shell());
  297. EXPECT_FALSE(
  298. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  299. // Allowlist via a reload.
  300. content::TestNavigationObserver navigation_observer(web_contents, 1);
  301. GetPrimaryPageThrottleManager()->OnReloadRequested();
  302. navigation_observer.Wait();
  303. EXPECT_TRUE(
  304. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  305. }
  306. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
  307. ContentSettingsAllowlistViaReload_AllowlistIsByDomain) {
  308. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  309. ASSERT_NO_FATAL_FAILURE(
  310. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  311. GURL test_url(embedded_test_server()->GetURL(
  312. "/subresource_filter/frame_with_included_script.html"));
  313. ActivateSubresourceFilterInWebContentsForURL(web_contents, test_url);
  314. NavigateAndWaitForCompletion(test_url, shell());
  315. EXPECT_FALSE(
  316. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  317. // Allowlist via a reload.
  318. content::TestNavigationObserver navigation_observer(web_contents, 1);
  319. GetPrimaryPageThrottleManager()->OnReloadRequested();
  320. navigation_observer.Wait();
  321. EXPECT_TRUE(
  322. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  323. // Another navigation to the same domain should be allowed too.
  324. NavigateAndWaitForCompletion(
  325. embedded_test_server()->GetURL(
  326. "/subresource_filter/frame_with_included_script.html?query"),
  327. shell());
  328. EXPECT_TRUE(
  329. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  330. // A cross site blocklisted navigation should stay activated, however.
  331. GURL a_url(embedded_test_server()->GetURL(
  332. "a.com", "/subresource_filter/frame_with_included_script.html"));
  333. ActivateSubresourceFilterInWebContentsForURL(web_contents, a_url);
  334. NavigateAndWaitForCompletion(a_url, shell());
  335. EXPECT_FALSE(
  336. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  337. }
  338. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
  339. AdsInterventionEnforced_PageActivated) {
  340. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  341. base::HistogramTester histogram_tester;
  342. ukm::TestAutoSetUkmRecorder ukm_recorder;
  343. auto* ads_intervention_manager =
  344. SubresourceFilterProfileContextFactory::GetForBrowserContext(
  345. web_contents->GetBrowserContext())
  346. ->ads_intervention_manager();
  347. auto test_clock = std::make_unique<base::SimpleTestClock>();
  348. ads_intervention_manager->set_clock_for_testing(test_clock.get());
  349. const GURL url(embedded_test_server()->GetURL(
  350. "/subresource_filter/frame_with_included_script.html"));
  351. ASSERT_NO_FATAL_FAILURE(
  352. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  353. // Should not trigger activation as the URL is not on the blocklist and
  354. // has no active ads interventions.
  355. NavigateAndWaitForCompletion(url, shell());
  356. EXPECT_TRUE(
  357. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  358. histogram_tester.ExpectTotalCount(kAdsInterventionRecordedHistogram, 0);
  359. histogram_tester.ExpectTotalCount(kTimeSinceAdsInterventionTriggeredHistogram,
  360. 0);
  361. auto entries = ukm_recorder.GetEntriesByName(
  362. ukm::builders::AdsIntervention_LastIntervention::kEntryName);
  363. EXPECT_EQ(0u, entries.size());
  364. // Trigger an ads violation and renavigate the page. Should trigger
  365. // subresource filter activation.
  366. GetPrimaryPageThrottleManager()->OnAdsViolationTriggered(
  367. web_contents->GetPrimaryMainFrame(),
  368. subresource_filter::mojom::AdsViolation::kMobileAdDensityByHeightAbove30);
  369. NavigateAndWaitForCompletion(url, shell());
  370. EXPECT_FALSE(
  371. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  372. histogram_tester.ExpectBucketCount(
  373. kAdsInterventionRecordedHistogram,
  374. static_cast<int>(subresource_filter::mojom::AdsViolation::
  375. kMobileAdDensityByHeightAbove30),
  376. 1);
  377. histogram_tester.ExpectBucketCount(
  378. kTimeSinceAdsInterventionTriggeredHistogram, 0, 1);
  379. entries = ukm_recorder.GetEntriesByName(
  380. ukm::builders::AdsIntervention_LastIntervention::kEntryName);
  381. EXPECT_EQ(1u, entries.size());
  382. ukm_recorder.ExpectEntryMetric(
  383. entries.front(),
  384. ukm::builders::AdsIntervention_LastIntervention::kInterventionTypeName,
  385. static_cast<int>(subresource_filter::mojom::AdsViolation::
  386. kMobileAdDensityByHeightAbove30));
  387. ukm_recorder.ExpectEntryMetric(
  388. entries.front(),
  389. ukm::builders::AdsIntervention_LastIntervention::kInterventionStatusName,
  390. static_cast<int>(AdsInterventionStatus::kBlocking));
  391. // Advance the clock to clear the intervention.
  392. test_clock->Advance(subresource_filter::kAdsInterventionDuration.Get());
  393. NavigateAndWaitForCompletion(url, shell());
  394. EXPECT_TRUE(
  395. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  396. histogram_tester.ExpectBucketCount(
  397. kAdsInterventionRecordedHistogram,
  398. static_cast<int>(subresource_filter::mojom::AdsViolation::
  399. kMobileAdDensityByHeightAbove30),
  400. 1);
  401. histogram_tester.ExpectBucketCount(
  402. kTimeSinceAdsInterventionTriggeredHistogram,
  403. subresource_filter::kAdsInterventionDuration.Get().InHours(), 1);
  404. entries = ukm_recorder.GetEntriesByName(
  405. ukm::builders::AdsIntervention_LastIntervention::kEntryName);
  406. EXPECT_EQ(2u, entries.size());
  407. // One of the entries is kBlocking, verify that the other is kExpired after
  408. // the intervention is cleared.
  409. EXPECT_TRUE(
  410. (*ukm_recorder.GetEntryMetric(
  411. entries.front(), ukm::builders::AdsIntervention_LastIntervention::
  412. kInterventionStatusName) ==
  413. static_cast<int>(AdsInterventionStatus::kExpired)) ||
  414. (*ukm_recorder.GetEntryMetric(
  415. entries.back(), ukm::builders::AdsIntervention_LastIntervention::
  416. kInterventionStatusName) ==
  417. static_cast<int>(AdsInterventionStatus::kExpired)));
  418. }
  419. IN_PROC_BROWSER_TEST_F(
  420. SubresourceFilterBrowserTest,
  421. MultipleAdsInterventions_PageActivationClearedAfterFirst) {
  422. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  423. base::HistogramTester histogram_tester;
  424. ukm::TestAutoSetUkmRecorder ukm_recorder;
  425. auto* ads_intervention_manager =
  426. SubresourceFilterProfileContextFactory::GetForBrowserContext(
  427. web_contents->GetBrowserContext())
  428. ->ads_intervention_manager();
  429. auto test_clock = std::make_unique<base::SimpleTestClock>();
  430. ads_intervention_manager->set_clock_for_testing(test_clock.get());
  431. const GURL url(embedded_test_server()->GetURL(
  432. "/subresource_filter/frame_with_included_script.html"));
  433. ASSERT_NO_FATAL_FAILURE(
  434. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  435. // Should not trigger activation as the URL is not on the blocklist and
  436. // has no active ads interventions.
  437. NavigateAndWaitForCompletion(url, shell());
  438. EXPECT_TRUE(
  439. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  440. histogram_tester.ExpectTotalCount(kAdsInterventionRecordedHistogram, 0);
  441. histogram_tester.ExpectTotalCount(kTimeSinceAdsInterventionTriggeredHistogram,
  442. 0);
  443. auto entries = ukm_recorder.GetEntriesByName(
  444. ukm::builders::AdsIntervention_LastIntervention::kEntryName);
  445. EXPECT_EQ(0u, entries.size());
  446. // Trigger an ads violation and renavigate the page. Should trigger
  447. // subresource filter activation.
  448. GetPrimaryPageThrottleManager()->OnAdsViolationTriggered(
  449. web_contents->GetPrimaryMainFrame(),
  450. subresource_filter::mojom::AdsViolation::kMobileAdDensityByHeightAbove30);
  451. NavigateAndWaitForCompletion(url, shell());
  452. EXPECT_FALSE(
  453. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  454. histogram_tester.ExpectBucketCount(
  455. kAdsInterventionRecordedHistogram,
  456. static_cast<int>(subresource_filter::mojom::AdsViolation::
  457. kMobileAdDensityByHeightAbove30),
  458. 1);
  459. histogram_tester.ExpectBucketCount(
  460. kTimeSinceAdsInterventionTriggeredHistogram, 0, 1);
  461. entries = ukm_recorder.GetEntriesByName(
  462. ukm::builders::AdsIntervention_LastIntervention::kEntryName);
  463. EXPECT_EQ(1u, entries.size());
  464. ukm_recorder.ExpectEntryMetric(
  465. entries.front(),
  466. ukm::builders::AdsIntervention_LastIntervention::kInterventionTypeName,
  467. static_cast<int>(subresource_filter::mojom::AdsViolation::
  468. kMobileAdDensityByHeightAbove30));
  469. ukm_recorder.ExpectEntryMetric(
  470. entries.front(),
  471. ukm::builders::AdsIntervention_LastIntervention::kInterventionStatusName,
  472. static_cast<int>(AdsInterventionStatus::kBlocking));
  473. // Advance the clock by less than kAdsInterventionDuration and trigger another
  474. // intervention. This intervention is a no-op.
  475. test_clock->Advance(subresource_filter::kAdsInterventionDuration.Get() -
  476. base::Minutes(30));
  477. GetPrimaryPageThrottleManager()->OnAdsViolationTriggered(
  478. web_contents->GetPrimaryMainFrame(),
  479. subresource_filter::mojom::AdsViolation::kMobileAdDensityByHeightAbove30);
  480. // Advance the clock to to kAdsInterventionDuration from the first
  481. // intervention, this clear the intervention.
  482. test_clock->Advance(base::Minutes(30));
  483. NavigateAndWaitForCompletion(url, shell());
  484. EXPECT_TRUE(
  485. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  486. histogram_tester.ExpectBucketCount(
  487. kAdsInterventionRecordedHistogram,
  488. static_cast<int>(subresource_filter::mojom::AdsViolation::
  489. kMobileAdDensityByHeightAbove30),
  490. 1);
  491. histogram_tester.ExpectBucketCount(
  492. kTimeSinceAdsInterventionTriggeredHistogram,
  493. subresource_filter::kAdsInterventionDuration.Get().InHours(), 1);
  494. entries = ukm_recorder.GetEntriesByName(
  495. ukm::builders::AdsIntervention_LastIntervention::kEntryName);
  496. EXPECT_EQ(2u, entries.size());
  497. // One of the entries is kBlocking, verify that the other is kExpired after
  498. // the intervention is cleared.
  499. EXPECT_TRUE(
  500. (*ukm_recorder.GetEntryMetric(
  501. entries.front(), ukm::builders::AdsIntervention_LastIntervention::
  502. kInterventionStatusName) ==
  503. static_cast<int>(AdsInterventionStatus::kExpired)) ||
  504. (*ukm_recorder.GetEntryMetric(
  505. entries.back(), ukm::builders::AdsIntervention_LastIntervention::
  506. kInterventionStatusName) ==
  507. static_cast<int>(AdsInterventionStatus::kExpired)));
  508. }
  509. class SubresourceFilterBrowserTestWithoutAdsInterventionEnforcement
  510. : public SubresourceFilterBrowserTest {
  511. public:
  512. SubresourceFilterBrowserTestWithoutAdsInterventionEnforcement() {
  513. feature_list_.InitAndDisableFeature(
  514. subresource_filter::kAdsInterventionsEnforced);
  515. }
  516. private:
  517. base::test::ScopedFeatureList feature_list_;
  518. };
  519. IN_PROC_BROWSER_TEST_F(
  520. SubresourceFilterBrowserTestWithoutAdsInterventionEnforcement,
  521. AdsInterventionNotEnforced_NoPageActivation) {
  522. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  523. base::HistogramTester histogram_tester;
  524. ukm::TestAutoSetUkmRecorder ukm_recorder;
  525. auto* ads_intervention_manager =
  526. SubresourceFilterProfileContextFactory::GetForBrowserContext(
  527. web_contents->GetBrowserContext())
  528. ->ads_intervention_manager();
  529. auto test_clock = std::make_unique<base::SimpleTestClock>();
  530. ads_intervention_manager->set_clock_for_testing(test_clock.get());
  531. const GURL url(embedded_test_server()->GetURL(
  532. "/subresource_filter/frame_with_included_script.html"));
  533. ASSERT_NO_FATAL_FAILURE(
  534. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  535. // Should not trigger activation as the URL is not on the blocklist and
  536. // has no active ads interventions.
  537. NavigateAndWaitForCompletion(url, shell());
  538. EXPECT_TRUE(
  539. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  540. auto entries = ukm_recorder.GetEntriesByName(
  541. ukm::builders::AdsIntervention_LastIntervention::kEntryName);
  542. EXPECT_EQ(0u, entries.size());
  543. // Trigger an ads violation and renavigate to the page. Interventions are not
  544. // enforced so no activation should occur.
  545. GetPrimaryPageThrottleManager()->OnAdsViolationTriggered(
  546. web_contents->GetPrimaryMainFrame(),
  547. subresource_filter::mojom::AdsViolation::kMobileAdDensityByHeightAbove30);
  548. const base::TimeDelta kRenavigationDelay = base::Hours(2);
  549. test_clock->Advance(kRenavigationDelay);
  550. NavigateAndWaitForCompletion(url, shell());
  551. EXPECT_TRUE(
  552. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  553. histogram_tester.ExpectBucketCount(
  554. kAdsInterventionRecordedHistogram,
  555. static_cast<int>(subresource_filter::mojom::AdsViolation::
  556. kMobileAdDensityByHeightAbove30),
  557. 1);
  558. histogram_tester.ExpectBucketCount(
  559. kTimeSinceAdsInterventionTriggeredHistogram, kRenavigationDelay.InHours(),
  560. 1);
  561. entries = ukm_recorder.GetEntriesByName(
  562. ukm::builders::AdsIntervention_LastIntervention::kEntryName);
  563. EXPECT_EQ(1u, entries.size());
  564. ukm_recorder.ExpectEntryMetric(
  565. entries.front(),
  566. ukm::builders::AdsIntervention_LastIntervention::kInterventionTypeName,
  567. static_cast<int>(subresource_filter::mojom::AdsViolation::
  568. kMobileAdDensityByHeightAbove30));
  569. ukm_recorder.ExpectEntryMetric(
  570. entries.front(),
  571. ukm::builders::AdsIntervention_LastIntervention::kInterventionStatusName,
  572. static_cast<int>(AdsInterventionStatus::kWouldBlock));
  573. }
  574. // Test the "smart" UI, aka the logic to hide the UI on subsequent same-domain
  575. // navigations, until a certain time threshold has been reached. This is an
  576. // android-only feature.
  577. IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
  578. DoNotShowUIUntilThresholdReached) {
  579. auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents();
  580. auto* settings_manager =
  581. SubresourceFilterProfileContextFactory::GetForBrowserContext(
  582. web_contents->GetBrowserContext())
  583. ->settings_manager();
  584. settings_manager->set_should_use_smart_ui_for_testing(true);
  585. ASSERT_NO_FATAL_FAILURE(
  586. SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
  587. GURL a_url(embedded_test_server()->GetURL(
  588. "a.com", "/subresource_filter/frame_with_included_script.html"));
  589. GURL b_url(embedded_test_server()->GetURL(
  590. "b.com", "/subresource_filter/frame_with_included_script.html"));
  591. // Test utils only support one blocklisted site at a time.
  592. // TODO(csharrison): Add support for more than one URL.
  593. ActivateSubresourceFilterInWebContentsForURL(web_contents, a_url);
  594. auto test_clock = std::make_unique<base::SimpleTestClock>();
  595. base::SimpleTestClock* raw_clock = test_clock.get();
  596. settings_manager->set_clock_for_testing(std::move(test_clock));
  597. base::HistogramTester histogram_tester;
  598. // First load should trigger the UI.
  599. NavigateAndWaitForCompletion(a_url, shell());
  600. EXPECT_FALSE(
  601. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  602. histogram_tester.ExpectBucketCount(
  603. kSubresourceFilterActionsHistogram,
  604. subresource_filter::SubresourceFilterAction::kUIShown, 1);
  605. histogram_tester.ExpectBucketCount(
  606. kSubresourceFilterActionsHistogram,
  607. subresource_filter::SubresourceFilterAction::kUISuppressed, 0);
  608. // Second load should not trigger the UI, but should still filter content.
  609. NavigateAndWaitForCompletion(a_url, shell());
  610. EXPECT_FALSE(
  611. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  612. histogram_tester.ExpectBucketCount(
  613. kSubresourceFilterActionsHistogram,
  614. subresource_filter::SubresourceFilterAction::kUIShown, 1);
  615. histogram_tester.ExpectBucketCount(
  616. kSubresourceFilterActionsHistogram,
  617. subresource_filter::SubresourceFilterAction::kUISuppressed, 1);
  618. ActivateSubresourceFilterInWebContentsForURL(web_contents, b_url);
  619. // Load to another domain should trigger the UI.
  620. NavigateAndWaitForCompletion(b_url, shell());
  621. EXPECT_FALSE(
  622. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  623. histogram_tester.ExpectBucketCount(
  624. kSubresourceFilterActionsHistogram,
  625. subresource_filter::SubresourceFilterAction::kUIShown, 2);
  626. ActivateSubresourceFilterInWebContentsForURL(web_contents, a_url);
  627. // Fast forward the clock, and a_url should trigger the UI again.
  628. raw_clock->Advance(
  629. subresource_filter::SubresourceFilterContentSettingsManager::
  630. kDelayBeforeShowingInfobarAgain);
  631. NavigateAndWaitForCompletion(a_url, shell());
  632. EXPECT_FALSE(
  633. WasParsedScriptElementLoaded(web_contents->GetPrimaryMainFrame()));
  634. histogram_tester.ExpectBucketCount(
  635. kSubresourceFilterActionsHistogram,
  636. subresource_filter::SubresourceFilterAction::kUIShown, 3);
  637. histogram_tester.ExpectBucketCount(
  638. kSubresourceFilterActionsHistogram,
  639. subresource_filter::SubresourceFilterAction::kUISuppressed, 1);
  640. }
  641. } // namespace weblayer