Added regexps work on adblocks.

This commit is contained in:
Martin Rotter 2017-07-19 13:39:20 +02:00
parent 566b03df76
commit 7c56d66492
9 changed files with 308 additions and 298 deletions

View file

@ -334,8 +334,7 @@ HEADERS += src/core/feeddownloader.h \
src/core/messagesmodelsqllayer.h \ src/core/messagesmodelsqllayer.h \
src/gui/treeviewcolumnsmenu.h \ src/gui/treeviewcolumnsmenu.h \
src/services/abstract/labelsrootitem.h \ src/services/abstract/labelsrootitem.h \
src/services/abstract/label.h \ src/services/abstract/label.h
src/gui/clickablelabel.h
SOURCES += src/core/feeddownloader.cpp \ SOURCES += src/core/feeddownloader.cpp \
src/core/feedsmodel.cpp \ src/core/feedsmodel.cpp \
@ -461,8 +460,7 @@ SOURCES += src/core/feeddownloader.cpp \
src/core/messagesmodelsqllayer.cpp \ src/core/messagesmodelsqllayer.cpp \
src/gui/treeviewcolumnsmenu.cpp \ src/gui/treeviewcolumnsmenu.cpp \
src/services/abstract/labelsrootitem.cpp \ src/services/abstract/labelsrootitem.cpp \
src/services/abstract/label.cpp \ src/services/abstract/label.cpp
src/gui/clickablelabel.cpp
OBJECTIVE_SOURCES += src/miscellaneous/disablewindowtabbing.mm OBJECTIVE_SOURCES += src/miscellaneous/disablewindowtabbing.mm
@ -518,7 +516,9 @@ equals(USE_WEBENGINE, true) {
src/network-web/adblock/adblocktreewidget.h \ src/network-web/adblock/adblocktreewidget.h \
src/network-web/adblock/adblockurlinterceptor.h \ src/network-web/adblock/adblockurlinterceptor.h \
src/network-web/urlinterceptor.h \ src/network-web/urlinterceptor.h \
src/network-web/networkurlinterceptor.h src/network-web/networkurlinterceptor.h \
src/gui/clickablelabel.h \
src/miscellaneous/simpleregexp.h
SOURCES += src/network-web/adblock/adblockaddsubscriptiondialog.cpp \ SOURCES += src/network-web/adblock/adblockaddsubscriptiondialog.cpp \
src/network-web/adblock/adblockdialog.cpp \ src/network-web/adblock/adblockdialog.cpp \
@ -530,7 +530,9 @@ equals(USE_WEBENGINE, true) {
src/network-web/adblock/adblocksubscription.cpp \ src/network-web/adblock/adblocksubscription.cpp \
src/network-web/adblock/adblocktreewidget.cpp \ src/network-web/adblock/adblocktreewidget.cpp \
src/network-web/adblock/adblockurlinterceptor.cpp \ src/network-web/adblock/adblockurlinterceptor.cpp \
src/network-web/networkurlinterceptor.cpp src/network-web/networkurlinterceptor.cpp \
src/gui/clickablelabel.cpp \
src/miscellaneous/simpleregexp.cpp
FORMS += src/network-web/adblock/adblockaddsubscriptiondialog.ui \ FORMS += src/network-web/adblock/adblockaddsubscriptiondialog.ui \
src/network-web/adblock/adblockdialog.ui src/network-web/adblock/adblockdialog.ui

View file

@ -26,6 +26,8 @@
#define ARGUMENTS_LIST_SEPARATOR "\n" #define ARGUMENTS_LIST_SEPARATOR "\n"
#define ADBLOCK_CUSTOMLIST_NAME "customlist.txt"
#define ADBLOCK_LISTS_SUBDIRECTORY "adblock"
#define ADBLOCK_EASYLIST_URL "https://easylist-downloads.adblockplus.org/easylist.txt" #define ADBLOCK_EASYLIST_URL "https://easylist-downloads.adblockplus.org/easylist.txt"
#define DEFAULT_SQL_MESSAGES_FILTER "0 > 1" #define DEFAULT_SQL_MESSAGES_FILTER "0 > 1"
#define MAX_MULTICOLUMN_SORT_STATES 3 #define MAX_MULTICOLUMN_SORT_STATES 3

View file

@ -28,9 +28,15 @@
// AdBlock. // AdBlock.
DKEY AdBlock::ID = "adblock"; DKEY AdBlock::ID = "adblock";
DKEY AdBlock::DisabledRules = "disabled_rules";
DVALUE(QStringList) AdBlock::DisabledRulesDef = QStringList();
DKEY AdBlock::AdBlockEnabled = "enabled"; DKEY AdBlock::AdBlockEnabled = "enabled";
DVALUE(bool) AdBlock::AdBlockEnabledDef = false; DVALUE(bool) AdBlock::AdBlockEnabledDef = false;
DKEY AdBlock::LastUpdatedOn = "last_updated_on";
DVALUE(QDateTime) AdBlock::LastUpdatedOnDef = QDateTime();
// Feeds. // Feeds.
DKEY Feeds::ID = "feeds"; DKEY Feeds::ID = "feeds";

View file

@ -28,6 +28,7 @@
#include <QStringList> #include <QStringList>
#include <QColor> #include <QColor>
#include <QByteArray> #include <QByteArray>
#include <QDateTime>
#define KEY extern const char* #define KEY extern const char*
#define DKEY const char* #define DKEY const char*
@ -45,6 +46,12 @@ namespace AdBlock {
KEY AdBlockEnabled; KEY AdBlockEnabled;
VALUE(bool) AdBlockEnabledDef; VALUE(bool) AdBlockEnabledDef;
KEY DisabledRules;
VALUE(QStringList) DisabledRulesDef;
KEY LastUpdatedOn;
VALUE(QDateTime) LastUpdatedOnDef;
} }
// Feeds. // Feeds.

View file

@ -34,6 +34,7 @@
#include <QMutexLocker> #include <QMutexLocker>
#include <QSaveFile> #include <QSaveFile>
#include <QWebEngineUrlRequestInfo> #include <QWebEngineUrlRequestInfo>
#include <QWebEngineProfile>
Q_GLOBAL_STATIC(AdBlockManager, qz_adblock_manager) Q_GLOBAL_STATIC(AdBlockManager, qz_adblock_manager)
@ -170,9 +171,8 @@ AdBlockSubscription *AdBlockManager::addSubscription(const QString &title, const
return 0; return 0;
} }
QString fileName = QzTools::filterCharsFromFilename(title.toLower()) + ".txt"; QString fileName = title + QSL(".txt");
QString filePath = QzTools::ensureUniqueFilename(DataPaths::currentProfilePath() + "/adblock/" + fileName); QString filePath = storedListsPath() + QDir::separator() + fileName;
QByteArray data = QString("Title: %1\nUrl: %2\n[Adblock Plus 1.1.1]").arg(title, url).toLatin1(); QByteArray data = QString("Title: %1\nUrl: %2\n[Adblock Plus 1.1.1]").arg(title, url).toLatin1();
QSaveFile file(filePath); QSaveFile file(filePath);
@ -212,10 +212,9 @@ bool AdBlockManager::removeSubscription(AdBlockSubscription* subscription) {
return true; return true;
} }
AdBlockCustomList* AdBlockManager::customList() const AdBlockCustomList *AdBlockManager::customList() const {
{ foreach (AdBlockSubscription *subscription, m_subscriptions) {
foreach (AdBlockSubscription* subscription, m_subscriptions) { AdBlockCustomList *list = qobject_cast<AdBlockCustomList*>(subscription);
AdBlockCustomList* list = qobject_cast<AdBlockCustomList*>(subscription);
if (list) { if (list) {
return list; return list;
@ -225,43 +224,40 @@ AdBlockCustomList* AdBlockManager::customList() const
return 0; return 0;
} }
void AdBlockManager::load() QString AdBlockManager::storedListsPath() const {
{ return qApp->getUserDataPath() + QDir::separator() + ADBLOCK_LISTS_SUBDIRECTORY;
}
void AdBlockManager::load() {
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
if (m_loaded) { if (m_loaded) {
return; return;
} }
#ifdef ADBLOCK_DEBUG m_enabled = qApp->settings()->value(GROUP(AdBlock), SETTING(AdBlock::AdBlockEnabled)).toBool();
QElapsedTimer timer; m_disabledRules = qApp->settings()->value(GROUP(AdBlock), SETTING(AdBlock::DisabledRules)).toStringList();
timer.start(); QDateTime lastUpdate = qApp->settings()->value(GROUP(AdBlock), SETTING(AdBlock::LastUpdatedOn)).toDateTime();
#endif
Settings settings;
settings.beginGroup("AdBlock");
m_enabled = settings.value("enabled", m_enabled).toBool();
m_disabledRules = settings.value("disabledRules", QStringList()).toStringList();
QDateTime lastUpdate = settings.value("lastUpdate", QDateTime()).toDateTime();
settings.endGroup();
if (!m_enabled) { if (!m_enabled) {
return; return;
} }
QDir adblockDir(DataPaths::currentProfilePath() + "/adblock"); QDir adblockDir(storedListsPath());
// Create if neccessary // Create if neccessary
if (!adblockDir.exists()) { if (!adblockDir.exists()) {
QDir(DataPaths::currentProfilePath()).mkdir("adblock"); QDir().mkpath(storedListsPath());
} }
foreach (const QString &fileName, adblockDir.entryList(QStringList("*.txt"), QDir::Files)) { foreach (const QString &fileName, adblockDir.entryList(QStringList("*.txt"), QDir::Files)) {
if (fileName == QLatin1String("customlist.txt")) { if (fileName == ADBLOCK_CUSTOMLIST_NAME) {
continue; continue;
} }
const QString absolutePath = adblockDir.absoluteFilePath(fileName); const QString absolutePath = adblockDir.absoluteFilePath(fileName);
QFile file(absolutePath); QFile file(absolutePath);
if (!file.open(QFile::ReadOnly)) { if (!file.open(QFile::ReadOnly)) {
continue; continue;
} }
@ -272,7 +268,7 @@ void AdBlockManager::load()
QUrl url = QUrl(textStream.readLine(1024).remove(QLatin1String("Url: "))); QUrl url = QUrl(textStream.readLine(1024).remove(QLatin1String("Url: ")));
if (title.isEmpty() || !url.isValid()) { if (title.isEmpty() || !url.isValid()) {
qWarning() << "AdBlockManager: Invalid subscription file" << absolutePath; qWarning("Invalid AdBlock subscription file '%s'.", qPrintable(absolutePath));
continue; continue;
} }
@ -283,21 +279,22 @@ void AdBlockManager::load()
m_subscriptions.append(subscription); m_subscriptions.append(subscription);
} }
// Prepend EasyList if subscriptions are empty // Prepend EasyList if subscriptions are empty.
if (m_subscriptions.isEmpty()) { if (m_subscriptions.isEmpty()) {
AdBlockSubscription* easyList = new AdBlockSubscription(tr("EasyList"), this); AdBlockSubscription* easyList = new AdBlockSubscription(tr("EasyList"), this);
easyList->setUrl(QUrl(ADBLOCK_EASYLIST_URL)); easyList->setUrl(QUrl(ADBLOCK_EASYLIST_URL));
easyList->setFilePath(DataPaths::currentProfilePath() + QLatin1String("/adblock/easylist.txt")); easyList->setFilePath(storedListsPath() + QDir::separator() + QSL("easylist.txt"));
m_subscriptions.prepend(easyList); m_subscriptions.prepend(easyList);
} }
// Append CustomList // Append CustomList.
AdBlockCustomList* customList = new AdBlockCustomList(this); AdBlockCustomList* customList = new AdBlockCustomList(this);
m_subscriptions.append(customList); m_subscriptions.append(customList);
// Load all subscriptions // Load all subscriptions
foreach (AdBlockSubscription* subscription, m_subscriptions) { foreach (AdBlockSubscription *subscription, m_subscriptions) {
subscription->loadSubscription(m_disabledRules); subscription->loadSubscription(m_disabledRules);
connect(subscription, SIGNAL(subscriptionUpdated()), mApp, SLOT(reloadUserStyleSheet())); connect(subscription, SIGNAL(subscriptionUpdated()), mApp, SLOT(reloadUserStyleSheet()));
@ -308,88 +305,73 @@ void AdBlockManager::load()
QTimer::singleShot(1000 * 60, this, SLOT(updateAllSubscriptions())); QTimer::singleShot(1000 * 60, this, SLOT(updateAllSubscriptions()));
} }
#ifdef ADBLOCK_DEBUG
qDebug() << "AdBlock loaded in" << timer.elapsed();
#endif
m_matcher->update(); m_matcher->update();
m_loaded = true; m_loaded = true;
mApp->networkManager()->installUrlInterceptor(m_interceptor); // TODO: instalovat interceptor, asi dát tu logiku
// někam sem, nedávat třeba do Application
//mApp->networkManager()->installUrlInterceptor(m_interceptor);
} }
void AdBlockManager::updateMatcher() void AdBlockManager::updateMatcher() {
{
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
m_matcher->update(); m_matcher->update();
} }
void AdBlockManager::updateAllSubscriptions() void AdBlockManager::updateAllSubscriptions() {
{
foreach (AdBlockSubscription* subscription, m_subscriptions) { foreach (AdBlockSubscription* subscription, m_subscriptions) {
subscription->updateSubscription(); subscription->updateSubscription();
} }
Settings settings; qApp->settings()->setValue(GROUP(AdBlock), AdBlock::LastUpdatedOn, QDateTime::currentDateTime());
settings.beginGroup("AdBlock");
settings.setValue("lastUpdate", QDateTime::currentDateTime());
settings.endGroup();
} }
void AdBlockManager::save() void AdBlockManager::save() {
{
if (!m_loaded) { if (!m_loaded) {
return; return;
} }
foreach (AdBlockSubscription* subscription, m_subscriptions) { foreach (AdBlockSubscription *subscription, m_subscriptions) {
subscription->saveSubscription(); subscription->saveSubscription();
} }
Settings settings; qApp->settings()->setValue(GROUP(AdBlock), AdBlock::AdBlockEnabled, m_enabled);
settings.beginGroup("AdBlock"); qApp->settings()->setValue(GROUP(AdBlock), AdBlock::DisabledRules, m_disabledRules);
settings.setValue("enabled", m_enabled);
settings.setValue("disabledRules", m_disabledRules);
settings.endGroup();
} }
bool AdBlockManager::isEnabled() const bool AdBlockManager::isEnabled() const {
{
return m_enabled; return m_enabled;
} }
bool AdBlockManager::canRunOnScheme(const QString &scheme) const bool AdBlockManager::canRunOnScheme(const QString &scheme) const {
{ return !(scheme == QSL("file") || scheme == QSL("qrc") || scheme == QSL("data") || scheme == QSL("abp"));
return !(scheme == QLatin1String("file") || scheme == QLatin1String("qrc")
|| scheme == QLatin1String("qupzilla") || scheme == QLatin1String("data")
|| scheme == QLatin1String("abp"));
} }
bool AdBlockManager::canBeBlocked(const QUrl &url) const bool AdBlockManager::canBeBlocked(const QUrl &url) const {
{
return !m_matcher->adBlockDisabledForUrl(url); return !m_matcher->adBlockDisabledForUrl(url);
} }
QString AdBlockManager::elementHidingRules(const QUrl &url) const QString AdBlockManager::elementHidingRules(const QUrl &url) const {
{ if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url)) {
if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url))
return QString(); return QString();
}
return m_matcher->elementHidingRules(); else {
return m_matcher->elementHidingRules();
}
} }
QString AdBlockManager::elementHidingRulesForDomain(const QUrl &url) const QString AdBlockManager::elementHidingRulesForDomain(const QUrl &url) const {
{ if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url)) {
if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url))
return QString(); return QString();
}
return m_matcher->elementHidingRulesForDomain(url.host()); else {
return m_matcher->elementHidingRulesForDomain(url.host());
}
} }
AdBlockSubscription* AdBlockManager::subscriptionByName(const QString &name) const AdBlockSubscription* AdBlockManager::subscriptionByName(const QString &name) const {
{ foreach (AdBlockSubscription *subscription, m_subscriptions) {
foreach (AdBlockSubscription* subscription, m_subscriptions) {
if (subscription->title() == name) { if (subscription->title() == name) {
return subscription; return subscription;
} }
@ -398,8 +380,7 @@ AdBlockSubscription* AdBlockManager::subscriptionByName(const QString &name) con
return 0; return 0;
} }
AdBlockDialog* AdBlockManager::showDialog() AdBlockDialog *AdBlockManager::showDialog() {
{
if (!m_adBlockDialog) { if (!m_adBlockDialog) {
m_adBlockDialog = new AdBlockDialog; m_adBlockDialog = new AdBlockDialog;
} }
@ -411,10 +392,9 @@ AdBlockDialog* AdBlockManager::showDialog()
return m_adBlockDialog.data(); return m_adBlockDialog.data();
} }
void AdBlockManager::showRule() void AdBlockManager::showRule() {
{ if (QAction *action = qobject_cast<QAction*>(sender())) {
if (QAction* action = qobject_cast<QAction*>(sender())) { const AdBlockRule *rule = static_cast<const AdBlockRule*>(action->data().value<void*>());
const AdBlockRule* rule = static_cast<const AdBlockRule*>(action->data().value<void*>());
if (rule) { if (rule) {
showDialog()->showRule(rule); showDialog()->showRule(rule);

View file

@ -67,6 +67,8 @@ class AdBlockManager : public QObject {
AdBlockCustomList *customList() const; AdBlockCustomList *customList() const;
QString storedListsPath() const;
static AdBlockManager *instance(); static AdBlockManager *instance();
signals: signals:

View file

@ -16,205 +16,220 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with RSS Guard. If not, see <http://www.gnu.org/licenses/>. // along with RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "adblockmatcher.h" #include "network-web/adblock/adblockmatcher.h"
#include "adblockmanager.h" #include "network-web/adblock/adblockmanager.h"
#include "adblockrule.h" #include "network-web/adblock/adblockrule.h"
#include "adblocksubscription.h" #include "network-web/adblock/adblocksubscription.h"
#include "definitions/definitions.h"
AdBlockMatcher::AdBlockMatcher(AdBlockManager* manager) AdBlockMatcher::AdBlockMatcher(AdBlockManager* manager)
: QObject(manager) : QObject(manager), m_manager(manager) {
, m_manager(manager)
{
} }
AdBlockMatcher::~AdBlockMatcher() AdBlockMatcher::~AdBlockMatcher() {
{ clear();
clear();
} }
const AdBlockRule* AdBlockMatcher::match(const QWebEngineUrlRequestInfo &request, const QString &urlDomain, const QString &urlString) const const AdBlockRule* AdBlockMatcher::match(const QWebEngineUrlRequestInfo &request, const QString &urlDomain, const QString &urlString) const {
{ // Exception rules.
// Exception rules if (m_networkExceptionTree.find(request, urlDomain, urlString)) {
if (m_networkExceptionTree.find(request, urlDomain, urlString))
return 0;
int count = m_networkExceptionRules.count();
for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = m_networkExceptionRules.at(i);
if (rule->networkMatch(request, urlDomain, urlString))
return 0;
}
// Block rules
if (const AdBlockRule* rule = m_networkBlockTree.find(request, urlDomain, urlString))
return rule;
count = m_networkBlockRules.count();
for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = m_networkBlockRules.at(i);
if (rule->networkMatch(request, urlDomain, urlString))
return rule;
}
return 0; return 0;
}
int count = m_networkExceptionRules.count();
for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = m_networkExceptionRules.at(i);
if (rule->networkMatch(request, urlDomain, urlString)) {
return 0;
}
}
// Block rules.
if (const AdBlockRule* rule = m_networkBlockTree.find(request, urlDomain, urlString)) {
return rule;
}
count = m_networkBlockRules.count();
for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = m_networkBlockRules.at(i);
if (rule->networkMatch(request, urlDomain, urlString)) {
return rule;
}
}
return 0;
} }
bool AdBlockMatcher::adBlockDisabledForUrl(const QUrl &url) const bool AdBlockMatcher::adBlockDisabledForUrl(const QUrl &url) const {
{ int count = m_documentRules.count();
int count = m_documentRules.count();
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i) {
if (m_documentRules.at(i)->urlMatch(url)) if (m_documentRules.at(i)->urlMatch(url)) {
return true; return true;
}
}
return false; return false;
} }
bool AdBlockMatcher::elemHideDisabledForUrl(const QUrl &url) const bool AdBlockMatcher::elemHideDisabledForUrl(const QUrl &url) const {
{ if (adBlockDisabledForUrl(url)) {
if (adBlockDisabledForUrl(url)) return true;
return true; }
int count = m_elemhideRules.count(); int count = m_elemhideRules.count();
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i) {
if (m_elemhideRules.at(i)->urlMatch(url)) if (m_elemhideRules.at(i)->urlMatch(url)) {
return true; return true;
}
}
return false; return false;
} }
QString AdBlockMatcher::elementHidingRules() const QString AdBlockMatcher::elementHidingRules() const {
{ return m_elementHidingRules;
return m_elementHidingRules;
} }
QString AdBlockMatcher::elementHidingRulesForDomain(const QString &domain) const QString AdBlockMatcher::elementHidingRulesForDomain(const QString &domain) const {
{ QString rules;
QString rules; int addedRulesCount = 0;
int addedRulesCount = 0; int count = m_domainRestrictedCssRules.count();
int count = m_domainRestrictedCssRules.count();
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = m_domainRestrictedCssRules.at(i); const AdBlockRule* rule = m_domainRestrictedCssRules.at(i);
if (!rule->matchDomain(domain))
continue;
if (Q_UNLIKELY(addedRulesCount == 1000)) { if (!rule->matchDomain(domain)) {
rules.append(rule->cssSelector()); continue;
rules.append(QL1S("{display:none !important;}\n")); }
addedRulesCount = 0;
if (Q_UNLIKELY(addedRulesCount == 1000)) {
rules.append(rule->cssSelector());
rules.append(QSL("{display:none !important;}\n"));
addedRulesCount = 0;
}
else {
rules.append(rule->cssSelector() + QLatin1Char(','));
addedRulesCount++;
}
}
if (addedRulesCount != 0) {
rules = rules.left(rules.size() - 1);
rules.append(QSL("{display:none !important;}\n"));
}
return rules;
}
void AdBlockMatcher::update() {
clear();
QHash<QString, const AdBlockRule*> cssRulesHash;
QVector<const AdBlockRule*> exceptionCssRules;
foreach (AdBlockSubscription* subscription, m_manager->subscriptions()) {
foreach (const AdBlockRule* rule, subscription->allRules()) {
// Don't add internally disabled rules to cache.
if (rule->isInternalDisabled()) {
continue;
}
if (rule->isCssRule()) {
// We will add only enabled css rules to cache, because there is no enabled/disabled
// check on match. They are directly embedded to pages.
if (!rule->isEnabled()) {
continue;
}
if (rule->isException()) {
exceptionCssRules.append(rule);
} }
else { else {
rules.append(rule->cssSelector() + QLatin1Char(',')); cssRulesHash.insert(rule->cssSelector(), rule);
addedRulesCount++;
} }
}
else if (rule->isDocument()) {
m_documentRules.append(rule);
}
else if (rule->isElemhide()) {
m_elemhideRules.append(rule);
}
else if (rule->isException()) {
if (!m_networkExceptionTree.add(rule)) {
m_networkExceptionRules.append(rule);
}
}
else {
if (!m_networkBlockTree.add(rule)) {
m_networkBlockRules.append(rule);
}
}
}
}
foreach (const AdBlockRule *rule, exceptionCssRules) {
const AdBlockRule *originalRule = cssRulesHash.value(rule->cssSelector());
// If we don't have this selector, the exception does nothing
if (!originalRule) {
continue;
} }
if (addedRulesCount != 0) { AdBlockRule *copiedRule = originalRule->copy();
rules = rules.left(rules.size() - 1); copiedRule->m_options |= AdBlockRule::DomainRestrictedOption;
rules.append(QL1S("{display:none !important;}\n")); copiedRule->m_blockedDomains.append(rule->m_allowedDomains);
}
return rules; cssRulesHash[rule->cssSelector()] = copiedRule;
m_createdRules.append(copiedRule);
}
// Apparently, excessive amount of selectors for one CSS rule is not what WebKit likes.
// (In my testings, 4931 is the number that makes it crash)
// So let's split it by 1000 selectors...
int hidingRulesCount = 0;
QHashIterator<QString, const AdBlockRule*> it(cssRulesHash);
while (it.hasNext()) {
it.next();
const AdBlockRule *rule = it.value();
if (rule->isDomainRestricted()) {
m_domainRestrictedCssRules.append(rule);
}
else if (Q_UNLIKELY(hidingRulesCount == 1000)) {
m_elementHidingRules.append(rule->cssSelector());
m_elementHidingRules.append(QL1S("{display:none !important;} "));
hidingRulesCount = 0;
}
else {
m_elementHidingRules.append(rule->cssSelector() + QLatin1Char(','));
hidingRulesCount++;
}
}
if (hidingRulesCount != 0) {
m_elementHidingRules = m_elementHidingRules.left(m_elementHidingRules.size() - 1);
m_elementHidingRules.append(QL1S("{display:none !important;} "));
}
} }
void AdBlockMatcher::update() void AdBlockMatcher::clear() {
{ m_networkExceptionTree.clear();
clear(); m_networkExceptionRules.clear();
m_networkBlockTree.clear();
QHash<QString, const AdBlockRule*> cssRulesHash; m_networkBlockRules.clear();
QVector<const AdBlockRule*> exceptionCssRules; m_domainRestrictedCssRules.clear();
m_elementHidingRules.clear();
foreach (AdBlockSubscription* subscription, m_manager->subscriptions()) { m_documentRules.clear();
foreach (const AdBlockRule* rule, subscription->allRules()) { m_elemhideRules.clear();
// Don't add internally disabled rules to cache qDeleteAll(m_createdRules);
if (rule->isInternalDisabled()) m_createdRules.clear();
continue;
if (rule->isCssRule()) {
// We will add only enabled css rules to cache, because there is no enabled/disabled
// check on match. They are directly embedded to pages.
if (!rule->isEnabled())
continue;
if (rule->isException())
exceptionCssRules.append(rule);
else
cssRulesHash.insert(rule->cssSelector(), rule);
}
else if (rule->isDocument()) {
m_documentRules.append(rule);
}
else if (rule->isElemhide()) {
m_elemhideRules.append(rule);
}
else if (rule->isException()) {
if (!m_networkExceptionTree.add(rule))
m_networkExceptionRules.append(rule);
}
else {
if (!m_networkBlockTree.add(rule))
m_networkBlockRules.append(rule);
}
}
}
foreach (const AdBlockRule* rule, exceptionCssRules) {
const AdBlockRule* originalRule = cssRulesHash.value(rule->cssSelector());
// If we don't have this selector, the exception does nothing
if (!originalRule)
continue;
AdBlockRule* copiedRule = originalRule->copy();
copiedRule->m_options |= AdBlockRule::DomainRestrictedOption;
copiedRule->m_blockedDomains.append(rule->m_allowedDomains);
cssRulesHash[rule->cssSelector()] = copiedRule;
m_createdRules.append(copiedRule);
}
// Apparently, excessive amount of selectors for one CSS rule is not what WebKit likes.
// (In my testings, 4931 is the number that makes it crash)
// So let's split it by 1000 selectors...
int hidingRulesCount = 0;
QHashIterator<QString, const AdBlockRule*> it(cssRulesHash);
while (it.hasNext()) {
it.next();
const AdBlockRule* rule = it.value();
if (rule->isDomainRestricted()) {
m_domainRestrictedCssRules.append(rule);
}
else if (Q_UNLIKELY(hidingRulesCount == 1000)) {
m_elementHidingRules.append(rule->cssSelector());
m_elementHidingRules.append(QL1S("{display:none !important;} "));
hidingRulesCount = 0;
}
else {
m_elementHidingRules.append(rule->cssSelector() + QLatin1Char(','));
hidingRulesCount++;
}
}
if (hidingRulesCount != 0) {
m_elementHidingRules = m_elementHidingRules.left(m_elementHidingRules.size() - 1);
m_elementHidingRules.append(QL1S("{display:none !important;} "));
}
}
void AdBlockMatcher::clear()
{
m_networkExceptionTree.clear();
m_networkExceptionRules.clear();
m_networkBlockTree.clear();
m_networkBlockRules.clear();
m_domainRestrictedCssRules.clear();
m_elementHidingRules.clear();
m_documentRules.clear();
m_elemhideRules.clear();
qDeleteAll(m_createdRules);
m_createdRules.clear();
} }

View file

@ -22,20 +22,18 @@
#include <QUrl> #include <QUrl>
#include <QObject> #include <QObject>
#include "qzcommon.h" #include "network-web/adblock/adblocksearchtree.h"
#include "adblocksearchtree.h"
class QWebEngineUrlRequestInfo; class QWebEngineUrlRequestInfo;
class AdBlockManager; class AdBlockManager;
class QUPZILLA_EXPORT AdBlockMatcher : public QObject class AdBlockMatcher : public QObject {
{
Q_OBJECT Q_OBJECT
public: public:
explicit AdBlockMatcher(AdBlockManager* manager); explicit AdBlockMatcher(AdBlockManager* manager);
~AdBlockMatcher(); virtual ~AdBlockMatcher();
const AdBlockRule* match(const QWebEngineUrlRequestInfo &request, const QString &urlDomain, const QString &urlString) const; const AdBlockRule* match(const QWebEngineUrlRequestInfo &request, const QString &urlDomain, const QString &urlString) const;
@ -45,12 +43,12 @@ public:
QString elementHidingRules() const; QString elementHidingRules() const;
QString elementHidingRulesForDomain(const QString &domain) const; QString elementHidingRulesForDomain(const QString &domain) const;
public slots: public slots:
void update(); void update();
void clear(); void clear();
private: private:
AdBlockManager* m_manager; AdBlockManager *m_manager;
QVector<AdBlockRule*> m_createdRules; QVector<AdBlockRule*> m_createdRules;
QVector<const AdBlockRule*> m_networkExceptionRules; QVector<const AdBlockRule*> m_networkExceptionRules;

View file

@ -51,26 +51,24 @@
#include <QStringList> #include <QStringList>
#include <QStringMatcher> #include <QStringMatcher>
#include "qzcommon.h" #include "miscellaneous/simpleregexp.h"
#include "qzregexp.h"
class QUrl; class QUrl;
class QWebEngineUrlRequestInfo; class QWebEngineUrlRequestInfo;
class AdBlockSubscription; class AdBlockSubscription;
class QUPZILLA_EXPORT AdBlockRule class AdBlockRule {
{
Q_DISABLE_COPY(AdBlockRule) Q_DISABLE_COPY(AdBlockRule)
public: public:
AdBlockRule(const QString &filter = QString(), AdBlockSubscription* subscription = 0); explicit AdBlockRule(const QString &filter = QString(), AdBlockSubscription *subscription = 0);
~AdBlockRule(); virtual ~AdBlockRule();
AdBlockRule* copy() const; AdBlockRule *copy() const;
AdBlockSubscription* subscription() const; AdBlockSubscription *subscription() const;
void setSubscription(AdBlockSubscription* subscription); void setSubscription(AdBlockSubscription *subscription);
QString filter() const; QString filter() const;
void setFilter(const QString &filter); void setFilter(const QString &filter);
@ -104,36 +102,36 @@ public:
bool matchStyleSheet(const QWebEngineUrlRequestInfo &request) const; bool matchStyleSheet(const QWebEngineUrlRequestInfo &request) const;
bool matchObjectSubrequest(const QWebEngineUrlRequestInfo &request) const; bool matchObjectSubrequest(const QWebEngineUrlRequestInfo &request) const;
protected: protected:
bool stringMatch(const QString &domain, const QString &encodedUrl) const; bool stringMatch(const QString &domain, const QString &encodedUrl) const;
bool isMatchingDomain(const QString &domain, const QString &filter) const; bool isMatchingDomain(const QString &domain, const QString &filter) const;
bool isMatchingRegExpStrings(const QString &url) const; bool isMatchingRegExpStrings(const QString &url) const;
QStringList parseRegExpFilter(const QString &filter) const; QStringList parseRegExpFilter(const QString &filter) const;
private: private:
enum RuleType { enum RuleType {
CssRule = 0, CssRule = 0,
DomainMatchRule = 1, DomainMatchRule = 1,
RegExpMatchRule = 2, RegExpMatchRule = 2,
StringEndsMatchRule = 3, StringEndsMatchRule = 3,
StringContainsMatchRule = 4, StringContainsMatchRule = 4,
Invalid = 5 Invalid = 5
}; };
enum RuleOption { enum RuleOption {
DomainRestrictedOption = 1, DomainRestrictedOption = 1,
ThirdPartyOption = 2, ThirdPartyOption = 2,
ObjectOption = 4, ObjectOption = 4,
SubdocumentOption = 8, SubdocumentOption = 8,
XMLHttpRequestOption = 16, XMLHttpRequestOption = 16,
ImageOption = 32, ImageOption = 32,
ScriptOption = 64, ScriptOption = 64,
StyleSheetOption = 128, StyleSheetOption = 128,
ObjectSubrequestOption = 256, ObjectSubrequestOption = 256,
// Exception only options // Exception only options.
DocumentOption = 1024, DocumentOption = 1024,
ElementHideOption = 2048 ElementHideOption = 2048
}; };
Q_DECLARE_FLAGS(RuleOptions, RuleOption) Q_DECLARE_FLAGS(RuleOptions, RuleOption)
@ -151,7 +149,7 @@ private:
QString createRegExpFromFilter(const QString &filter) const; QString createRegExpFromFilter(const QString &filter) const;
QList<QStringMatcher> createStringMatchers(const QStringList &filters) const; QList<QStringMatcher> createStringMatchers(const QStringList &filters) const;
AdBlockSubscription* m_subscription; AdBlockSubscription *m_subscription;
RuleType m_type; RuleType m_type;
RuleOptions m_options; RuleOptions m_options;
@ -172,12 +170,12 @@ private:
QStringList m_blockedDomains; QStringList m_blockedDomains;
struct RegExp { struct RegExp {
QzRegExp regExp; SimpleRegExp regExp;
QList<QStringMatcher> matchers; QList<QStringMatcher> matchers;
}; };
// Use dynamic allocation to save memory // Use dynamic allocation to save memory
RegExp* m_regExp; RegExp *m_regExp;
friend class AdBlockMatcher; friend class AdBlockMatcher;
friend class AdBlockSearchTree; friend class AdBlockSearchTree;