Browse Source

Add adblockrule_parse

Aqua-sama 4 weeks ago
parent
commit
566abfa991
Signed by: Aqua-sama <aqua@iserlohn-fortress.net> GPG Key ID: 5378B8349C1D5ADA

+ 5
- 17
lib/urlfilter/filterleaf.cpp View File

@@ -1,26 +1,14 @@
1 1
 #include "filterleaf.h"
2 2
 
3
-FilterLeaf::FilterLeaf(FilterLeaf &&other)
4
-{
5
-    m_isBlocking = other.m_isBlocking;
6
-    m_request = std::move(other.m_request);
7
-    m_redirect = std::move(other.m_redirect);
8
-}
9
-
10
-FilterLeaf &FilterLeaf::operator=(FilterLeaf &&other)
11
-{
12
-    m_isBlocking = other.m_isBlocking;
13
-    m_request = std::move(other.m_request);
14
-    m_redirect = std::move(other.m_redirect);
15
-    return *this;
16
-}
17
-
18 3
 const QString FilterLeaf::request() const
19 4
 {
20 5
     return m_request;
21 6
 }
22 7
 
23
-const QString FilterLeaf::redirect() const
8
+std::optional<bool> FilterLeaf::option(QWebEngineUrlRequestInfo::ResourceType opt) const
24 9
 {
25
-    return m_redirect;
10
+    if(resourceTypeOptions.contains(opt))
11
+        return resourceTypeOptions.value(opt);
12
+    else
13
+        return std::nullopt;
26 14
 }

+ 5
- 7
lib/urlfilter/filterleaf.h View File

@@ -13,6 +13,9 @@
13 13
 #include <QObject>
14 14
 #include <QString>
15 15
 #include <QWebEngineUrlRequestInfo>
16
+#include <optional>
17
+#include <utility>
18
+#include <QVariant>
16 19
 
17 20
 class FilterLeaf
18 21
 {
@@ -34,19 +37,15 @@ public:
34 37
         DomainMatch
35 38
     };
36 39
 
37
-    FilterLeaf(FilterLeaf &&other);
38
-    FilterLeaf &operator=(FilterLeaf &&other);
39 40
     virtual ~FilterLeaf() = default;
40 41
 
41 42
     virtual bool match(const QUrl &requestUrl) const = 0;
42
-    virtual Action action() const = 0;
43
+    virtual std::pair<Action, QVariant> action() const = 0;
43 44
 
44 45
     const QString request() const;
45
-    const QString redirect() const;
46
+    std::optional<bool> option(QWebEngineUrlRequestInfo::ResourceType opt) const;
46 47
 
47 48
 protected:
48
-    explicit FilterLeaf() = default;
49
-
50 49
     // rule matching
51 50
     UrlMatchType matchType = InvalidMatch;
52 51
     QHash<QWebEngineUrlRequestInfo::ResourceType, bool> resourceTypeOptions;
@@ -54,7 +53,6 @@ protected:
54 53
 
55 54
     // rule action
56 55
     bool m_isBlocking;
57
-    QString m_redirect;
58 56
 };
59 57
 
60 58
 Q_DECLARE_METATYPE(FilterLeaf::Action)

+ 33
- 167
lib/urlfilter/formats/adblockrule.cpp View File

@@ -5,174 +5,21 @@
5 5
  *
6 6
  * SPDX-License-Identifier: GPL-3.0
7 7
  */
8
-// Based on Falkon's AdBlockRule class
9 8
 
10 9
 #include "adblockrule.h"
10
+#include <QRegExp>
11
+#include <QStringMatcher>
11 12
 
12
-// adblock format documentation
13
-// https://adblockplus.org/filters
14
-
15
-// QString::mid(pos, len) - Returns a string starting at the specified position index.
16
-// QString::chop(len) - Removes n characters from the end of the string.
17
-// QString::remove(pos, len) - Removes n characters from the string, starting at the given position index.
18
-
19
-AdBlockRule *loadRule(const QString &filter)
20
-{
21
-    QString parsedLine = filter.trimmed();
22
-
23
-    // there is no rule, or it's a comment
24
-    if(parsedLine.isEmpty() || parsedLine.startsWith("!")) {
25
-        return nullptr;
26
-    }
27
-
28
-    // css rule -> filterleaves cannot do element blocking
29
-    if(parsedLine.contains(QLatin1Literal("##")) || parsedLine.contains(QLatin1Literal("#@#"))) {
30
-        return nullptr;
31
-    }
32
-
33
-    // exception rules
34
-    FilterLeaf::Action action = FilterLeaf::Block;
35
-    if(parsedLine.startsWith(QLatin1Literal("@@"))) {
36
-        action = FilterLeaf::Allow;
37
-        parsedLine.remove(0, 2);
38
-    }
39
-
40
-    // parse options
41
-    QStringList enabledOn, disabledOn;
42
-    QHash<QWebEngineUrlRequestInfo::ResourceType, bool> optionsHash;
43
-    {
44
-        const int sepPos = parsedLine.indexOf(QLatin1Literal("$"));
45
-        if(sepPos != -1) {
46
-            const auto options = parsedLine.mid(sepPos + 1).split(QLatin1Literal(","));
47
-            parsedLine = parsedLine.mid(0, sepPos);
48
-
49
-            for(const QString &option : options) {
50
-                if(option.startsWith(QLatin1Literal("domain"))) {
51
-                    const auto domainList = option.mid(7).split(QLatin1Literal("|"));
52
-
53
-                    for(const QString &domain : domainList) {
54
-                        if(domain.startsWith(QLatin1Literal("~"))) {
55
-                            disabledOn.append(domain.mid(1));
56
-                        } else {
57
-                            enabledOn.append(domain);
58
-                        }
59
-                    }
60
-                } else {
61
-                    const auto pair = parseOption(option);
62
-                    if(pair)
63
-                        optionsHash.insert(pair.value().first, pair.value().second);
64
-                }
65
-            }
66
-        }
67
-    }
68
-
69
-    FilterLeaf::UrlMatchType matchType;
70
-    QString pattern;
71
-
72
-    if(parsedLine.startsWith(QLatin1Literal("/")) && parsedLine.endsWith(QLatin1Literal("/"))) {
73
-        // regular expression rule
74
-        matchType = FilterLeaf::RegularExpressionMatch;
75
-        pattern = parsedLine.mid(1, parsedLine.length() - 2);
76
-
77
-    } else if(parsedLine.startsWith(QLatin1Literal("|")) && parsedLine.endsWith(QLatin1Literal("|"))) {
78
-        // string equals rule
79
-        matchType = FilterLeaf::StringEquals;
80
-        pattern = parsedLine.mid(1, parsedLine.length() - 2);
81
-
82
-    } else {
83
-
84
-        // Basic filter rules can use wildcards, which were supported by QRegExp,
85
-        // but were deprecated in QRegularExpression.
86
-
87
-        // remove beginning and ending wildcards
88
-        if(parsedLine.startsWith(QLatin1Literal("*")))
89
-            parsedLine = parsedLine.mid(1);
90
-
91
-        if(parsedLine.endsWith(QLatin1Literal("*")))
92
-            parsedLine.chop(1);
93
-
94
-        if(parsedLine.startsWith(QLatin1Literal("||")) && parsedLine.endsWith(QLatin1Literal("^"))) {
95
-            matchType = FilterLeaf::DomainMatch;
96
-            pattern = parsedLine.mid(2, parsedLine.length() - 3);
97
-
98
-        } else if(parsedLine.contains(QLatin1Literal("*")) || parsedLine.contains(QLatin1Literal("^"))) {
99
-            // check for wildcards and translate to regexp
100
-            // wildcard "*" - any number of characters
101
-            // separator "^" - end, ? or /
102
-            matchType = FilterLeaf::RegularExpressionMatch;
103
-            parsedLine.replace(QLatin1Literal("||"), QLatin1Literal("^\\w+://"));
104
-            parsedLine.replace(QLatin1Literal("|"), QLatin1Literal("\\|"));
105
-            parsedLine.replace(QLatin1Literal("*"), QLatin1Literal(".*"));
106
-            parsedLine.replace(QLatin1Literal("^"), QLatin1Literal("($|\\?|\\/)"));
107
-            pattern = parsedLine;
108
-        }
109
-    }
110
-
111
-    auto *rule = new AdBlockRule(matchType, pattern, action);
112
-    rule->mergeOptions(optionsHash);
113
-    return rule;
114
-}
115
-
116
-std::optional<QPair<QWebEngineUrlRequestInfo::ResourceType, bool>> parseOption(const QString &option)
117
-{
118
-    const bool exception = !option.startsWith(QLatin1Literal("~"));
119
-
120
-    if(option.endsWith(QLatin1Literal("script"))) {
121
-        //  external scripts loaded via HTML script tag
122
-        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeScript, exception);
123
-
124
-    } else if(option.endsWith(QLatin1Literal("image"))) {
125
-        // regular images, typically loaded via HTML img tag
126
-        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeImage, exception);
127
-
128
-    } else if(option.endsWith(QLatin1Literal("stylesheet"))) {
129
-        // external CSS stylesheet files
130
-        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeStylesheet, exception);
131
-
132
-    } else if(option.endsWith(QLatin1Literal("object"))) {
133
-        // content handled by browser plugins, e.g. Flash or Java
134
-        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeObject, exception);
135
-
136
-    } else if(option.endsWith(QLatin1Literal("xmlhttprequest"))) {
137
-        //  requests started using the XMLHttpRequest object or fetch() API
138
-        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeXhr, exception);
139
-
140
-    } else if(option.endsWith(QLatin1Literal("object-subrequest"))) {
141
-        // requests started by plugins like Flash
142
-        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypePluginResource, exception);
143
-
144
-    } else if(option.endsWith(QLatin1Literal("subdocument"))) {
145
-        // embedded pages, usually included via HTML frames
146
-        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeSubFrame, exception);
147
-
148
-    } else if(option.endsWith(QLatin1Literal("ping"))) {
149
-        // requests started by <a ping> or navigator.sendBeacon()
150
-        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypePing, exception);
151
-
152
-    } else if(option.endsWith(QLatin1Literal("websocket"))) {
153
-        // requests initiated via WebSocket object
154
-        qDebug("Resource type 'websocket' not available");
155
-
156
-    } else if(option.endsWith(QLatin1Literal("webrtc"))) {
157
-        // connections opened via RTCPeerConnection instances to ICE servers
158
-        qDebug("Resource type 'webrtc' not available");
159
-
160
-    } else if(option.endsWith(QLatin1Literal("document"))) {
161
-        // the page itself
162
-        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeMainFrame, exception);
163
-
164
-    } else if(option.endsWith(QLatin1Literal("other"))) {
165
-        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeUnknown, exception);
166
-    }
167
-
168
-    return std::nullopt;
169
-}
170
-
171
-AdBlockRule::AdBlockRule(FilterLeaf::UrlMatchType matchType, const QString& filter, FilterLeaf::Action action)
13
+AdBlockRule::AdBlockRule(FilterLeaf::UrlMatchType matchType, const QString &filter, FilterLeaf::Action action)
172 14
 {
173 15
     this->matchType = matchType;
174 16
     this->m_request = filter;
175
-    this->m_isBlocking = (action == FilterLeaf::Block) ? true : false;
17
+    this->m_isBlocking = (action == FilterLeaf::Block);
18
+    //matcher.setPattern(filter);
19
+    if(matchType == FilterLeaf::RegularExpressionMatch)
20
+        regExp = new QRegExp(filter);
21
+    else
22
+        stringMatcher = new QStringMatcher(filter);
176 23
 }
177 24
 
178 25
 void AdBlockRule::mergeOptions(const QHash<QWebEngineUrlRequestInfo::ResourceType, bool> &options)
@@ -180,17 +27,36 @@ void AdBlockRule::mergeOptions(const QHash<QWebEngineUrlRequestInfo::ResourceTyp
180 27
     this->resourceTypeOptions.unite(options);
181 28
 }
182 29
 
183
-bool AdBlockRule::match(const QUrl& requestUrl) const
30
+bool AdBlockRule::match(const QUrl &requestUrl) const
184 31
 {
185 32
     switch(matchType) {
186
-        case FilterLeaf::StringContains:
187
-            return requestUrl.toString().contains(m_request);
33
+    case FilterLeaf::RegularExpressionMatch:
34
+        return (regExp->indexIn(requestUrl.toString()) != -1);
35
+    default:
36
+        return false;
37
+    }
38
+}
39
+
40
+bool AdBlockRule::match(const QUrl &requestUrl, QWebEngineUrlRequestInfo::ResourceType type) const
41
+{
42
+    // if request is of the required type, or there are no types set (== apply to all requests)
43
+    if(this->resourceTypeOptions.contains(type) || this->resourceTypeOptions.isEmpty()) {
44
+        switch(matchType) {
45
+        case FilterLeaf::RegularExpressionMatch:
46
+            return (regExp->indexIn(requestUrl.toString()) != -1);
188 47
         default:
189 48
             return false;
49
+        }
190 50
     }
51
+
52
+    // request type is not matched
53
+    return false;
191 54
 }
192 55
 
193
-FilterLeaf::Action AdBlockRule::action() const
56
+std::pair<FilterLeaf::Action, QVariant> AdBlockRule::action() const
194 57
 {
195
-    return m_isBlocking ? FilterLeaf::Block : FilterLeaf::Allow;
58
+    if(m_isBlocking)
59
+        return std::make_pair(FilterLeaf::Block, QVariant());
60
+    else
61
+        return std::make_pair(FilterLeaf::Allow, QVariant());
196 62
 }

+ 13
- 4
lib/urlfilter/formats/adblockrule.h View File

@@ -16,13 +16,22 @@ class AdBlockRule : public FilterLeaf
16 16
 {
17 17
 public:
18 18
     explicit AdBlockRule(FilterLeaf::UrlMatchType matchType, const QString &filter, FilterLeaf::Action action);
19
+    ~AdBlockRule()
20
+    {
21
+        delete stringMatcher;
22
+        delete regExp;
23
+    };
24
+
19 25
     void mergeOptions(const QHash<QWebEngineUrlRequestInfo::ResourceType, bool> &options);
20 26
 
21 27
     bool match(const QUrl &requestUrl) const override;
22
-    FilterLeaf::Action action() const override;
23
-};
28
+    bool match(const QUrl &requestUrl, QWebEngineUrlRequestInfo::ResourceType type) const;
29
+    std::pair<FilterLeaf::Action, QVariant> action() const override;
24 30
 
25
-std::optional<QPair<QWebEngineUrlRequestInfo::ResourceType, bool>> parseOption(const QString &option);
26
-AdBlockRule *loadRule(const QString &filter);
31
+private:
32
+    /* Once C++20 comes out, perhaps this can be replaced with a concept template */
33
+    QStringMatcher *stringMatcher = nullptr;
34
+    QRegExp *regExp = nullptr;
35
+};
27 36
 
28 37
 #endif // SMOLBOTE_ADBLOCKRULE_H

+ 180
- 0
lib/urlfilter/formats/adblockrule_parse.cpp View File

@@ -0,0 +1,180 @@
1
+/*
2
+ * This file is part of smolbote. It's copyrighted by the contributors recorded
3
+ * in the version control history of the file, available from its original
4
+ * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
5
+ *
6
+ * SPDX-License-Identifier: GPL-3.0
7
+ */
8
+
9
+#include "adblockrule.h"
10
+#include "adblockrule_parse.h"
11
+
12
+// adblock format documentation
13
+// https://adblockplus.org/filters
14
+
15
+// QString::mid(pos, len) const - Returns a string starting at the specified position index.
16
+// QString::chop(len) - Removes n characters from the end of the string.
17
+// QString::remove(pos, len) - Removes n characters from the string, starting at the given position index.
18
+
19
+AdBlockRule *loadRule(const QString &filter)
20
+{
21
+    QString parsedLine = filter.trimmed();
22
+
23
+    // there is no rule, or it's a comment
24
+    if(parsedLine.isEmpty() || parsedLine.startsWith("!")) {
25
+        return nullptr;
26
+    }
27
+
28
+    // css rule -> filterleaves cannot do element blocking
29
+    if(parsedLine.contains(QLatin1Literal("##")) || parsedLine.contains(QLatin1Literal("#@#"))) {
30
+        return nullptr;
31
+    }
32
+
33
+    // exception rules
34
+    FilterLeaf::Action action = FilterLeaf::Block;
35
+    if(parsedLine.startsWith(QLatin1Literal("@@"))) {
36
+        action = FilterLeaf::Allow;
37
+        parsedLine.remove(0, 2);
38
+    }
39
+
40
+    // parse options
41
+    QStringList enabledOn, disabledOn;
42
+    QHash<QWebEngineUrlRequestInfo::ResourceType, bool> optionsHash;
43
+    {
44
+        const int sepPos = parsedLine.indexOf(QLatin1Literal("$"));
45
+        if(sepPos != -1) {
46
+            const auto options = parsedLine.mid(sepPos + 1).split(QLatin1Literal(","));
47
+            parsedLine = parsedLine.mid(0, sepPos);
48
+
49
+            for(const QString &option : options) {
50
+                if(option.startsWith(QLatin1Literal("domain"))) {
51
+                    const auto domainList = option.mid(7).split(QLatin1Literal("|"));
52
+
53
+                    for(const QString &domain : domainList) {
54
+                        if(domain.startsWith(QLatin1Literal("~"))) {
55
+                            disabledOn.append(domain.mid(1));
56
+                        } else {
57
+                            enabledOn.append(domain);
58
+                        }
59
+                    }
60
+                } else {
61
+                    const auto pair = parseOption(option);
62
+                    if(pair)
63
+                        optionsHash.insert(pair.value().first, pair.value().second);
64
+                }
65
+            }
66
+        }
67
+    }
68
+
69
+    FilterLeaf::UrlMatchType matchType = FilterLeaf::InvalidMatch;
70
+
71
+    if(parsedLine.startsWith(QLatin1Literal("/")) && parsedLine.endsWith(QLatin1Literal("/"))) {
72
+        // regular expression rule
73
+        matchType = FilterLeaf::RegularExpressionMatch;
74
+        parsedLine = parsedLine.mid(1, parsedLine.length() - 2);
75
+
76
+    } else if(parsedLine.startsWith(QLatin1Literal("||")) && parsedLine.endsWith(QLatin1Literal("^"))) {
77
+        matchType = FilterLeaf::DomainMatch;
78
+        parsedLine = parsedLine.mid(2, parsedLine.length() - 3);
79
+
80
+    } else if(parsedLine.startsWith(QLatin1Literal("|")) && parsedLine.endsWith(QLatin1Literal("|"))) {
81
+        // string equals rule
82
+        matchType = FilterLeaf::StringEquals;
83
+        parsedLine = parsedLine.mid(1, parsedLine.length() - 2);
84
+
85
+    } else if(parsedLine.startsWith(QLatin1Literal("||"))) {
86
+        // string starts with rule
87
+        matchType = FilterLeaf::StringStartsWith;
88
+        parsedLine = parsedLine.mid(2);
89
+
90
+    } else if(parsedLine.endsWith(QLatin1Literal("|"))) {
91
+        // string ends with rule
92
+        matchType = FilterLeaf::StringEndsWith;
93
+        parsedLine.chop(1);
94
+
95
+    } else {
96
+        // generic contains rule
97
+        matchType = FilterLeaf::StringContains;
98
+
99
+        // Basic filter rules can use wildcards, which were supported by QRegExp,
100
+        // but were deprecated in QRegularExpression.
101
+
102
+        // remove beginning and ending wildcards
103
+        if(parsedLine.startsWith(QLatin1Literal("*")))
104
+            parsedLine = parsedLine.mid(1);
105
+
106
+        if(parsedLine.endsWith(QLatin1Literal("*")))
107
+            parsedLine.chop(1);
108
+
109
+        if(parsedLine.contains(QLatin1Literal("*")) || parsedLine.contains(QLatin1Literal("^"))) {
110
+            // check for wildcards and translate to regexp
111
+            // wildcard "*" - any number of characters
112
+            // separator "^" - end, ? or /
113
+            parsedLine.replace(QLatin1Literal("||"), QLatin1Literal("^\\w+://"));
114
+            parsedLine.replace(QLatin1Literal("|"), QLatin1Literal("\\|"));
115
+            parsedLine.replace(QLatin1Literal("*"), QLatin1Literal(".*"));
116
+            parsedLine.replace(QLatin1Literal("^"), QLatin1Literal("($|\\?|\\/)"));
117
+
118
+            matchType = FilterLeaf::RegularExpressionMatch;
119
+        }
120
+    }
121
+
122
+    AdBlockRule *rule = new AdBlockRule(matchType, parsedLine, action);
123
+    rule->mergeOptions(optionsHash);
124
+    return rule;
125
+}
126
+
127
+std::optional<QPair<QWebEngineUrlRequestInfo::ResourceType, bool>> parseOption(const QString &option)
128
+{
129
+    const bool exception = !option.startsWith(QLatin1Literal("~"));
130
+
131
+    if(option.endsWith(QLatin1Literal("script"))) {
132
+        //  external scripts loaded via HTML script tag
133
+        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeScript, exception);
134
+
135
+    } else if(option.endsWith(QLatin1Literal("image"))) {
136
+        // regular images, typically loaded via HTML img tag
137
+        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeImage, exception);
138
+
139
+    } else if(option.endsWith(QLatin1Literal("stylesheet"))) {
140
+        // external CSS stylesheet files
141
+        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeStylesheet, exception);
142
+
143
+    } else if(option.endsWith(QLatin1Literal("object"))) {
144
+        // content handled by browser plugins, e.g. Flash or Java
145
+        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeObject, exception);
146
+
147
+    } else if(option.endsWith(QLatin1Literal("xmlhttprequest"))) {
148
+        //  requests started using the XMLHttpRequest object or fetch() API
149
+        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeXhr, exception);
150
+
151
+    } else if(option.endsWith(QLatin1Literal("object-subrequest"))) {
152
+        // requests started by plugins like Flash
153
+        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypePluginResource, exception);
154
+
155
+    } else if(option.endsWith(QLatin1Literal("subdocument"))) {
156
+        // embedded pages, usually included via HTML frames
157
+        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeSubFrame, exception);
158
+
159
+    } else if(option.endsWith(QLatin1Literal("ping"))) {
160
+        // requests started by <a ping> or navigator.sendBeacon()
161
+        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypePing, exception);
162
+
163
+    } else if(option.endsWith(QLatin1Literal("websocket"))) {
164
+        // requests initiated via WebSocket object
165
+        qDebug("Resource type 'websocket' not available");
166
+
167
+    } else if(option.endsWith(QLatin1Literal("webrtc"))) {
168
+        // connections opened via RTCPeerConnection instances to ICE servers
169
+        qDebug("Resource type 'webrtc' not available");
170
+
171
+    } else if(option.endsWith(QLatin1Literal("document"))) {
172
+        // the page itself
173
+        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeMainFrame, exception);
174
+
175
+    } else if(option.endsWith(QLatin1Literal("other"))) {
176
+        return qMakePair(QWebEngineUrlRequestInfo::ResourceTypeUnknown, exception);
177
+    }
178
+
179
+    return std::nullopt;
180
+}

+ 17
- 0
lib/urlfilter/formats/adblockrule_parse.h View File

@@ -0,0 +1,17 @@
1
+/*
2
+ * This file is part of smolbote. It's copyrighted by the contributors recorded
3
+ * in the version control history of the file, available from its original
4
+ * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
5
+ *
6
+ * SPDX-License-Identifier: GPL-3.0
7
+ */
8
+
9
+#ifndef ADBLOCKRULE_PARSE_H
10
+#define ADBLOCKRULE_PARSE_H
11
+
12
+class AdBlockRule;
13
+
14
+AdBlockRule *loadRule(const QString &filter);
15
+std::optional<QPair<QWebEngineUrlRequestInfo::ResourceType, bool>> parseOption(const QString &option);
16
+
17
+#endif // ADBLOCKRULE_PARSE_H

+ 3
- 3
lib/urlfilter/formats/hostlistrule.cpp View File

@@ -21,9 +21,9 @@ bool HostlistRule::match(const QUrl &requestUrl) const
21 21
     return (m_request == requestUrl.host());
22 22
 }
23 23
 
24
-FilterLeaf::Action HostlistRule::action() const
24
+std::pair<FilterLeaf::Action, QVariant> HostlistRule::action() const
25 25
 {
26 26
     if(m_isBlocking)
27
-        return FilterLeaf::Block;
28
-    return FilterLeaf::Redirect;
27
+        return std::make_pair(FilterLeaf::Block, QVariant());
28
+    return std::make_pair(FilterLeaf::Redirect, QVariant(m_redirect));
29 29
 }

+ 4
- 1
lib/urlfilter/formats/hostlistrule.h View File

@@ -18,7 +18,10 @@ public:
18 18
     explicit HostlistRule(const QString &domain, const QString &redirect);
19 19
 
20 20
     bool match(const QUrl &requestUrl) const override;
21
-    FilterLeaf::Action action() const override;
21
+    std::pair<FilterLeaf::Action, QVariant> action() const override;
22
+
23
+private:
24
+    QString m_redirect;
22 25
 };
23 26
 
24 27
 #endif // SMOLBOTE_HOSTLIST_RULE_H

+ 1
- 1
lib/urlfilter/meson.build View File

@@ -8,7 +8,7 @@ urlfilter_moc = qt5.preprocess(
8 8
 urlfilter_lib = static_library('urlfilter',
9 9
     ['filtertree.cpp', 'filterleaf.cpp', urlfilter_moc,
10 10
     'domain.cpp', 'domain.h',
11
-    'formats/adblockrule.cpp', 'formats/hostlistrule.cpp', ],
11
+    'formats/adblockrule.cpp', 'formats/adblockrule_parse.cpp', 'formats/hostlistrule.cpp', ],
12 12
     dependencies: dep_qt5
13 13
 )
14 14
 

+ 1
- 1
src/webengine/filter.cpp View File

@@ -72,7 +72,7 @@ void Filter::filterRequest(QWebEngineUrlRequestInfo &info) const
72 72
 {
73 73
     auto matches = filters.match(info.firstPartyUrl().toString(), info.requestUrl().toString());
74 74
     for(const auto &rule : matches) {
75
-        switch(rule->action()) {
75
+        switch(rule->action().first) {
76 76
         case FilterLeaf::NotMatched:
77 77
 #ifdef QT_DEBUG
78 78
             qDebug("Paradoxical match: request matched, but not matched.");

+ 5
- 1
test/adblock/adblocktest.cpp View File

@@ -1,11 +1,15 @@
1 1
 #include "adblocktest.h"
2 2
 #include <QtTest/QtTest>
3 3
 #include "formats/adblockrule.h"
4
+#include "formats/adblockrule_parse.h"
4 5
 
5 6
 void AdBlockTest::parseRule()
6 7
 {
7
-    FilterLeaf *rule = loadRule("spamdomain");
8
+    auto *rule = loadRule("/spamdomain/$domain=spamdomain.com,image");
8 9
     QCOMPARE(rule != nullptr, true);
10
+    QCOMPARE(rule->match(QUrl::fromUserInput("subdomain.spamdomain.com")), true);
11
+    QCOMPARE(rule->action().first == FilterLeaf::Block, true);
12
+    QCOMPARE(rule->option(QWebEngineUrlRequestInfo::ResourceTypeImage).value(), true);
9 13
 }
10 14
 
11 15
 /*void AdBlockTest::parseList()

+ 2
- 2
test/hostlist/hostlisttest.cpp View File

@@ -39,9 +39,9 @@ void HostlistTest::checkRules()
39 39
     auto result = tree.match(domain, request);
40 40
     QCOMPARE(result.length(), matches);
41 41
     if(matches > 0)
42
-        QCOMPARE(result.constFirst()->action(), action);
42
+        QCOMPARE(result.constFirst()->action().first, action);
43 43
     if(action == FilterLeaf::Redirect)
44
-        QCOMPARE(result.constFirst()->redirect(), QLatin1Literal("127.0.0.1"));
44
+        QCOMPARE(result.constFirst()->action().second, QLatin1Literal("127.0.0.1"));
45 45
 }
46 46
 
47 47
 void HostlistTest::benchmark_parse()

+ 2
- 2
test/meson.build View File

@@ -3,14 +3,14 @@ adblock = executable('AdblockTest',
3 3
     dependencies: [dep_qt5, dep_urlfilter],
4 4
     sources: ['adblock/adblocktest.cpp', qt5.preprocess(moc_headers: 'adblock/adblocktest.h', dependencies: dep_qt5)]
5 5
 )
6
-test('urlfilter-adblock', adblock)
6
+test('urlfilter-adblock', adblock, workdir: meson.current_source_dir())
7 7
 
8 8
 # Hostlist parsing test
9 9
 hostlist = executable('HostlistTest',
10 10
     dependencies: [dep_qt5, dep_urlfilter],
11 11
     sources: ['hostlist/hostlisttest.cpp', qt5.preprocess(moc_headers: 'hostlist/hostlisttest.h', dependencies: dep_qt5)]
12 12
 )
13
-test('urlfilter-hostlist', hostlist)
13
+test('urlfilter-hostlist', hostlist, workdir: meson.current_source_dir())
14 14
 
15 15
 # matching algorithms benchmark
16 16
 matcherbenchmark = executable('MatcherBenchmark',

Loading…
Cancel
Save