diff --git a/plugins/webengineurlinterceptor/adblock/lib/adblockmatcher.cpp b/plugins/webengineurlinterceptor/adblock/lib/adblockmatcher.cpp index e2effae0..23924893 100644 --- a/plugins/webengineurlinterceptor/adblock/lib/adblockmatcher.cpp +++ b/plugins/webengineurlinterceptor/adblock/lib/adblockmatcher.cpp @@ -1,263 +1,261 @@ /* Copyright (C) 2016 Montel Laurent This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* ============================================================ * QupZilla - WebKit based browser * Copyright (C) 2014 David Rosca * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================ */ #include "adblockmatcher.h" #include "adblockmanager.h" #include "adblockrule.h" #include "adblocksubscription.h" using namespace AdBlock; AdBlockMatcher::AdBlockMatcher(AdblockManager *manager) : QObject(manager) , m_manager(manager), m_enabled(false) { connect(manager, &AdblockManager::enabledChanged, this, &AdBlockMatcher::enabledChanged); } AdBlockMatcher::~AdBlockMatcher() { clear(); } const AdBlockRule *AdBlockMatcher::match(const QWebEngineUrlRequestInfo &request, const QString &urlDomain, const QString &urlString) const { // Exception rules if (m_networkExceptionTree.find(request, urlDomain, urlString)) { return Q_NULLPTR; } 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 Q_NULLPTR; } } // 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 Q_NULLPTR; } bool AdBlockMatcher::adBlockDisabledForUrl(const QUrl &url) const { const int count = m_documentRules.count(); for (int i = 0; i < count; ++i) if (m_documentRules.at(i)->urlMatch(url)) { return true; } return false; } bool AdBlockMatcher::elemHideDisabledForUrl(const QUrl &url) const { if (adBlockDisabledForUrl(url)) { return true; } const int count = m_elemhideRules.count(); for (int i = 0; i < count; ++i) if (m_elemhideRules.at(i)->urlMatch(url)) { return true; } return false; } QString AdBlockMatcher::elementHidingRules() const { return m_elementHidingRules; } QString AdBlockMatcher::elementHidingRulesForDomain(const QString &domain) const { QString rules; int addedRulesCount = 0; const int count = m_domainRestrictedCssRules.count(); for (int i = 0; i < count; ++i) { const AdBlockRule *rule = m_domainRestrictedCssRules.at(i); if (!rule->matchDomain(domain)) { continue; } if (Q_UNLIKELY(addedRulesCount == 1000)) { rules.append(rule->cssSelector()); rules.append(QLatin1String("{display:none !important;}\n")); addedRulesCount = 0; } else { rules.append(rule->cssSelector() + QLatin1Char(',')); addedRulesCount++; } } if (addedRulesCount != 0) { rules = rules.left(rules.size() - 1); rules.append(QLatin1String("{display:none !important;}\n")); } return rules; } bool AdBlockMatcher::isEnabled() const { return m_enabled; } void AdBlockMatcher::update() { clear(); QHash cssRulesHash; QVector exceptionCssRules; -#if 0 //FIXME Q_FOREACH (AdBlockSubscription *subscription, m_manager->subscriptions()) { Q_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 { 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 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(QLatin1String("{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(QLatin1String("{display:none !important;} ")); } -#endif } 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(); } void AdBlockMatcher::enabledChanged(bool enabled) { m_enabled = enabled; if (m_enabled) { update(); } else { clear(); } }