2 * Copyright 2024 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser PC <https://www.stoutner.com/privacy-browser-pc/>.
6 * Privacy Browser PC is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser PC is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser PC. If not, see <http://www.gnu.org/licenses/>.
20 // Application headers.
21 #include "FilterListHelper.h"
22 #include "structs/OverrideStruct.h"
24 // KDE Framework headers.
25 #include <KLocalizedString>
27 // Qt toolkit headers.
30 #include <QRegularExpression>
31 #include <QTextStream>
33 // Construct the class.
34 FilterListHelper::FilterListHelper()
36 // Populate the translated disposition strings. Translated entries cannot be public static const.
37 DEFAULT_STRING = i18nc("Default disposition", "Default - Allowed");
38 ALLOWED_STRING = i18nc("Allowed disposition", "Allowed");
39 BLOCKED_STRING = i18nc("Blocked disposition", "Blocked");
41 // Populate the translated filter option disposition strings. Translated entries cannot be public static const.
42 FILTER_OPTION_NULL = QString();
43 FILTER_OPTION_APPLY = i18nc("Apply filter option", "Apply");
44 FILTER_OPTION_OVERRIDE = i18nc("Override filter option", "Override");
46 // Populate the translated navigation type strings. Translated entries cannot be public static const.
47 NAVIGATION_TYPE_LINK = i18nc("Navigation type link", "Link");
48 NAVIGATION_TYPE_TYPED = i18nc("Navigation type typed", "Typed");
49 NAVIGATION_TYPE_FORM_SUBMITTED = i18nc("Navigation type form submitted", "Form Submitted");
50 NAVIGATION_TYPE_BACK_FORWARD = i18nc("Navigation type back/forward", "Back/Forward");
51 NAVIGATION_TYPE_RELOAD = i18nc("Navigation type reload", "Reload");
52 NAVIGATION_TYPE_REDIRECT = i18nc("Navigation type redirect", "Redirect");
53 NAVIGATION_TYPE_OTHER = i18nc("Navigation type other", "Other");
55 // Populate the translated resource type strings. Translated entries cannot be public static const.
56 RESOURCE_TYPE_MAIN_FRAME = i18nc("Resource type main frame", "Main Frame");
57 RESOURCE_TYPE_SUB_FRAME = i18nc("Resource type sub frame", "Sub Frame");
58 RESOURCE_TYPE_STYLESHEET = i18nc("Resource type stylesheet", "Stylesheet");
59 RESOURCE_TYPE_SCRIPT = i18nc("Resource type script", "Script");
60 RESOURCE_TYPE_IMAGE = i18nc("Resource type image", "Image");
61 RESOURCE_TYPE_FONT_RESOURCE = i18nc("Resource type font", "Font");
62 RESOURCE_TYPE_SUB_RESOURCE = i18nc("Resource type sub resource", "Sub Resource");
63 RESOURCE_TYPE_OBJECT = i18nc("Resource type object", "Object");
64 RESOURCE_TYPE_MEDIA = i18nc("Resource type media", "Media");
65 RESOURCE_TYPE_WORKER = i18nc("Resource type worker", "Worker");
66 RESOURCE_TYPE_SHARED_WORKER = i18nc("Resource type shared worker", "Shared Worker");
67 RESOURCE_TYPE_PREFETCH = i18nc("Resource type prefetch", "Prefetch");
68 RESOURCE_TYPE_FAVICON = i18nc("Resource type favicon", "Favicon");
69 RESOURCE_TYPE_XHR = i18nc("Resource type XML HTTP request", "XML HTTP Request");
70 RESOURCE_TYPE_PING = i18nc("Resource type HTTP ping", "HTTP Ping");
71 RESOURCE_TYPE_SERVICE_WORKER = i18nc("Resource type service worker", "Service Worker");
72 RESOURCE_TYPE_CSP_REPORT = i18nc("Resource type content security policy report", "Content Security Policy Report");
73 RESOURCE_TYPE_PLUGIN_RESOURCE = i18nc("Resource type plugin request", "Plugin Request");
74 RESOURCE_TYPE_NAVIGATION_PRELOAD_MAIN_FRAME = i18nc("Resource type preload main frame", "Preload Main Frame");
75 RESOURCE_TYPE_NAVIGATION_PRELOAD_SUB_FRAME = i18nc("Resource type preload sub frame", "Preload Sub Frame");
76 RESOURCE_TYPE_UNKNOWN = i18nc("Resource type unknown", "Unknown");
78 // Populate the translated sublist strings. Translated entries cannot be public static const.
79 MAIN_ALLOWLIST_STRING = i18nc("Main allowlist sublist", "Main Allow List");
80 MAIN_BLOCKLIST_STRING = i18nc("Main blocklist sublist", "Main Block List");
81 INITIAL_DOMAIN_BLOCKLIST_STRING = i18nc("Initial domain blocklist string", "Initial Domain Block List");
82 REGULAR_EXPRESSION_BLOCKLIST_STRING = i18nc("Regular expression blocklist string", "Regular Expression Block List");
84 // Populate the filter lists.
85 ultraPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/ultraprivacy.txt"));
86 ultraListStructPointer = populateFilterList(QLatin1String(":/filterlists/ultralist.txt"));
87 easyPrivacyStructPointer = populateFilterList(QLatin1String(":/filterlists/easyprivacy.txt"));
88 easyListStructPointer = populateFilterList(QLatin1String(":/filterlists/easylist.txt"));
89 fanboyAnnoyanceStructPointer = populateFilterList(QLatin1String(":/filterlists/fanboy-annoyance.txt"));
92 bool FilterListHelper::checkFilterLists(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer) const
94 // Initiate a continue checking tracker. If the tracker changes to false, all processing of the request will be stopped.
95 bool continueChecking = true;
97 // Create a URL struct.
101 QUrl firstPartyUrl = urlRequestInfo.firstPartyUrl();
102 QUrl requestUrl = urlRequestInfo.requestUrl();
105 QString firstPartyHost = firstPartyUrl.host();
106 urlStruct.fqdn = requestUrl.host();
108 // Determine if this is a third-party request.
109 urlStruct.isThirdPartyRequest = (firstPartyHost != urlStruct.fqdn);
111 // Get the request URL string.
112 urlStruct.urlString = requestUrl.toString();
114 // Create a URL string with separators.
115 urlStruct.urlStringWithSeparators = urlStruct.urlString;
117 // Replace the separators characters with `^`.
118 urlStruct.urlStringWithSeparators.replace(QLatin1Char(':'), QLatin1Char('^'));
119 urlStruct.urlStringWithSeparators.replace(QLatin1Char('/'), QLatin1Char('^'));
120 urlStruct.urlStringWithSeparators.replace(QLatin1Char('?'), QLatin1Char('^'));
121 urlStruct.urlStringWithSeparators.replace(QLatin1Char('='), QLatin1Char('^'));
122 urlStruct.urlStringWithSeparators.replace(QLatin1Char('&'), QLatin1Char('^'));
124 // Add a `^` to the end of the string it it doesn't already contain one.
125 if (!urlStruct.urlStringWithSeparators.endsWith(QLatin1Char('^')))
126 urlStruct.urlStringWithSeparators.append(QLatin1Char('^'));
128 // Create truncated URL strings and initially populate it with the original URL strings.
129 urlStruct.truncatedUrlString = urlStruct.urlString;
130 urlStruct.truncatedUrlStringWithSeparators = urlStruct.urlStringWithSeparators;
132 // Get the index of the beginning of the fully qualified domain name.
133 int fqdnIndex = urlStruct.truncatedUrlString.indexOf(QLatin1String("://")) + 3;
135 // Truncate the URL to the beginning of the fully qualified domain name.
136 urlStruct.truncatedUrlString.remove(0, fqdnIndex);
137 urlStruct.truncatedUrlStringWithSeparators.remove(0, fqdnIndex);
140 continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraPrivacyStructPointer);
142 // Check UltraPrivacy.
143 if (continueChecking)
144 continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, ultraListStructPointer);
146 // Check EasyPrivacy.
147 if (continueChecking)
148 continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyPrivacyStructPointer);
151 if (continueChecking)
152 continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, easyListStructPointer);
154 // Check Fanboy's Annoyance list.
155 if (continueChecking)
156 continueChecking = checkIndividualList(urlRequestInfo, urlStruct, requestStructPointer, fanboyAnnoyanceStructPointer);
158 // Return the continue checking status.
159 return continueChecking;
162 bool FilterListHelper::checkIndividualList(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, FilterListStruct *filterListStructPointer) const
164 // Initiate a continue checking tracker. If the tracker changes to false, all process of the request will be stopped.
165 bool continueChecking = true;
167 // Check the main allow list.
168 for (auto filterListEntry = filterListStructPointer->mainAllowListPointer->begin(); filterListEntry != filterListStructPointer->mainAllowListPointer->end(); ++filterListEntry)
170 // Get the entry struct.
171 EntryStruct *entryStructPointer = *filterListEntry;
173 // TODO. Temporarily ignore empty applied entries.
174 if (!entryStructPointer->appliedEntryList[0].isEmpty())
176 // Check if the URL string contains the applied entry. TODO.
177 if (urlStruct.urlString.contains(entryStructPointer->appliedEntryList[0]) || urlStruct.urlStringWithSeparators.contains(entryStructPointer->appliedEntryList[0]))
179 // Allow the request.
180 urlRequestInfo.block(false);
182 // Populate the request struct.
183 populateRequestStruct(requestStructPointer, ALLOWED, filterListStructPointer->title, MAIN_ALLOWLIST, entryStructPointer);
186 //qDebug().noquote().nospace() << "Allowed request: " << urlStruct.urlString << ", Filter list entry: " << entryStructPointer->appliedEntry;
188 // Returning `false` stops all processing of the request.
194 // Get the main block list end.
195 auto mainBlockListEnd = filterListStructPointer->mainBlockListPointer->end();
197 // Check the main block list.
198 for (auto mainBlockListEntry = filterListStructPointer->mainBlockListPointer->begin(); mainBlockListEntry != mainBlockListEnd; ++mainBlockListEntry)
200 // Exit the loop if continue checking is false.
201 if (!continueChecking)
204 // Get the entry struct.
205 EntryStruct *entryStructPointer = *mainBlockListEntry;
207 // Check the applied entries.
208 continueChecking = checkAppliedEntry(urlRequestInfo, urlStruct, requestStructPointer, filterListStructPointer->title, MAIN_BLOCKLIST, entryStructPointer, urlStruct.urlString,
209 urlStruct.urlStringWithSeparators);
212 // Get the initial domain block list end.
213 auto initialDomainBlockListEnd = filterListStructPointer->initialDomainBlockListPointer->end();
215 // Check the initial domain block list.
216 for (auto initialDomainBlockListEntry = filterListStructPointer->initialDomainBlockListPointer->begin(); initialDomainBlockListEntry != initialDomainBlockListEnd;
217 ++initialDomainBlockListEntry)
219 // Exit the loop if continue checking is false.
220 if (!continueChecking)
223 // Get the entry struct.
224 EntryStruct *entryStructPointer = *initialDomainBlockListEntry;
226 // Check the applied entries.
227 continueChecking = checkAppliedEntry(urlRequestInfo, urlStruct, requestStructPointer, filterListStructPointer->title, INITIAL_DOMAIN_BLOCKLIST, entryStructPointer,
228 urlStruct.truncatedUrlString, urlStruct.truncatedUrlStringWithSeparators);
231 // Get the regular expression block list end.
232 auto regularExpressionBlockListEnd = filterListStructPointer->regularExpressionBlockListPointer->end();
234 // Check the regular expression block list.
235 for (auto regularExpressionBlockListEntry = filterListStructPointer->regularExpressionBlockListPointer->begin(); regularExpressionBlockListEntry != regularExpressionBlockListEnd;
236 ++regularExpressionBlockListEntry)
238 // Exit the loop if continue checking is false.
239 if (!continueChecking)
242 // Get the entry struct.
243 EntryStruct *entryStructPointer = *regularExpressionBlockListEntry;
245 // Check the applied entries.
246 continueChecking = checkRegularExpression(urlRequestInfo, urlStruct, requestStructPointer, filterListStructPointer->title, REGULAR_EXPRESSION_BLOCKLIST, entryStructPointer);
249 // Return the continue checking status.
250 return continueChecking;
253 bool FilterListHelper::checkAppliedEntry(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle,
254 const int sublistInt, EntryStruct *entryStructPointer, QString &urlString, QString &urlStringWithSeparators) const
256 // Check the entries according to the number.
257 if (entryStructPointer->singleAppliedEntry)
259 // Process initial and final matches.
260 if (entryStructPointer->initialMatch && entryStructPointer->finalMatch) // This is both an initial and final match.
262 // Check the URL against the applied entry.
263 if ((urlString == entryStructPointer->appliedEntryList[0]) || (urlStringWithSeparators == entryStructPointer->appliedEntryList[0]))
265 // Check the domain status.
266 return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
269 else if (entryStructPointer->initialMatch) // This is an initial match.
271 // Check the URL against the applied entry.
272 if (urlString.startsWith(entryStructPointer->appliedEntryList[0]) || urlStringWithSeparators.startsWith(entryStructPointer->appliedEntryList[0]))
274 // Check the domain status.
275 return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
278 else if (entryStructPointer->finalMatch) // This is a final match.
280 // Check the URL against the applied entry.
281 if (urlString.endsWith(entryStructPointer->appliedEntryList[0]) || urlStringWithSeparators.endsWith(entryStructPointer->appliedEntryList[0]))
283 // Check the domain status.
284 return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
287 else // There is no initial or final matching.
289 // Check if the URL string contains the applied entry.
290 if (urlString.contains(entryStructPointer->appliedEntryList[0]) || urlStringWithSeparators.contains(entryStructPointer->appliedEntryList[0]))
292 // Check the domain status.
293 return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
297 else // There are multiple entries.
299 // Create a URL matches flag.
300 bool urlMatches = true;
302 // Process initial and final matches.
303 if (entryStructPointer->initialMatch && entryStructPointer->finalMatch) // This is both an initial and final match.
305 // Check the first entry.
306 if (urlString.startsWith(entryStructPointer->appliedEntryList[0]) ||
307 urlStringWithSeparators.startsWith(entryStructPointer->appliedEntryList[0])) // The URL string starts with the first applied entry.
309 // Get the number of characters to remove from the front of the URL strings.
310 int charactersToRemove = entryStructPointer->appliedEntryList[0].size();
312 // Remove the entry from the front of the URL string copies.
313 urlString.remove(0, charactersToRemove);
314 urlStringWithSeparators.remove(0, charactersToRemove);
316 else // The URL string does not end with the last applied entry.
318 // Mark the URL matches flag as false.
322 // Check the other entries if the URL still matches.
325 // Calculate the penultimate entry.
326 int penultimateEntryNumber = (entryStructPointer->sizeOfAppliedEntryList - 1);
327 int ultimateEntryIndex = penultimateEntryNumber;
329 // Check all the middle entries.
330 for (int i = 1; i < penultimateEntryNumber; ++i)
332 // Get the index of the applied entry, which will be `-1` if it doesn't exist.
333 int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]);
334 int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]);
336 // Get the larger of the two indexes.
337 int index = std::max(stringIndex, stringWithSeparatorsIndex);
339 // Check if the entry was found.
340 if (index >= 0) // The entry is contained in the URL string.
342 // Get the number of characters to remove from the front of the URL strings.
343 int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size();
345 // Remove the entry from the front of the URL string copies.
346 urlString.remove(0, charactersToRemove);
347 urlStringWithSeparators.remove(0, charactersToRemove);
349 else // The entry is not contained in the URL string.
351 // Mark the URL matches flag as false.
356 // Check the final entry if the URL still matches.
359 if (urlString.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex]) ||
360 urlStringWithSeparators.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex])) // The URL string ends with the last applied entry.
362 // There is no need to modify the URL string copies as no further checks will be performed.
364 else // The URL string does not end with the last applied entry.
366 // Mark the URL matches flag as false.
372 else if (entryStructPointer->initialMatch) // This is an initial match.
374 // Check the first entry.
375 if (urlString.startsWith(entryStructPointer->appliedEntryList[0]) ||
376 urlStringWithSeparators.startsWith(entryStructPointer->appliedEntryList[0])) // The URL string starts with the first applied entry.
378 // Get the number of characters to remove from the front of the URL strings.
379 int charactersToRemove = entryStructPointer->appliedEntryList[0].size();
381 // Remove the entry from the front of the URL string copies.
382 urlString.remove(0, charactersToRemove);
383 urlStringWithSeparators.remove(0, charactersToRemove);
385 else // The URL string does not end with the last applied entry.
387 // Mark the URL matches flag as false.
391 // Check the other entries if the URL still matches.
394 for (int i = 1; i < entryStructPointer->sizeOfAppliedEntryList; ++i)
396 // Get the index of the applied entry, which will be `-1` if it doesn't exist.
397 int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]);
398 int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]);
400 // Get the larger of the two indexes.
401 int index = std::max(stringIndex, stringWithSeparatorsIndex);
403 // Check if the entry was found.
404 if (index >= 0) // The entry is contained in the URL string.
406 // Get the number of characters to remove from the front of the URL strings.
407 int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size();
409 // Remove the entry from the front of the URL string copies.
410 urlString.remove(0, charactersToRemove);
411 urlStringWithSeparators.remove(0, charactersToRemove);
413 else // The entry is not contained in the URL string.
415 // Mark the URL matches flag as false.
421 else if (entryStructPointer->finalMatch) // This is a final match.
423 // Calculate the penultimate entry.
424 int penultimateEntryNumber = (entryStructPointer->sizeOfAppliedEntryList - 1);
425 int ultimateEntryIndex = penultimateEntryNumber;
427 // Check all the entries except the last one.
428 for (int i = 0; i < penultimateEntryNumber; ++i)
430 // Get the index of the applied entry, which will be `-1` if it doesn't exist.
431 int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]);
432 int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]);
434 // Get the larger of the two indexes.
435 int index = std::max(stringIndex, stringWithSeparatorsIndex);
437 // Check if the entry was found.
438 if (index >= 0) // The entry is contained in the URL string.
440 // Get the number of characters to remove from the front of the URL strings.
441 int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size();
443 // Remove the entry from the front of the URL string copies.
444 urlString.remove(0, charactersToRemove);
445 urlStringWithSeparators.remove(0, charactersToRemove);
447 else // The entry is not contained in the URL string.
449 // Mark the URL matches flag as false.
454 // Check the final entry if the URL still matches.
457 if (urlString.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex]) ||
458 urlStringWithSeparators.endsWith(entryStructPointer->appliedEntryList[ultimateEntryIndex])) // The URL string ends with the last applied entry.
460 // There is no need to modify the URL string copies as no further checks will be performed.
462 else // The URL string does not end with the last applied entry.
464 // Mark the URL matches flag as false.
469 else // There is no initial or final matching.
471 for (int i = 0; i < entryStructPointer->sizeOfAppliedEntryList; ++i)
473 // Get the index of the applied entry, which will be `-1` if it doesn't exist.
474 int stringIndex = urlString.indexOf(entryStructPointer->appliedEntryList[i]);
475 int stringWithSeparatorsIndex = urlStringWithSeparators.indexOf(entryStructPointer->appliedEntryList[i]);
477 // Get the larger of the two indexes.
478 int index = std::max(stringIndex, stringWithSeparatorsIndex);
480 // Check if the entry was found.
481 if (index >= 0) // The entry is contained in the URL string.
484 // Get the number of characters to remove from the front of the URL strings.
485 int charactersToRemove = index + entryStructPointer->appliedEntryList[i].size();
487 // Remove the entry from the front of the URL string copies.
488 urlString.remove(0, charactersToRemove);
489 urlStringWithSeparators.remove(0, charactersToRemove);
491 else // The entry is not contained in the URL string.
493 // Mark the URL matches flag as false.
499 // Check the domain status if the URL matches.
501 return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
504 // If the applied entry doesn't match, return `true` to continue processing the URL request.
508 bool FilterListHelper::checkRegularExpression(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle,
509 const int sublistInt, EntryStruct *entryStructPointer) const
511 // Create an applied entry regular expression.
512 QRegularExpression appliedEntryRegularExpression(entryStructPointer->appliedEntryList[0]);
514 // Check if the regular expression matches the applied entry.
515 if (urlStruct.urlString.contains(appliedEntryRegularExpression))
517 // Check the domain status.
518 return checkDomain(urlRequestInfo, urlStruct, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
521 // If the regular expression doesn't match, return `true` to continue processing the URL request.
525 bool FilterListHelper::checkDomain(QWebEngineUrlRequestInfo &urlRequestInfo, UrlStruct &urlStruct, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt,
526 EntryStruct *entryStructPointer) const
528 // Check domain status.
529 if (entryStructPointer->domain == FilterOptionEnum::Disposition::Null) // Ignore domain status.
531 // Check the third-party status.
532 return checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListTitle, sublistInt, entryStructPointer);
534 else if (entryStructPointer->domain == FilterOptionEnum::Disposition::Apply) // Block requests from listed domains.
536 // Check each domain.
537 foreach (QString blockedDomain, entryStructPointer->domainList)
539 // Check if the request came from a blocked domain.
540 if (urlStruct.fqdn.endsWith(blockedDomain))
542 // Check the third-party status.
543 return checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListTitle, sublistInt, entryStructPointer);
547 else if (entryStructPointer->domain == FilterOptionEnum::Disposition::Override) // Block domains that are not overridden.
549 // Create a block domain flag.
550 bool blockDomain = true;
552 // Check each overridden domain.
553 foreach (QString overriddenDomain, entryStructPointer->domainList)
555 // Check if the request came from an overridden domain.
556 if (urlStruct.fqdn.endsWith(overriddenDomain))
558 // Don't block the domain.
563 // Continue checking if the domain is blocked.
566 // Check the third-party status.
567 return checkThirdParty(urlRequestInfo, requestStructPointer, urlStruct.isThirdPartyRequest, filterListTitle, sublistInt, entryStructPointer);
571 // There is a domain specified that doesn't match this request. Return `true` to continue processing the URL request.
575 bool FilterListHelper::checkThirdParty(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const bool isThirdPartyRequest, const QString &filterListTitle,
576 const int sublistInt, EntryStruct *entryStructPointer) const
578 // Check third-party status.
579 if (entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Null) // Ignore third-party status.
581 // Check if request options are applied.
582 if (entryStructPointer->hasRequestOptions) // Request options are applied.
584 // Check the request options.
585 return checkRequestOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
587 else // Request options are not applied.
589 // Block the request.
590 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
593 else if ((entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Apply) && isThirdPartyRequest) // Block third-party request.
595 // Check if request options are applied.
596 if (entryStructPointer->hasRequestOptions) // Request options are applied.
598 // Check the request options.
599 return checkRequestOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
601 else // Request options are not applied.
603 // Block the request.
604 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
607 else if ((entryStructPointer->thirdParty == FilterOptionEnum::Disposition::Override) && !isThirdPartyRequest) // Block first-party requests.
609 // Check if request options are applied.
610 if (entryStructPointer->hasRequestOptions) // Request options are applied.
612 // Check the request options.
613 return checkRequestOptions(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
615 else // Request options are not applied.
617 // Block the request.
618 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
622 // The third-party option specified doesn't match this request. Return `true` to continue processing the URL request.
626 bool FilterListHelper::checkRequestOptions(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt,
627 EntryStruct *entryStructPointer) const
629 // Block font requests.
630 if ((entryStructPointer->font == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFontResource))
632 // Block the request.
633 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
636 // Block image requests.
637 if ((entryStructPointer->image == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeImage))
639 // Block the request.
640 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
643 // Block main frame requests.
644 if ((entryStructPointer->mainFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMainFrame) ||
645 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame)))
647 // Block the request.
648 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
651 // Block media requests.
652 if ((entryStructPointer->media == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeMedia))
654 // Block the request.
655 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
658 // Block object requests.
659 if ((entryStructPointer->object == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeObject))
661 // Block the request.
662 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
665 // Block other requests.
666 if ((entryStructPointer->other == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubResource) ||
667 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeWorker) ||
668 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSharedWorker) ||
669 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePrefetch) ||
670 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeFavicon) ||
671 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeServiceWorker) ||
672 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeCspReport) ||
673 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePluginResource) ||
674 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeUnknown)))
676 // Block the request.
677 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
680 // Block ping requests
681 if ((entryStructPointer->ping == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypePing))
683 // Block the request.
684 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
687 // Block script requests.
688 if ((entryStructPointer->script == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeScript))
690 // Block the request.
691 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
694 // Block style sheet requests.
695 if ((entryStructPointer->styleSheet == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeStylesheet))
697 // Block the request.
698 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
701 // Block sub resource requests.
702 if ((entryStructPointer->subFrame == FilterOptionEnum::Disposition::Apply) && ((requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeSubFrame) ||
703 (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame)))
705 // Block the request.
706 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
709 // Block XML HTTP requests.
710 if ((entryStructPointer->xmlHttpRequest == FilterOptionEnum::Disposition::Apply) && (requestStructPointer->resourceTypeInt == QWebEngineUrlRequestInfo::ResourceTypeXhr))
712 // Block the request.
713 return blockRequest(urlRequestInfo, requestStructPointer, filterListTitle, sublistInt, entryStructPointer);
716 // The request options specified don't match this request. Return `true` to continue processing the URL request.
720 bool FilterListHelper::blockRequest(QWebEngineUrlRequestInfo &urlRequestInfo, RequestStruct *requestStructPointer, const QString &filterListTitle, const int sublistInt,
721 EntryStruct *entryStructPointer) const
723 // Block the request.
724 urlRequestInfo.block(true);
726 // Populate the request struct.
727 populateRequestStruct(requestStructPointer, BLOCKED, filterListTitle, sublistInt, entryStructPointer);
730 //qDebug().noquote().nospace() << "Blocked request: " << urlRequestInfo.firstPartyUrl() << ", Filter list entry: " << entryStructPointer->appliedEntry;
732 // Returning `false` stops all processing of the request.
736 QString FilterListHelper::getDispositionString(int dispositionInt) const
738 // Return the translated disposition string.
739 switch (dispositionInt)
741 case ALLOWED: return ALLOWED_STRING;
742 case BLOCKED: return BLOCKED_STRING;
743 default: return DEFAULT_STRING;
747 QString FilterListHelper::getNavigationTypeString(int navigationTypeInt) const
749 // Return the translated navigation type string.
750 switch (navigationTypeInt)
752 case QWebEngineUrlRequestInfo::NavigationTypeLink: return NAVIGATION_TYPE_LINK;
753 case QWebEngineUrlRequestInfo::NavigationTypeTyped: return NAVIGATION_TYPE_TYPED;
754 case QWebEngineUrlRequestInfo::NavigationTypeFormSubmitted: return NAVIGATION_TYPE_FORM_SUBMITTED;
755 case QWebEngineUrlRequestInfo::NavigationTypeBackForward: return NAVIGATION_TYPE_BACK_FORWARD;
756 case QWebEngineUrlRequestInfo::NavigationTypeReload: return NAVIGATION_TYPE_RELOAD;
757 case QWebEngineUrlRequestInfo::NavigationTypeRedirect: return NAVIGATION_TYPE_REDIRECT;
758 default: return NAVIGATION_TYPE_OTHER;
762 QString FilterListHelper::getRequestOptionDispositionString(const FilterOptionEnum::Disposition filterOptionDisposition) const
764 // Return the translated filter option disposition string.
765 switch (filterOptionDisposition)
767 case FilterOptionEnum::Disposition::Apply: return FILTER_OPTION_APPLY;
768 case FilterOptionEnum::Disposition::Override: return FILTER_OPTION_OVERRIDE;
769 default: return FILTER_OPTION_NULL;
773 QString FilterListHelper::getResourceTypeString(int resourceTypeInt) const
775 // Return the translated resource type string.
776 switch (resourceTypeInt)
778 case QWebEngineUrlRequestInfo::ResourceTypeMainFrame: return RESOURCE_TYPE_MAIN_FRAME;
779 case QWebEngineUrlRequestInfo::ResourceTypeSubFrame: return RESOURCE_TYPE_SUB_FRAME;
780 case QWebEngineUrlRequestInfo::ResourceTypeStylesheet: return RESOURCE_TYPE_STYLESHEET;
781 case QWebEngineUrlRequestInfo::ResourceTypeScript: return RESOURCE_TYPE_SCRIPT;
782 case QWebEngineUrlRequestInfo::ResourceTypeImage: return RESOURCE_TYPE_IMAGE;
783 case QWebEngineUrlRequestInfo::ResourceTypeFontResource: return RESOURCE_TYPE_FONT_RESOURCE;
784 case QWebEngineUrlRequestInfo::ResourceTypeSubResource: return RESOURCE_TYPE_SUB_RESOURCE;
785 case QWebEngineUrlRequestInfo::ResourceTypeObject: return RESOURCE_TYPE_OBJECT;
786 case QWebEngineUrlRequestInfo::ResourceTypeMedia: return RESOURCE_TYPE_MEDIA;
787 case QWebEngineUrlRequestInfo::ResourceTypeWorker: return RESOURCE_TYPE_WORKER;
788 case QWebEngineUrlRequestInfo::ResourceTypeSharedWorker: return RESOURCE_TYPE_SHARED_WORKER;
789 case QWebEngineUrlRequestInfo::ResourceTypePrefetch: return RESOURCE_TYPE_PREFETCH;
790 case QWebEngineUrlRequestInfo::ResourceTypeFavicon: return RESOURCE_TYPE_FAVICON;
791 case QWebEngineUrlRequestInfo::ResourceTypeXhr: return RESOURCE_TYPE_XHR;
792 case QWebEngineUrlRequestInfo::ResourceTypePing: return RESOURCE_TYPE_PING;
793 case QWebEngineUrlRequestInfo::ResourceTypeServiceWorker: return RESOURCE_TYPE_SERVICE_WORKER;
794 case QWebEngineUrlRequestInfo::ResourceTypeCspReport: return RESOURCE_TYPE_CSP_REPORT;
795 case QWebEngineUrlRequestInfo::ResourceTypePluginResource: return RESOURCE_TYPE_PLUGIN_RESOURCE;
796 case QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadMainFrame: return RESOURCE_TYPE_NAVIGATION_PRELOAD_MAIN_FRAME;
797 case QWebEngineUrlRequestInfo::ResourceTypeNavigationPreloadSubFrame: return RESOURCE_TYPE_NAVIGATION_PRELOAD_SUB_FRAME;
798 default: return RESOURCE_TYPE_UNKNOWN;
802 QString FilterListHelper::getSublistName(int sublistInt) const
804 // Return the name of the requested sublist.
807 case MAIN_ALLOWLIST: return MAIN_ALLOWLIST_STRING;
808 case MAIN_BLOCKLIST: return MAIN_BLOCKLIST_STRING;
809 case INITIAL_DOMAIN_BLOCKLIST: return INITIAL_DOMAIN_BLOCKLIST_STRING;
810 case REGULAR_EXPRESSION_BLOCKLIST: return REGULAR_EXPRESSION_BLOCKLIST_STRING;
811 default: return QString(); // The default return should never be reached.
815 FilterListStruct* FilterListHelper::populateFilterList(const QString &filterListFileName) const
817 // Get the filter list file.
818 QFile filterListFile(filterListFileName);
820 // Open the filter list file.
821 filterListFile.open(QIODevice::ReadOnly);
823 // Create a filter list text stream.
824 QTextStream filterListTextStream(&filterListFile);
826 // Create a filter list struct.
827 FilterListStruct *filterListStructPointer = new FilterListStruct;
829 // Populate the filter list file name.
830 filterListStructPointer->filePath = filterListFileName;
832 // Create a filter list string.
833 QString filterListString;
835 // Process each line of the filter list.
836 while (filterListTextStream.readLineInto(&filterListString)) {
837 // Create an entry struct.
838 EntryStruct *entryStructPointer = new EntryStruct;
840 // Store the original entry.
841 entryStructPointer->originalEntry = filterListString;
843 // Process the entry.
844 if (filterListString.isEmpty()) // Ignore empty lines.
848 // Log the dropping of the line.
849 //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName << " (empty line).";
851 else if (filterListString.startsWith(QLatin1Char('['))) // The line starts with `[`, which is the file format.
855 // Log the dropping of the line.
856 //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName << " (file format).";
858 else if (filterListString.contains(QLatin1String("##")) ||
859 filterListString.contains(QLatin1String("#?#")) ||
860 filterListString.contains(QLatin1String("#@#")) ||
861 filterListString.contains(QLatin1String("#$#"))) // The line contains unimplemented content filtering.
865 // Log the dropping of the line.
866 //qDebug().noquote().nospace() << filterListString << " NOT added from " << filterListFileName << " (content filtering).";
868 else if (filterListString.startsWith(QLatin1Char('!'))) // The line starts with `!`, which are comments.
870 if (filterListString.startsWith(QLatin1String("! Title: "))) // The line contains the title.
872 // Add the title to the filter list struct.
873 filterListStructPointer->title = filterListString.remove(0, 9);
875 // Log the addition of the filter list title.
876 //qDebug().noquote().nospace() << "Filter list title: " << filterListString << " added from " << filterListFileName;
878 else if (filterListString.startsWith(QLatin1String("! Version: "))) // The line contains the version.
880 // Add the version to the filter list struct.
881 filterListStructPointer->version = filterListString.remove(0, 11);
883 // Log the addition of the filter list version.
884 //qDebug().noquote().nospace() << "Filter list version: " << filterListString << " added from " << filterListFileName;
889 // Log the dropping of the line.
890 //qDebug().noquote().nospace() << originalFilterListString << " NOT added from " << filterListFileName;
892 else // Process the filter options.
894 // Get the index of the last dollar sign.
895 int indexOfLastDollarSign = filterListString.lastIndexOf(QLatin1Char('$'));
897 // Process the filter options if they exist.
898 if (indexOfLastDollarSign > -1)
900 // Get the filter options.
901 entryStructPointer->originalFilterOptions = filterListString.section(QLatin1Char('$'), -1);
903 // Store the entry without the filter options as the filter list string.
904 filterListString.truncate(indexOfLastDollarSign);
906 // Split the filter options.
907 QStringList originalFilterOptionsList = entryStructPointer->originalFilterOptions.split(QLatin1Char(','));
909 // Create an applied filter options list.
910 QStringList appliedFilterOptionsList;
912 // Populate the applied filter options list.
913 foreach (QString filterOption, originalFilterOptionsList)
915 // Only add filter options that are handled by Privacy Browser.
916 if (!(filterOption.startsWith(QLatin1String("csp=")) ||
917 filterOption.startsWith(QLatin1String("method=")) ||
918 filterOption.startsWith(QLatin1String("redirect=")) ||
919 filterOption.startsWith(QLatin1String("rewrite="))))
920 appliedFilterOptionsList.append(filterOption);
923 // Store the applied filter options list.
924 entryStructPointer->appliedFilterOptionsList = appliedFilterOptionsList;
926 // Initialize an override struct.
927 OverrideStruct overrideStruct;
929 // Populate the filter options entries.
930 foreach (QString filterOption, appliedFilterOptionsList)
932 // Parse the filter options.
933 if (filterOption.startsWith(QLatin1String("domain="))) // Domain.
935 // Remove `domain=` from the filter option.
936 filterOption.remove(0, 7);
938 // Store the domain list.
939 entryStructPointer->domainList = filterOption.split(QLatin1Char('|'));
941 // Set the disposition.
942 if (entryStructPointer->domainList[0].startsWith(QLatin1Char('~'))) // Override domains.
944 // Populate the domain filter disposition.
945 entryStructPointer->domain = FilterOptionEnum::Disposition::Override;
947 // Remove the initial `~` from each domain.
948 entryStructPointer->domainList.replaceInStrings(QLatin1String("~"), QLatin1String(""));
950 else // Standard domains.
952 // Populate the domain filter disposition.
953 entryStructPointer->domain = FilterOptionEnum::Disposition::Apply;
956 else if (filterOption == QLatin1String("third-party")) // Third-party.
958 // Populate the third-party filter disposition.
959 entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Apply;
961 else if (filterOption == QLatin1String("~third-party")) // Third-party override.
963 // Populate the third-party filter disposition.
964 entryStructPointer->thirdParty = FilterOptionEnum::Disposition::Override;
966 else if ((filterOption == QLatin1String("document")) || (filterOption == QLatin1String("popup"))) // Document (and popup).
968 // Populate the main frame disposition.
969 entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply;
971 // Set the has request options flag.
972 entryStructPointer->hasRequestOptions = true;
974 else if (filterOption == QLatin1String("font")) // Font.
976 // Populate the font disposition.
977 entryStructPointer->font = FilterOptionEnum::Disposition::Apply;
979 // Set the has request options flag.
980 entryStructPointer->hasRequestOptions = true;
982 else if (filterOption == QLatin1String("image")) // Image.
984 // Populate the image disposition.
985 entryStructPointer->image = FilterOptionEnum::Disposition::Apply;
987 // Set the has request options flag.
988 entryStructPointer->hasRequestOptions = true;
990 else if (filterOption == QLatin1String("media")) // Media.
992 // Populate the media disposition.
993 entryStructPointer->media = FilterOptionEnum::Disposition::Apply;
995 // Set the has request options flag.
996 entryStructPointer->hasRequestOptions = true;
998 else if (filterOption == QLatin1String("object")) // Object.
1000 // Populate the object disposition.
1001 entryStructPointer->object = FilterOptionEnum::Disposition::Apply;
1003 // Set the has request options flag.
1004 entryStructPointer->hasRequestOptions = true;
1006 else if ((filterOption == QLatin1String("other")) || (filterOption == QLatin1String("webrtc")) || (filterOption == QLatin1String("websocket"))) // Other.
1007 { // `websocket` will get its own section in Qt6.
1008 // Populate the other disposition.
1009 entryStructPointer->other = FilterOptionEnum::Disposition::Apply;
1011 // Set the has request options flag.
1012 entryStructPointer->hasRequestOptions = true;
1014 else if (filterOption == QLatin1String("ping")) // Ping.
1016 // Populate the ping disposition.
1017 entryStructPointer->ping = FilterOptionEnum::Disposition::Apply;
1019 // Set the has request options flag.
1020 entryStructPointer->hasRequestOptions = true;
1022 else if (filterOption == QLatin1String("script")) // Script.
1024 // Populate the script disposition.
1025 entryStructPointer->script = FilterOptionEnum::Disposition::Apply;
1027 // Set the has request options flag.
1028 entryStructPointer->hasRequestOptions = true;
1030 else if (filterOption == QLatin1String("stylesheet")) // Style sheet.
1032 // Populate the script disposition.
1033 entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply;
1035 // Set the has request options flag.
1036 entryStructPointer->hasRequestOptions = true;
1038 else if (filterOption == QLatin1String("subdocument")) // Sub document.
1040 // Populate the sub resource disposition.
1041 entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply;
1043 // Set the has request options flag.
1044 entryStructPointer->hasRequestOptions = true;
1046 else if (filterOption == QLatin1String("xmlhttprequest")) // XML HTTP request.
1048 //Populate the XML HTTP request disposition.
1049 entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply;
1051 // Set the has request options flag.
1052 entryStructPointer->hasRequestOptions = true;
1054 else if (filterOption == QLatin1String("~document")) // Document override.
1056 // Populate the override struct.
1057 overrideStruct.hasOverride = true;
1058 overrideStruct.mainFrame = true;
1060 else if (filterOption == QLatin1String("~font")) // Font override.
1062 // Populate the override struct.
1063 overrideStruct.hasOverride = true;
1064 overrideStruct.font = true;
1066 else if (filterOption == QLatin1String("~image")) // Image override.
1068 // Populate the override struct.
1069 overrideStruct.hasOverride = true;
1070 overrideStruct.image = true;
1072 else if (filterOption == QLatin1String("~media")) // Media override.
1074 // Populate the override struct.
1075 overrideStruct.hasOverride = true;
1076 overrideStruct.media = true;
1078 else if (filterOption == QLatin1String("~object")) // Object override.
1080 // Populate the override struct.
1081 overrideStruct.hasOverride = true;
1082 overrideStruct.object = true;
1084 else if ((filterOption == QLatin1String("~other")) || (filterOption == QLatin1String("~webrtc")) || (filterOption == QLatin1String("~websocket"))) // Other override.
1085 { // `websocket` will get its own section in Qt6.
1086 // Populate the override struct.
1087 overrideStruct.hasOverride = true;
1088 overrideStruct.other = true;
1090 else if (filterOption == QLatin1String("~ping")) // Ping override.
1092 // Populate the override struct.
1093 overrideStruct.hasOverride = true;
1094 overrideStruct.ping = true;
1096 else if (filterOption == QLatin1String("~script")) // Script override.
1098 // Populate the override struct.
1099 overrideStruct.hasOverride = true;
1100 overrideStruct.script = true;
1102 else if (filterOption == QLatin1String("~stylesheet")) // Style sheet override.
1104 // Populate the override struct.
1105 overrideStruct.hasOverride = true;
1106 overrideStruct.styleSheet = true;
1108 else if (filterOption == QLatin1String("~subdocument")) // Sub document override.
1110 // Populate the override struct.
1111 overrideStruct.hasOverride = true;
1112 overrideStruct.subFrame = true;
1114 else if (filterOption == QLatin1String("~xmlhttprequest")) // XML HTTP request override.
1116 // Populate the override struct.
1117 overrideStruct.hasOverride = true;
1118 overrideStruct.xmlHttpRequest = true;
1122 // Apply the overrides.
1123 if (overrideStruct.hasOverride)
1125 // Set the has request options flag.
1126 entryStructPointer->hasRequestOptions = true;
1129 if (overrideStruct.font)
1130 entryStructPointer->font = FilterOptionEnum::Disposition::Override;
1132 entryStructPointer->font = FilterOptionEnum::Disposition::Apply;
1135 if (overrideStruct.image)
1136 entryStructPointer->image = FilterOptionEnum::Disposition::Override;
1138 entryStructPointer->image = FilterOptionEnum::Disposition::Apply;
1140 // Main Frame (document).
1141 if (overrideStruct.mainFrame)
1142 entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Override;
1144 entryStructPointer->mainFrame = FilterOptionEnum::Disposition::Apply;
1147 if (overrideStruct.media)
1148 entryStructPointer->media = FilterOptionEnum::Disposition::Override;
1150 entryStructPointer->media = FilterOptionEnum::Disposition::Apply;
1153 if (overrideStruct.object)
1154 entryStructPointer->object = FilterOptionEnum::Disposition::Override;
1156 entryStructPointer->object = FilterOptionEnum::Disposition::Apply;
1159 if (overrideStruct.other)
1160 entryStructPointer->other = FilterOptionEnum::Disposition::Override;
1162 entryStructPointer->other = FilterOptionEnum::Disposition::Apply;
1165 if (overrideStruct.ping)
1166 entryStructPointer->ping = FilterOptionEnum::Disposition::Override;
1168 entryStructPointer->ping = FilterOptionEnum::Disposition::Apply;
1171 if (overrideStruct.script)
1172 entryStructPointer->script = FilterOptionEnum::Disposition::Override;
1174 entryStructPointer->script = FilterOptionEnum::Disposition::Apply;
1177 if (overrideStruct.styleSheet)
1178 entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Override;
1180 entryStructPointer->styleSheet = FilterOptionEnum::Disposition::Apply;
1183 if (overrideStruct.subFrame)
1184 entryStructPointer->subFrame = FilterOptionEnum::Disposition::Override;
1186 entryStructPointer->subFrame = FilterOptionEnum::Disposition::Apply;
1188 // XML HTTP Request.
1189 if (overrideStruct.xmlHttpRequest)
1190 entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Override;
1192 entryStructPointer->xmlHttpRequest = FilterOptionEnum::Disposition::Apply;
1194 } // Finish processing filter options.
1197 if (filterListString.isEmpty() && !entryStructPointer->hasRequestOptions) // There are no applied entries and no request options.
1199 // Ignore these entries as they will block all requests generally or for a specified domain. Typically these are left over after removing `csp=` filter options.
1201 // Log the dropping of the entry.
1202 //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " NOT added from " << filterListFileName << ".";
1204 else if (filterListString.startsWith(QLatin1String("@@"))) // Process an allow list entry.
1206 // Remove the initial `@@`.
1207 filterListString.remove(0, 2);
1209 // Prepare the filter list string. TODO. Initial allow lists must be processed first.
1210 prepareFilterListString(filterListString, entryStructPointer);
1212 // Add the entry struct to the main allow list.
1213 filterListStructPointer->mainAllowListPointer->push_front(entryStructPointer);
1215 // Log the addition to the filter list.
1216 //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Main Allow List from " << filterListFileName << ".";
1218 else if (filterListString.startsWith(QLatin1String("||"))) // Process an initial domain block list entry.
1220 // Remove the initial `||`.
1221 filterListString.remove(0, 2);
1223 // Set the initial match flag.
1224 entryStructPointer->initialMatch = true;
1226 // Prepare the filter list string.
1227 prepareFilterListString(filterListString, entryStructPointer);
1229 // Add the entry struct to the initial domain block list.
1230 filterListStructPointer->initialDomainBlockListPointer->push_front(entryStructPointer);
1232 // Log the addition to the filter list.
1233 //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Initial Domain Block List from " << filterListFileName << ".";
1235 else if (filterListString.contains(QLatin1String("\\"))) // Process a regular expression block list entry.
1237 // Add the regular expression to the applied entry list.
1238 entryStructPointer->appliedEntryList.append(filterListString);
1240 // Add the entry struct to the regular expression block list.
1241 filterListStructPointer->regularExpressionBlockListPointer->push_front(entryStructPointer);
1243 else // Process a main block list entry.
1245 // Prepare the filter list string.
1246 prepareFilterListString(filterListString, entryStructPointer);
1248 // Add the entry struct to the main block list.
1249 filterListStructPointer->mainBlockListPointer->push_front(entryStructPointer);
1251 // Log the addition to the filter list.
1252 //qDebug().noquote().nospace() << entryStructPointer->originalEntry << " added to Main Block List from " << filterListFileName << ".";
1257 // Close the filter list file.
1258 filterListFile.close();
1260 // Return the filter list pair.
1261 return filterListStructPointer;
1264 void FilterListHelper::populateRequestStruct(RequestStruct *requestStructPointer, const int disposition, const QString &filterListTitle, const int sublistInt, EntryStruct *entryStructPointer) const
1266 // Populate the request struct.
1267 requestStructPointer->dispositionInt = disposition;
1268 requestStructPointer->filterListTitle = filterListTitle;
1269 requestStructPointer->sublistInt = sublistInt;
1270 requestStructPointer->entryStruct.appliedEntryList = entryStructPointer->appliedEntryList;
1271 requestStructPointer->entryStruct.originalEntry = entryStructPointer->originalEntry;
1274 void FilterListHelper::prepareFilterListString(QString &filterListString, EntryStruct *entryStructPointer) const
1276 // Check if this is an initial match.
1277 if (filterListString.startsWith(QLatin1Char('|')))
1279 // Strip the initial `|`.
1280 filterListString.remove(0, 1);
1282 // Set the initial match flag.
1283 entryStructPointer->initialMatch = true;
1286 // Check if this is a final match.
1287 if (filterListString.endsWith(QLatin1Char('|')))
1289 // Strip the final `|`.
1290 filterListString.chop(1);
1292 // Set the final match flag.
1293 entryStructPointer->finalMatch = true;
1296 // Remove the initial asterisk if it exists.
1297 if (filterListString.startsWith(QLatin1Char('*')))
1298 filterListString.remove(0, 1);
1300 // Remove the final asterisk if it exists.
1301 if (filterListString.endsWith(QLatin1Char('*')))
1302 filterListString.chop(1);
1304 // Split the filter list string and set it as the applied entry list.
1305 entryStructPointer->appliedEntryList = filterListString.split(QLatin1Char('*'));
1307 // Store the size of the applied entry list.
1308 entryStructPointer->sizeOfAppliedEntryList = entryStructPointer->appliedEntryList.size();
1310 // Determine if this is a single applied entry (including an empty entry).
1311 entryStructPointer->singleAppliedEntry = (entryStructPointer->sizeOfAppliedEntryList == 1);