LeOSium_webview/LeOS/leos/0002-eyeo-beta-118.0.5993.4...

9947 lines
434 KiB
Diff
Raw Normal View History

2023-11-18 11:46:19 +01:00
From: chromium-sdk <project_26591639_bot@noreply.gitlab.com>
Date: Thu, 12 Oct 2023 14:46:02 +0200
Subject: eyeo Browser Ad filtering Solution: Chrome Integration Module
Based on Chromium 118.0.5993.48
Pre-requisites: eyeo Browser Ad filtering Solution: Base Module
---
chrome/app/chrome_main_delegate.cc | 7 +-
chrome/browser/BUILD.gn | 29 ++
chrome/browser/adblock/README.md | 3 +
.../adblock/adblock_content_browser_client.cc | 320 ++++++++++++
.../adblock/adblock_content_browser_client.h | 100 ++++
...adblock_content_browser_client_unittest.cc | 203 ++++++++
.../adblock/adblock_controller_factory.cc | 67 +++
.../adblock/adblock_controller_factory.h | 49 ++
.../adblock_telemetry_service_factory.cc | 63 +++
.../adblock_telemetry_service_factory.h | 51 ++
chrome/browser/adblock/android/BUILD.gn | 68 +++
.../adblock/AdblockControllerTest.java | 43 ++
.../adblock/FilteringConfigurationTest.java | 418 ++++++++++++++++
.../ResourceClassificationNotifierTest.java | 135 +++++
.../adblock/TestPagesCircumventionTest.java | 51 ++
.../browser/adblock/TestPagesCspTest.java | 51 ++
.../adblock/TestPagesElemhideEmuInvTest.java | 48 ++
.../adblock/TestPagesElemhideEmuTest.java | 48 ++
.../adblock/TestPagesElemhideTest.java | 48 ++
.../adblock/TestPagesExceptionTest.java | 100 ++++
.../browser/adblock/TestPagesFilterTest.java | 101 ++++
.../adblock/TestPagesHeaderFilterTest.java | 51 ++
.../browser/adblock/TestPagesHelper.java | 121 +++++
.../browser/adblock/TestPagesRewriteTest.java | 51 ++
.../browser/adblock/TestPagesSiteKeyTest.java | 51 ++
.../adblock/TestPagesSnippetsTest.java | 51 ++
.../adblock/TestPagesWebsocketTest.java | 51 ++
...ontent_security_policy_injector_factory.cc | 69 +++
...content_security_policy_injector_factory.h | 49 ++
.../browser/adblock/element_hider_factory.cc | 63 +++
.../browser/adblock/element_hider_factory.h | 47 ++
.../resource_classification_runner_factory.cc | 71 +++
.../resource_classification_runner_factory.h | 49 ++
.../browser/adblock/session_stats_factory.cc | 64 +++
.../browser/adblock/session_stats_factory.h | 47 ++
.../adblock/sitekey_storage_factory.cc | 59 +++
.../browser/adblock/sitekey_storage_factory.h | 47 ++
...ubscription_persistent_metadata_factory.cc | 63 +++
...subscription_persistent_metadata_factory.h | 49 ++
.../adblock/subscription_service_factory.cc | 66 +++
.../adblock/subscription_service_factory.h | 50 ++
...lock_content_browser_client_browsertest.cc | 125 +++++
.../test/adblock_debug_url_browsertest.cc | 314 ++++++++++++
.../test/adblock_filter_list_browsertest.cc | 260 ++++++++++
...ck_filtering_configurations_browsertest.cc | 459 +++++++++++++++++
...ock_frame_hierarchy_builder_browsertest.cc | 464 ++++++++++++++++++
.../test/adblock_multiple_tabs_browsertest.cc | 160 ++++++
.../test/adblock_non_ascii_browsertest.cc | 78 +++
.../adblock/test/adblock_popup_browsertest.cc | 463 +++++++++++++++++
.../test/adblock_snippets_browsertest.cc | 80 +++
...dblock_subscription_service_browsertest.cc | 201 ++++++++
.../adblock_telemetry_service_browsertest.cc | 256 ++++++++++
.../test/adblock_web_bundle_browsertest.cc | 427 ++++++++++++++++
.../chrome_browser_interface_binders.cc | 9 +
.../client_hints/client_hints_browsertest.cc | 9 +-
chrome/browser/net/errorpage_browsertest.cc | 8 +
..._page_load_metrics_observer_browsertest.cc | 7 +-
chrome/browser/preferences/BUILD.gn | 5 +
.../prefs/chrome_pref_service_factory.cc | 11 +
...hrome_browser_main_extra_parts_profiles.cc | 26 +
.../profile_keyed_service_browsertest.cc | 42 +-
chrome/browser/resources/BUILD.gn | 5 +
.../resources/adblock_internals/BUILD.gn | 29 ++
.../adblock_internals/adblock_internals.html | 38 ++
.../adblock_internals/adblock_internals.ts | 43 ++
.../safe_browsing_blocking_page_test.cc | 8 +-
...subresource_filter_browser_test_harness.cc | 8 +-
chrome/browser/ui/BUILD.gn | 12 +-
chrome/browser/ui/prefs/pref_watcher.cc | 13 +
chrome/browser/ui/tab_helpers.cc | 18 +
.../ui/webui/adblock_internals/BUILD.gn | 23 +
.../adblock_internals/adblock_internals.mojom | 20 +
.../adblock_internals_page_handler_impl.cc | 115 +++++
.../adblock_internals_page_handler_impl.h | 51 ++
.../adblock_internals/adblock_internals_ui.cc | 47 ++
.../adblock_internals/adblock_internals_ui.h | 48 ++
.../webui/chrome_web_ui_controller_factory.cc | 11 +-
chrome/common/BUILD.gn | 3 +
chrome/common/webui_url_constants.cc | 5 +
chrome/common/webui_url_constants.h | 5 +
chrome/test/BUILD.gn | 27 +
chrome/test/base/chrome_test_launcher.cc | 7 +-
chrome/test/base/in_process_browser_test.cc | 21 +-
.../filterlist_that_allows_resource.txt | 7 +
.../filterlist_that_blocks_resource.txt | 6 +
.../filterlist_that_hides_resource.txt | 6 +
chrome/test/data/adblock/innermost_frame.html | 39 ++
chrome/test/data/adblock/middle_frame.html | 25 +
chrome/test/data/adblock/non-ascii.html | 26 +
chrome/test/data/adblock/outermost_frame.html | 37 ++
.../outermost_frame_with_about_blank.html | 37 ++
chrome/test/data/adblock/popup.html | 25 +
chrome/test/data/adblock/popup_opener.html | 26 +
chrome/test/data/adblock/popup_parent.html | 25 +
chrome/test/data/adblock/resource.png | Bin 0 -> 47293 bytes
chrome/test/data/adblock/tab-restore.html | 33 ++
chrome/test/data/adblock/wbn/LICENSE | 14 +
.../data/adblock/wbn/blocked_bundle/LICENSE | 14 +
.../fetch_result_1_blocked_bundle.json | 1 +
.../fetch_result_2_blocked_bundle.json | 1 +
.../data/adblock/wbn/by_bundle_file/LICENSE | 14 +
.../fetch_result_2_subresource_loading.json | 1 +
.../green_subresource_loading.css | 1 +
.../green_subresource_loading.png | Bin 0 -> 772 bytes
.../purple_subresource_loading.css | 1 +
.../purple_subresource_loading.png | Bin 0 -> 773 bytes
.../xhr_result_2_subresource_loading.json | 1 +
.../test/data/adblock/wbn/by_resource/LICENSE | 14 +
.../by_resource/blue_subresource_loading.css | 1 +
.../by_resource/blue_subresource_loading.png | Bin 0 -> 773 bytes
.../fetch_result_1_subresource_loading.json | 1 +
.../by_resource/red_subresource_loading.css | 1 +
.../by_resource/red_subresource_loading.png | Bin 0 -> 772 bytes
.../xhr_result_1_subresource_loading.json | 1 +
chrome/test/data/adblock/wbn/by_scope/LICENSE | 14 +
.../fetch_result_3_subresource_loading.json | 1 +
.../by_scope/orange_subresource_loading.css | 1 +
.../by_scope/orange_subresource_loading.png | Bin 0 -> 774 bytes
.../wbn/by_scope/pink_subresource_loading.css | 1 +
.../wbn/by_scope/pink_subresource_loading.png | Bin 0 -> 775 bytes
.../xhr_result_3_subresource_loading.json | 1 +
.../test/data/adblock/wbn/index.html.mustache | 157 ++++++
chrome/test/data/adblock/xpath3.html | 23 +
123 files changed, 7677 insertions(+), 12 deletions(-)
create mode 100644 chrome/browser/adblock/README.md
create mode 100644 chrome/browser/adblock/adblock_content_browser_client.cc
create mode 100644 chrome/browser/adblock/adblock_content_browser_client.h
create mode 100644 chrome/browser/adblock/adblock_content_browser_client_unittest.cc
create mode 100644 chrome/browser/adblock/adblock_controller_factory.cc
create mode 100644 chrome/browser/adblock/adblock_controller_factory.h
create mode 100644 chrome/browser/adblock/adblock_telemetry_service_factory.cc
create mode 100644 chrome/browser/adblock/adblock_telemetry_service_factory.h
create mode 100644 chrome/browser/adblock/android/BUILD.gn
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/AdblockControllerTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/FilteringConfigurationTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/ResourceClassificationNotifierTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesCircumventionTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesCspTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideEmuInvTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideEmuTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesExceptionTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesFilterTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesHeaderFilterTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesHelper.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesRewriteTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesSiteKeyTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesSnippetsTest.java
create mode 100644 chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesWebsocketTest.java
create mode 100644 chrome/browser/adblock/content_security_policy_injector_factory.cc
create mode 100644 chrome/browser/adblock/content_security_policy_injector_factory.h
create mode 100644 chrome/browser/adblock/element_hider_factory.cc
create mode 100644 chrome/browser/adblock/element_hider_factory.h
create mode 100644 chrome/browser/adblock/resource_classification_runner_factory.cc
create mode 100644 chrome/browser/adblock/resource_classification_runner_factory.h
create mode 100644 chrome/browser/adblock/session_stats_factory.cc
create mode 100644 chrome/browser/adblock/session_stats_factory.h
create mode 100644 chrome/browser/adblock/sitekey_storage_factory.cc
create mode 100644 chrome/browser/adblock/sitekey_storage_factory.h
create mode 100644 chrome/browser/adblock/subscription_persistent_metadata_factory.cc
create mode 100644 chrome/browser/adblock/subscription_persistent_metadata_factory.h
create mode 100644 chrome/browser/adblock/subscription_service_factory.cc
create mode 100644 chrome/browser/adblock/subscription_service_factory.h
create mode 100644 chrome/browser/adblock/test/adblock_content_browser_client_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_debug_url_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_filter_list_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_filtering_configurations_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_frame_hierarchy_builder_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_multiple_tabs_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_non_ascii_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_popup_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_snippets_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_subscription_service_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_telemetry_service_browsertest.cc
create mode 100644 chrome/browser/adblock/test/adblock_web_bundle_browsertest.cc
create mode 100644 chrome/browser/resources/adblock_internals/BUILD.gn
create mode 100644 chrome/browser/resources/adblock_internals/adblock_internals.html
create mode 100644 chrome/browser/resources/adblock_internals/adblock_internals.ts
create mode 100644 chrome/browser/ui/webui/adblock_internals/BUILD.gn
create mode 100644 chrome/browser/ui/webui/adblock_internals/adblock_internals.mojom
create mode 100644 chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.cc
create mode 100644 chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.h
create mode 100644 chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.cc
create mode 100644 chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.h
create mode 100644 chrome/test/data/adblock/filterlist_that_allows_resource.txt
create mode 100644 chrome/test/data/adblock/filterlist_that_blocks_resource.txt
create mode 100644 chrome/test/data/adblock/filterlist_that_hides_resource.txt
create mode 100644 chrome/test/data/adblock/innermost_frame.html
create mode 100644 chrome/test/data/adblock/middle_frame.html
create mode 100644 chrome/test/data/adblock/non-ascii.html
create mode 100644 chrome/test/data/adblock/outermost_frame.html
create mode 100644 chrome/test/data/adblock/outermost_frame_with_about_blank.html
create mode 100644 chrome/test/data/adblock/popup.html
create mode 100644 chrome/test/data/adblock/popup_opener.html
create mode 100644 chrome/test/data/adblock/popup_parent.html
create mode 100644 chrome/test/data/adblock/resource.png
create mode 100644 chrome/test/data/adblock/tab-restore.html
create mode 100644 chrome/test/data/adblock/wbn/LICENSE
create mode 100644 chrome/test/data/adblock/wbn/blocked_bundle/LICENSE
create mode 100644 chrome/test/data/adblock/wbn/blocked_bundle/fetch_result_1_blocked_bundle.json
create mode 100644 chrome/test/data/adblock/wbn/blocked_bundle/fetch_result_2_blocked_bundle.json
create mode 100644 chrome/test/data/adblock/wbn/by_bundle_file/LICENSE
create mode 100644 chrome/test/data/adblock/wbn/by_bundle_file/fetch_result_2_subresource_loading.json
create mode 100644 chrome/test/data/adblock/wbn/by_bundle_file/green_subresource_loading.css
create mode 100644 chrome/test/data/adblock/wbn/by_bundle_file/green_subresource_loading.png
create mode 100644 chrome/test/data/adblock/wbn/by_bundle_file/purple_subresource_loading.css
create mode 100644 chrome/test/data/adblock/wbn/by_bundle_file/purple_subresource_loading.png
create mode 100644 chrome/test/data/adblock/wbn/by_bundle_file/xhr_result_2_subresource_loading.json
create mode 100644 chrome/test/data/adblock/wbn/by_resource/LICENSE
create mode 100644 chrome/test/data/adblock/wbn/by_resource/blue_subresource_loading.css
create mode 100644 chrome/test/data/adblock/wbn/by_resource/blue_subresource_loading.png
create mode 100644 chrome/test/data/adblock/wbn/by_resource/fetch_result_1_subresource_loading.json
create mode 100644 chrome/test/data/adblock/wbn/by_resource/red_subresource_loading.css
create mode 100644 chrome/test/data/adblock/wbn/by_resource/red_subresource_loading.png
create mode 100644 chrome/test/data/adblock/wbn/by_resource/xhr_result_1_subresource_loading.json
create mode 100644 chrome/test/data/adblock/wbn/by_scope/LICENSE
create mode 100644 chrome/test/data/adblock/wbn/by_scope/fetch_result_3_subresource_loading.json
create mode 100644 chrome/test/data/adblock/wbn/by_scope/orange_subresource_loading.css
create mode 100644 chrome/test/data/adblock/wbn/by_scope/orange_subresource_loading.png
create mode 100644 chrome/test/data/adblock/wbn/by_scope/pink_subresource_loading.css
create mode 100644 chrome/test/data/adblock/wbn/by_scope/pink_subresource_loading.png
create mode 100644 chrome/test/data/adblock/wbn/by_scope/xhr_result_3_subresource_loading.json
create mode 100644 chrome/test/data/adblock/wbn/index.html.mustache
create mode 100644 chrome/test/data/adblock/xpath3.html
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -1,6 +1,10 @@
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include "chrome/app/chrome_main_delegate.h"
@@ -41,6 +45,7 @@
#include "base/trace_event/trace_event_impl.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "chrome/browser/adblock/adblock_content_browser_client.h"
#include "chrome/browser/buildflags.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/chrome_resource_bundle_helper.h"
@@ -1783,7 +1788,7 @@ content::ContentClient* ChromeMainDelegate::CreateContentClient() {
content::ContentBrowserClient*
ChromeMainDelegate::CreateContentBrowserClient() {
chrome_content_browser_client_ =
- std::make_unique<ChromeContentBrowserClient>();
+ std::make_unique<AdblockContentBrowserClient>();
return chrome_content_browser_client_.get();
}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1,6 +1,9 @@
# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+#
+# This source code is a part of eyeo Chromium SDK.
+# Use of this source code is governed by the GPLv3 that can be found in the components/adblock/LICENSE file.
import("//base/allocator/allocator.gni")
import("//build/buildflag_header.gni")
@@ -158,6 +161,26 @@ static_library("browser") {
"accessibility/page_colors.h",
"accessibility/page_colors_factory.cc",
"accessibility/page_colors_factory.h",
+ "adblock/adblock_content_browser_client.cc",
+ "adblock/adblock_content_browser_client.h",
+ "adblock/adblock_controller_factory.cc",
+ "adblock/adblock_controller_factory.h",
+ "adblock/adblock_telemetry_service_factory.cc",
+ "adblock/adblock_telemetry_service_factory.h",
+ "adblock/content_security_policy_injector_factory.cc",
+ "adblock/content_security_policy_injector_factory.h",
+ "adblock/element_hider_factory.cc",
+ "adblock/element_hider_factory.h",
+ "adblock/resource_classification_runner_factory.cc",
+ "adblock/resource_classification_runner_factory.h",
+ "adblock/session_stats_factory.cc",
+ "adblock/session_stats_factory.h",
+ "adblock/sitekey_storage_factory.cc",
+ "adblock/sitekey_storage_factory.h",
+ "adblock/subscription_persistent_metadata_factory.cc",
+ "adblock/subscription_persistent_metadata_factory.h",
+ "adblock/subscription_service_factory.cc",
+ "adblock/subscription_service_factory.h",
"after_startup_task_utils.cc",
"after_startup_task_utils.h",
"app_mode/app_mode_utils.cc",
@@ -2112,6 +2135,7 @@ static_library("browser") {
"//chrome/browser/ui/color:color_headers",
"//chrome/browser/ui/color:mixers",
"//chrome/browser/ui/webui:configs",
+ "//chrome/browser/ui/webui/adblock_internals:mojo_bindings",
"//chrome/browser/ui/webui/app_service_internals:mojo_bindings",
"//chrome/browser/ui/webui/feed:mojo_bindings",
"//chrome/browser/ui/webui/internals/user_education:mojo_bindings",
@@ -2134,6 +2158,8 @@ static_library("browser") {
"//chrome/common/notifications",
"//chrome/installer/util:with_no_strings",
"//chrome/services/speech/buildflags",
+ "//components/adblock/content:browser",
+ "//components/adblock/core/converter",
"//components/assist_ranker",
"//components/autofill/content/browser",
"//components/autofill/core/browser",
@@ -3411,6 +3437,8 @@ static_library("browser") {
"webauthn/android/webauthn_request_delegate_android.cc",
"webauthn/android/webauthn_request_delegate_android.h",
]
+
+
public_deps += [
"//chrome/android/features/dev_ui:buildflags",
"//components/image_fetcher/core",
@@ -3599,6 +3627,7 @@ static_library("browser") {
"//url:gurl_android",
]
+
if (safe_browsing_mode == 2) {
sources += [
"component_updater/real_time_url_checks_allowlist_component_installer.cc",
diff --git a/chrome/browser/adblock/README.md b/chrome/browser/adblock/README.md
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/README.md
@@ -0,0 +1,3 @@
+This folder contains the OS-agnostic, Chrome-specific source code of eyeo Chromium SDK.
+
+For the full documentation, refer to [components/adblock](/components/adblock).
diff --git a/chrome/browser/adblock/adblock_content_browser_client.cc b/chrome/browser/adblock/adblock_content_browser_client.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/adblock_content_browser_client.cc
@@ -0,0 +1,320 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/adblock_content_browser_client.h"
+
+#include "base/containers/unique_ptr_adapters.h"
+#include "base/ranges/algorithm.h"
+#include "chrome/browser/adblock/content_security_policy_injector_factory.h"
+#include "chrome/browser/adblock/element_hider_factory.h"
+#include "chrome/browser/adblock/resource_classification_runner_factory.h"
+#include "chrome/browser/adblock/sitekey_storage_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
+#include "components/adblock/content/browser/adblock_url_loader_factory.h"
+#include "components/adblock/content/browser/resource_classification_runner.h"
+#include "components/adblock/core/common/adblock_prefs.h"
+#include "components/adblock/core/configuration/filtering_configuration.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "components/embedder_support/user_agent_utils.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/network/public/mojom/websocket.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "third_party/blink/public/common/loader/url_loader_throttle.h"
+
+#ifdef EYEO_INTERCEPT_DEBUG_URL
+#include "components/adblock/content/browser/adblock_url_loader_factory_for_test.h"
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "chrome/browser/extensions/extension_util.h"
+#endif
+
+namespace {
+
+bool IsFilteringNeeded(content::RenderFrameHost* frame) {
+ if (frame) {
+ auto* profile =
+ Profile::FromBrowserContext(frame->GetProcess()->GetBrowserContext());
+ if (profile) {
+ // Filtering may be needed if there's at least one enabled
+ // FilteringConfiguration.
+ return base::ranges::any_of(
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(profile)
+ ->GetInstalledFilteringConfigurations(),
+ &adblock::FilteringConfiguration::IsEnabled);
+ }
+ }
+ return false;
+}
+
+// Owns all of the AdblockURLLoaderFactory for a given Profile.
+class AdblockContextData : public base::SupportsUserData::Data {
+ public:
+ AdblockContextData(const AdblockContextData&) = delete;
+ AdblockContextData& operator=(const AdblockContextData&) = delete;
+ ~AdblockContextData() override = default;
+
+ static void StartProxying(
+ Profile* profile,
+ content::RenderFrameHost* frame,
+ int render_process_id,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory,
+ bool use_test_loader) {
+ const void* const kAdblockContextUserDataKey = &kAdblockContextUserDataKey;
+ auto* self = static_cast<AdblockContextData*>(
+ profile->GetUserData(kAdblockContextUserDataKey));
+ if (!self) {
+ self = new AdblockContextData();
+ profile->SetUserData(kAdblockContextUserDataKey, base::WrapUnique(self));
+ }
+ auto* browser_context =
+ content::WebContents::FromRenderFrameHost(frame)->GetBrowserContext();
+ adblock::AdblockURLLoaderFactoryConfig config{
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(
+ browser_context),
+ adblock::ResourceClassificationRunnerFactory::GetForBrowserContext(
+ browser_context),
+ adblock::ElementHiderFactory::GetForBrowserContext(browser_context),
+ adblock::SitekeyStorageFactory::GetForBrowserContext(browser_context),
+ adblock::ContentSecurityPolicyInjectorFactory::GetForBrowserContext(
+ browser_context)};
+#ifdef EYEO_INTERCEPT_DEBUG_URL
+ if (use_test_loader) {
+ auto proxy = std::make_unique<adblock::AdblockURLLoaderFactoryForTest>(
+ std::move(config),
+ content::GlobalRenderFrameHostId(render_process_id,
+ frame->GetRoutingID()),
+ std::move(receiver), std::move(target_factory),
+ embedder_support::GetUserAgent(),
+ base::BindOnce(&AdblockContextData::RemoveProxy,
+ self->weak_factory_.GetWeakPtr()),
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(
+ Profile::FromBrowserContext(
+ frame->GetProcess()->GetBrowserContext())));
+ self->proxies_.emplace(std::move(proxy));
+ return;
+ }
+#endif
+ auto proxy = std::make_unique<adblock::AdblockURLLoaderFactory>(
+ std::move(config),
+ content::GlobalRenderFrameHostId(render_process_id,
+ frame->GetRoutingID()),
+ std::move(receiver), std::move(target_factory),
+ embedder_support::GetUserAgent(),
+ base::BindOnce(&AdblockContextData::RemoveProxy,
+ self->weak_factory_.GetWeakPtr()));
+ self->proxies_.emplace(std::move(proxy));
+ }
+
+ private:
+ void RemoveProxy(adblock::AdblockURLLoaderFactory* proxy) {
+ auto it = proxies_.find(proxy);
+ DCHECK(it != proxies_.end());
+ proxies_.erase(it);
+ }
+
+ AdblockContextData() = default;
+
+ std::set<std::unique_ptr<adblock::AdblockURLLoaderFactory>,
+ base::UniquePtrComparator>
+ proxies_;
+
+ base::WeakPtrFactory<AdblockContextData> weak_factory_{this};
+};
+
+} // namespace
+
+AdblockContentBrowserClient::AdblockContentBrowserClient() = default;
+
+AdblockContentBrowserClient::~AdblockContentBrowserClient() = default;
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+// static
+bool AdblockContentBrowserClient::force_adblock_proxy_for_testing_ = false;
+
+// static
+void AdblockContentBrowserClient::ForceAdblockProxyForTesting() {
+ force_adblock_proxy_for_testing_ = true;
+}
+#endif
+
+bool AdblockContentBrowserClient::WillInterceptWebSocket(
+ content::RenderFrameHost* frame) {
+ if (IsFilteringNeeded(frame)) {
+ return true;
+ }
+
+ return ChromeContentBrowserClient::WillInterceptWebSocket(frame);
+}
+
+void AdblockContentBrowserClient::CreateWebSocket(
+ content::RenderFrameHost* frame,
+ WebSocketFactory factory,
+ const GURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const absl::optional<std::string>& user_agent,
+ mojo::PendingRemote<network::mojom::WebSocketHandshakeClient>
+ handshake_client) {
+ if (IsFilteringNeeded(frame)) {
+ CreateWebSocketInternal(frame->GetGlobalId(), std::move(factory), url,
+ site_for_cookies, user_agent,
+ std::move(handshake_client));
+ } else {
+ DCHECK(ChromeContentBrowserClient::WillInterceptWebSocket(frame));
+ ChromeContentBrowserClient::CreateWebSocket(frame, std::move(factory), url,
+ site_for_cookies, user_agent,
+ std::move(handshake_client));
+ }
+}
+
+void AdblockContentBrowserClient::CreateWebSocketInternal(
+ content::GlobalRenderFrameHostId render_frame_host_id,
+ WebSocketFactory factory,
+ const GURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const absl::optional<std::string>& user_agent,
+ mojo::PendingRemote<network::mojom::WebSocketHandshakeClient>
+ handshake_client) {
+ auto* frame = content::RenderFrameHost::FromID(render_frame_host_id);
+ if (!frame) {
+ return;
+ }
+ auto* browser_context = frame->GetProcess()->GetBrowserContext();
+ auto* subscription_service =
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(
+ browser_context);
+ auto* classification_runner =
+ adblock::ResourceClassificationRunnerFactory::GetForBrowserContext(
+ browser_context);
+ classification_runner->CheckRequestFilterMatchForWebSocket(
+ subscription_service->GetCurrentSnapshot(), url, render_frame_host_id,
+ base::BindOnce(
+ &AdblockContentBrowserClient::OnWebSocketFilterCheckCompleted,
+ weak_factory_.GetWeakPtr(), render_frame_host_id, std::move(factory),
+ url, site_for_cookies, user_agent, std::move(handshake_client)));
+}
+
+void AdblockContentBrowserClient::OnWebSocketFilterCheckCompleted(
+ content::GlobalRenderFrameHostId render_frame_host_id,
+ ChromeContentBrowserClient::WebSocketFactory factory,
+ const GURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const absl::optional<std::string>& user_agent,
+ mojo::PendingRemote<network::mojom::WebSocketHandshakeClient>
+ handshake_client,
+ adblock::FilterMatchResult result) {
+ auto* frame = content::RenderFrameHost::FromID(render_frame_host_id);
+ if (!frame) {
+ return;
+ }
+ const bool has_blocking_filter =
+ result == adblock::FilterMatchResult::kBlockRule;
+ if (!has_blocking_filter) {
+ VLOG(1) << "[eyeo] Web socket allowed for " << url;
+ if (ChromeContentBrowserClient::WillInterceptWebSocket(frame)) {
+ ChromeContentBrowserClient::CreateWebSocket(
+ frame, std::move(factory), url, site_for_cookies, user_agent,
+ std::move(handshake_client));
+ return;
+ }
+
+ std::vector<network::mojom::HttpHeaderPtr> headers;
+ if (user_agent) {
+ headers.push_back(network::mojom::HttpHeader::New(
+ net::HttpRequestHeaders::kUserAgent, *user_agent));
+ }
+ std::move(factory).Run(url, std::move(headers), std::move(handshake_client),
+ mojo::NullRemote(), mojo::NullRemote());
+ }
+
+ VLOG(1) << "[eyeo] Web socket blocked for " << url;
+}
+
+bool AdblockContentBrowserClient::WillCreateURLLoaderFactory(
+ content::BrowserContext* browser_context,
+ content::RenderFrameHost* frame,
+ int render_process_id,
+ URLLoaderFactoryType type,
+ const url::Origin& request_initiator,
+ absl::optional<int64_t> navigation_id,
+ ukm::SourceIdObj ukm_source_id,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
+ header_client,
+ bool* bypass_redirect_checks,
+ bool* disable_secure_dns,
+ network::mojom::URLLoaderFactoryOverridePtr* factory_override,
+ scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner) {
+ // Create Chromium proxy first as WebRequestProxyingURLLoaderFactory logic
+ // depends on being first proxy
+ bool use_chrome_proxy =
+ ChromeContentBrowserClient::WillCreateURLLoaderFactory(
+ browser_context, frame, render_process_id, type, request_initiator,
+ navigation_id, ukm_source_id, factory_receiver, header_client,
+ bypass_redirect_checks, disable_secure_dns, factory_override,
+ navigation_response_task_runner);
+ auto* profile = frame ? Profile::FromBrowserContext(
+ frame->GetProcess()->GetBrowserContext())
+ : nullptr;
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ if (!force_adblock_proxy_for_testing_ &&
+ request_initiator.scheme() == extensions::kExtensionScheme) {
+ VLOG(1) << "[eyeo] Do not use adblock proxy for extensions requests "
+ "[extension id:"
+ << request_initiator.host() << "].";
+ return use_chrome_proxy;
+ }
+#endif
+
+ bool use_adblock_proxy =
+ (type == URLLoaderFactoryType::kDocumentSubResource ||
+ type == URLLoaderFactoryType::kNavigation) &&
+ IsFilteringNeeded(frame);
+
+ bool use_test_loader = false;
+#ifdef EYEO_INTERCEPT_DEBUG_URL
+ content::WebContents* wc = content::WebContents::FromRenderFrameHost(frame);
+ use_test_loader =
+ (type ==
+ content::ContentBrowserClient::URLLoaderFactoryType::kNavigation) &&
+ wc->GetVisibleURL().is_valid() &&
+ wc->GetVisibleURL().host() ==
+ adblock::AdblockURLLoaderFactoryForTest::kAdblockDebugDataHostName;
+ use_adblock_proxy |= use_test_loader;
+#endif
+
+ if (use_adblock_proxy) {
+ auto proxied_receiver = std::move(*factory_receiver);
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_remote;
+ *factory_receiver = target_factory_remote.InitWithNewPipeAndPassReceiver();
+ AdblockContextData::StartProxying(
+ profile, frame, render_process_id, std::move(proxied_receiver),
+ std::move(target_factory_remote), use_test_loader);
+ }
+ return use_adblock_proxy || use_chrome_proxy;
+}
diff --git a/chrome/browser/adblock/adblock_content_browser_client.h b/chrome/browser/adblock/adblock_content_browser_client.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/adblock_content_browser_client.h
@@ -0,0 +1,100 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_ADBLOCK_ADBLOCK_CONTENT_BROWSER_CLIENT_H_
+#define CHROME_BROWSER_ADBLOCK_ADBLOCK_CONTENT_BROWSER_CLIENT_H_
+
+#include "build/buildflag.h"
+#include "chrome/browser/chrome_content_browser_client.h"
+
+namespace adblock {
+enum class FilterMatchResult;
+} // namespace adblock
+
+/**
+ * @brief Intercepts network and UI events to inject ad-filtering.
+ * Provides ad-filtering implementations of URLLoaderThrottles.
+ * Binds a mojo connection between Renderer processes and the
+ * Browser-process-based ResourceClassificationRunner.
+ * Lives in browser process UI thread.
+ */
+class AdblockContentBrowserClient : public ChromeContentBrowserClient {
+ public:
+ AdblockContentBrowserClient();
+ ~AdblockContentBrowserClient() override;
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ // Enable ad filtering also for requests initiated by extensions.
+ // This allows implementing extension-driven browser tests.
+ // In production code, requests from extensions are not blocked.
+ static void ForceAdblockProxyForTesting();
+#endif
+
+ bool WillInterceptWebSocket(content::RenderFrameHost* frame) override;
+ void CreateWebSocket(
+ content::RenderFrameHost* frame,
+ WebSocketFactory factory,
+ const GURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const absl::optional<std::string>& user_agent,
+ mojo::PendingRemote<network::mojom::WebSocketHandshakeClient>
+ handshake_client) override;
+
+ bool WillCreateURLLoaderFactory(
+ content::BrowserContext* browser_context,
+ content::RenderFrameHost* frame,
+ int render_process_id,
+ URLLoaderFactoryType type,
+ const url::Origin& request_initiator,
+ absl::optional<int64_t> navigation_id,
+ ukm::SourceIdObj ukm_source_id,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
+ header_client,
+ bool* bypass_redirect_checks,
+ bool* disable_secure_dns,
+ network::mojom::URLLoaderFactoryOverridePtr* factory_override,
+ scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner)
+ override;
+
+ private:
+ void CreateWebSocketInternal(
+ content::GlobalRenderFrameHostId render_frame_host_id,
+ WebSocketFactory factory,
+ const GURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const absl::optional<std::string>& user_agent,
+ mojo::PendingRemote<network::mojom::WebSocketHandshakeClient>
+ handshake_client);
+ void OnWebSocketFilterCheckCompleted(
+ content::GlobalRenderFrameHostId render_frame_host_id,
+ ChromeContentBrowserClient::WebSocketFactory factory,
+ const GURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const absl::optional<std::string>& user_agent,
+ mojo::PendingRemote<network::mojom::WebSocketHandshakeClient>
+ handshake_client,
+ adblock::FilterMatchResult result);
+
+ base::WeakPtrFactory<AdblockContentBrowserClient> weak_factory_{this};
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ static bool force_adblock_proxy_for_testing_;
+#endif
+};
+
+#endif // CHROME_BROWSER_ADBLOCK_ADBLOCK_CONTENT_BROWSER_CLIENT_H_
diff --git a/chrome/browser/adblock/adblock_content_browser_client_unittest.cc b/chrome/browser/adblock/adblock_content_browser_client_unittest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/adblock_content_browser_client_unittest.cc
@@ -0,0 +1,203 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/adblock_content_browser_client.h"
+
+#include "base/callback_list.h"
+#include "base/memory/raw_ptr.h"
+#include "base/run_loop.h"
+#include "base/test/gmock_move_support.h"
+#include "base/test/mock_callback.h"
+#include "chrome/browser/adblock/resource_classification_runner_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/adblock/content/browser/test/mock_resource_classification_runner.h"
+#include "components/adblock/core/common/adblock_prefs.h"
+#include "components/adblock/core/common/content_type.h"
+#include "components/adblock/core/subscription/installed_subscription.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "components/adblock/core/subscription/test/mock_subscription_collection.h"
+#include "components/adblock/core/subscription/test/mock_subscription_service.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/test/mock_render_process_host.h"
+#include "content/public/test/test_renderer_host.h"
+#include "gmock/gmock.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/websocket.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Return;
+
+namespace adblock {
+
+class AdblockContentBrowserClientUnitTest
+ : public ChromeRenderViewHostTestHarness {
+ public:
+ TestingProfile::TestingFactories GetTestingFactories() const override {
+ return {std::make_pair(
+ SubscriptionServiceFactory::GetInstance(),
+ base::BindRepeating([](content::BrowserContext* bc)
+ -> std::unique_ptr<KeyedService> {
+ return std::make_unique<MockSubscriptionService>();
+ })),
+ std::make_pair(
+ ResourceClassificationRunnerFactory::GetInstance(),
+ base::BindRepeating([](content::BrowserContext* bc)
+ -> std::unique_ptr<KeyedService> {
+ return std::make_unique<MockResourceClassificationRunner>();
+ }))};
+ }
+
+ void SetUp() override {
+ ChromeRenderViewHostTestHarness::SetUp();
+
+ subscription_service_ = static_cast<MockSubscriptionService*>(
+ SubscriptionServiceFactory::GetForBrowserContext(profile()));
+ resource_classification_runner_ =
+ static_cast<MockResourceClassificationRunner*>(
+ ResourceClassificationRunnerFactory::GetForBrowserContext(
+ profile()));
+ }
+
+ void TearDown() override {
+ subscription_service_ = nullptr;
+ resource_classification_runner_ = nullptr;
+ ChromeRenderViewHostTestHarness::TearDown();
+ }
+
+ raw_ptr<MockSubscriptionService> subscription_service_;
+ raw_ptr<MockResourceClassificationRunner> resource_classification_runner_;
+};
+
+TEST_F(AdblockContentBrowserClientUnitTest,
+ WillInterceptWebSocketWhenFilteringEnabled) {
+ AdblockContentBrowserClient content_client;
+ subscription_service_->WillRequireFiltering(true);
+ EXPECT_TRUE(content_client.WillInterceptWebSocket(main_rfh()));
+}
+
+TEST_F(AdblockContentBrowserClientUnitTest,
+ WillNotInterceptWebSocketWhenFilteringDisabled) {
+ AdblockContentBrowserClient content_client;
+ subscription_service_->WillRequireFiltering(false);
+ EXPECT_FALSE(content_client.WillInterceptWebSocket(main_rfh()));
+}
+
+TEST_F(AdblockContentBrowserClientUnitTest,
+ RenderFrameHostDiesBeforeClassificationFinished) {
+ const auto kSocketUrl = GURL("wss://domain.com/test");
+ subscription_service_->WillRequireFiltering(true);
+ EXPECT_CALL(*subscription_service_, GetCurrentSnapshot()).WillOnce([]() {
+ SubscriptionService::Snapshot snapshot;
+ snapshot.push_back(std::make_unique<MockSubscriptionCollection>());
+ return snapshot;
+ });
+ CheckFilterMatchCallback classification_callback;
+ EXPECT_CALL(*resource_classification_runner_,
+ CheckRequestFilterMatchForWebSocket(_, kSocketUrl,
+ main_rfh()->GetGlobalId(), _))
+ .WillOnce(MoveArg<3>(&classification_callback));
+
+ AdblockContentBrowserClient content_client;
+ base::MockCallback<content::ContentBrowserClient::WebSocketFactory>
+ web_socket_factory;
+ // The web_socket_factory callback will never be called because the
+ // associated RenderFrameHost will be dead.
+ EXPECT_CALL(web_socket_factory, Run(_, _, _, _, _)).Times(0);
+
+ const net::SiteForCookies site_for_cookies;
+ content_client.CreateWebSocket(main_rfh(), web_socket_factory.Get(),
+ kSocketUrl, site_for_cookies, absl::nullopt,
+ {});
+ // Tab is closed.
+ DeleteContents();
+
+ // Classification finishes now. It will not trigger a call to
+ // |web_socket_factory| because the RFH is dead.
+ std::move(classification_callback).Run(FilterMatchResult::kBlockRule);
+
+ task_environment()->RunUntilIdle();
+}
+
+TEST_F(AdblockContentBrowserClientUnitTest, WebSocketAllowed) {
+ subscription_service_->WillRequireFiltering(true);
+ const auto kSocketUrl = GURL("wss://domain.com/test");
+ EXPECT_CALL(*subscription_service_, GetCurrentSnapshot()).WillOnce([]() {
+ SubscriptionService::Snapshot snapshot;
+ snapshot.push_back(std::make_unique<MockSubscriptionCollection>());
+ return snapshot;
+ });
+ CheckFilterMatchCallback classification_callback;
+ EXPECT_CALL(*resource_classification_runner_,
+ CheckRequestFilterMatchForWebSocket(_, kSocketUrl,
+ main_rfh()->GetGlobalId(), _))
+ .WillOnce(MoveArg<3>(&classification_callback));
+
+ AdblockContentBrowserClient content_client;
+ base::MockCallback<content::ContentBrowserClient::WebSocketFactory>
+ web_socket_factory;
+ // The web_socket_factory callback will be called to let the web socket
+ // continue connecting.
+ EXPECT_CALL(web_socket_factory, Run(kSocketUrl, _, _, _, _));
+
+ const net::SiteForCookies site_for_cookies;
+ content_client.CreateWebSocket(main_rfh(), web_socket_factory.Get(),
+ kSocketUrl, site_for_cookies, absl::nullopt,
+ {});
+
+ // Classification finishes now. It will trigger a call to |web_socket_factory|
+ std::move(classification_callback).Run(FilterMatchResult::kAllowRule);
+
+ task_environment()->RunUntilIdle();
+}
+
+TEST_F(AdblockContentBrowserClientUnitTest, WebSocketBlocked) {
+ subscription_service_->WillRequireFiltering(true);
+ const auto kSocketUrl = GURL("wss://domain.com/test");
+ EXPECT_CALL(*subscription_service_, GetCurrentSnapshot()).WillOnce([]() {
+ SubscriptionService::Snapshot snapshot;
+ snapshot.push_back(std::make_unique<MockSubscriptionCollection>());
+ return snapshot;
+ });
+ CheckFilterMatchCallback classification_callback;
+ EXPECT_CALL(*resource_classification_runner_,
+ CheckRequestFilterMatchForWebSocket(_, kSocketUrl,
+ main_rfh()->GetGlobalId(), _))
+ .WillOnce(MoveArg<3>(&classification_callback));
+
+ AdblockContentBrowserClient content_client;
+ base::MockCallback<content::ContentBrowserClient::WebSocketFactory>
+ web_socket_factory;
+ // The web_socket_factory callback will not be called as to disallow
+ // connection.
+ EXPECT_CALL(web_socket_factory, Run(kSocketUrl, _, _, _, _)).Times(0);
+
+ const net::SiteForCookies site_for_cookies;
+ content_client.CreateWebSocket(main_rfh(), web_socket_factory.Get(),
+ kSocketUrl, site_for_cookies, absl::nullopt,
+ {});
+
+ // Classification finishes now.
+ std::move(classification_callback).Run(FilterMatchResult::kBlockRule);
+
+ task_environment()->RunUntilIdle();
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/adblock_controller_factory.cc b/chrome/browser/adblock/adblock_controller_factory.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/adblock_controller_factory.cc
@@ -0,0 +1,67 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/adblock_controller_factory.h"
+
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/adblock/core/adblock_controller.h"
+
+namespace adblock {
+
+// static
+AdblockController* AdblockControllerFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<AdblockController*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+AdblockControllerFactory* AdblockControllerFactory::GetInstance() {
+ static base::NoDestructor<AdblockControllerFactory> instance;
+ return instance.get();
+}
+
+AdblockControllerFactory::AdblockControllerFactory()
+ : AdblockControllerFactoryBase() {
+ DependsOn(SubscriptionServiceFactory::GetInstance());
+}
+
+AdblockControllerFactory::~AdblockControllerFactory() = default;
+
+SubscriptionService* AdblockControllerFactory::GetSubscriptionService(
+ content::BrowserContext* context) const {
+ return SubscriptionServiceFactory::GetForBrowserContext(context);
+}
+
+PrefService* AdblockControllerFactory::GetPrefs(
+ content::BrowserContext* context) const {
+ return Profile::FromBrowserContext(context)->GetOriginalProfile()->GetPrefs();
+}
+
+const std::string& AdblockControllerFactory::GetLocale() const {
+ return g_browser_process->GetApplicationLocale();
+}
+
+content::BrowserContext* AdblockControllerFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/adblock_controller_factory.h b/chrome/browser/adblock/adblock_controller_factory.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/adblock_controller_factory.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_ADBLOCK_ADBLOCK_CONTROLLER_FACTORY_H_
+#define CHROME_BROWSER_ADBLOCK_ADBLOCK_CONTROLLER_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/adblock/content/browser/adblock_controller_factory_base.h"
+
+namespace adblock {
+
+class AdblockController;
+class AdblockControllerFactory : public AdblockControllerFactoryBase {
+ public:
+ static AdblockController* GetForBrowserContext(
+ content::BrowserContext* context);
+ static AdblockControllerFactory* GetInstance();
+
+ protected:
+ PrefService* GetPrefs(content::BrowserContext* context) const override;
+ const std::string& GetLocale() const override;
+ SubscriptionService* GetSubscriptionService(
+ content::BrowserContext* context) const override;
+
+ private:
+ friend class base::NoDestructor<AdblockControllerFactory>;
+ AdblockControllerFactory();
+ ~AdblockControllerFactory() override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace adblock
+
+#endif // CHROME_BROWSER_ADBLOCK_ADBLOCK_CONTROLLER_FACTORY_H_
diff --git a/chrome/browser/adblock/adblock_telemetry_service_factory.cc b/chrome/browser/adblock/adblock_telemetry_service_factory.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/adblock_telemetry_service_factory.cc
@@ -0,0 +1,63 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/adblock_telemetry_service_factory.h"
+
+#include "base/no_destructor.h"
+#include "chrome/browser/adblock/adblock_controller_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/adblock/core/adblock_telemetry_service.h"
+
+namespace adblock {
+
+// static
+AdblockTelemetryService* AdblockTelemetryServiceFactory::GetForProfile(
+ Profile* profile) {
+ return static_cast<AdblockTelemetryService*>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+// static
+AdblockTelemetryServiceFactory* AdblockTelemetryServiceFactory::GetInstance() {
+ static base::NoDestructor<AdblockTelemetryServiceFactory> instance;
+ return instance.get();
+}
+
+AdblockTelemetryServiceFactory::AdblockTelemetryServiceFactory()
+ : AdblockTelemetryServiceFactoryBase() {
+ DependsOn(AdblockControllerFactory::GetInstance());
+}
+
+AdblockTelemetryServiceFactory::~AdblockTelemetryServiceFactory() = default;
+
+SubscriptionService* AdblockTelemetryServiceFactory::GetSubscriptionService(
+ content::BrowserContext* context) const {
+ return SubscriptionServiceFactory::GetForBrowserContext(context);
+}
+
+PrefService* AdblockTelemetryServiceFactory::GetPrefs(
+ content::BrowserContext* context) const {
+ return Profile::FromBrowserContext(context)->GetOriginalProfile()->GetPrefs();
+}
+
+content::BrowserContext* AdblockTelemetryServiceFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/adblock_telemetry_service_factory.h b/chrome/browser/adblock/adblock_telemetry_service_factory.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/adblock_telemetry_service_factory.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_ADBLOCK_ADBLOCK_TELEMETRY_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_ADBLOCK_ADBLOCK_TELEMETRY_SERVICE_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/adblock/content/browser/adblock_telemetry_service_factory_base.h"
+
+class Profile;
+
+namespace adblock {
+class AdblockTelemetryService;
+class AdblockTelemetryServiceFactory
+ : public AdblockTelemetryServiceFactoryBase {
+ public:
+ static AdblockTelemetryService* GetForProfile(Profile* profile);
+ static AdblockTelemetryServiceFactory* GetInstance();
+
+ protected:
+ PrefService* GetPrefs(content::BrowserContext* context) const override;
+ SubscriptionService* GetSubscriptionService(
+ content::BrowserContext* context) const override;
+
+ private:
+ friend class base::NoDestructor<AdblockTelemetryServiceFactory>;
+ AdblockTelemetryServiceFactory();
+ ~AdblockTelemetryServiceFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace adblock
+
+#endif // CHROME_BROWSER_ADBLOCK_ADBLOCK_TELEMETRY_SERVICE_FACTORY_H_
diff --git a/chrome/browser/adblock/android/BUILD.gn b/chrome/browser/adblock/android/BUILD.gn
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/BUILD.gn
@@ -0,0 +1,68 @@
+# This file is part of eyeo Chromium SDK,
+# Copyright (C) 2006-present eyeo GmbH
+# eyeo Chromium SDK is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3 as
+# published by the Free Software Foundation.
+# eyeo Chromium SDK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+
+
+import("//build/config/android/rules.gni")
+
+android_library("adblock_java_tests") {
+ testonly = true
+
+ sources = [
+ "javatests/src/org/chromium/chrome/browser/adblock/AdblockControllerTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/FilteringConfigurationTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/ResourceClassificationNotifierTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesCircumventionTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesCspTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideEmuInvTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideEmuTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesExceptionTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesFilterTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesHeaderFilterTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesHelper.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesRewriteTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesSiteKeyTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesSnippetsTest.java",
+ "javatests/src/org/chromium/chrome/browser/adblock/TestPagesWebsocketTest.java",
+ ]
+
+
+ deps = [
+ "//base:base_java",
+ "//base:base_java_test_support",
+ "//chrome/android:chrome_java",
+ "//chrome/browser/flags:java",
+ "//chrome/browser/settings:test_support_java",
+ "//chrome/browser/tab:java",
+ "//chrome/browser/tabmodel:java",
+ "//chrome/test/android:chrome_java_integration_test_support",
+ "//chrome/test/android:chrome_java_test_support_common",
+ "//components/adblock/android:adblock_controller_java",
+ "//components/adblock/android:adblock_java_tests_base",
+ "//components/infobars/android:java",
+ "//components/infobars/core:infobar_enums_java",
+ "//components/messages/android/test:test_support_java",
+ "//content/public/android:content_full_java",
+ "//content/public/android:content_main_dex_java",
+ "//content/public/test/android:content_java_test_support",
+ "//net/android:net_java_test_support",
+ "//third_party/androidx:androidx_fragment_fragment_java",
+ "//third_party/androidx:androidx_test_monitor_java",
+ "//third_party/androidx:androidx_test_runner_java",
+ "//third_party/hamcrest:hamcrest_core_java",
+ "//third_party/hamcrest:hamcrest_library_java",
+ "//third_party/junit:junit",
+ "//ui/android:ui_no_recycler_view_java",
+ "//url:gurl_java",
+ ]
+
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/AdblockControllerTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/AdblockControllerTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/AdblockControllerTest.java
@@ -0,0 +1,43 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.AdblockControllerTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class AdblockControllerTest extends AdblockControllerTestBase {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+
+ @Before
+ public void setUp() {
+ mActivityTestRule.startMainActivityOnBlankPage();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/FilteringConfigurationTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/FilteringConfigurationTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/FilteringConfigurationTest.java
@@ -0,0 +1,418 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.IntegrationTest;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.FilteringConfiguration;
+import org.chromium.components.adblock.TestVerificationUtils;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.content_public.common.ContentSwitches;
+import org.chromium.net.test.EmbeddedTestServer;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+ ContentSwitches.HOST_RESOLVER_RULES + "=MAP * 127.0.0.1"})
+public class FilteringConfigurationTest {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final CallbackHelper mCallbackHelper = new CallbackHelper();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+ public FilteringConfiguration mConfigurationA;
+ public FilteringConfiguration mConfigurationB;
+ private EmbeddedTestServer mTestServer;
+ private String mTestUrl;
+
+ private static class TestConfigurationChangeObserver
+ implements FilteringConfiguration.ConfigurationChangeObserver {
+ public volatile boolean mOnEnabledStateChangedCalled;
+ public volatile boolean mOnFilterListsChanged;
+ public volatile boolean mOnAllowedDomainsChanged;
+ public volatile boolean mOnCustomFiltersChanged;
+
+ public TestConfigurationChangeObserver() {
+ mOnEnabledStateChangedCalled = false;
+ mOnFilterListsChanged = false;
+ mOnAllowedDomainsChanged = false;
+ mOnCustomFiltersChanged = false;
+ }
+
+ @Override
+ public void onEnabledStateChanged() {
+ mOnEnabledStateChangedCalled = true;
+ }
+ @Override
+ public void onFilterListsChanged() {
+ mOnFilterListsChanged = true;
+ }
+
+ @Override
+ public void onAllowedDomainsChanged() {
+ mOnAllowedDomainsChanged = true;
+ }
+
+ @Override
+ public void onCustomFiltersChanged() {
+ mOnCustomFiltersChanged = true;
+ }
+ }
+
+ public void loadTestUrl() throws InterruptedException {
+ mActivityTestRule.loadUrl(mTestUrl, 5);
+ }
+
+ @Before
+ public void setUp() throws TimeoutException {
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ mConfigurationA = FilteringConfiguration.createConfiguration("a");
+ mConfigurationB = FilteringConfiguration.createConfiguration("b");
+ mCallbackHelper.notifyCalled();
+ });
+ mCallbackHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ mHelper.setActivityTestRule(mActivityTestRule);
+ mActivityTestRule.startMainActivityOnBlankPage();
+ mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
+ mTestUrl = mTestServer.getURLWithHostName(
+ "test.org", "/chrome/test/data/adblock/innermost_frame.html");
+ }
+
+ @After
+ public void tearDown() {
+ mTestServer.stopAndDestroyServer();
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void addingAllowedDomains() throws Exception {
+ final List<String> allowedDomainsA = new ArrayList<>();
+ final List<String> allowedDomainsB = new ArrayList<>();
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ mConfigurationA.addAllowedDomain("foobar.com");
+ mConfigurationA.addAllowedDomain("domain.com/path/to/page.html");
+ mConfigurationA.addAllowedDomain("domain.com/duplicate.html");
+ allowedDomainsA.addAll(mConfigurationA.getAllowedDomains());
+
+ mConfigurationB.addAllowedDomain("https://scheme.com/path.html");
+ mConfigurationB.addAllowedDomain("https://second.com");
+ mConfigurationB.removeAllowedDomain("https://second.com");
+ mConfigurationB.addAllowedDomain("gibberish");
+ allowedDomainsB.addAll(mConfigurationB.getAllowedDomains());
+
+ mCallbackHelper.notifyCalled();
+ });
+ mCallbackHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ // We expect to see a sorted collection of domains (not URLs) without duplicates.
+ ArrayList<String> expectedAllowedDomainsA = new ArrayList<String>();
+ expectedAllowedDomainsA.add("domain.com");
+ expectedAllowedDomainsA.add("foobar.com");
+ Assert.assertEquals(expectedAllowedDomainsA, allowedDomainsA);
+
+ // We expect not to see second.com because it was removed after being added.
+ ArrayList<String> expectedAllowedDomainsB = new ArrayList<String>();
+ expectedAllowedDomainsB.add("scheme.com");
+ expectedAllowedDomainsB.add("www.gibberish.com");
+ Assert.assertEquals(expectedAllowedDomainsB, allowedDomainsB);
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void addingCustomFilters() throws Exception {
+ final List<String> customFiltersA = new ArrayList<>();
+ final List<String> customFiltersB = new ArrayList<>();
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ mConfigurationA.addCustomFilter("foobar.com");
+ mConfigurationA.addCustomFilter("foobar.com");
+ mConfigurationA.addCustomFilter("abc");
+ customFiltersA.addAll(mConfigurationA.getCustomFilters());
+
+ mConfigurationB.addCustomFilter("https://scheme.com/path.html");
+ mConfigurationB.addCustomFilter("https://second.com");
+ mConfigurationB.removeCustomFilter("https://second.com");
+ customFiltersB.addAll(mConfigurationB.getCustomFilters());
+
+ mCallbackHelper.notifyCalled();
+ });
+ mCallbackHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ // We expect to see a collection of custom filters without duplicates.
+ // The order represents order of addition.
+ ArrayList<String> expectedCustomFiltersA = new ArrayList<String>();
+ expectedCustomFiltersA.add("foobar.com");
+ expectedCustomFiltersA.add("abc");
+ Assert.assertEquals(expectedCustomFiltersA, customFiltersA);
+
+ // We expect not to see https://second.com because it was removed after being added.
+ ArrayList<String> expectedCustomFiltersB = new ArrayList<String>();
+ expectedCustomFiltersB.add("https://scheme.com/path.html");
+ Assert.assertEquals(expectedCustomFiltersB, customFiltersB);
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void addingFilterLists() throws Exception {
+ final URL filterList1 = new URL("http://filters.com/list1.txt");
+ final URL filterList2 = new URL("http://filters.com/list2.txt");
+ final List<URL> filterListsA = new ArrayList<URL>();
+ final List<URL> filterListsB = new ArrayList<URL>();
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ mConfigurationA.addFilterList(filterList1);
+ mConfigurationA.addFilterList(filterList2);
+ mConfigurationA.addFilterList(filterList1);
+ filterListsA.addAll(mConfigurationA.getFilterLists());
+
+ mConfigurationB.addFilterList(filterList1);
+ mConfigurationB.addFilterList(filterList2);
+ mConfigurationB.removeFilterList(filterList1);
+ filterListsB.addAll(mConfigurationB.getFilterLists());
+
+ mCallbackHelper.notifyCalled();
+ });
+ mCallbackHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ ArrayList<URL> expectedFilterListsA = new ArrayList<URL>();
+ expectedFilterListsA.add(filterList1);
+ expectedFilterListsA.add(filterList2);
+ Assert.assertEquals(expectedFilterListsA, filterListsA);
+
+ ArrayList<URL> expectedFilterListsB = new ArrayList<URL>();
+ expectedFilterListsB.add(filterList2);
+ Assert.assertEquals(expectedFilterListsB, filterListsB);
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void aliasedConfigurations() throws Exception {
+ final URL filterList1 = new URL("http://filters.com/list1.txt");
+ final URL filterList2 = new URL("http://filters.com/list2.txt");
+ final List<URL> filterListsA = new ArrayList<URL>();
+ final List<URL> filterListsB = new ArrayList<URL>();
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ // Create a new FilteringConfiguration with a name of one that
+ // already exist.
+ FilteringConfiguration aliasedConfiguration =
+ FilteringConfiguration.createConfiguration("a");
+
+ // We add filter lists only to the original configuration instance.
+ mConfigurationA.addFilterList(filterList1);
+ mConfigurationA.addFilterList(filterList2);
+
+ // We check what filter lists are present in the original and in the aliased instance.
+ filterListsA.addAll(mConfigurationA.getFilterLists());
+ filterListsB.addAll(aliasedConfiguration.getFilterLists());
+
+ mCallbackHelper.notifyCalled();
+ });
+ mCallbackHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ ArrayList<URL> expectedFilterLists = new ArrayList<URL>();
+ expectedFilterLists.add(filterList1);
+ expectedFilterLists.add(filterList2);
+ Assert.assertEquals(expectedFilterLists, filterListsA);
+ Assert.assertEquals(expectedFilterLists, filterListsB);
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void configurationChangeObserverNotified() throws Exception {
+ final URL filterList1 = new URL("http://filters.com/list1.txt");
+ final TestConfigurationChangeObserver observer = new TestConfigurationChangeObserver();
+ Assert.assertFalse(observer.mOnEnabledStateChangedCalled);
+ Assert.assertFalse(observer.mOnAllowedDomainsChanged);
+ Assert.assertFalse(observer.mOnCustomFiltersChanged);
+ Assert.assertFalse(observer.mOnFilterListsChanged);
+
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ // We'll create an aliased instance which will receive notifications triggered by
+ // changes made to the original instance.
+ FilteringConfiguration aliasedConfiguration =
+ FilteringConfiguration.createConfiguration("a");
+ aliasedConfiguration.addObserver(observer);
+
+ mConfigurationA.addFilterList(filterList1);
+ mConfigurationA.addAllowedDomain("test.com");
+ mConfigurationA.addCustomFilter("test.com");
+ mConfigurationA.setEnabled(false);
+
+ mCallbackHelper.notifyCalled();
+ });
+ mCallbackHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ Assert.assertTrue(observer.mOnEnabledStateChangedCalled);
+ Assert.assertTrue(observer.mOnAllowedDomainsChanged);
+ Assert.assertTrue(observer.mOnCustomFiltersChanged);
+ Assert.assertTrue(observer.mOnFilterListsChanged);
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void resourceBlockedByFilter() throws Exception {
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ mConfigurationA.addCustomFilter("resource.png");
+ mCallbackHelper.notifyCalled();
+ });
+ mCallbackHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ loadTestUrl();
+ TestVerificationUtils.expectResourceBlocked(mHelper, "subresource");
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void resourceAllowedByFilter() throws Exception {
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ mConfigurationA.addCustomFilter("resource.png");
+ // Allowing filter for the mocked test.org domain that mTestServer hosts.
+ mConfigurationA.addCustomFilter("@@test.org$document");
+ mCallbackHelper.notifyCalled();
+ });
+ mCallbackHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ loadTestUrl();
+ TestVerificationUtils.expectResourceShown(mHelper, "subresource");
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void resourceAllowedByAllowedDomain() throws Exception {
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ mConfigurationA.addCustomFilter("resource.png");
+ mConfigurationA.addAllowedDomain("test.org");
+ mCallbackHelper.notifyCalled();
+ });
+ mCallbackHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ loadTestUrl();
+ TestVerificationUtils.expectResourceShown(mHelper, "subresource");
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void resourceBlockedBySecondConfiguration() throws Exception {
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ // ConfigurationA allows the resource.
+ // Allowing rules take precedence within a FilteringConfiguration.
+ mConfigurationA.addCustomFilter("resource.png");
+ mConfigurationA.addAllowedDomain("test.org");
+ // But ConfigurationB blocks the resource.
+ // Blocking takes precedence across FilteringConfigurations.
+ mConfigurationB.addCustomFilter("resource.png");
+ mCallbackHelper.notifyCalled();
+ });
+ mCallbackHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ loadTestUrl();
+ TestVerificationUtils.expectResourceBlocked(mHelper, "subresource");
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void noBlockingWithoutFilters() throws Exception {
+ loadTestUrl();
+ TestVerificationUtils.expectResourceShown(mHelper, "subresource");
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void createAndRemoveConfiguration() throws Exception {
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ // Check initial state.
+ FilteringConfiguration.removeConfiguration("adblock");
+ ArrayList<FilteringConfiguration> expectedConfigurations =
+ new ArrayList<FilteringConfiguration>();
+ expectedConfigurations.add(mConfigurationA);
+ expectedConfigurations.add(mConfigurationB);
+ Assert.assertEquals(expectedConfigurations, FilteringConfiguration.getConfigurations());
+ // Add new configuration (twice) and check.
+ FilteringConfiguration configurationC = FilteringConfiguration.createConfiguration("c");
+ FilteringConfiguration configurationC2 =
+ FilteringConfiguration.createConfiguration("c");
+ // Confirm this is the same reference.
+ Assert.assertEquals(configurationC, configurationC2);
+ expectedConfigurations.add(configurationC);
+ Assert.assertEquals(expectedConfigurations, FilteringConfiguration.getConfigurations());
+ // Remove configuration "c" twice (2nd attempt has no effect) and check.
+ FilteringConfiguration.removeConfiguration("c");
+ FilteringConfiguration.removeConfiguration("c");
+ expectedConfigurations.remove(configurationC);
+ Assert.assertEquals(expectedConfigurations, FilteringConfiguration.getConfigurations());
+ });
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void cannotUseRemovedConfiguration() throws Exception {
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ FilteringConfiguration configurationC = FilteringConfiguration.createConfiguration("c");
+ configurationC.setEnabled(false);
+ Assert.assertFalse(configurationC.isEnabled());
+ FilteringConfiguration.removeConfiguration("c");
+ try {
+ configurationC.setEnabled(true);
+ Assert.fail();
+ } catch (final IllegalStateException e) {
+ // Expected
+ }
+ // Recreate.
+ configurationC = FilteringConfiguration.createConfiguration("c");
+ Assert.assertTrue(configurationC.isEnabled());
+ configurationC.setEnabled(false);
+ Assert.assertFalse(configurationC.isEnabled());
+ });
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/ResourceClassificationNotifierTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/ResourceClassificationNotifierTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/ResourceClassificationNotifierTest.java
@@ -0,0 +1,135 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.IntegrationTest;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.FilteringConfiguration;
+import org.chromium.components.adblock.ResourceClassificationNotifier;
+import org.chromium.components.adblock.TestAdBlockedObserver;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.content_public.common.ContentSwitches;
+import org.chromium.net.test.EmbeddedTestServer;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+ ContentSwitches.HOST_RESOLVER_RULES + "=MAP * 127.0.0.1"})
+public class ResourceClassificationNotifierTest {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final CallbackHelper mHelper = new CallbackHelper();
+ public FilteringConfiguration mConfiguration;
+ public TestAdBlockedObserver mAdBlockedObserver = new TestAdBlockedObserver();
+
+ private EmbeddedTestServer mTestServer;
+ private String mTestUrl;
+
+ public void loadTestUrl() {
+ mActivityTestRule.loadUrl(mTestUrl, 5);
+ }
+
+ @Before
+ public void setUp() throws TimeoutException {
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ mConfiguration = FilteringConfiguration.createConfiguration("a");
+ ResourceClassificationNotifier.getInstance().addOnAdBlockedObserver(mAdBlockedObserver);
+ mHelper.notifyCalled();
+ });
+ mHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ mActivityTestRule.startMainActivityOnBlankPage();
+ mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
+ mTestUrl = mTestServer.getURLWithHostName(
+ "test.org", "/chrome/test/data/adblock/innermost_frame.html");
+ }
+
+ @After
+ public void tearDown() {
+ mTestServer.stopAndDestroyServer();
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void noNotificationWithoutBlocking() throws Exception {
+ loadTestUrl();
+
+ Assert.assertTrue(mAdBlockedObserver.blockedInfos.isEmpty());
+ Assert.assertTrue(mAdBlockedObserver.allowedInfos.isEmpty());
+ Assert.assertTrue(mAdBlockedObserver.allowedPageInfos.isEmpty());
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void resourceBlockedByFilter() throws Exception {
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ mConfiguration.addCustomFilter("resource.png");
+ mHelper.notifyCalled();
+ });
+ mHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ loadTestUrl();
+ // Observer was notified about the blocking
+ Assert.assertTrue(mAdBlockedObserver.isBlocked("resource.png"));
+ Assert.assertTrue(mAdBlockedObserver.allowedInfos.isEmpty());
+ Assert.assertTrue(mAdBlockedObserver.allowedPageInfos.isEmpty());
+ }
+
+ @Test
+ @IntegrationTest
+ @LargeTest
+ @Feature({"adblock"})
+ public void pageAllowed() throws Exception {
+ TestThreadUtils.runOnUiThreadBlocking(() -> {
+ mConfiguration.addCustomFilter("resource.png");
+ mConfiguration.addAllowedDomain("test.org");
+ mHelper.notifyCalled();
+ });
+ mHelper.waitForCallback(0, 1, 10, TimeUnit.SECONDS);
+ loadTestUrl();
+ // Observer was notified about the allowed resource
+ Assert.assertTrue(mAdBlockedObserver.blockedInfos.isEmpty());
+ Assert.assertTrue(mAdBlockedObserver.isAllowed("resource.png"));
+
+ // TODO(mpawlowski): The observer could also be notified about the entire domain being
+ // allowed: Assert.assertTrue(mAdBlockedObserver.isPageAllowed("test.org")); However this is
+ // currently broken with multiple FilteringConfigurations (DPD-1729).
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesCircumventionTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesCircumventionTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesCircumventionTest.java
@@ -0,0 +1,51 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesCircumventionTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesCircumventionTest extends TestPagesCircumventionTestBase {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesCspTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesCspTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesCspTest.java
@@ -0,0 +1,51 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesCspTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesCspTest extends TestPagesCspTestBase {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideEmuInvTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideEmuInvTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideEmuInvTest.java
@@ -0,0 +1,48 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesElemhideEmuInvTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesElemhideEmuInvTest extends TestPagesElemhideEmuInvTestBase {
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideEmuTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideEmuTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideEmuTest.java
@@ -0,0 +1,48 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesElemhideEmuTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesElemhideEmuTest extends TestPagesElemhideEmuTestBase {
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesElemhideTest.java
@@ -0,0 +1,48 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesElemhideTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesElemhideTest extends TestPagesElemhideTestBase {
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesExceptionTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesExceptionTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesExceptionTest.java
@@ -0,0 +1,100 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.task.PostTask;
+import org.chromium.base.task.TaskTraits;
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesExceptionTestBase;
+import org.chromium.content_public.browser.test.util.JavaScriptUtils;
+import org.chromium.content_public.common.ContentSwitches;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesExceptionTest extends TestPagesExceptionTestBase {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @Test
+ @LargeTest
+ @Feature({"adblock"})
+ @CommandLineFlags.Add(ContentSwitches.DISABLE_POPUP_BLOCKING)
+ public void testVerifyPopupException() throws Exception {
+ final String POPUP_TESTACE_URL =
+ TestPagesHelper.EXCEPTION_TESTPAGES_TESTCASES_ROOT + "popup";
+ mHelper.loadUrl(POPUP_TESTACE_URL);
+ Assert.assertEquals(1, mHelper.getTabCount());
+ final CallbackHelper tabsLoadedWaiter = mHelper.getTabsOpenedAndLoadedWaiter();
+ PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> {
+ try {
+ String numElements = JavaScriptUtils.executeJavaScriptAndWaitForResult(
+ mHelper.getWebContents(),
+ "var elements = document.getElementsByClassName(\"testcase-trigger\");"
+ + "for (let i = 0; i < elements.length; ++i) {"
+ + " elements[i].click();"
+ + "}"
+ + "elements.length;");
+ Assert.assertEquals("3", numElements);
+ } catch (TimeoutException e) {
+ Assert.assertEquals("Popups were triggered", "Popups were NOT triggered");
+ }
+ });
+ // Wait for three tab loaded events
+ tabsLoadedWaiter.waitForCallback(0, 3, TestPagesHelper.TEST_TIMEOUT_SEC, TimeUnit.SECONDS);
+ Assert.assertEquals(4, mHelper.getTabCount());
+ Assert.assertEquals(3, mHelper.numAllowedPopups());
+ Assert.assertTrue(mHelper.isPopupAllowed(
+ TestPagesHelper.TESTPAGES_RESOURCES_ROOT + "popup_exception/link.html"));
+ Assert.assertTrue(mHelper.isPopupAllowed(
+ TestPagesHelper.TESTPAGES_RESOURCES_ROOT + "popup_exception/script-window.html"));
+ Assert.assertTrue(mHelper.isPopupAllowed(
+ TestPagesHelper.TESTPAGES_RESOURCES_ROOT + "popup_exception/script-tab.html"));
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesFilterTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesFilterTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesFilterTest.java
@@ -0,0 +1,101 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.task.PostTask;
+import org.chromium.base.task.TaskTraits;
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesFilterTestBase;
+import org.chromium.content_public.browser.test.util.JavaScriptUtils;
+import org.chromium.content_public.common.ContentSwitches;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesFilterTest extends TestPagesFilterTestBase {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @Test
+ @LargeTest
+ @Feature({"adblock"})
+ @CommandLineFlags.Add(ContentSwitches.DISABLE_POPUP_BLOCKING)
+ public void testVerifyPopupFilters() throws Exception {
+ final String POPUP_TESTACE_URL = TestPagesHelper.FILTER_TESTPAGES_TESTCASES_ROOT + "popup";
+ mHelper.loadUrl(POPUP_TESTACE_URL);
+ Assert.assertEquals(1, mHelper.getTabCount());
+ final CallbackHelper tabsOpenedAndClosedWaiter = mHelper.getTabsOpenedAndClosedWaiter();
+ // Trigger popups which open and close when blocked
+ PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> {
+ try {
+ String numElements = JavaScriptUtils.executeJavaScriptAndWaitForResult(
+ mHelper.getWebContents(),
+ "var elements = document.getElementsByClassName(\"testcase-trigger\");"
+ + "for (let i = 0; i < elements.length; ++i) {"
+ + " elements[i].click();"
+ + "}"
+ + "elements.length;");
+ Assert.assertEquals("3", numElements);
+ } catch (TimeoutException e) {
+ Assert.assertEquals("Popups were triggered", "Popups were NOT triggered");
+ }
+ });
+ // Wait for three tab open events and three close tabs events
+ tabsOpenedAndClosedWaiter.waitForCallback(
+ 0, 6, TestPagesHelper.TEST_TIMEOUT_SEC, TimeUnit.SECONDS);
+ Assert.assertEquals(3, mHelper.numBlockedPopups());
+ Assert.assertTrue(mHelper.isPopupBlocked(
+ TestPagesHelper.TESTPAGES_RESOURCES_ROOT + "popup/link.html"));
+ Assert.assertTrue(mHelper.isPopupBlocked(
+ TestPagesHelper.TESTPAGES_RESOURCES_ROOT + "popup/script-window.html"));
+ Assert.assertTrue(mHelper.isPopupBlocked(
+ TestPagesHelper.TESTPAGES_RESOURCES_ROOT + "popup/script-tab.html"));
+ Assert.assertEquals(1, mHelper.getTabCount());
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesHeaderFilterTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesHeaderFilterTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesHeaderFilterTest.java
@@ -0,0 +1,51 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesHeaderFilterTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesHeaderFilterTest extends TestPagesHeaderFilterTestBase {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesHelper.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesHelper.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesHelper.java
@@ -0,0 +1,121 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.Assert;
+
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModelObserver;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesHelperBase;
+import org.chromium.components.adblock.TestVerificationUtils;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.url.GURL;
+
+import java.util.concurrent.TimeoutException;
+
+public class TestPagesHelper extends TestPagesHelperBase {
+ private ChromeTabbedActivityTestRule mActivityTestRule;
+
+ public void setActivityTestRule(ChromeTabbedActivityTestRule activityTestRule) {
+ mActivityTestRule = activityTestRule;
+ }
+
+ public void setUp(final ChromeTabbedActivityTestRule activityRule) {
+ mActivityTestRule = activityRule;
+ mActivityTestRule.startMainActivityOnBlankPage();
+ super.setUp();
+ }
+
+ public CallbackHelper getTabsOpenedAndClosedWaiter() {
+ final CallbackHelper callbackHelper = new CallbackHelper();
+ final TabModelSelector tabModelSelector =
+ mActivityTestRule.getActivity().getTabModelSelectorSupplier().get();
+ Assert.assertNotNull(tabModelSelector);
+ TestThreadUtils.runOnUiThreadBlocking(
+ () -> tabModelSelector.getCurrentModel().addObserver(new TabModelObserver() {
+ @Override
+ public void onFinishingTabClosure(Tab tab) {
+ // For some reason TabModelObserver#tabRemoved() is not called.
+ // Let's wait a bit to make sure tab is indeed closed.
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignored) {
+ }
+ callbackHelper.notifyCalled();
+ }
+
+ @Override
+ public void didAddTab(
+ Tab tab, int type, int creationState, boolean markedForSelection) {
+ callbackHelper.notifyCalled();
+ }
+ }));
+ return callbackHelper;
+ }
+
+ public CallbackHelper getTabsOpenedAndLoadedWaiter() {
+ final CallbackHelper callbackHelper = new CallbackHelper();
+ final TabModelSelector tabModelSelector =
+ mActivityTestRule.getActivity().getTabModelSelectorSupplier().get();
+ Assert.assertNotNull(tabModelSelector);
+ TestThreadUtils.runOnUiThreadBlocking(
+ () -> tabModelSelector.getCurrentModel().addObserver(new TabModelObserver() {
+ @Override
+ public void didAddTab(
+ Tab tab, int type, int creationState, boolean markedForSelection) {
+ tab.addObserver(new EmptyTabObserver() {
+ @Override
+ public void onPageLoadFinished(Tab tab, GURL url) {
+ callbackHelper.notifyCalled();
+ }
+ });
+ }
+ }));
+ return callbackHelper;
+ }
+
+ public int getTabCount() {
+ final TabModelSelector tabModelSelector =
+ mActivityTestRule.getActivity().getTabModelSelectorSupplier().get();
+ Assert.assertNotNull(tabModelSelector);
+ return tabModelSelector.getTotalTabCount();
+ }
+
+ @Override
+ public WebContents getWebContents() {
+ return mActivityTestRule.getActivity().getCurrentWebContents();
+ }
+
+ @Override
+ public void loadUrl(final String url) throws InterruptedException, TimeoutException {
+ mActivityTestRule.loadUrl(url, TEST_TIMEOUT_SEC);
+ }
+
+ @Override
+ public void loadUrlWaitForContent(final String url)
+ throws InterruptedException, TimeoutException {
+ loadUrl(url);
+ TestVerificationUtils.verifyCondition(
+ this, "document.getElementsByClassName('testcase-waiting-content').length == 0");
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesRewriteTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesRewriteTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesRewriteTest.java
@@ -0,0 +1,51 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesRewriteTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesRewriteTest extends TestPagesRewriteTestBase {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesSiteKeyTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesSiteKeyTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesSiteKeyTest.java
@@ -0,0 +1,51 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesSiteKeyTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesSiteKeyTest extends TestPagesSiteKeyTestBase {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesSnippetsTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesSnippetsTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesSnippetsTest.java
@@ -0,0 +1,51 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesSnippetsTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesSnippetsTest extends TestPagesSnippetsTestBase {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesWebsocketTest.java b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesWebsocketTest.java
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/android/javatests/src/org/chromium/chrome/browser/adblock/TestPagesWebsocketTest.java
@@ -0,0 +1,51 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.chromium.chrome.browser.adblock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.adblock.TestPagesWebsocketTestBase;
+
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class TestPagesWebsocketTest extends TestPagesWebsocketTestBase {
+ @Rule
+ public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
+ @Rule
+ public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+ private final TestPagesHelper mHelper = new TestPagesHelper();
+
+ @Before
+ public void setUp() {
+ mHelper.setUp(mActivityTestRule);
+ super.setUp(mHelper);
+ }
+
+ @After
+ public void tearDown() {
+ mHelper.tearDown();
+ }
+}
diff --git a/chrome/browser/adblock/content_security_policy_injector_factory.cc b/chrome/browser/adblock/content_security_policy_injector_factory.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/content_security_policy_injector_factory.cc
@@ -0,0 +1,69 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/content_security_policy_injector_factory.h"
+
+#include <memory>
+
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/adblock/content/browser/content_security_policy_injector_impl.h"
+#include "components/adblock/content/browser/frame_hierarchy_builder.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+// static
+ContentSecurityPolicyInjector*
+ContentSecurityPolicyInjectorFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<ContentSecurityPolicyInjector*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+// static
+ContentSecurityPolicyInjectorFactory*
+ContentSecurityPolicyInjectorFactory::GetInstance() {
+ static base::NoDestructor<ContentSecurityPolicyInjectorFactory> instance;
+ return instance.get();
+}
+
+ContentSecurityPolicyInjectorFactory::ContentSecurityPolicyInjectorFactory()
+ : BrowserContextKeyedServiceFactory(
+ "ContentSecurityPolicyInjector",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(SubscriptionServiceFactory::GetInstance());
+}
+
+ContentSecurityPolicyInjectorFactory::~ContentSecurityPolicyInjectorFactory() =
+ default;
+
+KeyedService* ContentSecurityPolicyInjectorFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new ContentSecurityPolicyInjectorImpl(
+ SubscriptionServiceFactory::GetForBrowserContext(context),
+ std::make_unique<FrameHierarchyBuilder>());
+}
+
+content::BrowserContext*
+ContentSecurityPolicyInjectorFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/content_security_policy_injector_factory.h b/chrome/browser/adblock/content_security_policy_injector_factory.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/content_security_policy_injector_factory.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_ADBLOCK_CONTENT_SECURITY_POLICY_INJECTOR_FACTORY_H_
+#define CHROME_BROWSER_ADBLOCK_CONTENT_SECURITY_POLICY_INJECTOR_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+class ContentSecurityPolicyInjector;
+class ContentSecurityPolicyInjectorFactory
+ : public BrowserContextKeyedServiceFactory {
+ public:
+ static ContentSecurityPolicyInjector* GetForBrowserContext(
+ content::BrowserContext* context);
+ static ContentSecurityPolicyInjectorFactory* GetInstance();
+
+ private:
+ friend class base::NoDestructor<ContentSecurityPolicyInjectorFactory>;
+ ContentSecurityPolicyInjectorFactory();
+ ~ContentSecurityPolicyInjectorFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace adblock
+
+#endif // CHROME_BROWSER_ADBLOCK_CONTENT_SECURITY_POLICY_INJECTOR_FACTORY_H_
diff --git a/chrome/browser/adblock/element_hider_factory.cc b/chrome/browser/adblock/element_hider_factory.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/element_hider_factory.cc
@@ -0,0 +1,63 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/element_hider_factory.h"
+
+#include <memory>
+
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/adblock/content/browser/element_hider_impl.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+// static
+ElementHider* ElementHiderFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<ElementHider*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+// static
+ElementHiderFactory* ElementHiderFactory::GetInstance() {
+ static base::NoDestructor<ElementHiderFactory> instance;
+ return instance.get();
+}
+
+ElementHiderFactory::ElementHiderFactory()
+ : BrowserContextKeyedServiceFactory(
+ "ElementHider",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(adblock::SubscriptionServiceFactory::GetInstance());
+}
+
+ElementHiderFactory::~ElementHiderFactory() = default;
+
+KeyedService* ElementHiderFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new ElementHiderImpl(
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(context));
+}
+
+content::BrowserContext* ElementHiderFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/element_hider_factory.h b/chrome/browser/adblock/element_hider_factory.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/element_hider_factory.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_ADBLOCK_ELEMENT_HIDER_FACTORY_H_
+#define CHROME_BROWSER_ADBLOCK_ELEMENT_HIDER_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+class ElementHider;
+class ElementHiderFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ static ElementHider* GetForBrowserContext(content::BrowserContext* context);
+ static ElementHiderFactory* GetInstance();
+
+ private:
+ friend class base::NoDestructor<ElementHiderFactory>;
+ ElementHiderFactory();
+ ~ElementHiderFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace adblock
+
+#endif // CHROME_BROWSER_ADBLOCK_ELEMENT_HIDER_FACTORY_H_
diff --git a/chrome/browser/adblock/resource_classification_runner_factory.cc b/chrome/browser/adblock/resource_classification_runner_factory.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/resource_classification_runner_factory.cc
@@ -0,0 +1,71 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/resource_classification_runner_factory.h"
+
+#include <memory>
+
+#include "chrome/browser/adblock/sitekey_storage_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/adblock/content/browser/frame_hierarchy_builder.h"
+#include "components/adblock/content/browser/resource_classification_runner_impl.h"
+#include "components/adblock/core/classifier/resource_classifier_impl.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+// static
+ResourceClassificationRunner*
+ResourceClassificationRunnerFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<ResourceClassificationRunner*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+// static
+ResourceClassificationRunnerFactory*
+ResourceClassificationRunnerFactory::GetInstance() {
+ static base::NoDestructor<ResourceClassificationRunnerFactory> instance;
+ return instance.get();
+}
+
+ResourceClassificationRunnerFactory::ResourceClassificationRunnerFactory()
+ : BrowserContextKeyedServiceFactory(
+ "ResourceClassificationRunner",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(SitekeyStorageFactory::GetInstance());
+}
+
+ResourceClassificationRunnerFactory::~ResourceClassificationRunnerFactory() =
+ default;
+
+KeyedService* ResourceClassificationRunnerFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new ResourceClassificationRunnerImpl(
+ base::MakeRefCounted<ResourceClassifierImpl>(),
+ std::make_unique<FrameHierarchyBuilder>(),
+ SitekeyStorageFactory::GetForBrowserContext(context));
+}
+
+content::BrowserContext*
+ResourceClassificationRunnerFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/resource_classification_runner_factory.h b/chrome/browser/adblock/resource_classification_runner_factory.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/resource_classification_runner_factory.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_ADBLOCK_RESOURCE_CLASSIFICATION_RUNNER_FACTORY_H_
+#define CHROME_BROWSER_ADBLOCK_RESOURCE_CLASSIFICATION_RUNNER_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+class ResourceClassificationRunner;
+class ResourceClassificationRunnerFactory
+ : public BrowserContextKeyedServiceFactory {
+ public:
+ static ResourceClassificationRunner* GetForBrowserContext(
+ content::BrowserContext* context);
+ static ResourceClassificationRunnerFactory* GetInstance();
+
+ private:
+ friend class base::NoDestructor<ResourceClassificationRunnerFactory>;
+ ResourceClassificationRunnerFactory();
+ ~ResourceClassificationRunnerFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace adblock
+
+#endif // CHROME_BROWSER_ADBLOCK_RESOURCE_CLASSIFICATION_RUNNER_FACTORY_H_
diff --git a/chrome/browser/adblock/session_stats_factory.cc b/chrome/browser/adblock/session_stats_factory.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/session_stats_factory.cc
@@ -0,0 +1,64 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/session_stats_factory.h"
+
+#include <memory>
+
+#include "chrome/browser/adblock/resource_classification_runner_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/adblock/content/browser/session_stats_impl.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+// static
+SessionStats* SessionStatsFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<SessionStats*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+SessionStatsFactory* SessionStatsFactory::GetInstance() {
+ static base::NoDestructor<SessionStatsFactory> instance;
+ return instance.get();
+}
+
+SessionStatsFactory::SessionStatsFactory()
+ : BrowserContextKeyedServiceFactory(
+ "SessionStats",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(ResourceClassificationRunnerFactory::GetInstance());
+}
+
+SessionStatsFactory::~SessionStatsFactory() = default;
+
+KeyedService* SessionStatsFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new SessionStatsImpl(
+ ResourceClassificationRunnerFactory::GetForBrowserContext(context));
+}
+
+content::BrowserContext* SessionStatsFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/session_stats_factory.h b/chrome/browser/adblock/session_stats_factory.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/session_stats_factory.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_ADBLOCK_SESSION_STATS_FACTORY_H_
+#define CHROME_BROWSER_ADBLOCK_SESSION_STATS_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+class SessionStats;
+class SessionStatsFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ static SessionStats* GetForBrowserContext(content::BrowserContext* context);
+ static SessionStatsFactory* GetInstance();
+
+ private:
+ friend class base::NoDestructor<SessionStatsFactory>;
+ SessionStatsFactory();
+ ~SessionStatsFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace adblock
+
+#endif // CHROME_BROWSER_ADBLOCK_SESSION_STATS_FACTORY_H_
diff --git a/chrome/browser/adblock/sitekey_storage_factory.cc b/chrome/browser/adblock/sitekey_storage_factory.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/sitekey_storage_factory.cc
@@ -0,0 +1,59 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/sitekey_storage_factory.h"
+
+#include <memory>
+
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/adblock/core/sitekey_storage_impl.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+// static
+SitekeyStorage* SitekeyStorageFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<SitekeyStorage*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+// static
+SitekeyStorageFactory* SitekeyStorageFactory::GetInstance() {
+ static base::NoDestructor<SitekeyStorageFactory> instance;
+ return instance.get();
+}
+
+SitekeyStorageFactory::SitekeyStorageFactory()
+ : BrowserContextKeyedServiceFactory(
+ "SitekeyStorage",
+ BrowserContextDependencyManager::GetInstance()) {}
+
+SitekeyStorageFactory::~SitekeyStorageFactory() = default;
+
+KeyedService* SitekeyStorageFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new SitekeyStorageImpl();
+}
+
+content::BrowserContext* SitekeyStorageFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/sitekey_storage_factory.h b/chrome/browser/adblock/sitekey_storage_factory.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/sitekey_storage_factory.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_ADBLOCK_SITEKEY_STORAGE_FACTORY_H_
+#define CHROME_BROWSER_ADBLOCK_SITEKEY_STORAGE_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+class SitekeyStorage;
+class SitekeyStorageFactory : public BrowserContextKeyedServiceFactory {
+ public:
+ static SitekeyStorage* GetForBrowserContext(content::BrowserContext* context);
+ static SitekeyStorageFactory* GetInstance();
+
+ private:
+ friend class base::NoDestructor<SitekeyStorageFactory>;
+ SitekeyStorageFactory();
+ ~SitekeyStorageFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace adblock
+
+#endif // CHROME_BROWSER_ADBLOCK_SITEKEY_STORAGE_FACTORY_H_
diff --git a/chrome/browser/adblock/subscription_persistent_metadata_factory.cc b/chrome/browser/adblock/subscription_persistent_metadata_factory.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/subscription_persistent_metadata_factory.cc
@@ -0,0 +1,63 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/subscription_persistent_metadata_factory.h"
+
+#include <memory>
+
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/adblock/core/subscription/subscription_persistent_metadata_impl.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+// static
+SubscriptionPersistentMetadata*
+SubscriptionPersistentMetadataFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<SubscriptionPersistentMetadata*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+// static
+SubscriptionPersistentMetadataFactory*
+SubscriptionPersistentMetadataFactory::GetInstance() {
+ static base::NoDestructor<SubscriptionPersistentMetadataFactory> instance;
+ return instance.get();
+}
+
+SubscriptionPersistentMetadataFactory::SubscriptionPersistentMetadataFactory()
+ : BrowserContextKeyedServiceFactory(
+ "AdblockSubscriptionPersistentMetadata",
+ BrowserContextDependencyManager::GetInstance()) {}
+SubscriptionPersistentMetadataFactory::
+ ~SubscriptionPersistentMetadataFactory() = default;
+
+KeyedService* SubscriptionPersistentMetadataFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new SubscriptionPersistentMetadataImpl(
+ Profile::FromBrowserContext(context)->GetOriginalProfile()->GetPrefs());
+}
+
+content::BrowserContext*
+SubscriptionPersistentMetadataFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/subscription_persistent_metadata_factory.h b/chrome/browser/adblock/subscription_persistent_metadata_factory.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/subscription_persistent_metadata_factory.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_ADBLOCK_SUBSCRIPTION_PERSISTENT_METADATA_FACTORY_H_
+#define CHROME_BROWSER_ADBLOCK_SUBSCRIPTION_PERSISTENT_METADATA_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+class SubscriptionPersistentMetadata;
+class SubscriptionPersistentMetadataFactory
+ : public BrowserContextKeyedServiceFactory {
+ public:
+ static SubscriptionPersistentMetadata* GetForBrowserContext(
+ content::BrowserContext* context);
+ static SubscriptionPersistentMetadataFactory* GetInstance();
+
+ private:
+ friend class base::NoDestructor<SubscriptionPersistentMetadataFactory>;
+ SubscriptionPersistentMetadataFactory();
+ ~SubscriptionPersistentMetadataFactory() override;
+
+ // BrowserContextKeyedServiceFactory:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace adblock
+
+#endif // CHROME_BROWSER_ADBLOCK_SUBSCRIPTION_PERSISTENT_METADATA_FACTORY_H_
diff --git a/chrome/browser/adblock/subscription_service_factory.cc b/chrome/browser/adblock/subscription_service_factory.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/subscription_service_factory.cc
@@ -0,0 +1,66 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/subscription_service_factory.h"
+
+#include <memory>
+
+#include "chrome/browser/adblock/subscription_persistent_metadata_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+// static
+SubscriptionService* SubscriptionServiceFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<SubscriptionService*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+// static
+SubscriptionServiceFactory* SubscriptionServiceFactory::GetInstance() {
+ static base::NoDestructor<SubscriptionServiceFactory> instance;
+ return instance.get();
+}
+
+SubscriptionServiceFactory::SubscriptionServiceFactory()
+ : SubscriptionServiceFactoryBase() {
+ DependsOn(SubscriptionPersistentMetadataFactory::GetInstance());
+}
+
+SubscriptionServiceFactory::~SubscriptionServiceFactory() = default;
+
+SubscriptionPersistentMetadata*
+SubscriptionServiceFactory::GetSubscriptionPersistentMetadata(
+ content::BrowserContext* context) const {
+ return SubscriptionPersistentMetadataFactory::GetForBrowserContext(context);
+}
+
+PrefService* SubscriptionServiceFactory::GetPrefs(
+ content::BrowserContext* context) const {
+ return Profile::FromBrowserContext(context)->GetOriginalProfile()->GetPrefs();
+}
+
+content::BrowserContext* SubscriptionServiceFactory::GetBrowserContextToUse(
+ content::BrowserContext* context) const {
+ return chrome::GetBrowserContextRedirectedInIncognito(context);
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/subscription_service_factory.h b/chrome/browser/adblock/subscription_service_factory.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/subscription_service_factory.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_ADBLOCK_SUBSCRIPTION_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_ADBLOCK_SUBSCRIPTION_SERVICE_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/adblock/content/browser/subscription_service_factory_base.h"
+#include "content/public/browser/browser_context.h"
+
+namespace adblock {
+
+class SubscriptionService;
+class SubscriptionServiceFactory : public SubscriptionServiceFactoryBase {
+ public:
+ static SubscriptionService* GetForBrowserContext(
+ content::BrowserContext* context);
+ static SubscriptionServiceFactory* GetInstance();
+
+ protected:
+ PrefService* GetPrefs(content::BrowserContext* context) const override;
+ SubscriptionPersistentMetadata* GetSubscriptionPersistentMetadata(
+ content::BrowserContext* context) const override;
+
+ private:
+ friend class base::NoDestructor<SubscriptionServiceFactory>;
+ SubscriptionServiceFactory();
+ ~SubscriptionServiceFactory() override;
+
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+};
+
+} // namespace adblock
+
+#endif // CHROME_BROWSER_ADBLOCK_SUBSCRIPTION_SERVICE_FACTORY_H_
diff --git a/chrome/browser/adblock/test/adblock_content_browser_client_browsertest.cc b/chrome/browser/adblock/test/adblock_content_browser_client_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_content_browser_client_browsertest.cc
@@ -0,0 +1,125 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/adblock_content_browser_client.h"
+
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/core/common/adblock_constants.h"
+#include "components/adblock/core/common/adblock_prefs.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "components/adblock/core/subscription/test/mock_subscription_service.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/spawned_test_server/spawned_test_server.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace adblock {
+
+class AdblockContentBrowserClientBrowserTest : public InProcessBrowserTest {
+ public:
+ void SetUpOnMainThread() override {
+ watcher_ = std::make_unique<content::TitleWatcher>(
+ browser()->tab_strip_model()->GetActiveWebContents(), u"PASS");
+ watcher_->AlsoWaitForTitle(u"FAIL");
+ embedded_test_server()->ServeFilesFromSourceDirectory(
+ net::GetWebSocketTestDataDirectory());
+ ASSERT_TRUE(embedded_test_server()->Start());
+ }
+
+ void TearDownOnMainThread() override { watcher_.reset(); }
+
+ void NavigateToHTTP(const std::string& path) {
+ // Visit a HTTPS page for testing.
+ GURL::Replacements replacements;
+ replacements.SetSchemeStr("http");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), ws_server_.GetURL(path).ReplaceComponents(replacements)));
+ }
+
+ std::string WaitAndGetTitle() {
+ return base::UTF16ToUTF8(watcher_->WaitAndGetTitle());
+ }
+
+ net::SpawnedTestServer ws_server_{net::SpawnedTestServer::TYPE_WS,
+ net::GetWebSocketTestDataDirectory()};
+
+ private:
+ std::unique_ptr<content::TitleWatcher> watcher_;
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockContentBrowserClientBrowserTest,
+ WebSocketConnectionNotInterrupted) {
+ // Launch a WebSocket server.
+ ASSERT_TRUE(ws_server_.Start());
+
+ // Disable ad-filtering.
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ adblock_configuration->SetEnabled(false);
+
+ NavigateToHTTP("split_packet_check.html");
+
+ // WebSocket connected.
+ EXPECT_EQ("PASS", WaitAndGetTitle());
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockContentBrowserClientBrowserTest,
+ WebSocketConnectionInterruptedButNotBlocked) {
+ // Launch a WebSocket server.
+ ASSERT_TRUE(ws_server_.Start());
+
+ // Enable ad-filtering.
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ adblock_configuration->SetEnabled(true);
+
+ NavigateToHTTP("split_packet_check.html");
+
+ // WebSocket connected, there were no blocking filters.
+ EXPECT_EQ("PASS", WaitAndGetTitle());
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockContentBrowserClientBrowserTest,
+ WebSocketConnectionInterruptedAndBlocked) {
+ // Launch a WebSocket server.
+ ASSERT_TRUE(ws_server_.Start());
+
+ // Intercept WebSocket and block connection via a filter.
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ adblock_configuration->SetEnabled(true);
+ adblock_configuration->RemoveCustomFilter(kAllowlistEverythingFilter);
+ adblock_configuration->AddCustomFilter({"*$websocket"});
+
+ NavigateToHTTP("split_packet_check.html");
+
+ // WebSocket did not connect.
+ EXPECT_EQ("FAIL", WaitAndGetTitle());
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_debug_url_browsertest.cc b/chrome/browser/adblock/test/adblock_debug_url_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_debug_url_browsertest.cc
@@ -0,0 +1,314 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string>
+
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/content/browser/adblock_url_loader_factory_for_test.h"
+#include "components/adblock/core/subscription/subscription_config.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::HasSubstr;
+using testing::Mock;
+using testing::Return;
+using testing::StartsWith;
+
+namespace adblock {
+
+class AdblockDebugUrlTest : public InProcessBrowserTest {
+ public:
+ AdblockDebugUrlTest() {}
+ ~AdblockDebugUrlTest() override = default;
+ AdblockDebugUrlTest(const AdblockDebugUrlTest&) = delete;
+ AdblockDebugUrlTest& operator=(const AdblockDebugUrlTest&) = delete;
+
+ protected:
+ std::string ExecuteScriptAndExtractString(const std::string& js_code) const {
+ content::WebContents* web_contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ return content::EvalJs(web_contents->GetPrimaryMainFrame(), js_code)
+ .ExtractString();
+ }
+
+ bool IsAdblockEnabled() {
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ DCHECK(adblock_configuration) << "Test expects \"adblock\" configuration";
+ return adblock_configuration->IsEnabled();
+ }
+
+ bool IsAAEnabled() {
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ DCHECK(adblock_configuration) << "Test expects \"adblock\" configuration";
+ return base::ranges::any_of(
+ adblock_configuration->GetFilterLists(),
+ [&](const auto& url) { return url == AcceptableAdsUrl(); });
+ }
+
+ const std::string kReadPageBodyScript =
+ "document.getElementsByTagName('body')[0].firstChild.innerHTML";
+
+ const std::string kAdblockDebugUrl =
+ "http://" +
+ adblock::AdblockURLLoaderFactoryForTest::kAdblockDebugDataHostName;
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockDebugUrlTest, TestInvalidUrls) {
+ GURL no_command1(kAdblockDebugUrl);
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), no_command1));
+ ASSERT_EQ("INVALID_COMMAND",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL no_command2(kAdblockDebugUrl + "/");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), no_command2));
+ ASSERT_EQ("INVALID_COMMAND",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL invalid_command_url(kAdblockDebugUrl + "/some_invalid_command");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), invalid_command_url));
+ ASSERT_EQ("INVALID_COMMAND",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL invalid_topic(kAdblockDebugUrl + "/filter/add/%2Fadsponsor.");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), invalid_topic));
+ ASSERT_EQ("INVALID_COMMAND",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL invalid_command(kAdblockDebugUrl + "/filters/ad/%2Fadsponsor.");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), invalid_command));
+ ASSERT_EQ("INVALID_COMMAND",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockDebugUrlTest, TestFilterCommands) {
+ GURL clear_filters_url(kAdblockDebugUrl + "/filters/clear");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), clear_filters_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL list_filters_url(kAdblockDebugUrl + "/filters/list");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_filters_url));
+ std::string expected_no_filters = "OK";
+ ASSERT_EQ(expected_no_filters,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL add_filters_url(kAdblockDebugUrl +
+ "/filters/add/%2FadsPlugin%2F%2A%0A%2Fadsponsor.");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), add_filters_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_filters_url));
+ auto response = ExecuteScriptAndExtractString(kReadPageBodyScript);
+ ASSERT_THAT(response, StartsWith("OK\n\n"));
+ ASSERT_THAT(response, HasSubstr("adsPlugin/*"));
+ ASSERT_THAT(response, HasSubstr("adsponsor."));
+
+ GURL remove_filter_url(kAdblockDebugUrl + "/filters/remove/%2Fadsponsor.");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), remove_filter_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_filters_url));
+ std::string expected_one_filter = "OK\n\n/adsPlugin/*\n";
+ ASSERT_EQ(expected_one_filter,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), clear_filters_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_filters_url));
+ ASSERT_EQ(expected_no_filters,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockDebugUrlTest, TestDomainCommands) {
+ GURL clear_domains_url(kAdblockDebugUrl + "/domains/clear");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), clear_domains_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL list_domains_url(kAdblockDebugUrl + "/domains/list");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_domains_url));
+ std::string expected_no_domains = "OK";
+ ASSERT_EQ(expected_no_domains,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL add_domain_url(kAdblockDebugUrl +
+ "/domains/add/example.com%0Adomain.org");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), add_domain_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_domains_url));
+ auto response = ExecuteScriptAndExtractString(kReadPageBodyScript);
+ ASSERT_THAT(response, StartsWith("OK\n\n"));
+ ASSERT_THAT(response, HasSubstr("example.com"));
+ ASSERT_THAT(response, HasSubstr("domain.org"));
+
+ GURL remove_domain_url(kAdblockDebugUrl + "/domains/remove/example.com");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), remove_domain_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_domains_url));
+ std::string expected_one_domain = "OK\n\ndomain.org\n";
+ ASSERT_EQ(expected_one_domain,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), clear_domains_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_domains_url));
+ ASSERT_EQ(expected_no_domains,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockDebugUrlTest, TestSubscriptionCommands) {
+ GURL clear_subscriptions_url(kAdblockDebugUrl + "/subscriptions/clear");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), clear_subscriptions_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL list_subscriptions_url(kAdblockDebugUrl + "/subscriptions/list");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_subscriptions_url));
+ std::string expected_no_subscriptions = "OK";
+ ASSERT_EQ(expected_no_subscriptions,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL add_subscription_url(kAdblockDebugUrl +
+ "/subscriptions/add/"
+ "https%3A%2F%2Fexample.com%2Flist1.txt%0Ahttps%3A%"
+ "2F%2Fwww.domain.org%2Flist2.txt");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), add_subscription_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_subscriptions_url));
+ auto response = ExecuteScriptAndExtractString(kReadPageBodyScript);
+ ASSERT_THAT(response, StartsWith("OK\n\n"));
+ ASSERT_THAT(response, HasSubstr("https://example.com/list1.txt"));
+ ASSERT_THAT(response, HasSubstr("https://www.domain.org/list2.txt"));
+
+ GURL remove_subscription_url(
+ kAdblockDebugUrl +
+ "/subscriptions/remove/https%3A%2F%2Fwww.domain.org%2Flist2.txt");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), remove_subscription_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_subscriptions_url));
+ std::string expected_one_subscription =
+ "OK\n\nhttps://example.com/list1.txt\n";
+ ASSERT_EQ(expected_one_subscription,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), clear_subscriptions_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_subscriptions_url));
+ ASSERT_EQ(expected_no_subscriptions,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockDebugUrlTest, TestEnableAdblockCommands) {
+ GURL enable_adblock__url(kAdblockDebugUrl + "/adblock/enable");
+ GURL disable_adblock_url(kAdblockDebugUrl + "/adblock/disable");
+ GURL adblock_state_url(kAdblockDebugUrl + "/adblock/state");
+
+ ASSERT_TRUE(IsAdblockEnabled());
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), adblock_state_url));
+ ASSERT_EQ("OK\n\nenabled",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), disable_adblock_url));
+ ASSERT_FALSE(IsAdblockEnabled());
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), adblock_state_url));
+ ASSERT_EQ("OK\n\ndisabled",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), enable_adblock__url));
+ ASSERT_TRUE(IsAdblockEnabled());
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), adblock_state_url));
+ ASSERT_EQ("OK\n\nenabled",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockDebugUrlTest, TestEnableAACommands) {
+ GURL enable_aa_url(kAdblockDebugUrl + "/aa/enable");
+ GURL disable_aa_url(kAdblockDebugUrl + "/aa/disable");
+ GURL aa_state_url(kAdblockDebugUrl + "/aa/state");
+
+ ASSERT_TRUE(IsAAEnabled());
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), aa_state_url));
+ ASSERT_EQ("OK\n\nenabled",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), disable_aa_url));
+ ASSERT_FALSE(IsAAEnabled());
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), aa_state_url));
+ ASSERT_EQ("OK\n\ndisabled",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), enable_aa_url));
+ ASSERT_TRUE(IsAAEnabled());
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), aa_state_url));
+ ASSERT_EQ("OK\n\nenabled",
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockDebugUrlTest, TestFilterCommandsInOldFormat) {
+ GURL clear_filters_url(kAdblockDebugUrl + "/filters/clear");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), clear_filters_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL list_filters_url(kAdblockDebugUrl + "/filters/list");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_filters_url));
+ std::string expected_no_filters = "OK";
+ ASSERT_EQ(expected_no_filters,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ GURL add_filters_url(kAdblockDebugUrl +
+ "/add?payload=%2FadsPlugin%2F%2A%0A%2Fadsponsor.");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), add_filters_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_filters_url));
+ auto response = ExecuteScriptAndExtractString(kReadPageBodyScript);
+ ASSERT_THAT(response, StartsWith("OK\n\n"));
+ ASSERT_THAT(response, HasSubstr("adsPlugin/*"));
+ ASSERT_THAT(response, HasSubstr("adsponsor."));
+
+ GURL remove_filter_url(kAdblockDebugUrl + "/remove?payload=%2Fadsponsor.");
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), remove_filter_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_filters_url));
+ std::string expected_one_filter = "OK\n\n/adsPlugin/*\n";
+ ASSERT_EQ(expected_one_filter,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), clear_filters_url));
+ ASSERT_EQ("OK", ExecuteScriptAndExtractString(kReadPageBodyScript));
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), list_filters_url));
+ ASSERT_EQ(expected_no_filters,
+ ExecuteScriptAndExtractString(kReadPageBodyScript));
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_filter_list_browsertest.cc b/chrome/browser/adblock/test/adblock_filter_list_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_filter_list_browsertest.cc
@@ -0,0 +1,260 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "base/check.h"
+#include "base/environment.h"
+#include "base/functional/callback_forward.h"
+#include "base/run_loop.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/adblock/core/adblock_switches.h"
+#include "components/adblock/core/subscription/subscription_config.h"
+#include "components/version_info/version_info.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace adblock {
+
+class AdblockFilterListDownloadTestBase : public InProcessBrowserTest {
+ public:
+ AdblockFilterListDownloadTestBase()
+ : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
+ // We need to set server and request handler asap
+ void SetUpInProcessBrowserTestFixture() override {
+ InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+ host_resolver()->AddRule("easylist-downloads.adblockplus.org", "127.0.0.1");
+ https_server_.RegisterRequestHandler(
+ base::BindRepeating(&AdblockFilterListDownloadTestBase::RequestHandler,
+ base::Unretained(this)));
+ net::EmbeddedTestServer::ServerCertificateConfig cert_config;
+ cert_config.dns_names = {"easylist-downloads.adblockplus.org"};
+ https_server_.SetSSLConfig(cert_config);
+ ASSERT_TRUE(https_server_.Start());
+ SetFilterListServerPortForTesting(https_server_.port());
+ }
+
+ void CheckRequestParams(const net::test_server::HttpRequest& request,
+ std::string expected_disabled_value) {
+ std::string os;
+ base::ReplaceChars(version_info::GetOSType(), base::kWhitespaceASCII, "",
+ &os);
+ EXPECT_TRUE(request.relative_url.find("addonName=eyeo-chromium-sdk") !=
+ std::string::npos);
+ EXPECT_TRUE(request.relative_url.find("addonVersion=1.0") !=
+ std::string::npos);
+ EXPECT_TRUE(request.relative_url.find("platformVersion=1.0") !=
+ std::string::npos);
+ EXPECT_TRUE(request.relative_url.find("platform=" + os) !=
+ std::string::npos);
+ if (RunsOnEyeoCI()) {
+ // Those two checks below require "eyeo_application_name" and
+ // "eyeo_application_version" to be set as gn gen args.
+ EXPECT_TRUE(
+ request.relative_url.find("application=app_name_from_ci_config") !=
+ std::string::npos)
+ << "Did you set \"eyeo_application_name\" gn gen arg?";
+ EXPECT_TRUE(request.relative_url.find(
+ "applicationVersion=app_version_from_ci_config") !=
+ std::string::npos)
+ << "Did you set \"eyeo_application_version\" gn gen arg?";
+ }
+ EXPECT_TRUE(
+ request.relative_url.find("disabled=" + expected_disabled_value) !=
+ std::string::npos);
+ }
+
+ virtual std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
+ const net::test_server::HttpRequest& request) {
+ if (request.method == net::test_server::HttpMethod::METHOD_GET &&
+ (base::StartsWith(request.relative_url, "/abp-filters-anti-cv.txt") ||
+ base::StartsWith(request.relative_url, "/easylist.txt") ||
+ base::StartsWith(request.relative_url, "/exceptionrules.txt"))) {
+ CheckRequestParams(request, "false");
+ default_lists_.insert(request.relative_url.substr(
+ 1, request.relative_url.find_first_of("?") - 1));
+ }
+
+ // Unhandled requests result in the Embedded test server sending a 404. This
+ // is fine for the purpose of this test.
+ return nullptr;
+ }
+
+ void NotifyTestFinished() {
+ finish_condition_met_ = true;
+ // If the test is currently waiting for the finish condition to be met, we
+ // need to quit the run loop.
+ if (quit_closure_) {
+ quit_closure_.Run();
+ }
+ }
+
+ void RunUntilTestFinished() {
+ // If the finish condition is already met, we don't need to run the run
+ // loop.
+ if (finish_condition_met_) {
+ return;
+ }
+ // Wait until NotifyTestFinished() gets called.
+ base::RunLoop run_loop;
+ quit_closure_ = run_loop.QuitClosure();
+ std::move(run_loop).Run();
+ }
+
+ bool RunsOnEyeoCI() {
+ auto env = base::Environment::Create();
+ std::string value;
+ env->GetVar("CI_PROJECT_NAME", &value);
+ return value == "chromium-sdk";
+ }
+
+ protected:
+ net::EmbeddedTestServer https_server_;
+ std::set<std::string> default_lists_;
+ bool finish_condition_met_ = false;
+ base::RepeatingClosure quit_closure_;
+};
+
+class AdblockEnabledFilterListDownloadTest
+ : public AdblockFilterListDownloadTestBase {
+ public:
+ std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
+ const net::test_server::HttpRequest& request) override {
+ auto result = AdblockFilterListDownloadTestBase::RequestHandler(request);
+ // If we get all expected requests we simply finish the test by closing
+ // the browser, otherwise test will fail with a timeout.
+ if (default_lists_.size() == 3) {
+ NotifyTestFinished();
+ }
+
+ // Unhandled requests result in the Embedded test server sending a 404.
+ return result;
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockEnabledFilterListDownloadTest,
+ TestInitialDownloads) {
+ RunUntilTestFinished();
+}
+
+class AdblockEnabledAcceptableAdsDisabledFilterListDownloadTest
+ : public AdblockFilterListDownloadTestBase {
+ public:
+ AdblockEnabledAcceptableAdsDisabledFilterListDownloadTest() {
+ const auto testing_interval = base::Seconds(1);
+ SubscriptionServiceFactory::SetUpdateCheckAndDelayIntervalsForTesting(
+ testing_interval, testing_interval);
+ }
+
+ std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
+ const net::test_server::HttpRequest& request) override {
+ // If we get expected HEAD request we simply finish the test by closing
+ // the browser, otherwise test will fail with a timeout.
+ if (request.method == net::test_server::HttpMethod::METHOD_HEAD &&
+ base::StartsWith(request.relative_url, "/exceptionrules.txt")) {
+ CheckRequestParams(request, "true");
+ NotifyTestFinished();
+ }
+
+ return nullptr;
+ }
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(adblock::switches::kDisableAcceptableAds);
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(
+ AdblockEnabledAcceptableAdsDisabledFilterListDownloadTest,
+ TestInitialDownloads) {
+ RunUntilTestFinished();
+}
+
+enum class DisableSwitch { Adblock, Eyeo };
+
+class AdblockDisabledFilterListDownloadTest
+ : public AdblockFilterListDownloadTestBase,
+ public testing::WithParamInterface<DisableSwitch> {
+ public:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(GetParam() == DisableSwitch::Adblock
+ ? adblock::switches::kDisableAdblock
+ : adblock::switches::kDisableEyeoFiltering);
+ }
+
+ void VerifyNoDownloads() {
+ ASSERT_EQ(0u, default_lists_.size());
+ NotifyTestFinished();
+ }
+};
+
+IN_PROC_BROWSER_TEST_P(AdblockDisabledFilterListDownloadTest,
+ TestInitialDownloads) {
+ // This test assumes that inital downloads (for adblock enabled) will happen
+ // within 10 seconds. When tested locally it always happens within 3 seconds.
+ base::OneShotTimer timer;
+ timer.Start(
+ FROM_HERE, base::Seconds(10),
+ base::BindOnce(&AdblockDisabledFilterListDownloadTest::VerifyNoDownloads,
+ base::Unretained(this)));
+ RunUntilTestFinished();
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+ AdblockDisabledFilterListDownloadTest,
+ testing::Values(DisableSwitch::Adblock,
+ DisableSwitch::Eyeo));
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+class AdblockPtLocaleFilterListDownloadTest
+ : public AdblockFilterListDownloadTestBase {
+ public:
+ AdblockPtLocaleFilterListDownloadTest() { setenv("LANGUAGE", "pt_PT", 1); }
+
+ std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
+ const net::test_server::HttpRequest& request) override {
+ EXPECT_FALSE(base::StartsWith(request.relative_url, "/easylist.txt"));
+ if (request.method == net::test_server::HttpMethod::METHOD_GET &&
+ (base::StartsWith(request.relative_url, "/abp-filters-anti-cv.txt") ||
+ base::StartsWith(request.relative_url,
+ "/easylistportuguese+easylist.txt") ||
+ base::StartsWith(request.relative_url, "/exceptionrules.txt"))) {
+ CheckRequestParams(request, "false");
+ default_lists_.insert(request.relative_url.substr(
+ 1, request.relative_url.find_first_of("?") - 1));
+ }
+
+ // If we get all expected requests we simply finish the test by closing
+ // the browser, otherwise test will fail with a timeout.
+ if (default_lists_.size() == 3) {
+ NotifyTestFinished();
+ }
+
+ // Unhandled requests result in the Embedded test server sending a 404.
+ return nullptr;
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockPtLocaleFilterListDownloadTest,
+ TestInitialDownloads) {
+ RunUntilTestFinished();
+}
+#endif
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_filtering_configurations_browsertest.cc b/chrome/browser/adblock/test/adblock_filtering_configurations_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_filtering_configurations_browsertest.cc
@@ -0,0 +1,459 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <list>
+#include "base/memory/raw_ptr.h"
+#include "base/ranges/algorithm.h"
+#include "base/run_loop.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/core/adblock_switches.h"
+#include "components/adblock/core/common/adblock_constants.h"
+#include "components/adblock/core/configuration/filtering_configuration.h"
+#include "components/adblock/core/configuration/persistent_filtering_configuration.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "components/version_info/version_info.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "gmock/gmock.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "url/gurl.h"
+
+namespace adblock {
+
+class SubscriptionInstalledWaiter
+ : public SubscriptionService::SubscriptionObserver {
+ public:
+ explicit SubscriptionInstalledWaiter(
+ SubscriptionService* subscription_service)
+ : subscription_service_(subscription_service) {
+ subscription_service_->AddObserver(this);
+ }
+
+ ~SubscriptionInstalledWaiter() override {
+ subscription_service_->RemoveObserver(this);
+ }
+
+ void WaitUntilSubscriptionsInstalled(std::vector<GURL> subscriptions) {
+ awaited_subscriptions_ = std::move(subscriptions);
+ run_loop_.Run();
+ }
+
+ void OnSubscriptionInstalled(const GURL& subscription_url) override {
+ awaited_subscriptions_.erase(
+ base::ranges::remove(awaited_subscriptions_, subscription_url),
+ awaited_subscriptions_.end());
+ if (awaited_subscriptions_.empty()) {
+ run_loop_.Quit();
+ }
+ }
+
+ protected:
+ raw_ptr<SubscriptionService> subscription_service_;
+ base::RunLoop run_loop_;
+ std::vector<GURL> awaited_subscriptions_;
+};
+
+class AdblockFilteringConfigurationBrowserTest : public InProcessBrowserTest {
+ public:
+ void SetUpInProcessBrowserTestFixture() override {
+ InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+ host_resolver()->AddRule("*", "127.0.0.1");
+ embedded_test_server()->ServeFilesFromSourceDirectory(
+ "chrome/test/data/adblock");
+ ASSERT_TRUE(embedded_test_server()->Start());
+ }
+
+ void SetUpOnMainThread() override {
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ adblock_configuration->RemoveCustomFilter(kAllowlistEverythingFilter);
+ }
+
+ GURL BlockingFilterListUrl() {
+ return embedded_test_server()->GetURL(
+ "/filterlist_that_blocks_resource.txt");
+ }
+
+ GURL ElementHidingFilterListUrl() {
+ return embedded_test_server()->GetURL(
+ "/filterlist_that_hides_resource.txt");
+ }
+
+ GURL AllowingFilterListUrl() {
+ return embedded_test_server()->GetURL(
+ "/filterlist_that_allows_resource.txt");
+ }
+
+ GURL GetPageUrl() {
+ return embedded_test_server()->GetURL("test.org", "/innermost_frame.html");
+ }
+
+ void NavigateToPage() {
+ ASSERT_TRUE(NavigateToURL(
+ browser()->tab_strip_model()->GetActiveWebContents(), GetPageUrl()));
+ }
+
+ std::unique_ptr<PersistentFilteringConfiguration> MakeConfiguration(
+ std::string name) {
+ return std::make_unique<PersistentFilteringConfiguration>(
+ browser()->profile()->GetOriginalProfile()->GetPrefs(), name);
+ }
+
+ void InstallFilteringConfiguration(
+ std::unique_ptr<FilteringConfiguration> configuration) {
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->InstallFilteringConfiguration(std::move(configuration));
+ }
+
+ void UninstallFilteringConfiguration(const std::string& configuration_name) {
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->UninstallFilteringConfiguration(configuration_name);
+ }
+
+ void WaitUntilSubscriptionsInstalled(std::vector<GURL> subscriptions) {
+ SubscriptionInstalledWaiter waiter(
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile()));
+ waiter.WaitUntilSubscriptionsInstalled(std::move(subscriptions));
+ }
+
+ std::string GetResourcesComputedStyle() {
+ const std::string javascript =
+ "window.getComputedStyle(document.getElementById('subresource'))."
+ "display";
+ return content::EvalJs(browser()
+ ->tab_strip_model()
+ ->GetActiveWebContents()
+ ->GetPrimaryMainFrame(),
+ javascript)
+ .ExtractString();
+ }
+
+ void ExpectResourceBlocked() {
+ EXPECT_EQ("none", GetResourcesComputedStyle());
+ }
+
+ void ExpectResourceShown() {
+ EXPECT_EQ("inline", GetResourcesComputedStyle());
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ NoBlockingByDefault) {
+ auto configuration = MakeConfiguration("config");
+ InstallFilteringConfiguration(std::move(configuration));
+
+ NavigateToPage();
+ ExpectResourceShown();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ ResourceBlockedByFilteringConfigurationsList) {
+ auto configuration = MakeConfiguration("config");
+ configuration->AddFilterList(BlockingFilterListUrl());
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ WaitUntilSubscriptionsInstalled({BlockingFilterListUrl()});
+
+ NavigateToPage();
+ ExpectResourceBlocked();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ ResourceHiddenByFilteringConfigurationsList) {
+ auto configuration = MakeConfiguration("config");
+ configuration->AddFilterList(ElementHidingFilterListUrl());
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ WaitUntilSubscriptionsInstalled({ElementHidingFilterListUrl()});
+
+ NavigateToPage();
+ ExpectResourceBlocked();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ ResourceAllowedByFilteringConfigurationsList) {
+ auto configuration = MakeConfiguration("config");
+ configuration->AddFilterList(BlockingFilterListUrl());
+ configuration->AddFilterList(ElementHidingFilterListUrl());
+ configuration->AddFilterList(AllowingFilterListUrl());
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ WaitUntilSubscriptionsInstalled({BlockingFilterListUrl(),
+ AllowingFilterListUrl(),
+ ElementHidingFilterListUrl()});
+
+ NavigateToPage();
+ ExpectResourceShown();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ BlockingTakesPrecedenceBetweenConfigurations) {
+ auto blocking_configuration = MakeConfiguration("blocking");
+ blocking_configuration->AddFilterList(BlockingFilterListUrl());
+
+ auto allowing_configuration = MakeConfiguration("allowing");
+ allowing_configuration->AddFilterList(AllowingFilterListUrl());
+
+ InstallFilteringConfiguration(std::move(blocking_configuration));
+ InstallFilteringConfiguration(std::move(allowing_configuration));
+
+ WaitUntilSubscriptionsInstalled(
+ {BlockingFilterListUrl(), AllowingFilterListUrl()});
+
+ NavigateToPage();
+ ExpectResourceBlocked();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ ElementBlockedByCustomFilter) {
+ auto configuration = MakeConfiguration("config");
+ configuration->AddCustomFilter("*resource.png");
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ NavigateToPage();
+ ExpectResourceBlocked();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ ElementAllowedByCustomFilter) {
+ auto configuration = MakeConfiguration("config");
+ configuration->AddCustomFilter("*resource.png");
+ configuration->AddCustomFilter("@@*resource.png");
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ NavigateToPage();
+ ExpectResourceShown();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ ElementAllowedByAllowedDomain) {
+ auto configuration = MakeConfiguration("config");
+ configuration->AddCustomFilter("*resource.png");
+ configuration->AddAllowedDomain(GetPageUrl().host());
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ NavigateToPage();
+ ExpectResourceShown();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ PRE_CustomFiltersPersist) {
+ auto configuration = MakeConfiguration("persistent");
+ // This custom filter will survive browser restart.
+ configuration->AddCustomFilter("*resource.png");
+ InstallFilteringConfiguration(std::move(configuration));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ CustomFiltersPersist) {
+ auto configurations =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetInstalledFilteringConfigurations();
+ auto configuration = base::ranges::find(configurations, "persistent",
+ &FilteringConfiguration::GetName);
+ ASSERT_TRUE(configuration != configurations.end());
+ EXPECT_THAT((*configuration)->GetCustomFilters(),
+ testing::UnorderedElementsAre("*resource.png"));
+
+ NavigateToPage();
+ ExpectResourceBlocked();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ DisabledConfigurationDoesNotBlock) {
+ auto configuration = MakeConfiguration("config");
+ configuration->AddCustomFilter("*resource.png");
+ configuration->SetEnabled(false);
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ NavigateToPage();
+ ExpectResourceShown();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ ConfigurationCanBeUsedAfterInstalling) {
+ auto configuration = MakeConfiguration("config");
+ auto* configuration_ptr = configuration.get();
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ configuration_ptr->AddCustomFilter("*resource.png");
+
+ NavigateToPage();
+ ExpectResourceBlocked();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ ConfigurationCanBeDisabledAfterInstalling) {
+ auto configuration = MakeConfiguration("config");
+ auto* configuration_ptr = configuration.get();
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ configuration_ptr->AddCustomFilter("*resource.png");
+ configuration_ptr->SetEnabled(false);
+
+ NavigateToPage();
+ ExpectResourceShown();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ SubscriptionsDownloadedAfterConfigurationEnabled) {
+ auto configuration = MakeConfiguration("config");
+ configuration->SetEnabled(false);
+ configuration->AddFilterList(BlockingFilterListUrl());
+ configuration->AddFilterList(ElementHidingFilterListUrl());
+ configuration->AddFilterList(AllowingFilterListUrl());
+ auto* configuration_ptr = configuration.get();
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ configuration_ptr->SetEnabled(true);
+
+ WaitUntilSubscriptionsInstalled({BlockingFilterListUrl(),
+ AllowingFilterListUrl(),
+ ElementHidingFilterListUrl()});
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ PRE_DownloadedSubscriptionsPersistOnDisk) {
+ auto configuration = MakeConfiguration("config");
+ // This filter list setting will survive browser restart.
+ configuration->AddFilterList(BlockingFilterListUrl());
+
+ InstallFilteringConfiguration(std::move(configuration));
+
+ // This downloaded subscription won't need to be re-downloaded after restart.
+ WaitUntilSubscriptionsInstalled({BlockingFilterListUrl()});
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ DownloadedSubscriptionsPersistOnDisk) {
+ NavigateToPage();
+ ExpectResourceBlocked();
+}
+
+// 1st run: create.
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ PRE_PRE_CreateThenRemoveConfiguration) {
+ auto configuration = MakeConfiguration("persistent");
+ InstallFilteringConfiguration(std::move(configuration));
+}
+
+// 2nd run: remove.
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ PRE_CreateThenRemoveConfiguration) {
+ auto configurations =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetInstalledFilteringConfigurations();
+ auto configuration = base::ranges::find(configurations, "persistent",
+ &FilteringConfiguration::GetName);
+ ASSERT_TRUE(configuration != configurations.end());
+ UninstallFilteringConfiguration((*configuration)->GetName());
+ configurations =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetInstalledFilteringConfigurations();
+ configuration = base::ranges::find(configurations, "persistent",
+ &FilteringConfiguration::GetName);
+ ASSERT_TRUE(configuration == configurations.end());
+}
+
+// 3rd run: verify not present.
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationBrowserTest,
+ CreateThenRemoveConfiguration) {
+ auto configurations =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetInstalledFilteringConfigurations();
+ auto configuration = base::ranges::find(configurations, "persistent",
+ &FilteringConfiguration::GetName);
+ ASSERT_TRUE(configuration == configurations.end());
+}
+
+class AdblockFilteringConfigurationDisableSwitchBrowserTest
+ : public AdblockFilteringConfigurationBrowserTest {
+ public:
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ if (base::StartsWith(
+ ::testing::UnitTest::GetInstance()->current_test_info()->name(),
+ "PRE_CreateConfigAndConfirmEnableStateAfterReset")) {
+ command_line->AppendSwitch(adblock::switches::kDisableEyeoFiltering);
+ }
+ }
+};
+
+// 1st run: create configuration and make sure it is enabled by default.
+IN_PROC_BROWSER_TEST_F(
+ AdblockFilteringConfigurationDisableSwitchBrowserTest,
+ PRE_PRE_PRE_CreateConfigAndConfirmEnableStateAfterReset) {
+ auto configuration = MakeConfiguration("persistent");
+ ASSERT_TRUE(configuration->IsEnabled());
+ InstallFilteringConfiguration(std::move(configuration));
+}
+
+// 2nd run: make sure configuration is enabled after restart.
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationDisableSwitchBrowserTest,
+ PRE_PRE_CreateConfigAndConfirmEnableStateAfterReset) {
+ auto configurations =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetInstalledFilteringConfigurations();
+ auto configuration = base::ranges::find(configurations, "persistent",
+ &FilteringConfiguration::GetName);
+ ASSERT_TRUE(configuration != configurations.end());
+ ASSERT_TRUE((*configuration)->IsEnabled());
+}
+
+// 3rd run: after adding "--disable-eyeo-filtering" make sure configuration is
+// disabled.
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationDisableSwitchBrowserTest,
+ PRE_CreateConfigAndConfirmEnableStateAfterReset) {
+ auto configurations =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetInstalledFilteringConfigurations();
+ auto configuration = base::ranges::find(configurations, "persistent",
+ &FilteringConfiguration::GetName);
+ ASSERT_TRUE(configuration != configurations.end());
+ ASSERT_FALSE((*configuration)->IsEnabled());
+}
+
+// 4th run: without "--disable-eyeo-filtering" make sure configuration is still
+// disabled.
+IN_PROC_BROWSER_TEST_F(AdblockFilteringConfigurationDisableSwitchBrowserTest,
+ CreateConfigAndConfirmEnableStateAfterReset) {
+ auto configurations =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetInstalledFilteringConfigurations();
+ auto configuration = base::ranges::find(configurations, "persistent",
+ &FilteringConfiguration::GetName);
+ ASSERT_TRUE(configuration != configurations.end());
+ ASSERT_FALSE((*configuration)->IsEnabled());
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_frame_hierarchy_builder_browsertest.cc b/chrome/browser/adblock/test/adblock_frame_hierarchy_builder_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_frame_hierarchy_builder_browsertest.cc
@@ -0,0 +1,464 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <vector>
+
+#include "base/ranges/algorithm.h"
+#include "chrome/browser/adblock/resource_classification_runner_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ssl/https_upgrades_util.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/content/browser/adblock_filter_match.h"
+#include "components/adblock/content/browser/frame_hierarchy_builder.h"
+#include "components/adblock/content/browser/resource_classification_runner.h"
+#include "components/adblock/core/common/adblock_constants.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "components/blocked_content/popup_blocker_tab_helper.h"
+#include "components/embedder_support/switches.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace adblock {
+
+namespace {
+class TabAddedRemovedObserver : public TabStripModelObserver {
+ public:
+ explicit TabAddedRemovedObserver(TabStripModel* tab_strip_model) {
+ tab_strip_model->AddObserver(this);
+ }
+
+ void OnTabStripModelChanged(
+ TabStripModel* tab_strip_model,
+ const TabStripModelChange& change,
+ const TabStripSelectionChange& selection) override {
+ if (change.type() == TabStripModelChange::kInserted) {
+ inserted_ = true;
+ return;
+ }
+ if (change.type() == TabStripModelChange::kRemoved) {
+ EXPECT_TRUE(inserted_);
+ removed_ = true;
+ loop_.Quit();
+ return;
+ }
+ NOTREACHED();
+ }
+
+ void Wait() {
+ if (inserted_ && removed_) {
+ return;
+ }
+ loop_.Run();
+ }
+
+ private:
+ bool inserted_ = false;
+ bool removed_ = false;
+ base::RunLoop loop_;
+};
+} // namespace
+
+class ResourceClassificationRunnerObserver
+ : public ResourceClassificationRunner::Observer {
+ public:
+ ~ResourceClassificationRunnerObserver() override {
+ VerifyNoUnexpectedNotifications();
+ }
+ // ResourceClassificationRunner::Observer:
+ void OnAdMatched(const GURL& url,
+ FilterMatchResult match_result,
+ const std::vector<GURL>& parent_frame_urls,
+ ContentType content_type,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {
+ if (match_result == FilterMatchResult::kAllowRule) {
+ allowed_ads_notifications.push_back(url);
+ } else {
+ blocked_ads_notifications.push_back(url);
+ }
+ }
+
+ void OnPageAllowed(const GURL& url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {
+ allowed_pages_notifications.push_back(url);
+ }
+
+ void OnPopupMatched(const GURL& url,
+ FilterMatchResult match_result,
+ const GURL& opener_url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {
+ auto& list = (match_result == FilterMatchResult::kBlockRule
+ ? blocked_popups_notifications
+ : allowed_popups_notifications);
+ auto it = std::find(list.begin(), list.end(), url.ExtractFileName());
+ ASSERT_FALSE(it == list.end())
+ << "Path " << url.ExtractFileName() << " not on list";
+ list.erase(it);
+ if (popup_notifications_run_loop_ && allowed_popups_notifications.empty() &&
+ blocked_popups_notifications.empty()) {
+ popup_notifications_run_loop_->Quit();
+ }
+ }
+
+ void VerifyNotificationSent(base::StringPiece path, std::vector<GURL>& list) {
+ auto it = base::ranges::find(list, path, &GURL::ExtractFileName);
+ ASSERT_FALSE(it == list.end()) << "Path " << path << " not on list";
+ // Remove expected notifications so that we can verify there are no
+ // unexpected notifications left by the end of each test.
+ list.erase(it);
+ }
+
+ void VerifyNoUnexpectedNotifications() {
+ EXPECT_TRUE(blocked_ads_notifications.empty());
+ EXPECT_TRUE(allowed_ads_notifications.empty());
+ EXPECT_TRUE(blocked_popups_notifications.empty());
+ EXPECT_TRUE(allowed_popups_notifications.empty());
+ EXPECT_TRUE(allowed_pages_notifications.empty());
+ }
+
+ std::vector<GURL> blocked_ads_notifications;
+ std::vector<GURL> allowed_ads_notifications;
+ std::vector<GURL> allowed_pages_notifications;
+ std::vector<std::string> blocked_popups_notifications;
+ std::vector<std::string> allowed_popups_notifications;
+ std::unique_ptr<base::RunLoop> popup_notifications_run_loop_;
+};
+
+// Simulated setup:
+// http://outer.com/outermost_frame.html
+// has an iframe: http://middle.com/middle_frame.html
+// has an iframe: http://inner.com/innermost_frame.html
+// has a subresource http://inner.com/resource.png
+//
+// All of these files are in chrome/test/data/adblock. Cross-domain distribution
+// is simulated via SetupCrossSiteRedirector.
+// innermost_frame.html reports whether resource.png is visible via
+// window.top.postMessage to outermost_frame.html, which stores a global
+// subresource_visible JS variable.
+class AdblockFrameHierarchyBrowserTest : public InProcessBrowserTest {
+ public:
+ void SetUpOnMainThread() override {
+ InProcessBrowserTest::SetUpOnMainThread();
+ host_resolver()->AddRule("*", "127.0.0.1");
+ embedded_test_server()->ServeFilesFromSourceDirectory(
+ "chrome/test/data/adblock");
+ content::SetupCrossSiteRedirector(embedded_test_server());
+ AllowHttpForHostnamesForTesting({"outer.com", "inner.com", "middle.com"},
+ browser()->profile()->GetPrefs());
+ ASSERT_TRUE(embedded_test_server()->Start());
+ auto* classification_runner =
+ ResourceClassificationRunnerFactory::GetForBrowserContext(
+ browser()->profile());
+ classification_runner->AddObserver(&observer);
+ }
+
+ void TearDownOnMainThread() override {
+ auto* classification_runner =
+ ResourceClassificationRunnerFactory::GetForBrowserContext(
+ browser()->profile());
+ classification_runner->RemoveObserver(&observer);
+ InProcessBrowserTest::TearDownOnMainThread();
+ }
+
+ void SetUpCommandLine(base::CommandLine* command_line) override {
+ command_line->AppendSwitch(embedder_support::kDisablePopupBlocking);
+ }
+
+ void SetFilters(std::vector<std::string> filters) {
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ adblock_configuration->RemoveCustomFilter(kAllowlistEverythingFilter);
+ for (auto& filter : filters) {
+ adblock_configuration->AddCustomFilter(filter);
+ }
+ }
+
+ void NavigateToOutermostFrame() {
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), embedded_test_server()->GetURL(
+ "/cross-site/outer.com/outermost_frame.html")));
+ }
+
+ void NavigateToOutermostFrameWithAboutBlank() {
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL(
+ "/cross-site/outer.com/outermost_frame_with_about_blank.html")));
+ }
+
+ void NavigateToPopupParentFrameAndWaitForNotifications() {
+ observer.popup_notifications_run_loop_ = std::make_unique<base::RunLoop>();
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), embedded_test_server()->GetURL(
+ "/cross-site/outer.com/popup_parent.html")));
+ if (!(observer.allowed_popups_notifications.empty() &&
+ observer.blocked_popups_notifications.empty())) {
+ observer.popup_notifications_run_loop_->Run();
+ }
+ }
+
+ void VerifyTargetResourceShown(bool expected_shown) {
+ // Since in one test we dynamically load (write) `about:blank` iframe after
+ // parent page is loaded, we need to have some wait & poll mechanism to wait
+ // until such a frame (and its resources) is completely loaded by JS.
+ std::string script = base::StringPrintf(R"(
+ (async () => {
+ let count = 10;
+ function waitFor(condition) {
+ const poll = resolve => {
+ if(condition() || !count--) resolve();
+ else setTimeout(_ => poll(resolve), 200);
+ }
+ return new Promise(poll);
+ }
+ // Waits up to 2 seconds
+ await waitFor(_ => subresource_visible === %s);
+ return subresource_visible === true;
+ })()
+ )",
+ expected_shown ? "true" : "false");
+ EXPECT_EQ(
+ expected_shown,
+ content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
+ script));
+ }
+
+ int NumberOfOpenTabs() { return browser()->tab_strip_model()->GetTabCount(); }
+
+ ResourceClassificationRunnerObserver observer;
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest,
+ SubresourceShownWithNoFilters) {
+ SetFilters({});
+ NavigateToOutermostFrame();
+ VerifyTargetResourceShown(true);
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest, SubresourceBlocked) {
+ SetFilters({"/resource.png"});
+ NavigateToOutermostFrame();
+ VerifyTargetResourceShown(false);
+ observer.VerifyNotificationSent("resource.png",
+ observer.blocked_ads_notifications);
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest,
+ SubresourceAllowedViaInnerFrame) {
+ SetFilters({"/resource.png", "@@||inner.com^$document"});
+ NavigateToOutermostFrame();
+ VerifyTargetResourceShown(true);
+ observer.VerifyNotificationSent("resource.png",
+ observer.allowed_ads_notifications);
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest,
+ SubresourceAllowedViaMiddleFrame) {
+ SetFilters({"/resource.png", "@@||middle.com^$document"});
+ NavigateToOutermostFrame();
+ VerifyTargetResourceShown(true);
+ observer.VerifyNotificationSent("resource.png",
+ observer.allowed_ads_notifications);
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest,
+ SubresourceAllowedViaOutermostFrame) {
+ SetFilters({"/resource.png", "@@||outer.com^$document"});
+ NavigateToOutermostFrame();
+ VerifyTargetResourceShown(true);
+ observer.VerifyNotificationSent("resource.png",
+ observer.allowed_ads_notifications);
+ observer.VerifyNotificationSent("outermost_frame.html",
+ observer.allowed_pages_notifications);
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest,
+ SubresourceBlockedWhenInvalidAllowRule) {
+ SetFilters({"/resource.png", "@@||bogus.com^$document"});
+ NavigateToOutermostFrame();
+ VerifyTargetResourceShown(false);
+ observer.VerifyNotificationSent("resource.png",
+ observer.blocked_ads_notifications);
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest,
+ DISABLED_PopupHandledByChromiumWithoutFilters) {
+ // Without any popup-specific filters, blocking popups is handed over to
+ // Chromium, which has it's own heuristics that are not based on filters.
+ SetFilters({});
+ NavigateToPopupParentFrameAndWaitForNotifications();
+ // The popup was not opened:
+ EXPECT_EQ(1, NumberOfOpenTabs());
+ // Because Chromium's built-in popup blocker stopped it:
+ EXPECT_EQ(1u, blocked_content::PopupBlockerTabHelper::FromWebContents(
+ browser()->tab_strip_model()->GetActiveWebContents())
+ ->GetBlockedPopupsCount());
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest, PopupBlockedByFilter) {
+ SetFilters({"http://inner.com*/popup.html$popup"});
+ observer.blocked_popups_notifications.emplace_back("popup.html");
+ TabAddedRemovedObserver observer(browser()->tab_strip_model());
+ NavigateToPopupParentFrameAndWaitForNotifications();
+ observer.Wait();
+ EXPECT_EQ(1, NumberOfOpenTabs());
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest, PopupAllowedByFilter) {
+ SetFilters({"http://inner.com*/popup.html$popup",
+ "@@http://inner.com*/popup.html$popup"});
+ observer.allowed_popups_notifications.emplace_back("popup.html");
+ NavigateToPopupParentFrameAndWaitForNotifications();
+ // Popup was allowed to open in a new tab
+ EXPECT_EQ(2, NumberOfOpenTabs());
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest,
+ PopupAllowedByDomainSpecificFilter) {
+ // The frame that wants to open the popup is hosted on middle.com.
+ // The $popup allow rule applies to that frame.
+ SetFilters({"http://inner.com*/popup.html$popup",
+ "@@http://inner.com*/popup.html$popup,domain=middle.com"});
+ observer.allowed_popups_notifications.emplace_back("popup.html");
+ NavigateToPopupParentFrameAndWaitForNotifications();
+ // Popup was allowed to open in a new tab
+ EXPECT_EQ(2, NumberOfOpenTabs());
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest,
+ PopupNotAllowedByDomainSpecificFilter) {
+ // The frame that wants to open the popup is hosted on middle.com.
+ // The $popup allow rule does not apply because it is specific to outer.com.
+ // outer.com is not the frame that is opening the popup.
+ SetFilters({"http://inner.com*/popup.html$popup",
+ "@@http://inner.com*/popup.html$popup,domain=outer.com"});
+ observer.blocked_popups_notifications.emplace_back("popup.html");
+ TabAddedRemovedObserver observer(browser()->tab_strip_model());
+ NavigateToPopupParentFrameAndWaitForNotifications();
+ observer.Wait();
+ EXPECT_EQ(1, NumberOfOpenTabs());
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest,
+ PopupAllowedByParentDocument) {
+ // The outermost frame has a blanket allowing rule of $document type.
+ SetFilters({"http://inner.com*/popup.html$popup",
+ "@@||outer.com^$document,domain=outer.com"});
+ observer.allowed_popups_notifications.emplace_back("popup.html");
+ NavigateToPopupParentFrameAndWaitForNotifications();
+ // Popup was allowed to open in a new tab
+ EXPECT_EQ(2, NumberOfOpenTabs());
+ observer.VerifyNotificationSent("popup_parent.html",
+ observer.allowed_pages_notifications);
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest,
+ PopupAllowedByIntermediateParentDocument) {
+ // The middle frame has a blanket allowing rule of $document type.
+ SetFilters({"http://inner.com*/popup.html$popup",
+ "@@||middle.com^$document,domain=outer.com"});
+ observer.allowed_popups_notifications.emplace_back("popup.html");
+ NavigateToPopupParentFrameAndWaitForNotifications();
+ // Popup was allowed to open in a new tab
+ EXPECT_EQ(2, NumberOfOpenTabs());
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest, BlankFrameHiding) {
+ SetFilters({"##.about_blank_div"});
+ NavigateToOutermostFrameWithAboutBlank();
+ std::string script = R"(
+ function writeIframe() {
+ let frameDocument = document.getElementById("about_blank").contentWindow.document;
+ frameDocument.open("text/html");
+ frameDocument.write(`
+ <html>
+ <body>
+ <div class="about_blank_div">
+ <iframe id='middle_frame' src='/cross-site/middle.com/middle_frame.html' width='400'></iframe>
+ </div>
+ </body>
+ </html>`);
+ frameDocument.close();
+ }
+ if (document.readyState == "complete") {
+ writeIframe();
+ } else {
+ document.getElementById("about_blank").addEventListener("load", writeIframe);
+ }
+ )";
+ EXPECT_TRUE(content::ExecJs(
+ browser()->tab_strip_model()->GetActiveWebContents(), script));
+ VerifyTargetResourceShown(false);
+ SetFilters({"@@^eyeo=true$document"});
+ NavigateToOutermostFrameWithAboutBlank();
+ EXPECT_TRUE(content::ExecJs(
+ browser()->tab_strip_model()->GetActiveWebContents(), script));
+ VerifyTargetResourceShown(true);
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockFrameHierarchyBrowserTest, BlankFrameBlocking) {
+ SetFilters({"/resource.png"});
+ NavigateToOutermostFrameWithAboutBlank();
+ std::string script = R"(
+ function writeIframe() {
+ let frameDocument = document.getElementById("about_blank").contentWindow.document;
+ frameDocument.open("text/html");
+ frameDocument.write(`
+ <html>
+ <body>
+ <iframe id='middle_frame' src='/cross-site/middle.com/middle_frame.html' width='400'></iframe>
+ </body>
+ </html>`);
+ frameDocument.close();
+ }
+ if (document.readyState == "complete") {
+ writeIframe();
+ } else {
+ document.getElementById("about_blank").addEventListener("load", writeIframe);
+ }
+ )";
+ EXPECT_TRUE(content::ExecJs(
+ browser()->tab_strip_model()->GetActiveWebContents(), script));
+ VerifyTargetResourceShown(false);
+ observer.VerifyNotificationSent("resource.png",
+ observer.blocked_ads_notifications);
+ SetFilters({"@@^eyeo=true$document"});
+ NavigateToOutermostFrameWithAboutBlank();
+ EXPECT_TRUE(content::ExecJs(
+ browser()->tab_strip_model()->GetActiveWebContents(), script));
+ VerifyTargetResourceShown(true);
+ observer.VerifyNotificationSent("resource.png",
+ observer.allowed_ads_notifications);
+}
+
+// More tests can be added / parametrized, e.g.:
+// - elemhide blocking filters (in conjunction with $elemhide allow rules)
+// - $subdocument-based allow rules
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_multiple_tabs_browsertest.cc b/chrome/browser/adblock/test/adblock_multiple_tabs_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_multiple_tabs_browsertest.cc
@@ -0,0 +1,160 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/resource_classification_runner_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/content/browser/resource_classification_runner.h"
+#include "components/adblock/core/common/adblock_constants.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "components/sessions/content/session_tab_helper.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace adblock {
+
+class AdblockMultipleTabsBrowserTest
+ : public InProcessBrowserTest,
+ public ResourceClassificationRunner::Observer {
+ public:
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule(kTestDomain, "127.0.0.1");
+ embedded_test_server()->ServeFilesFromSourceDirectory(
+ "chrome/test/data/adblock");
+ ASSERT_TRUE(embedded_test_server()->Start());
+ ResourceClassificationRunnerFactory::GetForBrowserContext(
+ browser()->profile())
+ ->AddObserver(this);
+ SetFilters({"blocked.png", "allowed.png", "@@allowed.png"});
+ }
+
+ void TearDownInProcessBrowserTestFixture() override {
+ ASSERT_EQ(kTabsCount, static_cast<int>(tabs_with_blocked_resource_.size()));
+ ASSERT_EQ(kTabsCount, static_cast<int>(tabs_with_allowed_resource_.size()));
+ }
+
+ void SetFilters(std::vector<std::string> filters) {
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ adblock_configuration->RemoveCustomFilter(kAllowlistEverythingFilter);
+ for (auto& filter : filters) {
+ adblock_configuration->AddCustomFilter(filter);
+ }
+ }
+
+ void RestoreTabs(Browser* browser) {
+ content::DOMMessageQueue queue;
+ RecentTabsSubMenuModel menu(nullptr, browser);
+ menu.ExecuteCommand(menu.GetFirstRecentTabsCommandId(), 0);
+ for (int i = 0; i < kTabsCount; ++i) {
+ std::string message;
+ EXPECT_TRUE(queue.WaitForMessage(&message));
+ EXPECT_EQ("\"READY\"", message);
+ }
+ }
+
+ // ResourceClassificationRunner::Observer:
+ void OnAdMatched(const GURL& url,
+ FilterMatchResult match_result,
+ const std::vector<GURL>& parent_frame_urls,
+ ContentType content_type,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {
+ const content::WebContents* wc =
+ content::WebContents::FromRenderFrameHost(render_frame_host);
+ if (match_result == FilterMatchResult::kBlockRule &&
+ url.path() == "/blocked.png") {
+ tabs_with_blocked_resource_.insert(
+ sessions::SessionTabHelper::IdForTab(wc).id());
+ } else if (match_result == FilterMatchResult::kAllowRule &&
+ url.path() == "/allowed.png") {
+ tabs_with_allowed_resource_.insert(
+ sessions::SessionTabHelper::IdForTab(wc).id());
+ }
+ }
+
+ void OnPageAllowed(const GURL& url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {}
+
+ void OnPopupMatched(const GURL& url,
+ FilterMatchResult match_result,
+ const GURL& opener_url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {}
+
+ protected:
+ const int kTabsCount = 4;
+ const char* kTestDomain = "example.com";
+ std::set<int> tabs_with_blocked_resource_;
+ std::set<int> tabs_with_allowed_resource_;
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockMultipleTabsBrowserTest, PRE_OpenManyTabs) {
+ // Load page in already opened tab
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL(kTestDomain, "/tab-restore.html")));
+ // Open more tabs
+ for (int i = 0; i < kTabsCount - 1; ++i) {
+ ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
+ browser(),
+ embedded_test_server()->GetURL(kTestDomain, "/tab-restore.html"),
+ WindowOpenDisposition::NEW_FOREGROUND_TAB,
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
+ }
+ EXPECT_EQ(kTabsCount, browser()->tab_strip_model()->count());
+ EXPECT_EQ(kTabsCount, static_cast<int>(tabs_with_blocked_resource_.size()));
+ EXPECT_EQ(kTabsCount, static_cast<int>(tabs_with_allowed_resource_.size()));
+
+ // Open a new browser instance
+ ui_test_utils::NavigateToURLWithDisposition(
+ browser(), GURL(url::kAboutBlankURL), WindowOpenDisposition::NEW_WINDOW,
+ ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
+ BrowserList* active_browser_list = BrowserList::GetInstance();
+ EXPECT_EQ(2u, active_browser_list->size());
+
+ // Close the 1st browser and clear tabs test data
+ CloseBrowserSynchronously(browser());
+ EXPECT_EQ(1u, active_browser_list->size());
+ tabs_with_blocked_resource_.clear();
+ tabs_with_allowed_resource_.clear();
+
+ Browser* browser = active_browser_list->get(0);
+ // Restore tabs from1 st browser instance (already closed) in 2nd instance
+ RestoreTabs(browser);
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockMultipleTabsBrowserTest, OpenManyTabs) {
+ ASSERT_EQ(0u, tabs_with_blocked_resource_.size());
+ ASSERT_EQ(0u, tabs_with_allowed_resource_.size());
+ // Restore tabs from previous session (previous test)
+ RestoreTabs(browser());
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_non_ascii_browsertest.cc b/chrome/browser/adblock/test/adblock_non_ascii_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_non_ascii_browsertest.cc
@@ -0,0 +1,78 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/core/common/adblock_constants.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace adblock {
+
+class AdblockNonASCIIBrowserTest : public InProcessBrowserTest {
+ public:
+ void SetUpOnMainThread() override {
+ host_resolver()->AddRule("xn----dtbfdbwspgnceulm.xn--p1ai", "127.0.0.1");
+ embedded_test_server()->ServeFilesFromSourceDirectory(
+ "chrome/test/data/adblock");
+ content::SetupCrossSiteRedirector(embedded_test_server());
+ ASSERT_TRUE(embedded_test_server()->Start());
+ }
+
+ void SetFilters(std::vector<std::string> filters) {
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ adblock_configuration->RemoveCustomFilter(kAllowlistEverythingFilter);
+ for (auto& filter : filters) {
+ adblock_configuration->AddCustomFilter(filter);
+ }
+ }
+
+ std::string ExecuteScriptAndExtractString(const std::string& js_code) const {
+ content::WebContents* web_contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ return content::EvalJs(web_contents->GetPrimaryMainFrame(), js_code)
+ .ExtractString();
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockNonASCIIBrowserTest, BlockNonASCII) {
+ static constexpr char kCheckVisibility[] =
+ R"(getComputedStyle(document.getElementsByClassName("форум")[0]).display)";
+
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("форум-трейдеров.рф", "/non-ascii.html")));
+ EXPECT_EQ("block", ExecuteScriptAndExtractString(kCheckVisibility));
+
+ SetFilters({"xn----dtbfdbwspgnceulm.xn--p1ai##.форум"});
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(
+ browser(),
+ embedded_test_server()->GetURL("форум-трейдеров.рф", "/non-ascii.html")));
+
+ EXPECT_EQ("none", ExecuteScriptAndExtractString(kCheckVisibility));
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_popup_browsertest.cc b/chrome/browser/adblock/test/adblock_popup_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_popup_browsertest.cc
@@ -0,0 +1,463 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "base/run_loop.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/adblock/resource_classification_runner_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h"
+#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/content/browser/resource_classification_runner.h"
+#include "components/adblock/core/common/adblock_constants.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "gmock/gmock.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "url/gurl.h"
+
+namespace adblock {
+
+namespace {
+class TabAddedRemovedObserver : public TabStripModelObserver {
+ public:
+ explicit TabAddedRemovedObserver(TabStripModel* tab_strip_model) {
+ tab_strip_model->AddObserver(this);
+ }
+
+ void OnTabStripModelChanged(
+ TabStripModel* tab_strip_model,
+ const TabStripModelChange& change,
+ const TabStripSelectionChange& selection) override {
+ if (change.type() == TabStripModelChange::kInserted) {
+ inserted_ = true;
+ return;
+ }
+ if (change.type() == TabStripModelChange::kRemoved) {
+ EXPECT_TRUE(inserted_);
+ removed_ = true;
+ loop_.Quit();
+ return;
+ }
+ NOTREACHED();
+ }
+
+ void Wait() {
+ if (inserted_ && removed_) {
+ return;
+ }
+ loop_.Run();
+ }
+
+ private:
+ bool inserted_ = false;
+ bool removed_ = false;
+ base::RunLoop loop_;
+};
+
+enum class Redirection { ClientSide, ServerSide };
+
+} // namespace
+
+class AdblockPopupBrowserTest
+ : public InProcessBrowserTest,
+ public ResourceClassificationRunner::Observer,
+ public testing::WithParamInterface<Redirection> {
+ public:
+ void SetUpOnMainThread() override {
+ InProcessBrowserTest::SetUpOnMainThread();
+ host_resolver()->AddRule("*", "127.0.0.1");
+ embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
+ &AdblockPopupBrowserTest::RequestHandler, base::Unretained(this)));
+ ASSERT_TRUE(embedded_test_server()->Start());
+ ResourceClassificationRunnerFactory::GetForBrowserContext(
+ browser()->profile())
+ ->AddObserver(this);
+ }
+
+ void TearDownOnMainThread() override {
+ VerifyNoUnexpectedNotifications();
+ ResourceClassificationRunnerFactory::GetForBrowserContext(
+ browser()->profile())
+ ->RemoveObserver(this);
+ InProcessBrowserTest::TearDownOnMainThread();
+ }
+
+ void VerifyNoUnexpectedNotifications() {
+ EXPECT_TRUE(blocked_popups_notifications_expectations_.empty());
+ EXPECT_TRUE(allowed_popups_notifications_expectations_.empty());
+ }
+
+ bool IsServerSideRedirection() {
+ return GetParam() == Redirection::ServerSide;
+ }
+
+ virtual std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
+ const net::test_server::HttpRequest& request) {
+ if (base::StartsWith("/main_page.html", request.relative_url)) {
+ static constexpr char kPopupFrameParent[] =
+ R"(
+ <!DOCTYPE html>
+ <html>
+ <head></head>
+ <body>
+ <iframe id='popup_frame' src='/popup_frame.html'></iframe>
+ </body>
+ </html>)";
+ std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
+ new net::test_server::BasicHttpResponse);
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content(kPopupFrameParent);
+ http_response->set_content_type("text/html");
+ return std::move(http_response);
+ }
+ if (base::StartsWith("/popup_frame.html", request.relative_url)) {
+ static constexpr char kPopupFrame[] =
+ R"(
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <script>
+ "use strict";
+ let redirect_popup_url = "/popup_will_redirect.html";
+ function scriptPopupTab() {
+ window.open(redirect_popup_url);
+ }
+ function scriptPopupWindow() {
+ window.open(redirect_popup_url, "some-popup", "resizable");
+ }
+ </script>
+ </head>
+ <body>
+ <a href="/popup_will_redirect.html" target="_blank" id="popup_link_will_redirect">Trigger link based popup with redirect</a>
+ <a href="/popup_no_redirect.html" target="_blank" id="popup_link_no_redirect">Trigger link based popup without redirect</a>
+ <a href="#script-based-popup-tab" onclick="scriptPopupTab();" id="popup_script_tab">Trigger script based popup (tab) with redirect</a>
+ <a href="#script-based-popup-window" onclick="scriptPopupWindow();" id="popup_script_window">Trigger script based popup (window) with redirect</a>
+ </body>
+ </html>)";
+ std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
+ new net::test_server::BasicHttpResponse);
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content(kPopupFrame);
+ http_response->set_content_type("text/html");
+ return std::move(http_response);
+ }
+ if (base::StartsWith("/popup_no_redirect.html", request.relative_url) ||
+ base::StartsWith("/popup_redirected.html", request.relative_url)) {
+ std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
+ new net::test_server::BasicHttpResponse);
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content("");
+ http_response->set_content_type("text/html");
+ return std::move(http_response);
+ }
+ if (base::StartsWith("/popup_will_redirect.html", request.relative_url)) {
+ static constexpr char kClientSideRedirectingPopup[] =
+ R"(
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <script type="text/javascript">
+ window.location = "/popup_redirected.html"
+ </script>
+ </head>
+ <body></body>
+ </html>)";
+ std::unique_ptr<net::test_server::BasicHttpResponse> http_response(
+ new net::test_server::BasicHttpResponse);
+ if (IsServerSideRedirection()) {
+ http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
+ http_response->AddCustomHeader(
+ "Location", GetPageUrl("/popup_redirected.html").spec());
+ } else {
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content(kClientSideRedirectingPopup);
+ http_response->set_content_type("text/html");
+ }
+ return std::move(http_response);
+ }
+ return nullptr;
+ }
+
+ void SetFilters(std::vector<std::string> filters) {
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ adblock_configuration->RemoveCustomFilter(kAllowlistEverythingFilter);
+ for (auto& filter : filters) {
+ adblock_configuration->AddCustomFilter(filter);
+ }
+ }
+
+ void TriggerPopup(const std::string& popup_id) {
+ std::string script = base::StringPrintf(
+ R"(
+ let doc = document.querySelector('iframe[id="popup_frame"]').contentWindow.document;
+ let element = doc.getElementById('%s');
+ element.click();
+ )",
+ popup_id.c_str());
+ EXPECT_TRUE(content::ExecJs(
+ browser()->tab_strip_model()->GetActiveWebContents(), script));
+ }
+
+ GURL GetPageUrl(const std::string& page) {
+ return embedded_test_server()->GetURL("popup_frame.org", page);
+ }
+
+ void NavigateToPage() {
+ ASSERT_TRUE(
+ NavigateToURL(browser()->tab_strip_model()->GetActiveWebContents(),
+ GetPageUrl("/main_page.html")));
+ }
+
+ void WaitForTabToLoad() {
+ content::WebContents* popup =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ WaitForLoadStop(popup);
+ }
+
+ void SetupNotificationsWaiter(base::RunLoop* run_loop) {
+ run_loop_ = run_loop;
+ }
+
+ // ResourceClassificationRunner::Observer:
+ void OnAdMatched(const GURL& url,
+ FilterMatchResult match_result,
+ const std::vector<GURL>& parent_frame_urls,
+ ContentType content_type,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {}
+
+ void OnPageAllowed(const GURL& url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {}
+
+ void OnPopupMatched(const GURL& url,
+ FilterMatchResult match_result,
+ const GURL& opener_url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {
+ auto& list = (match_result == FilterMatchResult::kBlockRule
+ ? blocked_popups_notifications_expectations_
+ : allowed_popups_notifications_expectations_);
+ auto it = std::find(list.begin(), list.end(), url.ExtractFileName());
+ ASSERT_FALSE(it == list.end())
+ << "Path " << url.ExtractFileName() << " not on list";
+ list.erase(it);
+ if (run_loop_ && allowed_popups_notifications_expectations_.empty() &&
+ blocked_popups_notifications_expectations_.empty()) {
+ run_loop_->Quit();
+ }
+ }
+
+ std::vector<std::string> allowed_popups_notifications_expectations_;
+ std::vector<std::string> blocked_popups_notifications_expectations_;
+ raw_ptr<base::RunLoop> run_loop_ = nullptr;
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockPopupBrowserTest, PopupLinkBlocked) {
+ SetFilters({"popup_no_redirect.html^$popup"});
+ blocked_popups_notifications_expectations_.emplace_back(
+ "popup_no_redirect.html");
+ NavigateToPage();
+ TabAddedRemovedObserver observer(browser()->tab_strip_model());
+ TriggerPopup("popup_link_no_redirect");
+ observer.Wait();
+ EXPECT_EQ(1, browser()->tab_strip_model()->count());
+}
+
+IN_PROC_BROWSER_TEST_P(AdblockPopupBrowserTest,
+ PopupScriptTabWithRedirectBlocked) {
+ SetFilters({"popup_redirected.html^$popup"});
+ blocked_popups_notifications_expectations_.emplace_back(
+ "popup_redirected.html");
+ NavigateToPage();
+ TabAddedRemovedObserver observer(browser()->tab_strip_model());
+ TriggerPopup("popup_script_tab");
+ observer.Wait();
+ EXPECT_EQ(1, browser()->tab_strip_model()->count());
+}
+
+IN_PROC_BROWSER_TEST_P(AdblockPopupBrowserTest,
+ PopupScriptWindowWithRedirectBlocked) {
+ SetFilters({"popup_redirected.html^$popup"});
+ blocked_popups_notifications_expectations_.emplace_back(
+ "popup_redirected.html");
+ NavigateToPage();
+ TriggerPopup("popup_script_window");
+ // Wait for 2nd browser to get closed (new window popup blocked)
+ EXPECT_EQ(2u, BrowserList::GetInstance()->size());
+ ui_test_utils::WaitForBrowserToClose(BrowserList::GetInstance()->get(1));
+ EXPECT_EQ(1u, BrowserList::GetInstance()->size());
+}
+
+IN_PROC_BROWSER_TEST_P(AdblockPopupBrowserTest, PopupLinkWithRedirectBlocked) {
+ SetFilters({"popup_redirected.html^$popup"});
+ blocked_popups_notifications_expectations_.emplace_back(
+ "popup_redirected.html");
+ NavigateToPage();
+ TabAddedRemovedObserver observer(browser()->tab_strip_model());
+ TriggerPopup("popup_link_will_redirect");
+ observer.Wait();
+ EXPECT_EQ(1, browser()->tab_strip_model()->count());
+}
+
+IN_PROC_BROWSER_TEST_P(
+ AdblockPopupBrowserTest,
+ PopupScriptTabWithRedirectAllowedByIntermediateParentDocument) {
+ SetFilters({"popup_redirected.html^$popup", "@@/popup_frame.html^$document"});
+ allowed_popups_notifications_expectations_.emplace_back(
+ "popup_redirected.html");
+ NavigateToPage();
+ ui_test_utils::TabAddedWaiter waiter(browser());
+ TriggerPopup("popup_script_tab");
+ waiter.Wait();
+ WaitForTabToLoad();
+ EXPECT_EQ(2, browser()->tab_strip_model()->count());
+}
+
+IN_PROC_BROWSER_TEST_P(
+ AdblockPopupBrowserTest,
+ PopupScriptWindowWithRedirectAllowedByIntermediateParentDocument) {
+ SetFilters({"popup_redirected.html^$popup", "@@/popup_frame.html^$document"});
+ allowed_popups_notifications_expectations_.emplace_back(
+ "popup_redirected.html");
+ NavigateToPage();
+ base::RunLoop run_loop;
+ SetupNotificationsWaiter(&run_loop);
+ TriggerPopup("popup_script_window");
+ run_loop.Run();
+ EXPECT_EQ(2u, BrowserList::GetInstance()->size());
+}
+
+IN_PROC_BROWSER_TEST_P(
+ AdblockPopupBrowserTest,
+ PopupLinkWithRedirectAllowedByIntermediateParentDocument) {
+ SetFilters({"popup_redirected.html^$popup", "@@/popup_frame.html^$document"});
+ allowed_popups_notifications_expectations_.emplace_back(
+ "popup_redirected.html");
+ NavigateToPage();
+ ui_test_utils::TabAddedWaiter waiter(browser());
+ TriggerPopup("popup_link_will_redirect");
+ waiter.Wait();
+ WaitForTabToLoad();
+ EXPECT_EQ(2, browser()->tab_strip_model()->count());
+ ;
+}
+
+IN_PROC_BROWSER_TEST_P(AdblockPopupBrowserTest,
+ PopupScriptTabWithRedirectAllowedByParentDocument) {
+ SetFilters({"popup_redirected.html^$popup", "@@/main_page.html^$document"});
+ allowed_popups_notifications_expectations_.emplace_back(
+ "popup_redirected.html");
+ NavigateToPage();
+ ui_test_utils::TabAddedWaiter waiter(browser());
+ TriggerPopup("popup_script_tab");
+ waiter.Wait();
+ WaitForTabToLoad();
+ EXPECT_EQ(2, browser()->tab_strip_model()->count());
+}
+
+IN_PROC_BROWSER_TEST_P(AdblockPopupBrowserTest,
+ PopupScriptWindowWithRedirectAllowedByParentDocument) {
+ SetFilters({"popup_redirected.html^$popup", "@@/main_page.html^$document"});
+ allowed_popups_notifications_expectations_.emplace_back(
+ "popup_redirected.html");
+ NavigateToPage();
+ base::RunLoop run_loop;
+ SetupNotificationsWaiter(&run_loop);
+ TriggerPopup("popup_script_window");
+ run_loop.Run();
+ EXPECT_EQ(2u, BrowserList::GetInstance()->size());
+}
+
+IN_PROC_BROWSER_TEST_P(AdblockPopupBrowserTest,
+ PopupLinkWithRedirectAllowedByParentDocument) {
+ SetFilters({"popup_redirected.html^$popup", "@@/main_page.html^$document"});
+ allowed_popups_notifications_expectations_.emplace_back(
+ "popup_redirected.html");
+ NavigateToPage();
+ ui_test_utils::TabAddedWaiter waiter(browser());
+ TriggerPopup("popup_link_will_redirect");
+ waiter.Wait();
+ WaitForTabToLoad();
+ EXPECT_EQ(2, browser()->tab_strip_model()->count());
+}
+
+// Make sure that we correctly recognize and apply blocking of
+// redirected popups only for real popups.
+IN_PROC_BROWSER_TEST_P(AdblockPopupBrowserTest,
+ LinkOpenedByContextMenuInNewTabNotBlocked) {
+ SetFilters({"popup_redirected.html^$popup"});
+ ContextMenuNotificationObserver menu_observer(
+ IDC_CONTENT_CONTEXT_OPENLINKNEWTAB);
+ ui_test_utils::AllBrowserTabAddedWaiter add_tab;
+
+ std::string script = base::StringPrintf(
+ "data:text/html,<a href='%s'>link</a>",
+ GetPageUrl("/popup_will_redirect.html").spec().c_str());
+ // Go to a page with a link
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(script)));
+
+ // Opens a link in a new tab via a "real" context menu.
+ blink::WebMouseEvent mouse_event(
+ blink::WebInputEvent::Type::kMouseDown,
+ blink::WebInputEvent::kNoModifiers,
+ blink::WebInputEvent::GetStaticTimeStampForTests());
+ mouse_event.button = blink::WebMouseEvent::Button::kRight;
+ mouse_event.SetPositionInWidget(15, 15);
+ content::WebContents* tab =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ gfx::Rect offset = tab->GetContainerBounds();
+ mouse_event.SetPositionInScreen(15 + offset.x(), 15 + offset.y());
+ mouse_event.click_count = 1;
+ tab->GetPrimaryMainFrame()
+ ->GetRenderViewHost()
+ ->GetWidget()
+ ->ForwardMouseEvent(mouse_event);
+ mouse_event.SetType(blink::WebInputEvent::Type::kMouseUp);
+ tab->GetPrimaryMainFrame()
+ ->GetRenderViewHost()
+ ->GetWidget()
+ ->ForwardMouseEvent(mouse_event);
+
+ // The menu_observer will select "Open in new tab", wait for the new tab to
+ // be added.
+ tab = add_tab.Wait();
+ EXPECT_TRUE(content::WaitForLoadStop(tab));
+
+ // Verify that it's the correct tab.
+ EXPECT_EQ(GetPageUrl("/popup_redirected.html"), tab->GetLastCommittedURL());
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+ AdblockPopupBrowserTest,
+ testing::Values(Redirection::ClientSide,
+ Redirection::ServerSide));
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_snippets_browsertest.cc b/chrome/browser/adblock/test/adblock_snippets_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_snippets_browsertest.cc
@@ -0,0 +1,80 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <vector>
+
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/core/common/adblock_constants.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace adblock {
+
+class AdblockSnippetsBrowserTest : public InProcessBrowserTest {
+ public:
+ void SetUpOnMainThread() override {
+ InProcessBrowserTest::SetUpOnMainThread();
+ host_resolver()->AddRule("*", "127.0.0.1");
+ embedded_test_server()->ServeFilesFromSourceDirectory(
+ "chrome/test/data/adblock");
+ ASSERT_TRUE(embedded_test_server()->Start());
+ }
+
+ void SetFilters(std::vector<std::string> filters) {
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ adblock_configuration->RemoveCustomFilter(kAllowlistEverythingFilter);
+ for (auto& filter : filters) {
+ adblock_configuration->AddCustomFilter(filter);
+ }
+ }
+
+ GURL GetUrl(const std::string& path) {
+ return embedded_test_server()->GetURL("example.org", path);
+ }
+
+ void VerifyTargetVisibility(bool is_hidden, const std::string& id) {
+ std::string is_invisible_js =
+ "getComputedStyle(document.getElementById('{{node id}}')).display == "
+ "'none'";
+ base::ReplaceSubstringsAfterOffset(&is_invisible_js, 0, "{{node id}}", id);
+ EXPECT_EQ(
+ is_hidden,
+ content::EvalJs(browser()->tab_strip_model()->GetActiveWebContents(),
+ is_invisible_js));
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockSnippetsBrowserTest, VerifyXpath3) {
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl("/xpath3.html")));
+ VerifyTargetVisibility(false, "xpath3-target");
+ SetFilters(
+ {"example.org#$#hide-if-matches-xpath3 //*[@id=\"xpath3-target\"]"});
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl("/xpath3.html")));
+ VerifyTargetVisibility(true, "xpath3-target");
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_subscription_service_browsertest.cc b/chrome/browser/adblock/test/adblock_subscription_service_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_subscription_service_browsertest.cc
@@ -0,0 +1,201 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/ranges/algorithm.h"
+#include "base/run_loop.h"
+#include "base/strings/string_split.h"
+#include "base/test/bind.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "chrome/browser/adblock/subscription_persistent_metadata_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/core/subscription/subscription_config.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "components/version_info/version_info.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/http/http_request_headers.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace adblock {
+
+class AdblockSubscriptionServiceBrowserTest
+ : public InProcessBrowserTest,
+ public SubscriptionService::SubscriptionObserver {
+ public:
+ AdblockSubscriptionServiceBrowserTest() {
+ SubscriptionServiceFactory::SetUpdateCheckAndDelayIntervalsForTesting(
+ base::Seconds(1), base::Seconds(1));
+ }
+ void SetUpOnMainThread() override {
+ InProcessBrowserTest::SetUpOnMainThread();
+ https_server_ = std::make_unique<net::EmbeddedTestServer>(
+ net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_OK);
+ }
+
+ bool RequestHeadersContainAcceptLanguage(
+ const net::test_server::HttpRequest& request) {
+ const auto accept_language_it =
+ request.headers.find(net::HttpRequestHeaders::kAcceptLanguage);
+ return accept_language_it != request.headers.end() &&
+ !accept_language_it->second.empty();
+ }
+
+ bool RequestHeadersContainAcceptEncodingBrotli(
+ const net::test_server::HttpRequest& request) {
+ const auto accept_encoding_it =
+ request.headers.find(net::HttpRequestHeaders::kAcceptEncoding);
+ if (accept_encoding_it == request.headers.end()) {
+ return false;
+ }
+ const auto split_encodings =
+ base::SplitString(accept_encoding_it->second, ",",
+ base::WhitespaceHandling::TRIM_WHITESPACE,
+ base::SplitResult::SPLIT_WANT_NONEMPTY);
+ return base::ranges::find(split_encodings, "br") != split_encodings.end();
+ }
+
+ std::unique_ptr<net::test_server::HttpResponse>
+ HandleSubscriptionUpdateRequestWithUrlCheck(
+ std::string expected_url_part,
+ const net::test_server::HttpRequest& request) {
+ static const char kSubscriptionHeader[] =
+ "[Adblock Plus 2.0]\n"
+ "! Checksum: X5A8vtJDBW2a9EgS9glqbg\n"
+ "! Version: 202202061935\n"
+ "! Last modified: 06 Feb 2022 19:35 UTC\n"
+ "! Expires: 1 days (update frequency)\n\n";
+ if (base::StartsWith(request.relative_url, kSubscription,
+ base::CompareCase::SENSITIVE) &&
+ !request_already_handled_) {
+ request_already_handled_ = true;
+ EXPECT_TRUE(RequestHeadersContainAcceptLanguage(request));
+ EXPECT_TRUE(RequestHeadersContainAcceptEncodingBrotli(request));
+ std::string os;
+ base::ReplaceChars(version_info::GetOSType(), base::kWhitespaceASCII, "",
+ &os);
+ EXPECT_TRUE(request.relative_url.find(expected_url_part) !=
+ std::string::npos);
+ EXPECT_TRUE(request.relative_url.find("addonName=eyeo-chromium-sdk") !=
+ std::string::npos);
+ EXPECT_TRUE(request.relative_url.find("addonVersion=1.0") !=
+ std::string::npos);
+ EXPECT_TRUE(request.relative_url.find("platformVersion=1.0") !=
+ std::string::npos);
+ EXPECT_TRUE(request.relative_url.find("platform=" + os) !=
+ std::string::npos);
+ auto http_response =
+ std::make_unique<net::test_server::BasicHttpResponse>();
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content(kSubscriptionHeader);
+ http_response->set_content_type("text/plain");
+ return std::move(http_response);
+ }
+
+ // Unhandled requests result in the Embedded test server sending a 404.
+ return nullptr;
+ }
+
+ void ExpectFilterListRequestMadeWithLastVersion(std::string last_version) {
+ https_server_->RegisterRequestHandler(
+ base::BindRepeating(&AdblockSubscriptionServiceBrowserTest::
+ HandleSubscriptionUpdateRequestWithUrlCheck,
+ base::Unretained(this), last_version));
+ ASSERT_TRUE(https_server_->Start(kPort));
+ }
+
+ // adblock::SubscriptionService::SubscriptionObserver
+ void OnSubscriptionInstalled(const GURL& url) override {
+ if (base::StartsWith(url.spec(),
+ https_server_->GetURL(kSubscription).spec())) {
+ // In order to ensure next run requests an update, mark the subscription
+ // as almost expired.
+ SubscriptionPersistentMetadataFactory::GetForBrowserContext(
+ browser()->profile())
+ ->SetExpirationInterval(url, base::Milliseconds(1));
+ CloseBrowserAsynchronously(browser());
+ }
+ }
+
+ std::unique_ptr<net::EmbeddedTestServer> https_server_;
+ bool request_already_handled_ = false;
+ static const std::string kSubscription;
+ // Port is hardcoded so the server url is the same across tests
+ static const int kPort = 65432;
+};
+
+const std::string AdblockSubscriptionServiceBrowserTest::kSubscription =
+ "/subscription.txt";
+
+IN_PROC_BROWSER_TEST_F(AdblockSubscriptionServiceBrowserTest, PRE_LastVersion) {
+ ExpectFilterListRequestMadeWithLastVersion("&lastVersion=0&");
+ // Downloading a filter list and setting its expiry time to almost zero, so
+ // the next run will have to update it ASAP.
+
+ auto* subscription_service =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile());
+ subscription_service->AddObserver(this);
+ // Using a custom subscription URL here because before test sets
+ // up the server then SubscriptionService already started fetching default
+ // subscriptions.
+ subscription_service->GetAdblockFilteringConfiguration()->AddFilterList(
+ https_server_->GetURL(kSubscription));
+ // Wait until subscription is downloaded and stored.
+ RunUntilBrowserProcessQuits();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockSubscriptionServiceBrowserTest, LastVersion) {
+ ExpectFilterListRequestMadeWithLastVersion("&lastVersion=202202061935&");
+ auto* subscription_service =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile());
+ subscription_service->AddObserver(this);
+ // Wait for subscription update to trigger a network request.
+ RunUntilBrowserProcessQuits();
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockSubscriptionServiceBrowserTest,
+ FilterFileDeletedAfterConversion) {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ ConversionExecutors* conversion_executors =
+ SubscriptionServiceFactory::GetInstance();
+ DCHECK(conversion_executors);
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ const auto filter_list_path = temp_dir.GetPath().AppendASCII("easylist.txt");
+ std::vector<base::StringPiece> filter_list_contents = {
+ "[\"Adblock Plus 2.0\"]\n", "invalid file"};
+ for (const auto& file_content : filter_list_contents) {
+ base::WriteFile(filter_list_path, file_content);
+ ASSERT_TRUE(base::PathExists(filter_list_path));
+ base::RunLoop run_loop;
+ conversion_executors->ConvertFilterListFile(
+ DefaultSubscriptionUrl(), filter_list_path,
+ base::BindLambdaForTesting(
+ [&run_loop](ConversionResult result) { run_loop.Quit(); }));
+ run_loop.Run();
+ ASSERT_FALSE(base::PathExists(filter_list_path));
+ }
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_telemetry_service_browsertest.cc b/chrome/browser/adblock/test/adblock_telemetry_service_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_telemetry_service_browsertest.cc
@@ -0,0 +1,256 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "base/json/json_reader.h"
+#include "chrome/browser/adblock/adblock_telemetry_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "components/adblock/core/activeping_telemetry_topic_provider.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+namespace adblock {
+
+class AdblockTelemetryServiceBrowserTestBase : public InProcessBrowserTest {
+ public:
+ // We need to set server and request handler asap
+ void SetUpInProcessBrowserTestFixture() override {
+ InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+ host_resolver()->AddRule(
+ ActivepingTelemetryTopicProvider::DefaultBaseUrl().host(), "127.0.0.1");
+ http_server_.RegisterRequestHandler(base::BindRepeating(
+ &AdblockTelemetryServiceBrowserTestBase::RequestHandler,
+ base::Unretained(this)));
+ ASSERT_TRUE(http_server_.Start());
+ ActivepingTelemetryTopicProvider::SetHttpPortForTesting(
+ http_server_.port());
+ auto testing_interval = base::Seconds(2);
+ ActivepingTelemetryTopicProvider::SetIntervalsForTesting(testing_interval);
+ AdblockTelemetryServiceFactory::GetInstance()
+ ->SetCheckAndDelayIntervalsForTesting(testing_interval,
+ testing_interval);
+ }
+
+ base::Value* GetFirstPing(absl::optional<base::Value>& parsed) {
+ return GetPayload(parsed)->Find("first_ping");
+ }
+
+ base::Value* GetLastPing(absl::optional<base::Value>& parsed) {
+ return GetPayload(parsed)->Find("last_ping");
+ }
+
+ base::Value* GetLastPingTag(absl::optional<base::Value>& parsed) {
+ return GetPayload(parsed)->Find("last_ping_tag");
+ }
+
+ base::Value* GetPreviousLastPing(absl::optional<base::Value>& parsed) {
+ return GetPayload(parsed)->Find("previous_last_ping");
+ }
+
+ void CloseBrowserFromAnyThread() {
+ content::GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
+ ->PostTask(FROM_HERE,
+ base::BindOnce(&AdblockTelemetryServiceBrowserTestBase::
+ CloseBrowserAsynchronously,
+ base::Unretained(this), browser()));
+ }
+
+ std::unique_ptr<net::test_server::HttpResponse> CreateResponse(
+ const std::string& token) {
+ auto http_response =
+ std::make_unique<net::test_server::BasicHttpResponse>();
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content("{\"token\": \"" + token + "\"}");
+ http_response->set_content_type("text/plain");
+ return std::move(http_response);
+ }
+
+ virtual std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
+ const net::test_server::HttpRequest& request) = 0;
+
+ private:
+ base::Value::Dict* GetPayload(absl::optional<base::Value>& parsed) {
+ EXPECT_TRUE(parsed && parsed->is_dict());
+ base::Value::Dict* parsed_dict = parsed->GetIfDict();
+ EXPECT_TRUE(parsed_dict);
+ base::Value::Dict* payload = parsed_dict->FindDict("payload");
+ EXPECT_TRUE(payload);
+ return payload;
+ }
+
+ net::EmbeddedTestServer http_server_;
+};
+
+// Test three initial pings each after startup and each fails for the 1st time
+class AdblockTelemetryServiceFirstPingAfterRestartWithRetryBrowserTest
+ : public AdblockTelemetryServiceBrowserTestBase {
+ public:
+ std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
+ const net::test_server::HttpRequest& request) override {
+ EXPECT_TRUE(base::StartsWith(request.relative_url,
+ "/topic/eyeochromium_activeping/version/1"));
+ EXPECT_TRUE(request.has_content);
+ absl::optional<base::Value> parsed =
+ base::JSONReader::Read(request.content);
+ base::Value* first_ping = GetFirstPing(parsed);
+ base::Value* last_ping = GetLastPing(parsed);
+ base::Value* previous_last_ping = GetPreviousLastPing(parsed);
+
+ if (expected_first_ping_.empty()) {
+ EXPECT_FALSE(first_ping);
+ } else {
+ EXPECT_EQ(expected_first_ping_, *first_ping);
+ }
+
+ if (expected_last_ping_.empty()) {
+ EXPECT_FALSE(last_ping);
+ } else {
+ EXPECT_EQ(expected_last_ping_, *last_ping);
+ }
+
+ if (expected_previous_last_ping_.empty()) {
+ EXPECT_FALSE(previous_last_ping);
+ } else {
+ EXPECT_EQ(expected_previous_last_ping_, *previous_last_ping);
+ }
+
+ if (!attempt_++) {
+ // Force retry by 404 response but 1st save last_ping_tag if any
+ base::Value* last_ping_tag = GetLastPingTag(parsed);
+ if (last_ping_tag) {
+ previous_last_ping_tag_ = last_ping_tag->GetString();
+ }
+ return nullptr;
+ }
+
+ // Verifies that retried ping has the same last_ping_tag
+ if (!previous_last_ping_tag_.empty()) {
+ base::Value* last_ping_tag = GetLastPingTag(parsed);
+ EXPECT_EQ(previous_last_ping_tag_, *last_ping_tag);
+ }
+
+ // If we get expected telemetry ping with retry we simply finish the test
+ // by closing the browser, otherwise test will fail with a timeout.
+ CloseBrowserFromAnyThread();
+
+ // This will be still processed before CloseBrowserFromAnyThread() applies
+ return CreateResponse(server_response_);
+ }
+
+ void TearDownInProcessBrowserTestFixture() override {
+ // Make sure we called RequestHandler exactly twice: 1st ping failed, 2nd
+ // was successful
+ EXPECT_EQ(2, attempt_);
+ }
+
+ protected:
+ std::string server_response_;
+ std::string expected_first_ping_;
+ std::string expected_last_ping_;
+ std::string expected_previous_last_ping_;
+
+ private:
+ int attempt_ = 0;
+ std::string previous_last_ping_tag_ = "";
+};
+
+IN_PROC_BROWSER_TEST_F(
+ AdblockTelemetryServiceFirstPingAfterRestartWithRetryBrowserTest,
+ PRE_PRE_TestPing) {
+ // Sets the ping to be returned by the server and checked in the next test
+ server_response_ = "11111";
+ RunUntilBrowserProcessQuits();
+}
+
+IN_PROC_BROWSER_TEST_F(
+ AdblockTelemetryServiceFirstPingAfterRestartWithRetryBrowserTest,
+ PRE_TestPing) {
+ // Sets the ping to be returned by the server and checked in the next test
+ server_response_ = "22222";
+ expected_first_ping_ = expected_last_ping_ = "11111";
+ RunUntilBrowserProcessQuits();
+}
+
+IN_PROC_BROWSER_TEST_F(
+ AdblockTelemetryServiceFirstPingAfterRestartWithRetryBrowserTest,
+ TestPing) {
+ expected_first_ping_ = "11111";
+ expected_last_ping_ = "22222";
+ expected_previous_last_ping_ = "11111";
+ RunUntilBrowserProcessQuits();
+}
+
+// Test three inital pings
+class AdblockTelemetryServiceSubsequentPingsBrowserTest
+ : public AdblockTelemetryServiceBrowserTestBase {
+ public:
+ std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
+ const net::test_server::HttpRequest& request) override {
+ EXPECT_TRUE(base::StartsWith(request.relative_url,
+ "/topic/eyeochromium_activeping/version/1"));
+ EXPECT_TRUE(request.has_content);
+ absl::optional<base::Value> parsed =
+ base::JSONReader::Read(request.content);
+ base::Value* first_ping = GetFirstPing(parsed);
+ base::Value* last_ping = GetLastPing(parsed);
+ base::Value* previous_last_ping = GetPreviousLastPing(parsed);
+
+ if (count_ == 1) {
+ // No ping payload in the very 1st ping
+ EXPECT_FALSE(first_ping);
+ EXPECT_FALSE(last_ping);
+ } else if (count_ == 2) {
+ // For 2nd ping `first_ping` == `last_ping`
+ EXPECT_EQ(first_ping_, *first_ping);
+ EXPECT_EQ(first_ping_, *last_ping);
+ } else if (count_ == 3) {
+ // From 3rd ping onward `first_ping` != `last_ping` and we also get
+ // `previous_last_ping`
+ EXPECT_EQ(first_ping_, *first_ping);
+ EXPECT_EQ(second_ping_, *last_ping);
+ EXPECT_EQ(first_ping_, *previous_last_ping);
+ }
+
+ // If we get three expected telemetry pings we simply finish the test by
+ // closing the browser, otherwise test will fail with a timeout.
+ if (count_ == 3) {
+ CloseBrowserFromAnyThread();
+ return nullptr;
+ }
+ return CreateResponse(count_++ == 1 ? first_ping_ : second_ping_);
+ }
+
+ void TearDownInProcessBrowserTestFixture() override {
+ // Make sure we called RequestHandler exactly three times
+ EXPECT_EQ(3, count_);
+ }
+
+ private:
+ const std::string first_ping_ = "11111";
+ const std::string second_ping_ = "22222";
+ int count_ = 1;
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockTelemetryServiceSubsequentPingsBrowserTest,
+ TestPing) {
+ RunUntilBrowserProcessQuits();
+}
+
+} // namespace adblock
diff --git a/chrome/browser/adblock/test/adblock_web_bundle_browsertest.cc b/chrome/browser/adblock/test/adblock_web_bundle_browsertest.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/adblock/test/adblock_web_bundle_browsertest.cc
@@ -0,0 +1,427 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <cstdint>
+#include <vector>
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/functional/bind.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/adblock/resource_classification_runner_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/content/browser/resource_classification_runner.h"
+#include "components/adblock/core/common/adblock_constants.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+#include "components/web_package/web_bundle_builder.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/browser_test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/request_handler_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace adblock {
+
+class AdblockWebBundleBrowserTest
+ : public InProcessBrowserTest,
+ public ResourceClassificationRunner::Observer {
+ public:
+ void SetUpOnMainThread() override {
+ InProcessBrowserTest::SetUpOnMainThread();
+ host_resolver()->AddRule("*", "127.0.0.1");
+ embedded_test_server()->RegisterDefaultHandler(
+ base::BindRepeating(&AdblockWebBundleBrowserTest::HandleFileRequest,
+ base::Unretained(this)));
+ ASSERT_TRUE(embedded_test_server()->Start());
+ PrepareTempDirWithContent();
+ ResourceClassificationRunnerFactory::GetForBrowserContext(
+ browser()->profile())
+ ->AddObserver(this);
+ }
+
+ void TearDownOnMainThread() override {
+ ResourceClassificationRunnerFactory::GetForBrowserContext(
+ browser()->profile())
+ ->RemoveObserver(this);
+ InProcessBrowserTest::TearDownOnMainThread();
+ }
+
+ void PrepareTempDirWithContent() {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ CreateIndexFile();
+ CreateByResourceWebBundle();
+ CreateByBundleFileWebBundle();
+ CreateByScopeFileWebBundle();
+ }
+
+ std::string GetFileContentFromTestDir(
+ base::FilePath::StringType relative_path) {
+ base::FilePath root;
+ CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &root));
+ root = root.AppendASCII("chrome/test/data/adblock/wbn");
+ std::string content;
+ CHECK(base::ReadFileToString(root.Append(relative_path), &content));
+ return content;
+ }
+
+ // In order for an html file to use absolute URLs in 'src' attributes to
+ // resources hosted by the embedded_test_server(), we need to replace
+ // {{{baseUrl}}} with the server's URL. It changes for every run.
+ std::string GetHtmlContentWithReplacements(
+ base::FilePath::StringType relative_path) {
+ std::string content = GetFileContentFromTestDir(relative_path);
+ base::ReplaceSubstringsAfterOffset(
+ &content, 0, "{{{baseUrl}}}",
+ embedded_test_server()->GetURL("example.org", "/").spec());
+ return content;
+ }
+
+ void CreateByResourceWebBundle() {
+ web_package::WebBundleBuilder builder;
+ builder.AddExchange("by_resource/blue_subresource_loading.css",
+ {{":status", "200"}, {"content-type", "text/css"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_resource/blue_subresource_loading.css")));
+ builder.AddExchange("by_resource/blue_subresource_loading.png",
+ {{":status", "200"}, {"content-type", "image/png"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_resource/blue_subresource_loading.png")));
+ builder.AddExchange("by_resource/red_subresource_loading.css",
+ {{":status", "200"}, {"content-type", "text/css"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_resource/red_subresource_loading.css")));
+ builder.AddExchange("by_resource/red_subresource_loading.png",
+ {{":status", "200"}, {"content-type", "image/png"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_resource/red_subresource_loading.png")));
+ builder.AddExchange(
+ "by_resource/xhr_result_1_subresource_loading.json",
+ {{":status", "200"}, {"content-type", "application/json"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_resource/xhr_result_1_subresource_loading.json")));
+ builder.AddExchange(
+ "by_resource/fetch_result_1_subresource_loading.json",
+ {{":status", "200"}, {"content-type", "application/json"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_resource/fetch_result_1_subresource_loading.json")));
+ builder.AddPrimaryURL(embedded_test_server()->GetURL("example.org", "/"));
+ const auto binary_data = builder.CreateBundle();
+ ASSERT_TRUE(base::WriteFile(
+ temp_dir_.GetPath().AppendASCII("by_resource.wbn"), binary_data));
+ }
+
+ void CreateByBundleFileWebBundle() {
+ web_package::WebBundleBuilder builder;
+ builder.AddExchange("by_bundle_file/green_subresource_loading.css",
+ {{":status", "200"}, {"content-type", "text/css"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_bundle_file/green_subresource_loading.css")));
+ builder.AddExchange("by_bundle_file/green_subresource_loading.png",
+ {{":status", "200"}, {"content-type", "image/png"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_bundle_file/green_subresource_loading.png")));
+ builder.AddExchange("by_bundle_file/purple_subresource_loading.css",
+ {{":status", "200"}, {"content-type", "text/css"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_bundle_file/purple_subresource_loading.css")));
+ builder.AddExchange("by_bundle_file/purple_subresource_loading.png",
+ {{":status", "200"}, {"content-type", "image/png"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_bundle_file/purple_subresource_loading.png")));
+ builder.AddExchange(
+ "by_bundle_file/xhr_result_2_subresource_loading.json",
+ {{":status", "200"}, {"content-type", "application/json"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_bundle_file/xhr_result_2_subresource_loading.json")));
+ builder.AddExchange(
+ "by_bundle_file/fetch_result_2_subresource_loading.json",
+ {{":status", "200"}, {"content-type", "application/json"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_bundle_file/fetch_result_2_subresource_loading.json")));
+ builder.AddPrimaryURL(embedded_test_server()->GetURL("example.org", "/"));
+ const auto binary_data = builder.CreateBundle();
+ ASSERT_TRUE(base::WriteFile(
+ temp_dir_.GetPath().AppendASCII("by_bundle_file.wbn"), binary_data));
+ }
+
+ void CreateByScopeFileWebBundle() {
+ web_package::WebBundleBuilder builder;
+ builder.AddExchange("by_scope/orange_subresource_loading.css",
+ {{":status", "200"}, {"content-type", "text/css"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_scope/orange_subresource_loading.css")));
+ builder.AddExchange("by_scope/orange_subresource_loading.png",
+ {{":status", "200"}, {"content-type", "image/png"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_scope/orange_subresource_loading.png")));
+ builder.AddExchange("by_scope/pink_subresource_loading.css",
+ {{":status", "200"}, {"content-type", "text/css"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_scope/pink_subresource_loading.css")));
+ builder.AddExchange("by_scope/pink_subresource_loading.png",
+ {{":status", "200"}, {"content-type", "image/png"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_scope/pink_subresource_loading.png")));
+ builder.AddExchange(
+ "by_scope/xhr_result_3_subresource_loading.json",
+ {{":status", "200"}, {"content-type", "application/json"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_scope/xhr_result_3_subresource_loading.json")));
+ builder.AddExchange(
+ "by_scope/fetch_result_3_subresource_loading.json",
+ {{":status", "200"}, {"content-type", "application/json"}},
+ GetFileContentFromTestDir(FILE_PATH_LITERAL(
+ "by_scope/fetch_result_3_subresource_loading.json")));
+ builder.AddPrimaryURL(embedded_test_server()->GetURL("example.org", "/"));
+ const auto binary_data = builder.CreateBundle();
+ ASSERT_TRUE(base::WriteFile(temp_dir_.GetPath().AppendASCII("by_scope.wbn"),
+ binary_data));
+ }
+
+ void CreateIndexFile() {
+ const auto html = GetHtmlContentWithReplacements(
+ FILE_PATH_LITERAL("index.html.mustache"));
+ ASSERT_TRUE(
+ base::WriteFile(temp_dir_.GetPath().AppendASCII("index.html"), html));
+ }
+
+ std::unique_ptr<net::test_server::HttpResponse> HandleFileRequest(
+ const net::test_server::HttpRequest& request) {
+ auto response =
+ net::test_server::HandleFileRequest(temp_dir_.GetPath(), request);
+ if (response) {
+ auto* basic =
+ static_cast<net::test_server::BasicHttpResponse*>(response.get());
+ if (temp_dir_.GetPath()
+ .AppendASCII(request.GetURL().path().substr(1))
+ .MatchesExtension(FILE_PATH_LITERAL(".wbn"))) {
+ basic->set_content_type("application/webbundle");
+ }
+ basic->AddCustomHeader("X-Content-Type-Options", "nosniff");
+ basic->AddCustomHeader("Access-Control-Allow-Origin", "*");
+ }
+ return response;
+ }
+
+ GURL GetUrl() {
+ return embedded_test_server()->GetURL("example.org", "/index.html");
+ }
+
+ void SetFilters(std::vector<std::string> filters) {
+ auto* adblock_configuration =
+ SubscriptionServiceFactory::GetForBrowserContext(browser()->profile())
+ ->GetAdblockFilteringConfiguration();
+ adblock_configuration->RemoveCustomFilter(kAllowlistEverythingFilter);
+ for (auto& filter : filters) {
+ adblock_configuration->AddCustomFilter(filter);
+ }
+ }
+
+ bool EvaluateJs(std::string value) {
+ return content::EvalJs(browser()
+ ->tab_strip_model()
+ ->GetActiveWebContents()
+ ->GetPrimaryMainFrame(),
+ value)
+ .ExtractBool();
+ }
+
+ bool IsImageLoaded(std::string selector) {
+ return EvaluateJs(
+ "(function(){ node = document.querySelector('" + selector +
+ "'); return node.complete && node.naturalHeight !== 0; })()");
+ }
+
+ bool IsCssBlocked(std::string selector) {
+ // On the test page, a box with this |id| is grey if element-specific CSS
+ // was blocked. Grey is the default color for divs, and gets overridden
+ // to element-specific colors by blockable CSS files.
+ return EvaluateJs(
+ "(function(){ return "
+ "window.getComputedStyle(document.querySelector('" +
+ selector + "')).backgroundColor == 'rgb(128, 128, 128)'; })()");
+ }
+
+ // Waits until the textContent of the selected item stops being "Pending" and
+ // returns whatever it's final value is.
+ // This asynchronous wait is because scripts that change the textContent may
+ // execute with a delay.
+ std::string GetSelectorTextContent(std::string selector) {
+ return content::EvalJs(browser()
+ ->tab_strip_model()
+ ->GetActiveWebContents()
+ ->GetPrimaryMainFrame(),
+ R"(
+ (async function (selector) {
+ return new Promise(resolve => {
+ if (!document.querySelector(selector).textContent.includes('Pending')) {
+ return resolve(document.querySelector(selector).textContent);
+ }
+
+ const observer = new MutationObserver(mutations => {
+ if (!document.querySelector(selector).textContent.includes('Pending')) {
+ resolve(document.querySelector(selector).textContent);
+ observer.disconnect();
+ }
+ });
+
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true
+ });
+ });
+})(' )" + selector + "');")
+ .ExtractString();
+ }
+
+ bool IsXhrOrFetchRequestBlocked(std::string selector) {
+ return GetSelectorTextContent(selector).find("Error") != std::string::npos;
+ }
+
+ bool IsXhrOrFetchRequestAllowed(std::string selector) {
+ return GetSelectorTextContent(selector).find("succeeded") !=
+ std::string::npos;
+ }
+
+ // ResourceClassificationRunner::Observer:
+ void OnAdMatched(const GURL& url,
+ FilterMatchResult match_result,
+ const std::vector<GURL>& parent_frame_urls,
+ ContentType content_type,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {
+ if (match_result == FilterMatchResult::kBlockRule) {
+ blocked_ads_notifications_.push_back(url);
+ }
+ }
+
+ void OnPageAllowed(const GURL& url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {}
+
+ void OnPopupMatched(const GURL& url,
+ FilterMatchResult match_result,
+ const GURL& opener_url,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& subscription,
+ const std::string& configuration_name) override {}
+
+ base::ScopedTempDir temp_dir_;
+ std::vector<GURL> blocked_ads_notifications_;
+};
+
+IN_PROC_BROWSER_TEST_F(AdblockWebBundleBrowserTest, BlockImageByResource) {
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ const auto* blocked_image_selector =
+ R"(img[src="by_resource/blue_subresource_loading.png"])";
+ const auto* other_image_selector =
+ R"(img[src="by_resource/red_subresource_loading.png"])";
+ EXPECT_TRUE(IsImageLoaded(blocked_image_selector));
+ EXPECT_TRUE(IsImageLoaded(other_image_selector));
+ SetFilters({"/blue_subresource_loading.png"});
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ EXPECT_FALSE(IsImageLoaded(blocked_image_selector));
+ EXPECT_TRUE(IsImageLoaded(other_image_selector));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockWebBundleBrowserTest, BlockCssByResource) {
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ EXPECT_FALSE(IsCssBlocked("div.blue"));
+ SetFilters({"blue_subresource_loading.css"});
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ EXPECT_TRUE(IsCssBlocked("div.blue"));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockWebBundleBrowserTest, BlockXhrByResource) {
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ const auto* blocked_selector = "code#xhr_result_by_resource";
+ EXPECT_TRUE(IsXhrOrFetchRequestAllowed(blocked_selector));
+ SetFilters({"/xhr_result_1_subresource_loading.json"});
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ EXPECT_TRUE(IsXhrOrFetchRequestBlocked(blocked_selector));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockWebBundleBrowserTest, BlockFetchByResource) {
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ const auto* blocked_selector = "code#fetch_result_by_resource";
+ EXPECT_TRUE(IsXhrOrFetchRequestAllowed(blocked_selector));
+ SetFilters({"/fetch_result_1_subresource_loading.json"});
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ EXPECT_TRUE(IsXhrOrFetchRequestBlocked(blocked_selector));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockWebBundleBrowserTest, BlockByBundle) {
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ const auto* blocked_image_selector =
+ R"(img[src="by_bundle_file/green_subresource_loading.png"])";
+ EXPECT_TRUE(IsImageLoaded(blocked_image_selector));
+ EXPECT_FALSE(IsCssBlocked("div.green"));
+ EXPECT_FALSE(IsCssBlocked("div.purple"));
+ EXPECT_TRUE(IsXhrOrFetchRequestAllowed("code#xhr_result_by_bundle_file"));
+ EXPECT_TRUE(IsXhrOrFetchRequestAllowed("code#fetch_result_by_bundle_file"));
+
+ SetFilters({"by_bundle_file.wbn$webbundle"});
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ EXPECT_FALSE(IsImageLoaded(blocked_image_selector));
+ EXPECT_TRUE(IsCssBlocked("div.green"));
+ EXPECT_TRUE(IsCssBlocked("div.purple"));
+ EXPECT_THAT(blocked_ads_notifications_,
+ testing::Contains(embedded_test_server()->GetURL(
+ "example.org", "/by_bundle_file.wbn")));
+ // FIXME the following two expectations fail because the state of the requests
+ // is "pending" rather than allowed or blocked: DPD-1887
+ // EXPECT_TRUE(IsXhrOrFetchRequestBlocked("code#xhr_result_by_bundle_file"));
+ // EXPECT_TRUE(IsXhrOrFetchRequestBlocked("code#fetch_result_by_bundle_file"));
+}
+
+IN_PROC_BROWSER_TEST_F(AdblockWebBundleBrowserTest, BlockByScope) {
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ const auto* blocked_image_selector =
+ R"(img[src="by_scope/orange_subresource_loading.png"])";
+ EXPECT_TRUE(IsImageLoaded(blocked_image_selector));
+ EXPECT_FALSE(IsCssBlocked("div.orange"));
+ EXPECT_FALSE(IsCssBlocked("div.pink"));
+ EXPECT_TRUE(IsXhrOrFetchRequestAllowed("code#xhr_result_by_scope"));
+ EXPECT_TRUE(IsXhrOrFetchRequestAllowed("code#fetch_result_by_scope"));
+
+ SetFilters({"by_scope/"});
+ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetUrl()));
+ EXPECT_FALSE(IsImageLoaded(blocked_image_selector));
+ EXPECT_TRUE(IsCssBlocked("div.orange"));
+ EXPECT_TRUE(IsCssBlocked("div.pink"));
+ EXPECT_TRUE(IsXhrOrFetchRequestBlocked("code#xhr_result_by_scope"));
+ EXPECT_TRUE(IsXhrOrFetchRequestBlocked("code#fetch_result_by_scope"));
+}
+
+// TODO:
+// - Mixed origins
+// - Signed bundles. including case of navigation between signed and unsigned
+// content.
+// - If you block the whole bundle, all resources requests to components
+// declared in <script type="webbundle"> should be aborted. See sample test
+// here:
+// https://gitlab.com/eyeo/adblockplus/abc/webext-sdk/-/merge_requests/623/diffs#c24c6bdc211dc8e196dc5e2e32ddbefeb5fd4390_179_179
+
+} // namespace adblock
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -1,6 +1,10 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include "chrome/browser/chrome_browser_interface_binders.h"
@@ -39,6 +43,7 @@
#include "chrome/browser/ui/side_panel/companion/companion_utils.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/web_applications/draggable_region_host_impl.h"
+#include "chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.h"
#include "chrome/browser/ui/webui/browsing_topics/browsing_topics_internals_ui.h"
#include "chrome/browser/ui/webui/engagement/site_engagement_ui.h"
#include "chrome/browser/ui/webui/internals/internals_ui.h"
@@ -1043,6 +1048,10 @@ void PopulateChromeWebUIFrameBinders(
media::mojom::MediaEngagementScoreDetailsProvider, MediaEngagementUI>(
map);
+ RegisterWebUIControllerInterfaceBinder<
+ ::mojom::adblock_internals::AdblockInternalsPageHandler,
+ AdblockInternalsUI>(map);
+
RegisterWebUIControllerInterfaceBinder<browsing_topics::mojom::PageHandler,
BrowsingTopicsInternalsUI>(map);
diff --git a/chrome/browser/client_hints/client_hints_browsertest.cc b/chrome/browser/client_hints/client_hints_browsertest.cc
--- a/chrome/browser/client_hints/client_hints_browsertest.cc
+++ b/chrome/browser/client_hints/client_hints_browsertest.cc
@@ -1,6 +1,10 @@
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include <cstddef>
#include <memory>
@@ -653,7 +657,10 @@ class ClientHintsBrowserTest : public policy::PolicyTest {
feature_list->InitializeFromCommandLine(
"UserAgentClientHint,CriticalClientHint,AcceptCHFrame,"
"ClientHintsFormFactor,ClientHintsPrefersReducedTransparency",
- "");
+ // Disabling AdblockPlus because the async implementation of
+ // AdblockURLLoaderThrottle::WillStartRequest confuses
+ // ThirdPartyURLLoaderInterceptor.
+ "AdblockPlus");
return feature_list;
}
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc
--- a/chrome/browser/net/errorpage_browsertest.cc
+++ b/chrome/browser/net/errorpage_browsertest.cc
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
+
#include <algorithm>
#include <memory>
#include <utility>
@@ -38,6 +42,7 @@
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/core/adblock_switches.h"
#include "components/browsing_data/content/browsing_data_helper.h"
#include "components/embedder_support/switches.h"
#include "components/error_page/content/browser/net_error_auto_reloader.h"
@@ -636,6 +641,9 @@ class ErrorPageAutoReloadTest : public InProcessBrowserTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(embedder_support::kEnableAutoReload);
+ // The URLLoaderInterceptor is not resilient to the browser making
+ // adblock-related requests, they confuse this test.
+ command_line->AppendSwitch(adblock::switches::kDisableAdblock);
}
void TearDownOnMainThread() override { url_loader_interceptor_.reset(); }
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -1,6 +1,10 @@
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include <memory>
#include <string>
@@ -20,6 +24,7 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/core/features.h"
#include "components/heavy_ad_intervention/heavy_ad_features.h"
#include "components/page_load_metrics/browser/ads_page_load_metrics_test_waiter.h"
#include "components/page_load_metrics/browser/observers/ad_metrics/ad_intervention_browser_test_utils.h"
@@ -1490,7 +1495,7 @@ class AdsPageLoadMetricsObserverResourceBrowserTest
{heavy_ad_intervention::features::kHeavyAdIntervention, {}},
{heavy_ad_intervention::features::kHeavyAdPrivacyMitigations,
{{"host-threshold", "3"}}}},
- {});
+ {adblock::kAdblockPlusFeature});
}
~AdsPageLoadMetricsObserverResourceBrowserTest() override {}
diff --git a/chrome/browser/preferences/BUILD.gn b/chrome/browser/preferences/BUILD.gn
--- a/chrome/browser/preferences/BUILD.gn
+++ b/chrome/browser/preferences/BUILD.gn
@@ -1,6 +1,10 @@
# Copyright 2019 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+#
+# This source code is a part of eyeo Chromium SDK.
+# Use of this source code is governed by the GPLv3 that can be found in the components/adblock/LICENSE file.
+
import("//build/config/android/rules.gni")
import("//third_party/jni_zero/jni_zero.gni")
@@ -38,6 +42,7 @@ android_library("java") {
java_cpp_strings("java_pref_names_srcjar") {
sources = [
"//chrome/common/pref_names.h",
+ "//components/adblock/core/common/adblock_prefs.cc",
"//components/autofill/core/common/autofill_prefs.cc",
"//components/commerce/core/pref_names.cc",
"//components/dom_distiller/core/pref_names.cc",
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc
--- a/chrome/browser/prefs/chrome_pref_service_factory.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -1,6 +1,10 @@
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include "chrome/browser/prefs/chrome_pref_service_factory.h"
@@ -39,6 +43,7 @@
#include "chrome/grit/branded_strings.h"
#include "chrome/grit/browser_resources.h"
#include "chrome/grit/generated_resources.h"
+#include "components/adblock/core/common/adblock_prefs.h"
#include "components/component_updater/pref_names.h"
#include "components/policy/core/browser/configuration_policy_pref_store.h"
#include "components/pref_registry/pref_registry_syncable.h"
@@ -177,6 +182,12 @@ const prefs::TrackedPreferenceMetadata kTrackedPrefs[] = {
{32, prefs::kMediaCdmOriginData, EnforcementLevel::ENFORCE_ON_LOAD,
PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL},
#endif // BUILDFLAG(IS_WIN)
+ {100, adblock::common::prefs::kSubscriptionSignatures,
+ EnforcementLevel::ENFORCE_ON_LOAD, PrefTrackingStrategy::SPLIT,
+ ValueType::IMPERSONAL},
+ {101, adblock::common::prefs::kLastUsedSchemaVersion,
+ EnforcementLevel::ENFORCE_ON_LOAD, PrefTrackingStrategy::ATOMIC,
+ ValueType::IMPERSONAL},
// See note at top, new items added here also need to be added to
// histograms.xml's TrackedPreference enum.
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -1,6 +1,10 @@
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include "chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h"
@@ -12,6 +16,15 @@
#include "build/chromeos_buildflags.h"
#include "chrome/browser/accessibility/accessibility_labels_service_factory.h"
#include "chrome/browser/accessibility/page_colors_factory.h"
+#include "chrome/browser/adblock/adblock_controller_factory.h"
+#include "chrome/browser/adblock/adblock_telemetry_service_factory.h"
+#include "chrome/browser/adblock/content_security_policy_injector_factory.h"
+#include "chrome/browser/adblock/element_hider_factory.h"
+#include "chrome/browser/adblock/resource_classification_runner_factory.h"
+#include "chrome/browser/adblock/session_stats_factory.h"
+#include "chrome/browser/adblock/sitekey_storage_factory.h"
+#include "chrome/browser/adblock/subscription_persistent_metadata_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
#include "chrome/browser/autocomplete/document_suggestions_service_factory.h"
#include "chrome/browser/autocomplete/in_memory_url_index_factory.h"
@@ -249,6 +262,8 @@
#include "chrome/browser/signin/signin_manager_android_factory.h"
#include "components/commerce/core/commerce_feature_list.h"
#include "components/commerce/core/proto/merchant_signal_db_content.pb.h"
+
+
#else
#include "chrome/browser/accessibility/live_caption/live_caption_controller_factory.h"
#include "chrome/browser/accessibility/live_translate_controller_factory.h"
@@ -735,8 +750,19 @@ void ChromeBrowserMainExtraPartsProfiles::
#if BUILDFLAG(ENABLE_SESSION_SERVICE)
ExitTypeServiceFactory::GetInstance();
#endif
+ adblock::AdblockControllerFactory::GetInstance();
+ adblock::AdblockTelemetryServiceFactory::GetInstance();
+ adblock::ContentSecurityPolicyInjectorFactory::GetInstance();
+ adblock::ElementHiderFactory::GetInstance();
+ adblock::ResourceClassificationRunnerFactory::GetInstance();
+ adblock::SessionStatsFactory::GetInstance();
+ adblock::SitekeyStorageFactory::GetInstance();
+ adblock::SubscriptionPersistentMetadataFactory::GetInstance();
+ adblock::SubscriptionServiceFactory::GetInstance();
#if BUILDFLAG(IS_ANDROID)
FastCheckoutCapabilitiesFetcherFactory::GetInstance();
+
+
#endif
FaviconServiceFactory::GetInstance();
feature_engagement::TrackerFactory::GetInstance();
diff --git a/chrome/browser/profiles/profile_keyed_service_browsertest.cc b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
--- a/chrome/browser/profiles/profile_keyed_service_browsertest.cc
+++ b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
+
#include <sstream>
#include "base/ranges/algorithm.h"
@@ -189,12 +193,22 @@ IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
SystemProfileParent_NeededServices) {
+ // clang-format off
+ // List of services expected to be created for the Parent System Profile.
+ std::set<std::string> system_active_services {
+ // eyeo Chromium SDK services:
+ "AdblockController",
+ "AdblockSubscriptionPersistentMetadata",
+ "AdblockSubscriptionService",
+ "AdblockTelemetryService",
+ };
+ // clang-format on
+
Profile* system_profile =
CreateProfileAndWaitForAllTasks(ProfileManager::GetSystemProfilePath());
ASSERT_FALSE(system_profile->IsOffTheRecord());
ASSERT_TRUE(system_profile->IsSystemProfile());
- TestKeyedProfileServicesActives(system_profile,
- /*expected_active_services_names=*/{});
+ TestKeyedProfileServicesActives(system_profile, system_active_services);
}
IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
@@ -271,7 +285,7 @@ IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
"UkmBackgroundRecorderService",
"UsbDeviceManager",
"UsbDeviceResourceManager",
- "sct_reporting::Factory"
+ "sct_reporting::Factory",
};
// clang-format on
@@ -524,6 +538,17 @@ IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
"feedback::FeedbackUploaderChrome",
"sct_reporting::Factory",
"ZeroSuggestCacheServiceFactory",
+
+ // eyeo Chromium SDK services:
+ "AdblockController",
+ "AdblockPrivateAPI",
+ "AdblockSubscriptionPersistentMetadata",
+ "AdblockSubscriptionService",
+ "AdblockTelemetryService",
+ "EyeoFilteringPrivateAPI",
+ "ResourceClassificationRunner",
+ "SessionStats",
+ "SitekeyStorage",
};
// clang-format on
@@ -570,6 +595,17 @@ IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
"PermissionsUpdaterShutdownFactory",
"PluginInfoHostImpl",
"TurnSyncOnHelperShutdownNotifier",
+
+ // Eyeo services:
+ "AdblockController",
+ "AdblockSubscriptionPersistentMetadata",
+ "AdblockSubscriptionService",
+ "AdblockTelemetryService",
+ "ContentSecurityPolicyInjector",
+ "ElementHider",
+ "ResourceClassificationRunner",
+ "SessionStats",
+ "SitekeyStorage",
};
// clang-format on
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -1,6 +1,9 @@
# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+#
+# This source code is a part of eyeo Chromium SDK.
+# Use of this source code is governed by the GPLv3 that can be found in the components/adblock/LICENSE file.
import("//build/config/chromebox_for_meetings/buildflags.gni")
import("//build/config/chromeos/ui_mode.gni")
@@ -220,6 +223,7 @@ if (!is_android) {
group("dev_ui_resources") {
public_deps = [
"accessibility:resources",
+ "adblock_internals:resources",
"bluetooth_internals:resources",
"browsing_topics:resources",
"components:resources",
@@ -274,6 +278,7 @@ repack("dev_ui_paks") {
sources = [
"$root_gen_dir/chrome/accessibility_resources.pak",
+ "$root_gen_dir/chrome/adblock_internals_resources.pak",
"$root_gen_dir/chrome/bluetooth_internals_resources.pak",
"$root_gen_dir/chrome/browsing_topics_internals_resources.pak",
"$root_gen_dir/chrome/components_resources.pak",
diff --git a/chrome/browser/resources/adblock_internals/BUILD.gn b/chrome/browser/resources/adblock_internals/BUILD.gn
new file mode 100644
--- /dev/null
+++ b/chrome/browser/resources/adblock_internals/BUILD.gn
@@ -0,0 +1,29 @@
+#
+# This file is part of eyeo Chromium SDK,
+# Copyright (C) 2006-present eyeo GmbH
+#
+# eyeo Chromium SDK is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3 as
+# published by the Free Software Foundation.
+#
+# eyeo Chromium SDK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+
+import("//ui/webui/resources/tools/build_webui.gni")
+
+build_webui("build") {
+ grd_prefix = "adblock_internals"
+ static_files = [ "adblock_internals.html" ]
+ non_web_component_files = [ "adblock_internals.ts" ]
+ mojo_files_deps = [ "//chrome/browser/ui/webui/adblock_internals:mojo_bindings_ts__generator" ]
+ mojo_files = [ "$root_gen_dir/chrome/browser/ui/webui/adblock_internals/adblock_internals.mojom-webui.ts" ]
+ ts_deps = [
+ "//ui/webui/resources/js:build_ts",
+ "//ui/webui/resources/mojo:build_ts",
+ ]
+}
diff --git a/chrome/browser/resources/adblock_internals/adblock_internals.html b/chrome/browser/resources/adblock_internals/adblock_internals.html
new file mode 100644
--- /dev/null
+++ b/chrome/browser/resources/adblock_internals/adblock_internals.html
@@ -0,0 +1,38 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE HTML>
+<html lang="en">
+
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>Ad-Filtering Internals</title>
+ <script type="module" src="adblock_internals.js"></script>
+</head>
+
+<body>
+ <button id="download-button">Download</button>
+ <button id="copy-button">Copy to Clipboard</button>
+ <button id="refresh">Refresh</button>
+
+ <hr>
+
+ <pre id="content" style="white-space: pre-wrap;"></pre>
+</body>
+
+</html>
diff --git a/chrome/browser/resources/adblock_internals/adblock_internals.ts b/chrome/browser/resources/adblock_internals/adblock_internals.ts
new file mode 100644
--- /dev/null
+++ b/chrome/browser/resources/adblock_internals/adblock_internals.ts
@@ -0,0 +1,43 @@
+// This file is part of eyeo Chromium SDK,
+// Copyright (C) 2006-present eyeo GmbH
+//
+// eyeo Chromium SDK is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 3 as
+// published by the Free Software Foundation.
+//
+// eyeo Chromium SDK is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+
+import {getRequiredElement} from 'chrome://resources/js/util_ts.js';
+import {AdblockInternalsPageHandler} from './adblock_internals.mojom-webui.js';
+
+async function debugInfo(): Promise<string> {
+ const info = await AdblockInternalsPageHandler.getRemote().getDebugInfo();
+ return info.debugInfo;
+}
+
+async function refresh() {
+ getRequiredElement('content').innerText = await debugInfo();
+}
+
+getRequiredElement('copy-button').addEventListener('click', async () => {
+ navigator.clipboard.writeText(await debugInfo());
+});
+
+getRequiredElement('download-button').addEventListener('click', async () => {
+ const url = URL.createObjectURL(new Blob([await debugInfo()], {type: 'text/plain'}));
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = 'adblock-internals.txt';
+ a.click();
+ URL.revokeObjectURL(url);
+});
+
+getRequiredElement('refresh').addEventListener('click', refresh);
+
+document.addEventListener('DOMContentLoaded', refresh);
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -5,6 +5,10 @@
// This test creates a fake safebrowsing service, where we can inject known-
// threat urls. It then uses a real browser to go to these urls, and sends
// "goback" or "proceed" commands and verifies they work.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include <algorithm>
#include <map>
@@ -62,6 +66,7 @@
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
+#include "components/adblock/core/features.h"
#include "components/google/core/common/google_util.h"
#include "components/grit/components_resources.h"
#include "components/omnibox/browser/omnibox_prefs.h"
@@ -608,7 +613,8 @@ class SafeBrowsingBlockingPageBrowserTest
{kTagAndAttributeParamName, "div,foo,div,baz"}};
base::test::FeatureRefAndParams tag_and_attribute(
safe_browsing::kThreatDomDetailsTagAndAttributeFeature, parameters);
- scoped_feature_list_.InitWithFeaturesAndParameters({tag_and_attribute}, {});
+ scoped_feature_list_.InitWithFeaturesAndParameters(
+ {tag_and_attribute}, {adblock::kAdblockPlusFeature});
}
SafeBrowsingBlockingPageBrowserTest(
diff --git a/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc b/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc
--- a/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_browser_test_harness.cc
@@ -1,6 +1,10 @@
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include "chrome/browser/subresource_filter/subresource_filter_browser_test_harness.h"
@@ -22,6 +26,7 @@
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/chrome_test_utils.h"
+#include "components/adblock/core/features.h"
#include "components/blocked_content/safe_browsing_triggered_popup_blocker.h"
#include "components/content_settings/browser/page_specific_content_settings.h"
#include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
@@ -71,7 +76,8 @@ MockSubresourceFilterObserver::~MockSubresourceFilterObserver() = default;
SubresourceFilterBrowserTest::SubresourceFilterBrowserTest() {
scoped_feature_list_.InitWithFeatures(
/*enabled_features=*/{kAdTagging},
- /*disabled_features=*/{features::kHttpsUpgrades});
+ /*disabled_features=*/{features::kHttpsUpgrades,
+ adblock::kAdblockPlusFeature});
}
SubresourceFilterBrowserTest::~SubresourceFilterBrowserTest() = default;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1,6 +1,10 @@
# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+#
+# This source code is a part of eyeo Chromium SDK.
+# Use of this source code is governed by the GPLv3 that can be found in the components/adblock/LICENSE file.
+
import("//build/config/buildflags_paint_preview.gni")
import("//build/config/chromebox_for_meetings/buildflags.gni")
@@ -231,6 +235,10 @@ static_library("ui") {
"webid/identity_dialog_controller.h",
"webui/about_ui.cc",
"webui/about_ui.h",
+ "webui/adblock_internals/adblock_internals_page_handler_impl.cc",
+ "webui/adblock_internals/adblock_internals_page_handler_impl.h",
+ "webui/adblock_internals/adblock_internals_ui.cc",
+ "webui/adblock_internals/adblock_internals_ui.h",
"webui/autofill_and_password_manager_internals/autofill_internals_ui.cc",
"webui/autofill_and_password_manager_internals/autofill_internals_ui.h",
"webui/autofill_and_password_manager_internals/internals_ui_handler.cc",
@@ -432,12 +440,13 @@ static_library("ui") {
"//chrome/browser/share",
"//chrome/browser/storage_access_api",
"//chrome/browser/ui/side_panel:side_panel_enums",
- "//chrome/browser/ui/webui:configs",
+ "//chrome/browser/ui/webui/adblock_internals:mojo_bindings",
"//chrome/browser/ui/webui/location_internals:mojo_bindings",
"//chrome/browser/ui/webui/omnibox:mojo_bindings",
"//chrome/browser/ui/webui/segmentation_internals:mojo_bindings",
"//chrome/browser/ui/webui/suggest_internals:mojo_bindings",
"//chrome/browser/ui/webui/usb_internals:mojo_bindings",
+ "//chrome/browser/ui/webui:configs",
"//chrome/common",
"//chrome/common/net",
"//chrome/common/search:mojo_bindings",
@@ -449,6 +458,7 @@ static_library("ui") {
"//components/about_ui",
"//components/access_code_cast/common:metrics",
"//components/account_id",
+ "//components/adblock/content:browser",
"//components/autofill/content/browser",
"//components/autofill/content/browser:risk_proto",
"//components/autofill/core/browser",
diff --git a/chrome/browser/ui/prefs/pref_watcher.cc b/chrome/browser/ui/prefs/pref_watcher.cc
--- a/chrome/browser/ui/prefs/pref_watcher.cc
+++ b/chrome/browser/ui/prefs/pref_watcher.cc
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
+
#include "chrome/browser/ui/prefs/pref_watcher.h"
#include "base/functional/bind.h"
@@ -13,6 +17,7 @@
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
#include "chrome/common/pref_names.h"
+#include "components/adblock/core/common/adblock_prefs.h"
#include "components/language/core/browser/pref_names.h"
#include "components/live_caption/pref_names.h"
#include "components/privacy_sandbox/tracking_protection_settings.h"
@@ -68,6 +73,14 @@ const char* const kWebPrefsToObserve[] = {
#else
prefs::kAccessibilityFocusHighlightEnabled,
#endif
+
+ adblock::common::prefs::kAdblockAllowedDomainsLegacy,
+ adblock::common::prefs::kAdblockCustomFiltersLegacy,
+ adblock::common::prefs::kAdblockCustomSubscriptionsLegacy,
+ adblock::common::prefs::kAdblockSubscriptionsLegacy,
+ adblock::common::prefs::kEnableAcceptableAdsLegacy,
+ adblock::common::prefs::kEnableAdblockLegacy,
+
};
const int kWebPrefsToObserveLength = std::size(kWebPrefsToObserve);
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -1,6 +1,10 @@
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include "chrome/browser/ui/tab_helpers.h"
@@ -13,6 +17,9 @@
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "chrome/browser/adblock/element_hider_factory.h"
+#include "chrome/browser/adblock/sitekey_storage_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/breadcrumbs/breadcrumb_manager_tab_helper.h"
#include "chrome/browser/browser_process.h"
@@ -111,6 +118,7 @@
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_isolated_world_ids.h"
#include "chrome/common/chrome_switches.h"
+#include "components/adblock/content/browser/adblock_webcontents_observer.h"
#include "components/autofill/content/browser/content_autofill_client.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/autofill/core/browser/browser_autofill_manager.h"
@@ -341,6 +349,16 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) {
optimization_guide_decider);
}
}
+
+ AdblockWebContentObserver::CreateForWebContents(
+ web_contents,
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(
+ web_contents->GetBrowserContext()),
+ adblock::ElementHiderFactory::GetForBrowserContext(
+ web_contents->GetBrowserContext()),
+ adblock::SitekeyStorageFactory::GetForBrowserContext(
+ web_contents->GetBrowserContext()),
+ std::make_unique<adblock::FrameHierarchyBuilder>());
autofill::ChromeAutofillClient::CreateForWebContents(web_contents);
if (breadcrumbs::IsEnabled())
BreadcrumbManagerTabHelper::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/webui/adblock_internals/BUILD.gn b/chrome/browser/ui/webui/adblock_internals/BUILD.gn
new file mode 100644
--- /dev/null
+++ b/chrome/browser/ui/webui/adblock_internals/BUILD.gn
@@ -0,0 +1,23 @@
+#
+# This file is part of eyeo Chromium SDK,
+# Copyright (C) 2006-present eyeo GmbH
+#
+# eyeo Chromium SDK is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3 as
+# published by the Free Software Foundation.
+#
+# eyeo Chromium SDK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojo_bindings") {
+ sources = [ "adblock_internals.mojom" ]
+ webui_module_path = "/"
+ use_typescript_sources = true
+}
diff --git a/chrome/browser/ui/webui/adblock_internals/adblock_internals.mojom b/chrome/browser/ui/webui/adblock_internals/adblock_internals.mojom
new file mode 100644
--- /dev/null
+++ b/chrome/browser/ui/webui/adblock_internals/adblock_internals.mojom
@@ -0,0 +1,20 @@
+// This file is part of eyeo Chromium SDK,
+// Copyright (C) 2006-present eyeo GmbH
+//
+// eyeo Chromium SDK is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 3 as
+// published by the Free Software Foundation.
+//
+// eyeo Chromium SDK is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+
+module mojom.adblock_internals;
+
+interface AdblockInternalsPageHandler {
+ GetDebugInfo() => (string debug_info);
+};
diff --git a/chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.cc b/chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.cc
@@ -0,0 +1,115 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.h"
+
+#include "base/time/time_to_iso8601.h"
+#include "chrome/browser/adblock/adblock_telemetry_service_factory.h"
+#include "chrome/browser/adblock/session_stats_factory.h"
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "components/adblock/core/adblock_telemetry_service.h"
+#include "components/adblock/core/session_stats.h"
+#include "components/adblock/core/subscription/subscription_config.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+
+namespace {
+
+std::string SubscriptionInstallationStateToString(
+ adblock::Subscription::InstallationState state) {
+ using State = adblock::Subscription::InstallationState;
+ switch (state) {
+ case State::Installed:
+ return "Installed";
+ case State::Installing:
+ return "Installing";
+ case State::Preloaded:
+ return "Preloaded";
+ case State::Unknown:
+ return "Unknown";
+ }
+ NOTREACHED();
+ return "";
+}
+
+std::string DebugLine(std::string name, std::string value, int level) {
+ return std::string(2 * level, ' ') + name + ": " + value + '\n';
+}
+
+std::string DebugLine(std::string name, int value, int level) {
+ return DebugLine(name, std::to_string(value), level);
+}
+
+} // namespace
+
+AdblockInternalsPageHandlerImpl::AdblockInternalsPageHandlerImpl(
+ Profile* profile,
+ mojo::PendingReceiver<mojom::adblock_internals::AdblockInternalsPageHandler>
+ receiver)
+ : profile_(profile), receiver_(this, std::move(receiver)) {}
+
+AdblockInternalsPageHandlerImpl::~AdblockInternalsPageHandlerImpl() = default;
+
+void AdblockInternalsPageHandlerImpl::GetDebugInfo(
+ GetDebugInfoCallback callback) {
+ CHECK(profile_);
+ auto* service =
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(profile_);
+ auto* stats = adblock::SessionStatsFactory::GetForBrowserContext(profile_);
+ auto allowed = stats->GetSessionAllowedAdsCount();
+ auto blocked = stats->GetSessionBlockedAdsCount();
+ std::string content;
+ for (auto* config : service->GetInstalledFilteringConfigurations()) {
+ content += DebugLine("Configuration", config->GetName(), 0);
+ content += DebugLine("Enabled", config->IsEnabled(), 1);
+ for (const auto& it : config->GetAllowedDomains()) {
+ content += DebugLine("Allowed domain", it, 1);
+ }
+ for (const auto& it : config->GetCustomFilters()) {
+ content += DebugLine("Custom filter", it, 1);
+ }
+ for (auto it : service->GetCurrentSubscriptions(config)) {
+ auto url = it->GetSourceUrl();
+ content += DebugLine("Subscription", url.spec(), 1);
+ content += DebugLine(
+ "State",
+ SubscriptionInstallationStateToString(it->GetInstallationState()), 2);
+ content += DebugLine("Title", it->GetTitle(), 2);
+ content += DebugLine("Version", it->GetCurrentVersion(), 2);
+ content += DebugLine("Last update",
+ base::TimeToISO8601(it->GetInstallationTime()), 2);
+ content += DebugLine("Total allowed", allowed[url], 2);
+ content += DebugLine("Total blocked", blocked[url], 2);
+ }
+ }
+
+ auto* telemetry_service =
+ adblock::AdblockTelemetryServiceFactory::GetForProfile(profile_);
+ telemetry_service->GetTopicProvidersDebugInfo(base::BindOnce(
+ &AdblockInternalsPageHandlerImpl::OnTelemetryServiceInfoArrived,
+ std::move(callback), std::move(content)));
+}
+
+void AdblockInternalsPageHandlerImpl::OnTelemetryServiceInfoArrived(
+ GetDebugInfoCallback callback,
+ std::string content,
+ std::vector<std::string> topic_provider_content) {
+ for (auto& topic_provider_debug_info : topic_provider_content) {
+ content +=
+ DebugLine("Eyeometry topic provider", topic_provider_debug_info, 0);
+ }
+ std::move(callback).Run(std::move(content));
+}
diff --git a/chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.h b/chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_UI_WEBUI_ADBLOCK_INTERNALS_ADBLOCK_INTERNALS_PAGE_HANDLER_IMPL_H_
+#define CHROME_BROWSER_UI_WEBUI_ADBLOCK_INTERNALS_ADBLOCK_INTERNALS_PAGE_HANDLER_IMPL_H_
+
+#include "base/memory/raw_ptr.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/adblock_internals/adblock_internals.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+
+class AdblockInternalsPageHandlerImpl
+ : public mojom::adblock_internals::AdblockInternalsPageHandler {
+ public:
+ explicit AdblockInternalsPageHandlerImpl(
+ Profile* profile,
+ mojo::PendingReceiver<
+ mojom::adblock_internals::AdblockInternalsPageHandler> receiver);
+ AdblockInternalsPageHandlerImpl(const AdblockInternalsPageHandlerImpl&) =
+ delete;
+ AdblockInternalsPageHandlerImpl& operator=(
+ const AdblockInternalsPageHandlerImpl&) = delete;
+ ~AdblockInternalsPageHandlerImpl() override;
+
+ // mojom::adblock_internals::AdblockInternalsPageHandler:
+ void GetDebugInfo(GetDebugInfoCallback callback) override;
+
+ private:
+ static void OnTelemetryServiceInfoArrived(
+ GetDebugInfoCallback callback,
+ std::string content,
+ std::vector<std::string> topic_provider_content);
+ raw_ptr<Profile> profile_;
+ mojo::Receiver<mojom::adblock_internals::AdblockInternalsPageHandler>
+ receiver_;
+};
+#endif // CHROME_BROWSER_UI_WEBUI_ADBLOCK_INTERNALS_ADBLOCK_INTERNALS_PAGE_HANDLER_IMPL_H_
diff --git a/chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.cc b/chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.cc
@@ -0,0 +1,47 @@
+/* \
+ * This file is part of eyeo Chromium SDK, \
+ * Copyright (C) 2006-present eyeo GmbH \
+ * \
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify \
+ * it under the terms of the GNU General Public License version 3 as \
+ * published by the Free Software Foundation. \
+ * \
+ * eyeo Chromium SDK is distributed in the hope that it will be useful, \
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of \
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \
+ * GNU General Public License for more details. \
+ * \
+ * You should have received a copy of the GNU General Public License \
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>. \
+ */
+
+#include "chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/adblock_internals/adblock_internals_page_handler_impl.h"
+#include "chrome/browser/ui/webui/webui_util.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/grit/adblock_internals_resources.h"
+#include "chrome/grit/adblock_internals_resources_map.h"
+#include "content/public/browser/web_ui_data_source.h"
+
+AdblockInternalsUI::AdblockInternalsUI(content::WebUI* web_ui)
+ : ui::MojoWebUIController(web_ui), profile_(Profile::FromWebUI(web_ui)) {
+ content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd(
+ profile_, chrome::kChromeUIAdblockInternalsHost);
+ webui::SetupWebUIDataSource(source,
+ base::make_span(kAdblockInternalsResources,
+ kAdblockInternalsResourcesSize),
+ IDR_ADBLOCK_INTERNALS_ADBLOCK_INTERNALS_HTML);
+}
+
+AdblockInternalsUI::~AdblockInternalsUI() = default;
+
+WEB_UI_CONTROLLER_TYPE_IMPL(AdblockInternalsUI)
+
+void AdblockInternalsUI::BindInterface(
+ mojo::PendingReceiver<mojom::adblock_internals::AdblockInternalsPageHandler>
+ receiver) {
+ handler_ = std::make_unique<AdblockInternalsPageHandlerImpl>(
+ profile_, std::move(receiver));
+}
diff --git a/chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.h b/chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of eyeo Chromium SDK,
+ * Copyright (C) 2006-present eyeo GmbH
+ *
+ * eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * eyeo Chromium SDK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CHROME_BROWSER_UI_WEBUI_ADBLOCK_INTERNALS_ADBLOCK_INTERNALS_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_ADBLOCK_INTERNALS_ADBLOCK_INTERNALS_UI_H_
+
+#include "chrome/browser/ui/webui/adblock_internals/adblock_internals.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "ui/webui/mojo_web_ui_controller.h"
+
+class Profile;
+
+class AdblockInternalsUI : public ui::MojoWebUIController {
+ public:
+ explicit AdblockInternalsUI(content::WebUI* web_ui);
+
+ AdblockInternalsUI(const AdblockInternalsUI&) = delete;
+ AdblockInternalsUI& operator=(const AdblockInternalsUI&) = delete;
+
+ ~AdblockInternalsUI() override;
+
+ void BindInterface(
+ mojo::PendingReceiver<
+ mojom::adblock_internals::AdblockInternalsPageHandler> receiver);
+
+ private:
+ WEB_UI_CONTROLLER_TYPE_DECL();
+
+ raw_ptr<Profile> profile_;
+ std::unique_ptr<mojom::adblock_internals::AdblockInternalsPageHandler>
+ handler_;
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_ADBLOCK_INTERNALS_ADBLOCK_INTERNALS_UI_H_
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -1,6 +1,10 @@
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
@@ -32,6 +36,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/signin_features.h"
#include "chrome/browser/ui/webui/about_ui.h"
+#include "chrome/browser/ui/webui/adblock_internals/adblock_internals_ui.h"
#include "chrome/browser/ui/webui/autofill_and_password_manager_internals/autofill_internals_ui.h"
#include "chrome/browser/ui/webui/autofill_and_password_manager_internals/password_manager_internals_ui.h"
#include "chrome/browser/ui/webui/browsing_topics/browsing_topics_internals_ui.h"
@@ -434,8 +439,12 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
// after the host name.
if (url.host_piece() == chrome::kChromeUIAccessibilityHost)
return &NewWebUI<AccessibilityUI>;
- if (url.host_piece() == chrome::kChromeUIAutofillInternalsHost)
+ if (url.host_piece() == chrome::kChromeUIAdblockInternalsHost) {
+ return &NewWebUI<AdblockInternalsUI>;
+ }
+ if (url.host_piece() == chrome::kChromeUIAutofillInternalsHost) {
return &NewWebUI<AutofillInternalsUI>;
+ }
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (url.host_piece() == chrome::kChromeUIAppDisabledHost)
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -1,6 +1,9 @@
# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+#
+# This source code is a part of eyeo Chromium SDK.
+# Use of this source code is governed by the GPLv3 that can be found in the components/adblock/LICENSE file.
import("//build/buildflag_header.gni")
import("//build/config/chrome_build.gni")
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -1,6 +1,10 @@
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include "chrome/common/webui_url_constants.h"
@@ -32,6 +36,7 @@ const char kChromeUIAboutURL[] = "chrome://about/";
const char kChromeUIActivateSafetyCheckSettingsURL[] =
"chrome://settings/safetyCheck?activateSafetyCheck";
const char kChromeUIAccessibilityHost[] = "accessibility";
+const char kChromeUIAdblockInternalsHost[] = "adblock-internals";
const char kChromeUIAllSitesPath[] = "/content/all";
const char kChromeUIAppIconHost[] = "app-icon";
const char kChromeUIAppIconURL[] = "chrome://app-icon/";
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -1,6 +1,10 @@
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
// Contains constants for WebUI UI/Host/SubPage constants. Anything else go in
// chrome/common/url_constants.h.
@@ -33,6 +37,7 @@ extern const char kChromeUIAboutHost[];
extern const char kChromeUIAboutURL[];
extern const char kChromeUIActivateSafetyCheckSettingsURL[];
extern const char kChromeUIAccessibilityHost[];
+extern const char kChromeUIAdblockInternalsHost[];
extern const char kChromeUIAllSitesPath[];
extern const char kChromeUIAppIconHost[];
extern const char kChromeUIAppIconURL[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1,6 +1,9 @@
# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+#
+# This source code is a part of eyeo Chromium SDK.
+# Use of this source code is governed by the GPLv3 that can be found in the components/adblock/LICENSE file.
import("//build/cipd/cipd.gni")
import("//build/config/buildflags_paint_preview.gni")
@@ -25,6 +28,7 @@ import("//chrome/test/base/js2gtest.gni")
import("//chrome/test/include_js_tests.gni")
import("//chrome/version.gni")
import("//chromeos/ash/components/assistant/assistant.gni")
+import("//components/adblock/features.gni")
import("//components/captive_portal/core/features.gni")
import("//components/enterprise/buildflags/buildflags.gni")
import("//components/feed/features.gni")
@@ -1206,6 +1210,7 @@ if (is_android) {
deps += [
":persisted_tab_data_test_proto",
+ "//components/adblock/content:browser",
"//components/autofill/content/browser:test_support",
"//components/back_forward_cache:back_forward_cache",
"//components/browsing_data/core:core",
@@ -1587,6 +1592,7 @@ if (!is_android) {
"//chrome/test/data/webui/mojo:mojo_bindings",
"//chrome/test/media_router/access_code_cast:access_code_cast_integration_base",
"//chrome/test/payments:test_support",
+ "//components/adblock/content:browser",
"//components/autofill/content/browser:risk_proto",
"//components/autofill/content/browser:test_support",
"//components/autofill/content/common/mojom",
@@ -1924,6 +1930,7 @@ if (!is_android) {
"//ash/components/arc/test/data/icons",
"//chrome/browser/page_load_metrics/integration_tests/data/",
"//chrome/renderer/resources/extensions/",
+ "//chrome/test/data/adblock/",
"//chrome/test/data/cart/",
"//components/test/data/ad_tagging/",
"//components/test/data/ads_observer/",
@@ -2007,6 +2014,17 @@ if (!is_android) {
"../browser/accessibility/image_annotation_browsertest.cc",
"../browser/accessibility/interstitial_accessibility_browsertest.cc",
"../browser/accessibility/page_colors_browsertest.cc",
+ "../browser/adblock/test/adblock_content_browser_client_browsertest.cc",
+ "../browser/adblock/test/adblock_filter_list_browsertest.cc",
+ "../browser/adblock/test/adblock_filtering_configurations_browsertest.cc",
+ "../browser/adblock/test/adblock_frame_hierarchy_builder_browsertest.cc",
+ "../browser/adblock/test/adblock_multiple_tabs_browsertest.cc",
+ "../browser/adblock/test/adblock_non_ascii_browsertest.cc",
+ "../browser/adblock/test/adblock_popup_browsertest.cc",
+ "../browser/adblock/test/adblock_snippets_browsertest.cc",
+ "../browser/adblock/test/adblock_subscription_service_browsertest.cc",
+ "../browser/adblock/test/adblock_telemetry_service_browsertest.cc",
+ "../browser/adblock/test/adblock_web_bundle_browsertest.cc",
"../browser/apps/guest_view/app_view_browsertest.cc",
"../browser/apps/guest_view/web_view_browsertest.cc",
"../browser/apps/platform_apps/app_browsertest.cc",
@@ -2736,6 +2754,10 @@ if (!is_android) {
sources += [ "../browser/chrome_for_testing/chrome_for_testing_info_bar_browsertest.cc" ]
}
+ if (eyeo_intercept_debug_url) {
+ sources += [ "../browser/adblock/test/adblock_debug_url_browsertest.cc" ]
+ }
+
if (enable_reporting) {
sources += [ "../browser/net/reporting_browsertest.cc" ]
}
@@ -3570,6 +3592,7 @@ if (!is_android) {
]
}
+
if (is_chromeos_ash && enable_extensions) {
deps +=
[ "//chromeos/ash/components/network/portal_detector:test_support" ]
@@ -5860,6 +5883,7 @@ test("unit_tests") {
"../browser/about_flags_unittest.cc",
"../browser/accessibility/media_app/ax_media_app_handler_unittest.cc",
"../browser/active_use_util_unittest.cc",
+ "../browser/adblock/adblock_content_browser_client_unittest.cc",
"../browser/after_startup_task_utils_unittest.cc",
"../browser/apps/icon_standardizer_unittest.cc",
"../browser/apps/user_type_filter_unittest.cc",
@@ -6528,6 +6552,8 @@ test("unit_tests") {
"//chrome/services/file_util:unit_tests",
"//chrome/services/qrcode_generator/public/cpp",
"//components/account_id",
+ "//components/adblock/content/browser:test_support",
+ "//components/adblock/core:test_support",
"//components/assist_ranker/proto",
"//components/autofill/content/browser:test_support",
"//components/background_sync",
@@ -10003,6 +10029,7 @@ if (!is_android) {
public_deps = [
"//chrome/browser:test_support_ui",
+ "//components/adblock/core:test_support",
"//content/public/browser",
"//content/test:test_support",
"//google_apis:test_support",
diff --git a/chrome/test/base/chrome_test_launcher.cc b/chrome/test/base/chrome_test_launcher.cc
--- a/chrome/test/base/chrome_test_launcher.cc
+++ b/chrome/test/base/chrome_test_launcher.cc
@@ -1,6 +1,10 @@
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+//
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
#include "chrome/test/base/chrome_test_launcher.h"
@@ -26,6 +30,7 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "chrome/browser/adblock/adblock_content_browser_client.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/metrics/chrome_feature_list_creator.h"
#include "chrome/common/chrome_constants.h"
@@ -154,7 +159,7 @@ ChromeTestLauncherDelegate::GetUserDataDirectoryCommandLineSwitch() {
// watch for long-running tasks and produce a useful timeout message in order to
// find the cause of flaky timeout tests.
class BrowserTestChromeContentBrowserClient
- : public ChromeContentBrowserClient {
+ : public AdblockContentBrowserClient {
public:
bool CreateThreadPool(base::StringPiece name) override {
base::test::TaskEnvironment::CreateThreadPool();
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This source code is a part of eyeo Chromium SDK.
+// Use of this source code is governed by the GPLv3 that can be found in the
+// components/adblock/LICENSE file.
+
#include "chrome/test/base/in_process_browser_test.h"
#include <map>
@@ -163,6 +167,10 @@
#include "content/public/test/network_connection_change_simulator.h"
#endif
+#include "chrome/browser/adblock/subscription_service_factory.h"
+#include "components/adblock/core/common/adblock_constants.h"
+#include "components/adblock/core/subscription/subscription_service.h"
+
namespace {
#if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -653,8 +661,19 @@ void InProcessBrowserTest::CreatedBrowserMainParts(
void InProcessBrowserTest::SelectFirstBrowser() {
const BrowserList* browser_list = BrowserList::GetInstance();
- if (!browser_list->empty())
+ if (!browser_list->empty()) {
browser_ = browser_list->get(0);
+ // Adding an allowing filter that overrides and disables all blocking
+ // filters in order to avoid unwanted interactions with simulated network
+ // loads. This custom filter is removed for tests that specifically verify
+ // ad-filtering.
+ auto* adblock_configuration =
+ adblock::SubscriptionServiceFactory::GetForBrowserContext(browser_->profile())
+ ->GetAdblockFilteringConfiguration();
+ if (adblock_configuration) {
+ adblock_configuration->AddCustomFilter(adblock::kAllowlistEverythingFilter);
+ }
+ }
}
void InProcessBrowserTest::RecordPropertyFromMap(
diff --git a/chrome/test/data/adblock/filterlist_that_allows_resource.txt b/chrome/test/data/adblock/filterlist_that_allows_resource.txt
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/filterlist_that_allows_resource.txt
@@ -0,0 +1,7 @@
+ [Adblock Plus 2.0]
+! Version: 202212191158
+! Title: Allow resource.png
+! Expires: 1 days
+
+@@*resource.png
+#@##subresource
diff --git a/chrome/test/data/adblock/filterlist_that_blocks_resource.txt b/chrome/test/data/adblock/filterlist_that_blocks_resource.txt
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/filterlist_that_blocks_resource.txt
@@ -0,0 +1,6 @@
+ [Adblock Plus 2.0]
+! Version: 202212191158
+! Title: Block resource.png
+! Expires: 1 days
+
+*resource.png
diff --git a/chrome/test/data/adblock/filterlist_that_hides_resource.txt b/chrome/test/data/adblock/filterlist_that_hides_resource.txt
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/filterlist_that_hides_resource.txt
@@ -0,0 +1,6 @@
+ [Adblock Plus 2.0]
+! Version: 202212191158
+! Title: Hide resource.png
+! Expires: 1 days
+
+###subresource
diff --git a/chrome/test/data/adblock/innermost_frame.html b/chrome/test/data/adblock/innermost_frame.html
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/innermost_frame.html
@@ -0,0 +1,39 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html>
+
+<head>
+ <script>
+ // Notify the outermost frame whether subresource is visible.
+ // Since these frames have different origins, we must bypass
+ // cross-site-scripting security and send the information via window.top.
+ window.onload = function () {
+ // `offsetWidth !== 0 `is used to check if element is not visible when
+ // it is hidden directly or when parent is hidden.
+ let subresource_visble = document.getElementById('subresource').offsetWidth !== 0;
+ window.top.postMessage(subresource_visble, '*');
+ };
+ </script>
+</head>
+
+<body>
+ <img id='subresource' src='resource.png' />
+</body>
+
+</html>
diff --git a/chrome/test/data/adblock/middle_frame.html b/chrome/test/data/adblock/middle_frame.html
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/middle_frame.html
@@ -0,0 +1,25 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html>
+
+<body>
+ <iframe id='innermost_frame' src='/cross-site/inner.com/innermost_frame.html'></iframe>
+</body>
+
+</html>
diff --git a/chrome/test/data/adblock/non-ascii.html b/chrome/test/data/adblock/non-ascii.html
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/non-ascii.html
@@ -0,0 +1,26 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+</head>
+<body>
+ <div class="форум">Should be shidden</div>
+</body>
+</html>
diff --git a/chrome/test/data/adblock/outermost_frame.html b/chrome/test/data/adblock/outermost_frame.html
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/outermost_frame.html
@@ -0,0 +1,37 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html>
+
+<head>
+ <script>
+ // Innermost frame has a script that sends us whether subresource
+ // is visible. This variable is inspected from C++.
+ var subresource_visible = null;
+
+ window.onmessage = function (event) {
+ subresource_visible = event.data
+ }
+ </script>
+</head>
+
+<body>
+ <iframe id='middle_frame' src='/cross-site/middle.com/middle_frame.html' width='400'></iframe>
+</body>
+
+</html>
diff --git a/chrome/test/data/adblock/outermost_frame_with_about_blank.html b/chrome/test/data/adblock/outermost_frame_with_about_blank.html
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/outermost_frame_with_about_blank.html
@@ -0,0 +1,37 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html>
+
+<head>
+ <script>
+ // Innermost frame has a script that sends us whether subresource
+ // is visible. This variable is inspected from C++.
+ var subresource_visible = null;
+
+ window.onmessage = function (event) {
+ subresource_visible = event.data
+ }
+ </script>
+</head>
+
+<body>
+ <iframe id='about_blank' src='about:blank?eyeo=true' width='400'></iframe>
+</body>
+
+</html>
diff --git a/chrome/test/data/adblock/popup.html b/chrome/test/data/adblock/popup.html
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/popup.html
@@ -0,0 +1,25 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html>
+
+<body>
+ <img id='subresource' src='resource.png' />
+</body>
+
+</html>
diff --git a/chrome/test/data/adblock/popup_opener.html b/chrome/test/data/adblock/popup_opener.html
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/popup_opener.html
@@ -0,0 +1,26 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html>
+
+<body>
+ <a href="/cross-site/inner.com/popup.html" target="_blank" id="popup_link">Trigger link based popup</a>
+ <script>document.getElementById('popup_link').click();</script>
+</body>
+
+</html>
diff --git a/chrome/test/data/adblock/popup_parent.html b/chrome/test/data/adblock/popup_parent.html
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/popup_parent.html
@@ -0,0 +1,25 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html>
+
+<body>
+ <iframe id='middle_frame' src='/cross-site/middle.com/popup_opener.html' width='400'></iframe>
+</body>
+
+</html>
diff --git a/chrome/test/data/adblock/resource.png b/chrome/test/data/adblock/resource.png
new file mode 100644
index 0000000000000000000000000000000000000000..39f3630072b2677debf4aac66b20096852453a7f
GIT binary patch
literal 47293
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
KkuH-o3HTopq;ALn
literal 0
HcmV?d00001
diff --git a/chrome/test/data/adblock/tab-restore.html b/chrome/test/data/adblock/tab-restore.html
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/tab-restore.html
@@ -0,0 +1,33 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+ function onLoaded() {
+ if (window.domAutomationController) {
+ domAutomationController.send("READY");
+ }
+ }
+</script>
+</head>
+<body onload="onLoaded()">
+ <img id="blocked" src="blocked.png" />
+ <img id="allowed" src="allowed.png" />
+</body>
+</html>
diff --git a/chrome/test/data/adblock/wbn/LICENSE b/chrome/test/data/adblock/wbn/LICENSE
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/LICENSE
@@ -0,0 +1,14 @@
+// This file is part of eyeo Chromium SDK,
+// Copyright (C) 2006-present eyeo GmbH
+//
+// eyeo Chromium SDK is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 3 as
+// published by the Free Software Foundation.
+//
+// eyeo Chromium SDK is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
diff --git a/chrome/test/data/adblock/wbn/blocked_bundle/LICENSE b/chrome/test/data/adblock/wbn/blocked_bundle/LICENSE
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/blocked_bundle/LICENSE
@@ -0,0 +1,14 @@
+// This file is part of eyeo Chromium SDK,
+// Copyright (C) 2006-present eyeo GmbH
+//
+// eyeo Chromium SDK is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 3 as
+// published by the Free Software Foundation.
+//
+// eyeo Chromium SDK is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
diff --git a/chrome/test/data/adblock/wbn/blocked_bundle/fetch_result_1_blocked_bundle.json b/chrome/test/data/adblock/wbn/blocked_bundle/fetch_result_1_blocked_bundle.json
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/blocked_bundle/fetch_result_1_blocked_bundle.json
@@ -0,0 +1 @@
+{ "method": "fetch", "result": 1 }
diff --git a/chrome/test/data/adblock/wbn/blocked_bundle/fetch_result_2_blocked_bundle.json b/chrome/test/data/adblock/wbn/blocked_bundle/fetch_result_2_blocked_bundle.json
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/blocked_bundle/fetch_result_2_blocked_bundle.json
@@ -0,0 +1 @@
+{ "method": "fetch", "result": 2 }
diff --git a/chrome/test/data/adblock/wbn/by_bundle_file/LICENSE b/chrome/test/data/adblock/wbn/by_bundle_file/LICENSE
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_bundle_file/LICENSE
@@ -0,0 +1,14 @@
+// This file is part of eyeo Chromium SDK,
+// Copyright (C) 2006-present eyeo GmbH
+//
+// eyeo Chromium SDK is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 3 as
+// published by the Free Software Foundation.
+//
+// eyeo Chromium SDK is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
diff --git a/chrome/test/data/adblock/wbn/by_bundle_file/fetch_result_2_subresource_loading.json b/chrome/test/data/adblock/wbn/by_bundle_file/fetch_result_2_subresource_loading.json
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_bundle_file/fetch_result_2_subresource_loading.json
@@ -0,0 +1 @@
+{ "method": "fetch", "result": 2 }
diff --git a/chrome/test/data/adblock/wbn/by_bundle_file/green_subresource_loading.css b/chrome/test/data/adblock/wbn/by_bundle_file/green_subresource_loading.css
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_bundle_file/green_subresource_loading.css
@@ -0,0 +1 @@
+.green { background-color: green }
diff --git a/chrome/test/data/adblock/wbn/by_bundle_file/green_subresource_loading.png b/chrome/test/data/adblock/wbn/by_bundle_file/green_subresource_loading.png
new file mode 100644
index 0000000000000000000000000000000000000000..2040a0a2b2cd006f3ade7be290ff37ad8fd0452e
GIT binary patch
literal 772
zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911L)MWvCLm<Um?Bp53!NGC+q5lI02Btlp
zE{-7;bKYJyWMoj_Ik2IzXo+&NyD)2Q)id6dyKfn8q%d6KahS#EVa$-prf`;FiDZKb
k^Mtff!O;L2@WfDicn?#9amJ!hV6tZLboFyt=akR{0LG@<V*mgE
literal 0
HcmV?d00001
diff --git a/chrome/test/data/adblock/wbn/by_bundle_file/purple_subresource_loading.css b/chrome/test/data/adblock/wbn/by_bundle_file/purple_subresource_loading.css
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_bundle_file/purple_subresource_loading.css
@@ -0,0 +1 @@
+.purple { background-color: purple }
diff --git a/chrome/test/data/adblock/wbn/by_bundle_file/purple_subresource_loading.png b/chrome/test/data/adblock/wbn/by_bundle_file/purple_subresource_loading.png
new file mode 100644
index 0000000000000000000000000000000000000000..448a0b426580cc8813f57724bc75b4ccf5e1f2fe
GIT binary patch
literal 773
zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911L)MWvCLm<Um?Bp53!NGC+q5lI02By89
zE{-7;bKYJyWMoj_Ibh)MbBS`YyD)2Q)$=ortG3HB%;s^J#pq$okjbWSmSKrxg9-D5
lG=@u~f};U4;E7=if221v1Fu`iSzx+m@O1TaS?83{1OO8~*{=Wq
literal 0
HcmV?d00001
diff --git a/chrome/test/data/adblock/wbn/by_bundle_file/xhr_result_2_subresource_loading.json b/chrome/test/data/adblock/wbn/by_bundle_file/xhr_result_2_subresource_loading.json
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_bundle_file/xhr_result_2_subresource_loading.json
@@ -0,0 +1 @@
+{ "method": "xhr", "result": 2 }
diff --git a/chrome/test/data/adblock/wbn/by_resource/LICENSE b/chrome/test/data/adblock/wbn/by_resource/LICENSE
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_resource/LICENSE
@@ -0,0 +1,14 @@
+// This file is part of eyeo Chromium SDK,
+// Copyright (C) 2006-present eyeo GmbH
+//
+// eyeo Chromium SDK is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 3 as
+// published by the Free Software Foundation.
+//
+// eyeo Chromium SDK is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
diff --git a/chrome/test/data/adblock/wbn/by_resource/blue_subresource_loading.css b/chrome/test/data/adblock/wbn/by_resource/blue_subresource_loading.css
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_resource/blue_subresource_loading.css
@@ -0,0 +1 @@
+.blue { background-color: blue }
diff --git a/chrome/test/data/adblock/wbn/by_resource/blue_subresource_loading.png b/chrome/test/data/adblock/wbn/by_resource/blue_subresource_loading.png
new file mode 100644
index 0000000000000000000000000000000000000000..7a0773bec90118a4a83069ee0900449dcc511a49
GIT binary patch
literal 773
zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911L)MWvCLm<Um?Bp53!NGC+q5lI02By89
zE{-7;bKYJyWMoj_Ik2Iz{=7o6yD)2QRoXp=t9SVteAyJvGAxm7FkzmM#&C(pVHTr@
lF+=94;Anshcw)H49<Ipr-{e@aD==L%c)I$ztaD0e0ssS_+mHYN
literal 0
HcmV?d00001
diff --git a/chrome/test/data/adblock/wbn/by_resource/fetch_result_1_subresource_loading.json b/chrome/test/data/adblock/wbn/by_resource/fetch_result_1_subresource_loading.json
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_resource/fetch_result_1_subresource_loading.json
@@ -0,0 +1 @@
+{ "method": "fetch", "result": 1 }
diff --git a/chrome/test/data/adblock/wbn/by_resource/red_subresource_loading.css b/chrome/test/data/adblock/wbn/by_resource/red_subresource_loading.css
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_resource/red_subresource_loading.css
@@ -0,0 +1 @@
+.red { background-color: red }
diff --git a/chrome/test/data/adblock/wbn/by_resource/red_subresource_loading.png b/chrome/test/data/adblock/wbn/by_resource/red_subresource_loading.png
new file mode 100644
index 0000000000000000000000000000000000000000..68da171a4052cc60dd0c7303f16b8cb149c701af
GIT binary patch
literal 772
zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911L)MWvCLm<Um?Bp53!NGC+q5lI02Btlp
zE{-7;bKYJyWMoj_Ibd*L|8vD;cVX7rs^<>ZZ}T<yvMHQpSR&bA!aO03;S!I-EJhDw
khRjjH(Eu6n#Bhr}Ql9C*ankNgV6tZLboFyt=akR{05TujQ2+n{
literal 0
HcmV?d00001
diff --git a/chrome/test/data/adblock/wbn/by_resource/xhr_result_1_subresource_loading.json b/chrome/test/data/adblock/wbn/by_resource/xhr_result_1_subresource_loading.json
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_resource/xhr_result_1_subresource_loading.json
@@ -0,0 +1 @@
+{ "method": "xhr", "result": 1 }
diff --git a/chrome/test/data/adblock/wbn/by_scope/LICENSE b/chrome/test/data/adblock/wbn/by_scope/LICENSE
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_scope/LICENSE
@@ -0,0 +1,14 @@
+// This file is part of eyeo Chromium SDK,
+// Copyright (C) 2006-present eyeo GmbH
+//
+// eyeo Chromium SDK is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 3 as
+// published by the Free Software Foundation.
+//
+// eyeo Chromium SDK is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
diff --git a/chrome/test/data/adblock/wbn/by_scope/fetch_result_3_subresource_loading.json b/chrome/test/data/adblock/wbn/by_scope/fetch_result_3_subresource_loading.json
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_scope/fetch_result_3_subresource_loading.json
@@ -0,0 +1 @@
+{ "method": "fetch", "result": 3 }
diff --git a/chrome/test/data/adblock/wbn/by_scope/orange_subresource_loading.css b/chrome/test/data/adblock/wbn/by_scope/orange_subresource_loading.css
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_scope/orange_subresource_loading.css
@@ -0,0 +1 @@
+.orange { background-color: orange }
diff --git a/chrome/test/data/adblock/wbn/by_scope/orange_subresource_loading.png b/chrome/test/data/adblock/wbn/by_scope/orange_subresource_loading.png
new file mode 100644
index 0000000000000000000000000000000000000000..348f1275fa97592546d48a3f5a339625c231ba2e
GIT binary patch
literal 774
zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911L)MWvCLm<Um?Bp53!NGC+q5lI02Bv+U
zE{-7;bKYJyWMoj_Ibd*LKW|A>kF2lAmzQ<rj@M@LHF&ZqoMl)d*<ivvA&ub@kHaiR
m4`YVRQNhsw8Sun#i(T?5^OAFk>ji)bo59o7&t;ucLK6V><lLnI
literal 0
HcmV?d00001
diff --git a/chrome/test/data/adblock/wbn/by_scope/pink_subresource_loading.css b/chrome/test/data/adblock/wbn/by_scope/pink_subresource_loading.css
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_scope/pink_subresource_loading.css
@@ -0,0 +1 @@
+.pink { background-color: pink }
diff --git a/chrome/test/data/adblock/wbn/by_scope/pink_subresource_loading.png b/chrome/test/data/adblock/wbn/by_scope/pink_subresource_loading.png
new file mode 100644
index 0000000000000000000000000000000000000000..a0ffba40eee8d497e2fd9ab5b138ba05e70d987f
GIT binary patch
literal 775
zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911L)MWvCLm<Um?Bp53!NGC+q5lI02B!U<
zE{-7;bKYK7WMoiaIAE}#Uc+Xg0^6hLrrGCrpKn<8)taHsh#`|r;Vi=v$p#bV326+M
ncpPRidKixijt0npCk8py(=1&@rd{>Gl+EDj>gTe~DWM4fjk(;R
literal 0
HcmV?d00001
diff --git a/chrome/test/data/adblock/wbn/by_scope/xhr_result_3_subresource_loading.json b/chrome/test/data/adblock/wbn/by_scope/xhr_result_3_subresource_loading.json
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/by_scope/xhr_result_3_subresource_loading.json
@@ -0,0 +1 @@
+{ "method": "xhr", "result": 3 }
diff --git a/chrome/test/data/adblock/wbn/index.html.mustache b/chrome/test/data/adblock/wbn/index.html.mustache
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/wbn/index.html.mustache
@@ -0,0 +1,157 @@
+<!DOCTYPE html>
+<script type="webbundle">
+{
+ "source": "by_resource.wbn",
+ "resources": [
+ "by_resource/blue_subresource_loading.css",
+ "by_resource/blue_subresource_loading.png",
+ "by_resource/red_subresource_loading.css",
+ "by_resource/red_subresource_loading.png",
+ "by_resource/fetch_result_1_subresource_loading.json",
+ "by_resource/xhr_result_1_subresource_loading.json"
+ ]
+}
+</script>
+<script type="webbundle">
+ {
+ "source": "by_bundle_file.wbn",
+ "resources": [
+ "by_bundle_file/green_subresource_loading.css",
+ "by_bundle_file/green_subresource_loading.png",
+ "by_bundle_file/purple_subresource_loading.css",
+ "by_bundle_file/purple_subresource_loading.png",
+ "by_bundle_file/fetch_result_2_subresource_loading.json",
+ "by_bundle_file/xhr_result_2_subresource_loading.json"
+ ]
+ }
+</script>
+<script type="webbundle">
+ {
+ "source": "by_scope.wbn",
+ "scopes": [
+ "by_scope"
+ ]
+ }
+</script>
+
+<link rel="stylesheet" href="by_resource/blue_subresource_loading.css">
+<link rel="stylesheet" href="by_resource/red_subresource_loading.css">
+<link rel="stylesheet" href="by_bundle_file/green_subresource_loading.css">
+<link rel="stylesheet" href="by_bundle_file/purple_subresource_loading.css">
+<link rel="stylesheet" href="by_scope/orange_subresource_loading.css">
+<link rel="stylesheet" href="by_scope/pink_subresource_loading.css">
+
+<style>
+div {
+ background-color: grey;
+ width: 30px;
+ height: 30px;
+}
+img {
+ width: 30px;
+ height: 30px;
+}
+</style>
+
+<h3>Chromium Web bundles test</h3>
+
+<h4>Identified by resource</h4>
+
+<ul>
+ <li> Resources in by_resource.wbn
+ <ul>
+ <li>Shows blue box with by_resource/blue_subresource_loading.css, grey box after the css blocked:
+ <div class="blue"></div></li>
+ <li>Shows by_resource/blue_subresource_loading.png, nothing after the png blocked:
+ <br><img src="by_resource/blue_subresource_loading.png" /></li>
+ <li>Shows red box with by_resource/red_subresource_loading.css, grey box after the css blocked:
+ <div class="red"></div></li>
+ <li>Shows by_resource/red_subresource_loading.png, nothing after the png blocked:
+ <br><img src="by_resource/red_subresource_loading.png" /></li>
+ <li>Shows xhr result for by_resource/xhr_result_1_subresource_loading.json:
+ <br><code id='xhr_result_by_resource'>Pending</code></li>
+ <li>Shows fetch result for by_resource/fetch_result_1_subresource_loading.json:
+ <br><code id='fetch_result_by_resource'>Pending</code></li>
+ </ul>
+ </li>
+</ul>
+
+<h4>Identified by bundle file</h4>
+
+<ul>
+ <li> Resources in by_bundle_file.wbn (Please click <a href="fetch_subresources_in_blocked_bundle.html">here</a> to check fetch behavior with blocked bundle)
+ <ul>
+ <li>Shows green box with by_bundle_file/green_subresource_loading.css, grey box after the css blocked:
+ <div class="green"></div></li>
+ <li>Shows by_bundle_file/green_subresource_loading.png, nothing after the png blocked:
+ <br><img src="by_bundle_file/green_subresource_loading.png" /></li>
+ <li>Shows purple box with by_bundle_file/purple_subresource_loading.css, grey box after the css blocked:
+ <div class="purple"></div></li>
+ <li>Shows by_bundle_file/purple_subresource_loading.png, nothing after the png blocked:
+ <br><img src="by_bundle_file/purple_subresource_loading.png" /></li>
+ <li>Shows xhr result for by_bundle_file/xhr_result_2_subresource_loading.json:
+ <br><code id='xhr_result_by_bundle_file'>Pending</code></li>
+ <li>Shows fetch result for by_bundle_file/fetch_result_2_subresource_loading.json:
+ <br><code id='fetch_result_by_bundle_file'>Pending</code></li>
+ </ul>
+ </li>
+</ul>
+
+<h4>Identified by scope</h4>
+
+<ul>
+ <li> Resources in by_scope.wbn
+ <ul>
+ <li>Shows orange box with by_scope/orange_subresource_loading.css, grey box after the css blocked:
+ <div class="orange"></div></li>
+ <li>Shows by_scope/orange_subresource_loading.png, nothing after the png blocked:
+ <br><img src="by_scope/orange_subresource_loading.png" /></li>
+ <li>Shows pink box with by_scope/pink_subresource_loading.css, grey box after the css blocked:
+ <div class="pink"></div></li>
+ <li>Shows by_scope/pink_subresource_loading.png, nothing after the png blocked:
+ <br><img src="by_scope/pink_subresource_loading.png" /></li>
+ <li>Shows xhr result for by_scope/xhr_result_3_subresource_loading.json:
+ <br><code id='xhr_result_by_scope'>Pending</code></li>
+ <li>Shows fetch result for by_scope/fetch_result_3_subresource_loading.json:
+ <br><code id='fetch_result_by_scope'>Pending</code></li>
+ </ul>
+ </li>
+</ul>
+
+<p>
+To navigate to <a href="{{{navigation_to_unsigned_bundles_baseUrl}}}">{{{navigation_to_unsigned_bundles_baseUrl}}}</a> within a bundle file, download the bundle file by <a href="{{{navigation_to_unsigned_bundles_baseUrl}}}/navigation_to_unsigned_bundles.wbn">clicking here</a>.
+</p>
+
+<script>
+function testFetchXHR(method, url, log_element) {
+ if (method == "fetch") {
+ fetch(url)
+ .then((response) => response.json())
+ .then((data) => {
+ log_element.innerHTML = `fetch succeeded: ${JSON.stringify(data)}`;
+ })
+ .catch((error) => {
+ log_element.innerHTML = `Error occured: ${error}`;
+ });
+ } else if (method == "xhr") {
+ const xhr = new XMLHttpRequest();
+ xhr.addEventListener("load", (e) => {
+ log_element.innerHTML = `XMLHttpRequest succeeded: ${xhr.response}`;
+ });
+ xhr.addEventListener("error", (e) => {
+ log_element.innerHTML = `Error occured: ${e.type}`;
+ });
+ xhr.open("GET", url);
+ xhr.send();
+ } else {
+ log_element.innerHTML = `Invalid method: ${method}`;
+ }
+}
+
+testFetchXHR("xhr", "by_resource/xhr_result_1_subresource_loading.json", xhr_result_by_resource);
+testFetchXHR("fetch", "by_resource/fetch_result_1_subresource_loading.json", fetch_result_by_resource);
+testFetchXHR("xhr", "by_bundle_file/xhr_result_2_subresource_loading.json", xhr_result_by_bundle_file);
+testFetchXHR("fetch", "by_bundle_file/fetch_result_2_subresource_loading.json", fetch_result_by_bundle_file);
+testFetchXHR("xhr", "by_scope/xhr_result_3_subresource_loading.json", xhr_result_by_scope);
+testFetchXHR("fetch", "by_scope/fetch_result_3_subresource_loading.json", fetch_result_by_scope);
+</script>
diff --git a/chrome/test/data/adblock/xpath3.html b/chrome/test/data/adblock/xpath3.html
new file mode 100644
--- /dev/null
+++ b/chrome/test/data/adblock/xpath3.html
@@ -0,0 +1,23 @@
+<!--
+ This file is part of eyeo Chromium SDK,
+ Copyright (C) 2006-present eyeo GmbH
+
+ eyeo Chromium SDK is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 3 as
+ published by the Free Software Foundation.
+
+ eyeo Chromium SDK is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with eyeo Chromium SDK. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<!DOCTYPE html>
+<html>
+<body>
+<div id="xpath3-target">Target</div>
+</body>
+</html>
--
2.25.1