1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-20 10:46:35 +01:00

AdBlock: Support for $elemhide and $document exception rules

- with @@||qupzilla.com^$document you can completely disable
  AdBlock from running on qupzilla.com site
This commit is contained in:
nowrep 2012-07-04 16:00:53 +02:00
parent 526c7475d4
commit 2dc0785aff
8 changed files with 116 additions and 14 deletions

View File

@ -90,6 +90,10 @@ QNetworkReply* AdBlockManager::block(const QNetworkRequest &request)
QVariant v = request.attribute((QNetworkRequest::Attribute)(QNetworkRequest::User + 100)); QVariant v = request.attribute((QNetworkRequest::Attribute)(QNetworkRequest::User + 100));
WebPage* webPage = static_cast<WebPage*>(v.value<void*>()); WebPage* webPage = static_cast<WebPage*>(v.value<void*>());
if (WebPage::isPointerSafeToUse(webPage)) { if (WebPage::isPointerSafeToUse(webPage)) {
if (!canBeBlocked(webPage->url())) {
return 0;
}
webPage->addAdBlockRule(blockedRule, request.url()); webPage->addAdBlockRule(blockedRule, request.url());
} }
@ -269,6 +273,17 @@ bool AdBlockManager::canRunOnScheme(const QString &scheme) const
return !(scheme == "file" || scheme == "qrc" || scheme == "qupzilla" || scheme == "data" || scheme == "abp"); return !(scheme == "file" || scheme == "qrc" || scheme == "qupzilla" || scheme == "data" || scheme == "abp");
} }
bool AdBlockManager::canBeBlocked(const QUrl &url) const
{
foreach(AdBlockSubscription * subscription, m_subscriptions) {
if (subscription->adBlockDisabledForUrl(url)) {
return false;
}
}
return true;
}
QString AdBlockManager::elementHidingRules() const QString AdBlockManager::elementHidingRules() const
{ {
QString rules; QString rules;
@ -285,12 +300,16 @@ QString AdBlockManager::elementHidingRules() const
return rules; return rules;
} }
QString AdBlockManager::elementHidingRulesForDomain(const QString &domain) const QString AdBlockManager::elementHidingRulesForDomain(const QUrl &url) const
{ {
QString rules; QString rules;
foreach(AdBlockSubscription * subscription, m_subscriptions) { foreach(AdBlockSubscription * subscription, m_subscriptions) {
rules.append(subscription->elementHidingRulesForDomain(domain)); if (subscription->elemHideDisabledForUrl(url)) {
return QString();
}
rules.append(subscription->elementHidingRulesForDomain(url.host()));
} }
// Remove last "," // Remove last ","

View File

@ -46,7 +46,7 @@ public:
bool canRunOnScheme(const QString &scheme) const; bool canRunOnScheme(const QString &scheme) const;
QString elementHidingRules() const; QString elementHidingRules() const;
QString elementHidingRulesForDomain(const QString &domain) const; QString elementHidingRulesForDomain(const QUrl &url) const;
AdBlockSubscription* subscriptionByName(const QString &name) const; AdBlockSubscription* subscriptionByName(const QString &name) const;
QList<AdBlockSubscription*> subscriptions() const; QList<AdBlockSubscription*> subscriptions() const;
@ -69,6 +69,7 @@ public slots:
AdBlockDialog* showDialog(); AdBlockDialog* showDialog();
private: private:
bool canBeBlocked(const QUrl &url) const;
static AdBlockManager* s_adBlockManager; static AdBlockManager* s_adBlockManager;
bool m_loaded; bool m_loaded;

View File

@ -112,6 +112,8 @@ AdBlockRule::AdBlockRule(const QString &filter, AdBlockSubscription* subscriptio
, m_subdocumentException(false) , m_subdocumentException(false)
, m_xmlhttprequest(false) , m_xmlhttprequest(false)
, m_xmlhttprequestException(false) , m_xmlhttprequestException(false)
, m_document(false)
, m_elemhide(false)
, m_caseSensitivity(Qt::CaseInsensitive) , m_caseSensitivity(Qt::CaseInsensitive)
{ {
setFilter(filter); setFilter(filter);
@ -148,6 +150,16 @@ QString AdBlockRule::cssSelector() const
return m_cssSelector; return m_cssSelector;
} }
bool AdBlockRule::isDocument() const
{
return m_document;
}
bool AdBlockRule::isElemhide() const
{
return m_elemhide;
}
bool AdBlockRule::isDomainRestricted() const bool AdBlockRule::isDomainRestricted() const
{ {
return m_domainRestricted; return m_domainRestricted;
@ -234,6 +246,18 @@ bool AdBlockRule::networkMatch(const QNetworkRequest &request, const QString &do
return matched; return matched;
} }
bool AdBlockRule::urlMatch(const QUrl &url) const
{
if (!m_document && !m_elemhide) {
return false;
}
const QString &encodedUrl = url.toEncoded();
const QString &domain = url.host();
return networkMatch(QNetworkRequest(url), domain, encodedUrl);
}
bool AdBlockRule::matchDomain(const QString &domain) const bool AdBlockRule::matchDomain(const QString &domain) const
{ {
if (!m_domainRestricted) { if (!m_domainRestricted) {
@ -386,6 +410,14 @@ void AdBlockRule::parseFilter()
m_xmlhttprequestException = option.startsWith('~'); m_xmlhttprequestException = option.startsWith('~');
++handledOptions; ++handledOptions;
} }
else if (option == "document" && m_exception) {
m_document = true;
++handledOptions;
}
else if (option == "elemhide" && m_exception) {
m_elemhide = true;
++handledOptions;
}
else if (option == "collapse") { else if (option == "collapse") {
// Hiding placeholders of blocked elements // Hiding placeholders of blocked elements
++handledOptions; ++handledOptions;

View File

@ -71,6 +71,9 @@ public:
bool isCssRule() const; bool isCssRule() const;
QString cssSelector() const; QString cssSelector() const;
bool isDocument() const;
bool isElemhide() const;
bool isDomainRestricted() const; bool isDomainRestricted() const;
bool isException() const; bool isException() const;
@ -82,6 +85,7 @@ public:
bool isInternalDisabled() const; bool isInternalDisabled() const;
bool networkMatch(const QNetworkRequest &request, const QString &domain, const QString &encodedUrl) const; bool networkMatch(const QNetworkRequest &request, const QString &domain, const QString &encodedUrl) const;
bool urlMatch(const QUrl &url) const;
bool matchDomain(const QString &domain) const; bool matchDomain(const QString &domain) const;
bool matchThirdParty(const QNetworkRequest &request) const; bool matchThirdParty(const QNetworkRequest &request) const;
@ -128,6 +132,10 @@ private:
bool m_xmlhttprequest; bool m_xmlhttprequest;
bool m_xmlhttprequestException; bool m_xmlhttprequestException;
// Exception only options
bool m_document;
bool m_elemhide;
Qt::CaseSensitivity m_caseSensitivity; Qt::CaseSensitivity m_caseSensitivity;
}; };

View File

@ -53,7 +53,6 @@
#include <QTimer> #include <QTimer>
#include <QNetworkReply> #include <QNetworkReply>
#include <QDebug> #include <QDebug>
// #define ADBLOCKSUBSCRIPTION_DEBUG
AdBlockSubscription::AdBlockSubscription(const QString &title, QObject* parent) AdBlockSubscription::AdBlockSubscription(const QString &title, QObject* parent)
: QObject(parent) : QObject(parent)
@ -203,6 +202,32 @@ const AdBlockRule* AdBlockSubscription::match(const QNetworkRequest &request, co
return 0; return 0;
} }
bool AdBlockSubscription::adBlockDisabledForUrl(const QUrl &url) const
{
foreach(const AdBlockRule * rule, m_documentRules) {
if (rule->urlMatch(url)) {
return true;
}
}
return false;
}
bool AdBlockSubscription::elemHideDisabledForUrl(const QUrl &url) const
{
if (adBlockDisabledForUrl(url)) {
return true;
}
foreach(const AdBlockRule * rule, m_elemhideRules) {
if (rule->urlMatch(url)) {
return true;
}
}
return false;
}
QString AdBlockSubscription::elementHidingRules() const QString AdBlockSubscription::elementHidingRules() const
{ {
return m_elementHidingRules; return m_elementHidingRules;
@ -296,8 +321,11 @@ void AdBlockSubscription::populateCache()
m_networkBlockRules.clear(); m_networkBlockRules.clear();
m_domainRestrictedCssRules.clear(); m_domainRestrictedCssRules.clear();
m_elementHidingRules.clear(); m_elementHidingRules.clear();
m_documentRules.clear();
m_elemhideRules.clear();
for (int i = 0; i < m_rules.count(); ++i) { int count = m_rules.count();
for (int i = 0; i < count; ++i) {
const AdBlockRule* rule = &m_rules.at(i); const AdBlockRule* rule = &m_rules.at(i);
if (!rule->isEnabled()) { if (!rule->isEnabled()) {
continue; continue;
@ -310,10 +338,14 @@ void AdBlockSubscription::populateCache()
else { else {
m_elementHidingRules.append(rule->cssSelector() + ","); m_elementHidingRules.append(rule->cssSelector() + ",");
} }
continue;
} }
else if (rule->isDocument()) {
if (rule->isException()) { m_documentRules.append(rule);
}
else if (rule->isElemhide()) {
m_elemhideRules.append(rule);
}
else if (rule->isException()) {
m_networkExceptionRules.append(rule); m_networkExceptionRules.append(rule);
} }
else { else {

View File

@ -46,6 +46,7 @@
#ifndef ADBLOCKSUBSCRIPTION_H #ifndef ADBLOCKSUBSCRIPTION_H
#define ADBLOCKSUBSCRIPTION_H #define ADBLOCKSUBSCRIPTION_H
#include <QVarLengthArray>
#include <QList> #include <QList>
#include <QUrl> #include <QUrl>
@ -77,6 +78,9 @@ public:
const AdBlockRule* match(const QNetworkRequest &request, const QString &urlDomain, const QString &urlString) const; const AdBlockRule* match(const QNetworkRequest &request, const QString &urlDomain, const QString &urlString) const;
bool adBlockDisabledForUrl(const QUrl &url) const;
bool elemHideDisabledForUrl(const QUrl &url) const;
QString elementHidingRules() const; QString elementHidingRules() const;
QString elementHidingRulesForDomain(const QString &domain) const; QString elementHidingRulesForDomain(const QString &domain) const;
@ -112,10 +116,12 @@ protected:
QList<AdBlockRule> m_rules; QList<AdBlockRule> m_rules;
QString m_elementHidingRules; QString m_elementHidingRules;
// sorted list QVarLengthArray<const AdBlockRule*> m_networkExceptionRules;
QList<const AdBlockRule*> m_networkExceptionRules; QVarLengthArray<const AdBlockRule*> m_networkBlockRules;
QList<const AdBlockRule*> m_networkBlockRules; QVarLengthArray<const AdBlockRule*> m_domainRestrictedCssRules;
QList<const AdBlockRule*> m_domainRestrictedCssRules;
QVarLengthArray<const AdBlockRule*> m_documentRules;
QVarLengthArray<const AdBlockRule*> m_elemhideRules;
private: private:
QString m_title; QString m_title;

View File

@ -543,7 +543,11 @@ void WebPage::cleanBlockedObjects()
} }
// Apply domain-specific element hiding rules // Apply domain-specific element hiding rules
QString elementHiding = AdBlockManager::instance()->elementHidingRulesForDomain(url().host()); QString elementHiding = AdBlockManager::instance()->elementHidingRulesForDomain(url());
if (elementHiding.isEmpty()) {
return;
}
elementHiding.append("{display: none !important;}\n</style>"); elementHiding.append("{display: none !important;}\n</style>");
QWebElement bodyElement = docElement.findFirst("body"); QWebElement bodyElement = docElement.findFirst("body");

View File

@ -35,7 +35,7 @@
<location filename="../testplugin_sidebar.cpp" line="32"/> <location filename="../testplugin_sidebar.cpp" line="32"/>
<location filename="../testplugin_sidebar.cpp" line="37"/> <location filename="../testplugin_sidebar.cpp" line="37"/>
<source>Testing Sidebar</source> <source>Testing Sidebar</source>
<translation type="unfinished"></translation> <translation>Testovací postranní bar</translation>
</message> </message>
</context> </context>
</TS> </TS>