LibWeb: Rename ContentFilter to ContentBlocker
Rename the local content blocking implementation and its tests from ContentFilter to ContentBlocker while keeping the existing substring matcher backend and behavior. Update the WebContent IPC method, WebView option names, debug toggle, and default config file name to use content blocker terminology.
This commit is contained in:
parent
640965d052
commit
46e1a08742
21 changed files with 193 additions and 193 deletions
|
|
@ -807,7 +807,7 @@ set(SOURCES
|
|||
Layout/TreeBuilder.cpp
|
||||
Layout/VideoBox.cpp
|
||||
Layout/Viewport.cpp
|
||||
Loader/ContentFilter.cpp
|
||||
Loader/ContentBlocker.cpp
|
||||
Loader/FileRequest.cpp
|
||||
Loader/GeneratedPagesLoader.cpp
|
||||
Loader/ProxyMappings.cpp
|
||||
|
|
|
|||
|
|
@ -9,21 +9,21 @@
|
|||
#include <AK/Queue.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/Span.h>
|
||||
#include <LibWeb/Loader/ContentFilter.h>
|
||||
#include <LibWeb/Loader/ContentBlocker.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
ContentFilter& ContentFilter::the()
|
||||
ContentBlocker& ContentBlocker::the()
|
||||
{
|
||||
static ContentFilter filter;
|
||||
return filter;
|
||||
static ContentBlocker blocker;
|
||||
return blocker;
|
||||
}
|
||||
|
||||
ContentFilter::ContentFilter() = default;
|
||||
ContentBlocker::ContentBlocker() = default;
|
||||
|
||||
ContentFilter::~ContentFilter() = default;
|
||||
ContentBlocker::~ContentBlocker() = default;
|
||||
|
||||
bool ContentFilter::is_filtered(URL::URL const& url) const
|
||||
bool ContentBlocker::is_filtered(URL::URL const& url) const
|
||||
{
|
||||
if (!filtering_enabled())
|
||||
return false;
|
||||
|
|
@ -33,14 +33,14 @@ bool ContentFilter::is_filtered(URL::URL const& url) const
|
|||
return contains(url.to_string());
|
||||
}
|
||||
|
||||
bool ContentFilter::contains(StringView text) const
|
||||
bool ContentBlocker::contains(StringView text) const
|
||||
{
|
||||
if (!m_matcher)
|
||||
return false;
|
||||
return m_matcher->contains(text);
|
||||
}
|
||||
|
||||
ErrorOr<void> ContentFilter::set_patterns(ReadonlySpan<String> patterns)
|
||||
ErrorOr<void> ContentBlocker::set_patterns(ReadonlySpan<String> patterns)
|
||||
{
|
||||
m_matcher = make<AsciiStringMatcher>(patterns);
|
||||
return {};
|
||||
|
|
@ -37,9 +37,9 @@ private:
|
|||
Vector<Transition> m_transitions;
|
||||
};
|
||||
|
||||
class WEB_API ContentFilter {
|
||||
class WEB_API ContentBlocker {
|
||||
public:
|
||||
static ContentFilter& the();
|
||||
static ContentBlocker& the();
|
||||
|
||||
bool filtering_enabled() const { return m_filtering_enabled; }
|
||||
void set_filtering_enabled(bool const enabled) { m_filtering_enabled = enabled; }
|
||||
|
|
@ -48,8 +48,8 @@ public:
|
|||
ErrorOr<void> set_patterns(ReadonlySpan<String>);
|
||||
|
||||
private:
|
||||
ContentFilter();
|
||||
~ContentFilter();
|
||||
ContentBlocker();
|
||||
~ContentBlocker();
|
||||
|
||||
bool contains(StringView text) const;
|
||||
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
#include <LibURL/Parser.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h>
|
||||
#include <LibWeb/Fetch/Infrastructure/URL.h>
|
||||
#include <LibWeb/Loader/ContentFilter.h>
|
||||
#include <LibWeb/Loader/ContentBlocker.h>
|
||||
#include <LibWeb/Loader/GeneratedPagesLoader.h>
|
||||
#include <LibWeb/Loader/LoadRequest.h>
|
||||
#include <LibWeb/Loader/ProxyMappings.h>
|
||||
|
|
@ -77,7 +77,7 @@ void ResourceLoader::prefetch_dns(URL::URL const& url)
|
|||
if (url.scheme().is_one_of("file"sv, "data"sv))
|
||||
return;
|
||||
|
||||
if (ContentFilter::the().is_filtered(url)) {
|
||||
if (ContentBlocker::the().is_filtered(url)) {
|
||||
dbgln("ResourceLoader: Refusing to prefetch DNS for '{}': \033[31;1mURL was filtered\033[0m", url);
|
||||
return;
|
||||
}
|
||||
|
|
@ -92,7 +92,7 @@ void ResourceLoader::preconnect(URL::URL const& url)
|
|||
if (url.scheme().is_one_of("file"sv, "data"sv))
|
||||
return;
|
||||
|
||||
if (ContentFilter::the().is_filtered(url)) {
|
||||
if (ContentBlocker::the().is_filtered(url)) {
|
||||
dbgln("ResourceLoader: Refusing to pre-connect to '{}': \033[31;1mURL was filtered\033[0m", url);
|
||||
return;
|
||||
}
|
||||
|
|
@ -189,7 +189,7 @@ static bool should_block_request(LoadRequest const& request)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (ContentFilter::the().is_filtered(url)) {
|
||||
if (ContentBlocker::the().is_filtered(url)) {
|
||||
log_filtered_request(request);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ ErrorOr<void> Application::initialize(Main::Arguments const& arguments)
|
|||
bool enable_idl_tracing = false;
|
||||
bool disable_http_memory_cache = false;
|
||||
bool disable_http_disk_cache = false;
|
||||
bool disable_content_filter = false;
|
||||
bool disable_content_blocker = false;
|
||||
Optional<StringView> resource_substitution_map_path;
|
||||
bool enable_autoplay = false;
|
||||
bool expose_experimental_interfaces = false;
|
||||
|
|
@ -233,7 +233,7 @@ ErrorOr<void> Application::initialize(Main::Arguments const& arguments)
|
|||
args_parser.add_option(enable_idl_tracing, "Enable IDL tracing", "enable-idl-tracing");
|
||||
args_parser.add_option(disable_http_memory_cache, "Disable HTTP memory cache", "disable-http-memory-cache");
|
||||
args_parser.add_option(disable_http_disk_cache, "Disable HTTP disk cache", "disable-http-disk-cache");
|
||||
args_parser.add_option(disable_content_filter, "Disable content filter", "disable-content-filter");
|
||||
args_parser.add_option(disable_content_blocker, "Disable content blocker", "disable-content-blocker");
|
||||
args_parser.add_option(enable_autoplay, "Enable multimedia autoplay", "enable-autoplay");
|
||||
args_parser.add_option(expose_experimental_interfaces, "Expose experimental IDL interfaces", "expose-experimental-interfaces");
|
||||
args_parser.add_option(expose_internals_object, "Expose internals object", "expose-internals-object");
|
||||
|
|
@ -330,7 +330,7 @@ ErrorOr<void> Application::initialize(Main::Arguments const& arguments)
|
|||
: DNSSettings(DNSOverUDP(dns_server_address.release_value(), *dns_server_port, validate_dnssec_locally)) }
|
||||
: OptionalNone()),
|
||||
.devtools_port = devtools_port,
|
||||
.enable_content_filter = disable_content_filter ? EnableContentFilter::No : EnableContentFilter::Yes,
|
||||
.enable_content_blocker = disable_content_blocker ? EnableContentBlocker::No : EnableContentBlocker::Yes,
|
||||
};
|
||||
|
||||
if (screenshot_delay.has_value())
|
||||
|
|
@ -1224,9 +1224,9 @@ void Application::initialize_actions()
|
|||
m_enable_scripting_action->set_checked(m_browser_options.disable_scripting == WebView::DisableScripting::No);
|
||||
m_debug_menu->add_action(*m_enable_scripting_action);
|
||||
|
||||
m_enable_content_filtering_action = Action::create_checkable("Enable Content Filtering"sv, ActionID::EnableContentFiltering, check(m_enable_content_filtering_action, "content-filtering"sv));
|
||||
m_enable_content_filtering_action->set_checked(m_browser_options.enable_content_filter == WebView::EnableContentFilter::Yes);
|
||||
m_debug_menu->add_action(*m_enable_content_filtering_action);
|
||||
m_enable_content_blocking_action = Action::create_checkable("Enable Content Blocking"sv, ActionID::EnableContentBlocking, check(m_enable_content_blocking_action, "content-blocking"sv));
|
||||
m_enable_content_blocking_action->set_checked(m_browser_options.enable_content_blocker == WebView::EnableContentBlocker::Yes);
|
||||
m_debug_menu->add_action(*m_enable_content_blocking_action);
|
||||
|
||||
m_block_pop_ups_action = Action::create_checkable("Block Pop-ups"sv, ActionID::BlockPopUps, check(m_block_pop_ups_action, "block-pop-ups"sv));
|
||||
m_block_pop_ups_action->set_checked(m_browser_options.allow_popups == AllowPopups::No);
|
||||
|
|
@ -1241,7 +1241,7 @@ void Application::apply_view_options(Badge<ViewImplementation>, ViewImplementati
|
|||
|
||||
view.debug_request("set-line-box-borders"sv, m_show_line_box_borders_action->checked() ? "on"sv : "off"sv);
|
||||
view.debug_request("scripting"sv, m_enable_scripting_action->checked() ? "on"sv : "off"sv);
|
||||
view.debug_request("content-filtering"sv, m_enable_content_filtering_action->checked() ? "on"sv : "off"sv);
|
||||
view.debug_request("content-blocking"sv, m_enable_content_blocking_action->checked() ? "on"sv : "off"sv);
|
||||
view.debug_request("block-pop-ups"sv, m_block_pop_ups_action->checked() ? "on"sv : "off"sv);
|
||||
view.debug_request("spoof-user-agent"sv, m_user_agent_string);
|
||||
view.debug_request("navigator-compatibility-mode"sv, m_navigator_compatibility_mode);
|
||||
|
|
|
|||
|
|
@ -325,7 +325,7 @@ private:
|
|||
RefPtr<Menu> m_debug_menu;
|
||||
RefPtr<Action> m_show_line_box_borders_action;
|
||||
RefPtr<Action> m_enable_scripting_action;
|
||||
RefPtr<Action> m_enable_content_filtering_action;
|
||||
RefPtr<Action> m_enable_content_blocking_action;
|
||||
RefPtr<Action> m_block_pop_ups_action;
|
||||
StringView m_user_agent_string;
|
||||
StringView m_navigator_compatibility_mode;
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ enum class ActionID {
|
|||
SpoofUserAgent,
|
||||
NavigatorCompatibilityMode,
|
||||
EnableScripting,
|
||||
EnableContentFiltering,
|
||||
EnableContentBlocking,
|
||||
BlockPopUps,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ using DNSSettings = Variant<SystemDNS, DNSOverTLS, DNSOverUDP>;
|
|||
|
||||
constexpr inline u16 default_devtools_port = 6000;
|
||||
|
||||
enum class EnableContentFilter {
|
||||
enum class EnableContentBlocker {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
|
|
@ -91,7 +91,7 @@ struct BrowserOptions {
|
|||
Optional<ByteString> webdriver_endpoint {};
|
||||
Optional<DNSSettings> dns_settings {};
|
||||
Optional<u16> devtools_port;
|
||||
EnableContentFilter enable_content_filter { EnableContentFilter::Yes };
|
||||
EnableContentBlocker enable_content_blocker { EnableContentBlocker::Yes };
|
||||
};
|
||||
|
||||
enum class HTTPDiskCacheMode {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/Infra/Strings.h>
|
||||
#include <LibWeb/Layout/Viewport.h>
|
||||
#include <LibWeb/Loader/ContentFilter.h>
|
||||
#include <LibWeb/Loader/ContentBlocker.h>
|
||||
#include <LibWeb/Loader/ProxyMappings.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
#include <LibWeb/Loader/UserAgent.h>
|
||||
|
|
@ -457,8 +457,8 @@ void ConnectionFromClient::debug_request(u64 page_id, ByteString request, ByteSt
|
|||
return;
|
||||
}
|
||||
|
||||
if (request == "content-filtering") {
|
||||
Web::ContentFilter::the().set_filtering_enabled(argument == "on");
|
||||
if (request == "content-blocking") {
|
||||
Web::ContentBlocker::the().set_filtering_enabled(argument == "on");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1144,9 +1144,9 @@ void ConnectionFromClient::paste(u64 page_id, Utf16String text)
|
|||
page->page().focused_navigable().paste(text);
|
||||
}
|
||||
|
||||
void ConnectionFromClient::set_content_filters(u64, Vector<String> filters)
|
||||
void ConnectionFromClient::set_content_blockers(u64, Vector<String> patterns)
|
||||
{
|
||||
Web::ContentFilter::the().set_patterns(filters).release_value_but_fixme_should_propagate_errors();
|
||||
Web::ContentBlocker::the().set_patterns(patterns).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
void ConnectionFromClient::set_autoplay_allowed_on_all_websites(u64)
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ private:
|
|||
virtual void clone_dom_node(u64 page_id, Web::UniqueNodeID node_id) override;
|
||||
virtual void remove_dom_node(u64 page_id, Web::UniqueNodeID node_id) override;
|
||||
|
||||
virtual void set_content_filters(u64 page_id, Vector<String>) override;
|
||||
virtual void set_content_blockers(u64 page_id, Vector<String> patterns) override;
|
||||
virtual void set_autoplay_allowed_on_all_websites(u64 page_id) override;
|
||||
virtual void set_autoplay_allowlist(u64 page_id, Vector<String> allowlist) override;
|
||||
virtual void set_proxy_mappings(u64 page_id, Vector<ByteString>, HashMap<ByteString, size_t>) override;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ endpoint WebContentServer
|
|||
find_in_page_next_match(u64 page_id) =|
|
||||
find_in_page_previous_match(u64 page_id) =|
|
||||
|
||||
set_content_filters(u64 page_id, Vector<String> filters) =|
|
||||
set_content_blockers(u64 page_id, Vector<String> patterns) =|
|
||||
set_autoplay_allowed_on_all_websites(u64 page_id) =|
|
||||
set_autoplay_allowlist(u64 page_id, Vector<String> allowlist) =|
|
||||
set_proxy_mappings(u64 page_id, Vector<ByteString> proxies, HashMap<ByteString, size_t> mappings) =|
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#include <LibWeb/HTML/UniversalGlobalScope.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/Internals/Internals.h>
|
||||
#include <LibWeb/Loader/ContentFilter.h>
|
||||
#include <LibWeb/Loader/ContentBlocker.h>
|
||||
#include <LibWeb/Loader/GeneratedPagesLoader.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
#include <LibWeb/Painting/PaintableBox.h>
|
||||
|
|
@ -100,7 +100,7 @@ static void install_crash_signal_handlers()
|
|||
}
|
||||
#endif
|
||||
|
||||
static ErrorOr<void> load_content_filters(StringView config_path);
|
||||
static ErrorOr<void> load_content_blockers(StringView config_path);
|
||||
|
||||
static ErrorOr<void> connect_to_resource_loader(GC::Heap& heap, IPC::TransportHandle const& handle);
|
||||
static ErrorOr<void> connect_to_image_decoder(IPC::TransportHandle const& handle);
|
||||
|
|
@ -251,9 +251,9 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
|
|||
Web::WebIDL::set_enable_idl_tracing(true);
|
||||
}
|
||||
|
||||
auto maybe_content_filter_error = load_content_filters(config_path);
|
||||
if (maybe_content_filter_error.is_error())
|
||||
dbgln("Failed to load content filters: {}", maybe_content_filter_error.error());
|
||||
auto maybe_content_blocker_error = load_content_blockers(config_path);
|
||||
if (maybe_content_blocker_error.is_error())
|
||||
dbgln("Failed to load content blockers: {}", maybe_content_blocker_error.error());
|
||||
|
||||
#if defined(AK_OS_MACOS)
|
||||
auto browser_port = TRY(Core::MachPort::look_up_from_bootstrap_server(ByteString { mach_server_name }));
|
||||
|
|
@ -277,17 +277,17 @@ ErrorOr<int> ladybird_main(Main::Arguments arguments)
|
|||
return event_loop.exec();
|
||||
}
|
||||
|
||||
static ErrorOr<void> load_content_filters(StringView config_path)
|
||||
static ErrorOr<void> load_content_blockers(StringView config_path)
|
||||
{
|
||||
auto buffer = TRY(ByteBuffer::create_uninitialized(4096));
|
||||
|
||||
auto file = TRY(Core::File::open(ByteString::formatted("{}/BrowserContentFilters.txt", config_path), Core::File::OpenMode::Read));
|
||||
auto ad_filter_list = TRY(Core::InputBufferedFile::create(move(file)));
|
||||
auto file = TRY(Core::File::open(ByteString::formatted("{}/BrowserContentBlockers.txt", config_path), Core::File::OpenMode::Read));
|
||||
auto content_blocker_list = TRY(Core::InputBufferedFile::create(move(file)));
|
||||
|
||||
Vector<String> patterns;
|
||||
|
||||
while (TRY(ad_filter_list->can_read_line())) {
|
||||
auto line = TRY(ad_filter_list->read_line(buffer));
|
||||
while (TRY(content_blocker_list->can_read_line())) {
|
||||
auto line = TRY(content_blocker_list->read_line(buffer));
|
||||
if (line.is_empty())
|
||||
continue;
|
||||
|
||||
|
|
@ -295,8 +295,8 @@ static ErrorOr<void> load_content_filters(StringView config_path)
|
|||
TRY(patterns.try_append(move(pattern)));
|
||||
}
|
||||
|
||||
auto& content_filter = Web::ContentFilter::the();
|
||||
TRY(content_filter.set_patterns(patterns));
|
||||
auto& content_blocker = Web::ContentBlocker::the();
|
||||
TRY(content_blocker.set_patterns(patterns));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
set(TEST_SOURCES
|
||||
TestCSSIDSpeed.cpp
|
||||
TestContentFilter.cpp
|
||||
TestContentBlocker.cpp
|
||||
TestControlMessageQueue.cpp
|
||||
TestCSSInheritedProperty.cpp
|
||||
TestCSSPixels.cpp
|
||||
|
|
@ -24,7 +24,7 @@ endforeach()
|
|||
|
||||
ladybird_utility(css-tokenizer SOURCES css-tokenizer.cpp LIBS LibFileSystem LibMain LibWeb)
|
||||
|
||||
target_link_libraries(TestContentFilter PRIVATE LibURL)
|
||||
target_link_libraries(TestContentBlocker PRIVATE LibURL)
|
||||
target_link_libraries(TestControlMessageQueue PRIVATE LibSync)
|
||||
target_link_libraries(TestFetchURL PRIVATE LibURL)
|
||||
target_link_libraries(TestSourceHighlighter PRIVATE LibURL LibWebView)
|
||||
|
|
|
|||
126
Tests/LibWeb/TestContentBlocker.cpp
Normal file
126
Tests/LibWeb/TestContentBlocker.cpp
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibTest/TestCase.h>
|
||||
#include <LibURL/Parser.h>
|
||||
#include <LibURL/URL.h>
|
||||
#include <LibWeb/Loader/ContentBlocker.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
static ContentBlocker& make_blocker(Vector<String> patterns)
|
||||
{
|
||||
auto& blocker = ContentBlocker::the();
|
||||
MUST(blocker.set_patterns(patterns));
|
||||
return blocker;
|
||||
}
|
||||
|
||||
static URL::URL url(StringView string)
|
||||
{
|
||||
auto result = URL::Parser::basic_parse(string);
|
||||
EXPECT(result.has_value());
|
||||
return result.release_value();
|
||||
}
|
||||
|
||||
TEST_CASE(empty_pattern_list)
|
||||
{
|
||||
auto& blocker = make_blocker({});
|
||||
|
||||
EXPECT(!blocker.is_filtered(url("https://anything.com"sv)));
|
||||
EXPECT(!blocker.is_filtered(url("data:text/plain,hi"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(basic_blocking)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
"ads."_string,
|
||||
"?banner"_string,
|
||||
"tracker"_string
|
||||
};
|
||||
|
||||
auto& blocker = make_blocker(move(patterns));
|
||||
|
||||
EXPECT(blocker.is_filtered(url("https://example.com/ads.js"sv)));
|
||||
EXPECT(blocker.is_filtered(url("http://site.com/page.html?banner=true"sv)));
|
||||
EXPECT(blocker.is_filtered(url("https://tracker.example.org/ping"sv)));
|
||||
EXPECT(!blocker.is_filtered(url("https://ds.example.com/page.html"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(data_urls_exempt)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
{ "data:"_string },
|
||||
{ "evil.com"_string }
|
||||
};
|
||||
|
||||
auto& blocker = make_blocker(move(patterns));
|
||||
|
||||
EXPECT(!blocker.is_filtered(url("data:text/plain,hello"sv)));
|
||||
EXPECT(!blocker.is_filtered(url("data:image/png;base64,abc123"sv)));
|
||||
EXPECT(blocker.is_filtered(url("https://evil.com/script.js"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(disable_filtering)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
{ "example.com"_string }
|
||||
};
|
||||
|
||||
auto& blocker = make_blocker(move(patterns));
|
||||
blocker.set_filtering_enabled(false);
|
||||
|
||||
EXPECT(!blocker.is_filtered(url("https://example.com"sv)));
|
||||
EXPECT(!blocker.is_filtered(url("http://example.com/ads"sv)));
|
||||
|
||||
blocker.set_filtering_enabled(true);
|
||||
EXPECT(blocker.is_filtered(url("https://example.com"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(substring_matches)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
{ "ads"_string },
|
||||
{ "ad/"_string }
|
||||
};
|
||||
|
||||
auto& blocker = make_blocker(move(patterns));
|
||||
|
||||
EXPECT(blocker.is_filtered(url("https://site.com/ads/banner.jpg"sv)));
|
||||
EXPECT(blocker.is_filtered(url("http://marketing.com/ad/page"sv)));
|
||||
EXPECT(!blocker.is_filtered(url("https://site.com/content/article.html"sv)));
|
||||
EXPECT(!blocker.is_filtered(url("http://advancedtech.com/home"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(file_scheme_can_be_filtered)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
{ "secret"_string },
|
||||
{ ".txt"_string }
|
||||
};
|
||||
|
||||
auto& blocker = make_blocker(move(patterns));
|
||||
|
||||
EXPECT(blocker.is_filtered(url("file:///home/user/secret.txt"sv)));
|
||||
EXPECT(!blocker.is_filtered(url("file:///home/user/document.pdf"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(query_parameters_and_fragments)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
{ "#ad="_string },
|
||||
{ "?ad="_string },
|
||||
{ "#sponsored"_string }
|
||||
};
|
||||
|
||||
auto& blocker = make_blocker(move(patterns));
|
||||
|
||||
EXPECT(blocker.is_filtered(url("https://site.com/page?ad=123"sv)));
|
||||
EXPECT(blocker.is_filtered(url("https://site.com/page#ad=456"sv)));
|
||||
EXPECT(blocker.is_filtered(url("https://site.com/page?ref=home&ad=1#sponsored"sv)));
|
||||
EXPECT(!blocker.is_filtered(url("https://site.com/page?ref=home"sv)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibTest/TestCase.h>
|
||||
#include <LibURL/Parser.h>
|
||||
#include <LibURL/URL.h>
|
||||
#include <LibWeb/Loader/ContentFilter.h>
|
||||
|
||||
namespace Web {
|
||||
|
||||
static ContentFilter& make_filter(Vector<String> patterns)
|
||||
{
|
||||
auto& filter = ContentFilter::the();
|
||||
MUST(filter.set_patterns(patterns));
|
||||
return filter;
|
||||
}
|
||||
|
||||
static URL::URL url(StringView string)
|
||||
{
|
||||
auto result = URL::Parser::basic_parse(string);
|
||||
EXPECT(result.has_value());
|
||||
return result.release_value();
|
||||
}
|
||||
|
||||
TEST_CASE(empty_pattern_list)
|
||||
{
|
||||
auto& filter = make_filter({});
|
||||
|
||||
EXPECT(!filter.is_filtered(url("https://anything.com"sv)));
|
||||
EXPECT(!filter.is_filtered(url("data:text/plain,hi"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(basic_blocking)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
"ads."_string,
|
||||
"?banner"_string,
|
||||
"tracker"_string
|
||||
};
|
||||
|
||||
auto& filter = make_filter(move(patterns));
|
||||
|
||||
EXPECT(filter.is_filtered(url("https://example.com/ads.js"sv)));
|
||||
EXPECT(filter.is_filtered(url("http://site.com/page.html?banner=true"sv)));
|
||||
EXPECT(filter.is_filtered(url("https://tracker.example.org/ping"sv)));
|
||||
EXPECT(!filter.is_filtered(url("https://ds.example.com/page.html"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(data_urls_exempt)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
{ "data:"_string },
|
||||
{ "evil.com"_string }
|
||||
};
|
||||
|
||||
auto& filter = make_filter(move(patterns));
|
||||
|
||||
EXPECT(!filter.is_filtered(url("data:text/plain,hello"sv)));
|
||||
EXPECT(!filter.is_filtered(url("data:image/png;base64,abc123"sv)));
|
||||
EXPECT(filter.is_filtered(url("https://evil.com/script.js"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(disable_filtering)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
{ "example.com"_string }
|
||||
};
|
||||
|
||||
auto& filter = make_filter(move(patterns));
|
||||
filter.set_filtering_enabled(false);
|
||||
|
||||
EXPECT(!filter.is_filtered(url("https://example.com"sv)));
|
||||
EXPECT(!filter.is_filtered(url("http://example.com/ads"sv)));
|
||||
|
||||
filter.set_filtering_enabled(true);
|
||||
EXPECT(filter.is_filtered(url("https://example.com"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(substring_matches)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
{ "ads"_string },
|
||||
{ "ad/"_string }
|
||||
};
|
||||
|
||||
auto& filter = make_filter(move(patterns));
|
||||
|
||||
EXPECT(filter.is_filtered(url("https://site.com/ads/banner.jpg"sv)));
|
||||
EXPECT(filter.is_filtered(url("http://marketing.com/ad/page"sv)));
|
||||
EXPECT(!filter.is_filtered(url("https://site.com/content/article.html"sv)));
|
||||
EXPECT(!filter.is_filtered(url("http://advancedtech.com/home"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(file_scheme_can_be_filtered)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
{ "secret"_string },
|
||||
{ ".txt"_string }
|
||||
};
|
||||
|
||||
auto& filter = make_filter(move(patterns));
|
||||
|
||||
EXPECT(filter.is_filtered(url("file:///home/user/secret.txt"sv)));
|
||||
EXPECT(!filter.is_filtered(url("file:///home/user/document.pdf"sv)));
|
||||
}
|
||||
|
||||
TEST_CASE(query_parameters_and_fragments)
|
||||
{
|
||||
Vector<String> patterns = {
|
||||
{ "#ad="_string },
|
||||
{ "?ad="_string },
|
||||
{ "#sponsored"_string }
|
||||
};
|
||||
|
||||
auto& filter = make_filter(move(patterns));
|
||||
|
||||
EXPECT(filter.is_filtered(url("https://site.com/page?ad=123"sv)));
|
||||
EXPECT(filter.is_filtered(url("https://site.com/page#ad=456"sv)));
|
||||
EXPECT(filter.is_filtered(url("https://site.com/page?ref=home&ad=1#sponsored"sv)));
|
||||
EXPECT(!filter.is_filtered(url("https://site.com/page?ref=home"sv)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -25,9 +25,9 @@ TestWebView::TestWebView(Core::AnonymousBuffer theme, Web::DevicePixelSize viewp
|
|||
{
|
||||
}
|
||||
|
||||
void TestWebView::clear_content_filters()
|
||||
void TestWebView::clear_content_blockers()
|
||||
{
|
||||
client().async_set_content_filters(m_client_state.page_index, {});
|
||||
client().async_set_content_blockers(m_client_state.page_index, {});
|
||||
}
|
||||
|
||||
pid_t TestWebView::web_content_pid() const
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class TestWebView final : public WebView::HeadlessWebView {
|
|||
public:
|
||||
static NonnullOwnPtr<TestWebView> create(Core::AnonymousBuffer theme, Web::DevicePixelSize window_size);
|
||||
|
||||
void clear_content_filters();
|
||||
void clear_content_blockers();
|
||||
pid_t web_content_pid() const;
|
||||
|
||||
NonnullRefPtr<Core::Promise<RefPtr<Gfx::Bitmap const>>> take_screenshot();
|
||||
|
|
|
|||
|
|
@ -1291,7 +1291,7 @@ static ErrorOr<int> run_tests(Core::AnonymousBuffer const& theme, Web::DevicePix
|
|||
|
||||
for (auto [view_id, view] : enumerate(views)) {
|
||||
set_ui_callbacks_for_tests(*view, test_run_capture);
|
||||
view->clear_content_filters();
|
||||
view->clear_content_blockers();
|
||||
|
||||
auto cleanup_test = [&, view = view.ptr()](size_t test_index, TestResult test_result) {
|
||||
view->on_load_finish = {};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
#include <LibRequests/RequestClient.h>
|
||||
#include <LibWeb/Bindings/MainThreadVM.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/Loader/ContentFilter.h>
|
||||
#include <LibWeb/Loader/ContentBlocker.h>
|
||||
#include <LibWeb/Loader/GeneratedPagesLoader.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
#include <LibWeb/PermissionsPolicy/AutoplayAllowlist.h>
|
||||
|
|
@ -40,7 +40,7 @@ static ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> bind_image_decoder_ser
|
|||
return bind_service<ImageDecoderClient::Client>(&bind_image_decoder_java);
|
||||
}
|
||||
|
||||
static ErrorOr<void> load_content_filters();
|
||||
static ErrorOr<void> load_content_blockers();
|
||||
|
||||
static ErrorOr<void> load_autoplay_allowlist();
|
||||
|
||||
|
|
@ -68,9 +68,9 @@ ErrorOr<int> service_main(int ipc_socket)
|
|||
// in order to make it work. For now, it's better to just disable it.
|
||||
WebView::disable_site_isolation();
|
||||
|
||||
auto maybe_content_filter_error = load_content_filters();
|
||||
if (maybe_content_filter_error.is_error())
|
||||
dbgln("Failed to load content filters: {}", maybe_content_filter_error.error());
|
||||
auto maybe_content_blocker_error = load_content_blockers();
|
||||
if (maybe_content_blocker_error.is_error())
|
||||
dbgln("Failed to load content blockers: {}", maybe_content_blocker_error.error());
|
||||
|
||||
auto maybe_autoplay_allowlist_error = load_autoplay_allowlist();
|
||||
if (maybe_autoplay_allowlist_error.is_error())
|
||||
|
|
@ -102,20 +102,20 @@ ErrorOr<NonnullRefPtr<Client>> bind_service(void (*bind_method)(int))
|
|||
return new_client;
|
||||
}
|
||||
|
||||
static ErrorOr<void> load_content_filters()
|
||||
static ErrorOr<void> load_content_blockers()
|
||||
{
|
||||
auto file_or_error = Core::File::open(ByteString::formatted("{}/res/ladybird/default-config/BrowserContentFilters.txt", WebView::s_ladybird_resource_root), Core::File::OpenMode::Read);
|
||||
auto file_or_error = Core::File::open(ByteString::formatted("{}/res/ladybird/default-config/BrowserContentBlockers.txt", WebView::s_ladybird_resource_root), Core::File::OpenMode::Read);
|
||||
if (file_or_error.is_error())
|
||||
return file_or_error.release_error();
|
||||
|
||||
auto file = file_or_error.release_value();
|
||||
auto ad_filter_list = TRY(Core::InputBufferedFile::create(move(file)));
|
||||
auto content_blocker_list = TRY(Core::InputBufferedFile::create(move(file)));
|
||||
auto buffer = TRY(ByteBuffer::create_uninitialized(4096));
|
||||
|
||||
Vector<String> patterns;
|
||||
|
||||
while (TRY(ad_filter_list->can_read_line())) {
|
||||
auto line = TRY(ad_filter_list->read_line(buffer));
|
||||
while (TRY(content_blocker_list->can_read_line())) {
|
||||
auto line = TRY(content_blocker_list->read_line(buffer));
|
||||
if (line.is_empty())
|
||||
continue;
|
||||
|
||||
|
|
@ -123,8 +123,8 @@ static ErrorOr<void> load_content_filters()
|
|||
TRY(patterns.try_append(move(pattern)));
|
||||
}
|
||||
|
||||
auto& content_filter = Web::ContentFilter::the();
|
||||
TRY(content_filter.set_patterns(patterns));
|
||||
auto& content_blocker = Web::ContentBlocker::the();
|
||||
TRY(content_blocker.set_patterns(patterns));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ set(THEMES
|
|||
list(TRANSFORM THEMES PREPEND "${LADYBIRD_SOURCE_DIR}/Base/res/themes/")
|
||||
|
||||
set(CONFIG_RESOURCES
|
||||
BrowserContentFilters.txt
|
||||
BrowserContentBlockers.txt
|
||||
)
|
||||
list(TRANSFORM CONFIG_RESOURCES PREPEND "${LADYBIRD_SOURCE_DIR}/Base/res/ladybird/default-config/")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue