diff options
-rw-r--r-- | plugins/AdblockFilter/test/filterlist.cpp | 2 | ||||
-rw-r--r-- | plugins/AdblockFilter/test/options.cpp | 2 | ||||
-rw-r--r-- | plugins/AdblockFilter/test/rule.cpp | 2 | ||||
-rw-r--r-- | plugins/HostlistFilter/filterlist.cpp | 54 | ||||
-rw-r--r-- | plugins/HostlistFilter/filterlist.h | 64 | ||||
-rw-r--r-- | plugins/HostlistFilter/test/filterlist.cpp | 16 | ||||
-rw-r--r-- | plugins/HostlistFilter/test/plugin.cpp | 2 | ||||
-rw-r--r-- | plugins/HostlistFilter/test/rule.cpp | 58 |
8 files changed, 120 insertions, 80 deletions
diff --git a/plugins/AdblockFilter/test/filterlist.cpp b/plugins/AdblockFilter/test/filterlist.cpp index d3ec513..90860fd 100644 --- a/plugins/AdblockFilter/test/filterlist.cpp +++ b/plugins/AdblockFilter/test/filterlist.cpp @@ -3,6 +3,8 @@ #include <QBuffer> #include <catch2/catch.hpp> +// clazy:skip + using namespace AdblockPlus; QByteArray sampleList = diff --git a/plugins/AdblockFilter/test/options.cpp b/plugins/AdblockFilter/test/options.cpp index 67dc143..19f972c 100644 --- a/plugins/AdblockFilter/test/options.cpp +++ b/plugins/AdblockFilter/test/options.cpp @@ -2,6 +2,8 @@ #include "options.h" #include <catch2/catch.hpp> +// clazy:skip + using namespace AdblockPlus; SCENARIO("parsing adblock options") diff --git a/plugins/AdblockFilter/test/rule.cpp b/plugins/AdblockFilter/test/rule.cpp index 07186b9..a1cd3ed 100644 --- a/plugins/AdblockFilter/test/rule.cpp +++ b/plugins/AdblockFilter/test/rule.cpp @@ -2,6 +2,8 @@ #include "rule.h" #include <catch2/catch.hpp> +// clazy:skip + using namespace AdblockPlus; SCENARIO("MatcherRule") diff --git a/plugins/HostlistFilter/filterlist.cpp b/plugins/HostlistFilter/filterlist.cpp index a0fd414..8faa4ef 100644 --- a/plugins/HostlistFilter/filterlist.cpp +++ b/plugins/HostlistFilter/filterlist.cpp @@ -10,49 +10,47 @@ #include <QIODevice> #include <QTextStream> -using namespace Hostlist; - -#ifdef FUZZER -extern "C" int LLVMFuzzerTestOneInput(const char *Data, long long Size) +inline void Hostlist::parseRule(const QString &line, QStringList &blocked, QHash<QString, QString> &redirected) { - Filterlist::parseRule(QString::fromLatin1(Data, Size)); - return 0; -} -#endif - -std::map<Filterlist::DomainHash, Filterlist::Rule> Filterlist::parseRule(const QString &line) -{ - if(line.isEmpty() || line.at(0) == '#') { - return {}; - } + if(line.isEmpty() || line.at(0) == '#') + return; auto parts = line.trimmed().split(' '); - if(parts.size() < 2) { - return {}; - } + if(parts.size() < 2) + return; - const auto redirect = (parts[0] == "0.0.0.0") ? QString() : parts[0]; + if(parts[0] == "0.0.0.0") { + parts.pop_front(); + blocked << parts; + return; + } - std::map<DomainHash, Rule> r; for(int i = 1; i < parts.size(); ++i) { - r.emplace(qHash(parts[i], 0), Filterlist::Rule{ parts[i], redirect }); + redirected.insert(parts[i], parts[0]); } - return r; } -bool Filterlist::load(QIODevice &from) +#ifdef FUZZER +extern "C" int LLVMFuzzerTestOneInput(const char *Data, long long Size) +{ + QStringList b; + QHash<QString, QString> r; + Hostlist::parseRule(QString::fromLatin1(Data, static_cast<int>(Size)), b, r); + b.clear(); + r.clear(); + return 0; +} +#endif + +bool Hostlist::Filterlist::load(QIODevice &from) { if(!from.isReadable() || !from.isTextModeEnabled()) { return false; } while(from.bytesAvailable() > 0) { - const auto line = from.readLine(512).trimmed(); - auto r = parseRule(line); - if(!r.empty()) { - qDebug("merging in %lu rules", r.size()); - rules.merge(r); - } + const auto line = from.readLine(512); + parseRule(line, blocked, redirected); } return true; } diff --git a/plugins/HostlistFilter/filterlist.h b/plugins/HostlistFilter/filterlist.h index 7301f20..a0fa6f7 100644 --- a/plugins/HostlistFilter/filterlist.h +++ b/plugins/HostlistFilter/filterlist.h @@ -6,53 +6,79 @@ * SPDX-License-Identifier: GPL-3.0 */ -#pragma once +#ifndef SMOLBOTE_HOSTLIST_FILTERLIST +#define SMOLBOTE_HOSTLIST_FILTERLIST -#include <map> +#include <QHash> #include <smolbote/filterinterface.hpp> namespace Hostlist { +void parseRule(const QString &line, QStringList &blocked, QHash<QString, QString> &redirected); + class Filterlist final : public FilterList { public: - typedef uint DomainHash; - struct Rule { - QString domain; - QString redirect; - }; - Filterlist() = default; + Filterlist(const Filterlist &) = delete; + Filterlist &operator=(const Filterlist &) = delete; ~Filterlist() = default; - [[nodiscard]] bool findMatch(const QString &domain) const + enum Match { + NotFound, + Block, + Redirect + }; + + [[nodiscard]] Match findMatch(QUrl &url) const { - const auto hash = qHash(domain, 0); - const auto found = rules.find(hash); - if(found != rules.end()) { - return true; + const auto domain = url.host(); + + if(blocked.contains(domain)) + return Block; + + const auto iter = redirected.find(domain); + if(iter != redirected.end()) { + url.setHost(iter.value()); + return Redirect; } - return false; + + return NotFound; } - int count() const + + [[nodiscard]] auto count() const { - return rules.size(); + return blocked.size() + redirected.size(); } [[nodiscard]] bool filter(QWebEngineUrlRequestInfo &info) const { - return false; + auto url = info.requestUrl(); + switch(findMatch(url)) { + case NotFound: + return false; + case Block: + info.block(true); + return true; + case Redirect: + info.block(false); + info.redirect(url); + return true; + } } + [[nodiscard]] bool isUpToDate() const { return true; } bool load(QIODevice &device); - [[nodiscard]] static std::map<DomainHash, Rule> parseRule(const QString &line); private: - std::map<DomainHash, Rule> rules; + QStringList blocked; + QHash<QString, QString> redirected; }; } // namespace Hostlist + +#endif // SMOLBOTE_HOSTLIST_FILTERLIST diff --git a/plugins/HostlistFilter/test/filterlist.cpp b/plugins/HostlistFilter/test/filterlist.cpp index 4aa532b..b9b3812 100644 --- a/plugins/HostlistFilter/test/filterlist.cpp +++ b/plugins/HostlistFilter/test/filterlist.cpp @@ -3,6 +3,8 @@ #include <QFile> #include <catch2/catch.hpp> +// clazy:skip + using namespace Hostlist; TEST_CASE("Hostlist") @@ -20,10 +22,16 @@ TEST_CASE("Hostlist") REQUIRE(list.count() == 4); - REQUIRE(list.findMatch("blockeddomain.first")); - REQUIRE(list.findMatch("blockeddomain.second")); + QUrl first("http://blockeddomain.first"); + REQUIRE(list.findMatch(first) == Filterlist::Block); + + QUrl second("http://blockeddomain.second/path/to/something"); + REQUIRE(list.findMatch(second) == Filterlist::Block); - REQUIRE(list.findMatch("localhost.localdomain")); + QUrl localhost("http://localhost.localdomain"); + REQUIRE(list.findMatch(localhost) == Filterlist::Redirect); + REQUIRE(localhost.toString() == "http://127.0.0.1"); - REQUIRE(!list.findMatch("other.domain")); + QUrl other("http://other.domain"); + REQUIRE(list.findMatch(other) == Filterlist::NotFound); } diff --git a/plugins/HostlistFilter/test/plugin.cpp b/plugins/HostlistFilter/test/plugin.cpp index fad34f2..026f579 100644 --- a/plugins/HostlistFilter/test/plugin.cpp +++ b/plugins/HostlistFilter/test/plugin.cpp @@ -3,6 +3,8 @@ #include <QFile> #include <catch2/catch.hpp> +// clazy:skip + TEST_CASE("Hostlist") { HostlistFilterPlugin plugin; diff --git a/plugins/HostlistFilter/test/rule.cpp b/plugins/HostlistFilter/test/rule.cpp index b5ba6e0..5ee9881 100644 --- a/plugins/HostlistFilter/test/rule.cpp +++ b/plugins/HostlistFilter/test/rule.cpp @@ -2,56 +2,56 @@ #include "filterlist.h" #include <catch2/catch.hpp> +// clazy:skip + using namespace Hostlist; SCENARIO("Hostlist::Rule") { GIVEN("an invalid rule") { - const auto rule = Filterlist::parseRule("0.0.0.0 "); - REQUIRE(rule.empty()); + QStringList b; + QHash<QString, QString> r; + parseRule("0.0.0.0 ", b, r); + + REQUIRE(b.empty()); + REQUIRE(r.empty()); } GIVEN("127.0.0.1 localhost.localdomain") { - auto rule = Filterlist::parseRule("127.0.0.1 localhost.localdomain"); + QStringList b; + QHash<QString, QString> r; + parseRule("127.0.0.1 localhost.localdomain", b, r); - REQUIRE(!rule.empty()); - REQUIRE(rule.size() == 1); + REQUIRE(b.empty()); + REQUIRE(r.size() == 1); - // note: you need to force it to hash a string, rather than the address itself - const auto index = qHash(QString("localhost.localdomain"), 0); - REQUIRE(rule[index].domain == "localhost.localdomain"); - REQUIRE(rule[index].redirect == "127.0.0.1"); + REQUIRE(r.value("localhost.localdomain") == "127.0.0.1"); } GIVEN("0.0.0.0 blockeddomain.com") { - auto rule = Filterlist::parseRule("0.0.0.0 blockeddomain.com"); + QStringList b; + QHash<QString, QString> r; + parseRule("0.0.0.0 blockeddomain.com", b, r); - REQUIRE(!rule.empty()); - REQUIRE(rule.size() == 1); + REQUIRE(b.size() == 1); + REQUIRE(r.empty()); - const auto index = qHash(QString("blockeddomain.com"), 0); - REQUIRE(rule[index].domain == "blockeddomain.com"); - REQUIRE(rule[index].redirect.isEmpty()); + REQUIRE(b.contains("blockeddomain.com")); ; } GIVEN("0.0.0.0 blockeddomain.first blockeddomain.second") { - auto rule = Filterlist::parseRule("0.0.0.0 blockeddomain.first blockeddomain.second"); - - REQUIRE(!rule.empty()); - REQUIRE(rule.size() == 2); - { - const auto index = qHash(QString("blockeddomain.first"), 0); - REQUIRE(rule[index].domain == "blockeddomain.first"); - REQUIRE(rule[index].redirect.isEmpty()); - } - { - const auto index = qHash(QString("blockeddomain.second"), 0); - REQUIRE(rule[index].domain == "blockeddomain.second"); - REQUIRE(rule[index].redirect.isEmpty()); - } + QStringList b; + QHash<QString, QString> r; + parseRule("0.0.0.0 blockeddomain.first blockeddomain.second", b, r); + + REQUIRE(b.size() == 2); + REQUIRE(r.empty()); + + REQUIRE(b.contains("blockeddomain.first")); + REQUIRE(b.contains("blockeddomain.second")); } } |