Adblock works.

This commit is contained in:
Martin Rotter 2016-03-23 08:22:55 +01:00
parent 8e3e6d1b62
commit c7b127343e
21 changed files with 142 additions and 646 deletions

@ -1 +1 @@
Subproject commit 572da127bb14842bba6f84e6315a5ecefb44ed07
Subproject commit 176715f7b3229289e2fb0dffb000c436664a26ff

View File

@ -30,7 +30,6 @@
#include "miscellaneous/skinfactory.h"
#include "miscellaneous/textfactory.h"
#include "network-web/webfactory.h"
#include "network-web/webbrowsernetworkaccessmanager.h"
#include "network-web/silentnetworkaccessmanager.h"
#include "network-web/webbrowser.h"
#include "gui/systemtrayicon.h"
@ -448,7 +447,6 @@ void FormSettings::saveProxy() {
// Reload settings for all network access managers.
SilentNetworkAccessManager::instance()->loadSettings();
WebBrowserNetworkAccessManager::instance()->loadSettings();
}
void FormSettings::loadLanguage() {

View File

@ -19,12 +19,14 @@
#include "miscellaneous/application.h"
#include "miscellaneous/iofactory.h"
#include "network-web/adblock/requestinterceptor.h"
#include <QDebug>
#include <QDir>
#include <QPointer>
#include <QWebEngineSettings>
#include <QLocale>
#include <QWebEngineProfile>
// Feeds.
@ -357,6 +359,9 @@ Settings *Settings::setupSettings(QObject *parent) {
// Portable settings are available, use them.
new_settings = new Settings(properties.m_absoluteSettingsFileName, QSettings::IniFormat, properties.m_type, parent);
// Set Blick communication interceptor for simple Adblocking.
QWebEngineProfile::defaultProfile()->setRequestInterceptor(new RequestInterceptor(new_settings));
// Check if portable settings are available.
if (properties.m_type == SettingsProperties::Portable) {
qDebug("Initializing settings in '%s' (portable way).", qPrintable(QDir::toNativeSeparators(properties.m_absoluteSettingsFileName)));

View File

@ -1,81 +0,0 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2014-2015 by Martin Rotter <rotter.martinos@gmail.com>
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
//
// RSS Guard 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 3 of the License, or
// (at your option) any later version.
//
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
/**
* Copyright (c) 2009, Benjamin C. Meyer <ben@meyerhome.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Benjamin Meyer nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "network-web/adblock/adblockblockednetworkreply.h"
#include "network-web/adblock/adblocksubscription.h"
#include "network-web/adblock/adblockrule.h"
#include <QNetworkRequest>
#include <QTimer>
AdBlockBlockedNetworkReply::AdBlockBlockedNetworkReply(const AdBlockRule *rule, QObject *parent)
: QNetworkReply(parent) {
setOperation(QNetworkAccessManager::GetOperation);
setError(QNetworkReply::ContentAccessDenied, QString("Adblock: %1 (%2)").arg(rule->subscription()->title(), rule->filter()));
open(QIODevice::ReadOnly);
QTimer::singleShot(0, this, SLOT(delayedFinished()));
}
void AdBlockBlockedNetworkReply::abort() {
}
void AdBlockBlockedNetworkReply::setRequest(const QNetworkRequest &request) {
QNetworkReply::setRequest(request);
setUrl(request.url());
}
qint64 AdBlockBlockedNetworkReply::readData(char *data, qint64 maxSize) {
Q_UNUSED(data);
Q_UNUSED(maxSize);
return -1;
}
void AdBlockBlockedNetworkReply::delayedFinished() {
emit error(QNetworkReply::ContentAccessDenied);
emit finished();
}

View File

@ -1,73 +0,0 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2014-2015 by Martin Rotter <rotter.martinos@gmail.com>
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
//
// RSS Guard 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 3 of the License, or
// (at your option) any later version.
//
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
/**
* Copyright (c) 2009, Benjamin C. Meyer <ben@meyerhome.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Benjamin Meyer nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef ADBLOCKBLOCKEDNETWORKREPLY_H
#define ADBLOCKBLOCKEDNETWORKREPLY_H
#include <QNetworkReply>
class AdBlockRule;
class AdBlockSubscription;
class AdBlockBlockedNetworkReply : public QNetworkReply{
Q_OBJECT
public:
explicit AdBlockBlockedNetworkReply(const AdBlockRule *rule, QObject *parent = 0);
void abort();
void setRequest(const QNetworkRequest &request);
protected:
qint64 readData(char *data, qint64 maxSize);
private slots:
void delayedFinished();
};
#endif // ADBLOCKBLOCKEDNETWORKREPLY_H

View File

@ -30,7 +30,6 @@
#include <QMenu>
#include <QMouseEvent>
#include <QWebEnginePage>
AdBlockIcon::AdBlockIcon(QWidget *window, QWidget *parent)
@ -77,9 +76,9 @@ void AdBlockIcon::createMenu(QMenu *menu) {
menu->addSeparator();
if (!page_url.host().isEmpty() && m_enabled && manager->canRunOnScheme(page_url.scheme())) {
const QString host = page_url.host().contains(QLatin1String("www.")) ? page_url.host().mid(4) : page_url.host();
const QString host_filter = QString("@@||%1^$document").arg(host);
const QString page_filter = QString("@@|%1|$document").arg(page_url.toString());
const QString host = page_url.host().contains(QSL("www.")) ? page_url.host().mid(4) : page_url.host();
const QString host_filter = QString(QSL("@@||%1^$document")).arg(host);
const QString page_filter = QString(QSL("@@|%1|$document")).arg(page_url.toString());
QAction *act;
@ -97,41 +96,6 @@ void AdBlockIcon::createMenu(QMenu *menu) {
menu->addSeparator();
}
if (!m_blockedPopups.isEmpty()) {
menu->addAction(tr("Blocked popup windows"))->setEnabled(false);
for (int i = 0; i < m_blockedPopups.count(); i++) {
const QPair<AdBlockRule*,QUrl> &pair = m_blockedPopups.at(i);
const QString address = pair.second.toString().right(55);
QString action_text = tr("%1 with (%2)").arg(address,
pair.first->filter()).replace(QLatin1Char('&'), QLatin1String("&&"));
QAction *action = menu->addAction(action_text, manager, SLOT(showRule()));
action->setData(QVariant::fromValue((void*)pair.first));
}
}
menu->addSeparator();
const QVector<WebPage::AdBlockedEntry> entries = page->adBlockedEntries();
if (entries.isEmpty()) {
menu->addAction(tr("No content blocked"))->setEnabled(false);
}
else {
menu->addAction(tr("Blocked some content - click to edit rule"))->setEnabled(false);
foreach (const WebPage::AdBlockedEntry &entry, entries) {
QString address = entry.url.toString().right(55);
QString action_text = tr("%1 with (%2)").arg(address,
entry.rule->filter()).replace(QLatin1Char('&'), QLatin1String("&&"));
QAction *action = menu->addAction(action_text, manager, SLOT(showRule()));
action->setData(QVariant::fromValue((void*)entry.rule));
}
}
}
void AdBlockIcon::showMenu(const QPoint &pos) {

View File

@ -21,10 +21,8 @@
#include "network-web/adblock/adblockdialog.h"
#include "network-web/adblock/adblockmatcher.h"
#include "network-web/adblock/adblocksubscription.h"
#include "network-web/adblock/adblockblockednetworkreply.h"
#include "network-web/adblock/adblockicon.h"
#include "network-web/webpage.h"
#include "network-web/silentnetworkaccessmanager.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "definitions/definitions.h"
@ -34,7 +32,6 @@
#include <QTextStream>
#include <QDir>
#include <QTimer>
#include <QWebEnginePage>
AdBlockManager *AdBlockManager::s_adBlockManager = NULL;
@ -51,7 +48,7 @@ AdBlockManager::~AdBlockManager() {
AdBlockManager *AdBlockManager::instance() {
if (s_adBlockManager == NULL) {
s_adBlockManager = new AdBlockManager(SilentNetworkAccessManager::instance());
s_adBlockManager = new AdBlockManager(qApp);
}
return s_adBlockManager;
@ -74,36 +71,27 @@ QList<AdBlockSubscription*> AdBlockManager::subscriptions() const {
return m_subscriptions;
}
QNetworkReply *AdBlockManager::block(const QNetworkRequest &request) {
const QString url_string = request.url().toEncoded().toLower();
const QString url_domain = request.url().host().toLower();
const QString url_scheme = request.url().scheme().toLower();
bool AdBlockManager::shouldBlock(const QUrl &url, const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type) {
const QString url_string = url.toEncoded().toLower();
const QString url_domain = url.host().toLower();
const QString url_scheme = url.scheme().toLower();
if (!isEnabled() || !canRunOnScheme(url_scheme)) {
return NULL;
}
const AdBlockRule *blocked_rule = m_matcher->match(request, url_domain, url_string);
const AdBlockRule *blocked_rule = m_matcher->match(url, url_domain, url_string, referer, resource_type);
if (blocked_rule != NULL) {
QVariant v = request.attribute((QNetworkRequest::Attribute)(QNetworkRequest::User + 100));
WebPage *web_page = static_cast<WebPage*>(v.value<void*>());
if (WebPage::isPointerSafeToUse(web_page)) {
if (!canBeBlocked(web_page->url())) {
return NULL;
}
web_page->addAdBlockRule(blocked_rule, request.url());
if (!canBeBlocked(url, referer, resource_type)) {
return false;
}
else {
return true;
}
AdBlockBlockedNetworkReply *reply = new AdBlockBlockedNetworkReply(blocked_rule, this);
reply->setRequest(request);
return reply;
}
return NULL;
return false;
}
QStringList AdBlockManager::disabledRules() const {
@ -306,25 +294,8 @@ void AdBlockManager::setUseLimitedEasyList(bool use_limited) {
}
}
bool AdBlockManager::canBeBlocked(const QUrl &url) const {
return !m_matcher->adBlockDisabledForUrl(url);
}
QString AdBlockManager::elementHidingRules() const {
return m_matcher->elementHidingRules();
}
QString AdBlockManager::elementHidingRulesForDomain(const QUrl &url) const {
if (!isEnabled() || !canRunOnScheme(url.scheme()) || !canBeBlocked(url)) {
return QString();
}
// Acid3 doesn't like the way element hiding rules are embedded into page
else if (url.host() == QL1S("acid3.acidtests.org")) {
return QString();
}
else {
return m_matcher->elementHidingRulesForDomain(url.host());
}
bool AdBlockManager::canBeBlocked(const QUrl &url, const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type) const {
return !m_matcher->adBlockDisabledForUrl(url, referer, resource_type);
}
AdBlockSubscription *AdBlockManager::subscriptionByName(const QString &name) const {

View File

@ -23,12 +23,10 @@
#include <QStringList>
#include <QPointer>
#include <QWebEngineUrlRequestInfo>
class QUrl;
class QNetworkReply;
class QNetworkRequest;
class AdBlockRule;
class AdBlockDialog;
class AdBlockMatcher;
@ -52,13 +50,10 @@ class AdBlockManager : public QObject {
bool useLimitedEasyList() const;
void setUseLimitedEasyList(bool use_limited);
QString elementHidingRules() const;
QString elementHidingRulesForDomain(const QUrl &url) const;
AdBlockSubscription *subscriptionByName(const QString &name) const;
QList<AdBlockSubscription*> subscriptions() const;
QNetworkReply *block(const QNetworkRequest &request);
bool shouldBlock(const QUrl &url, const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type);
QStringList disabledRules() const;
void addDisabledRule(const QString &filter);
@ -74,9 +69,6 @@ class AdBlockManager : public QObject {
static QString baseSubscriptionDirectory();
static AdBlockManager *instance();
signals:
void enabledChanged(bool enabled);
public slots:
void setEnabled(bool enabled);
void showRule();
@ -84,8 +76,11 @@ class AdBlockManager : public QObject {
AdBlockDialog *showDialog();
signals:
void enabledChanged(bool enabled);
private:
bool canBeBlocked(const QUrl &url) const;
bool canBeBlocked(const QUrl &url, const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type) const;
bool m_loaded;
bool m_enabled;

View File

@ -32,30 +32,31 @@ AdBlockMatcher::~AdBlockMatcher() {
clear();
}
const AdBlockRule *AdBlockMatcher::match(const QNetworkRequest &request, const QString &url_domain,
const QString &url_string) const {
const AdBlockRule *AdBlockMatcher::match(const QUrl &url, const QString &url_domain,
const QString &url_string, const QString &referer,
QWebEngineUrlRequestInfo::ResourceType resource_type) const {
// Exception rules.
if (m_networkExceptionTree.find(request, url_domain, url_string)) {
if (m_networkExceptionTree.find(url, url_domain, url_string, referer, resource_type)) {
return NULL;
}
for (int i = 0, count = m_networkExceptionRules.size(); i < count; i++) {
const AdBlockRule *rule = m_networkExceptionRules.at(i);
if (rule->networkMatch(request, url_domain, url_string)) {
if (rule->networkMatch(url, url_domain, url_string, referer, resource_type)) {
return NULL;
}
}
// Block rules.
if (const AdBlockRule* rule = m_networkBlockTree.find(request, url_domain, url_string)) {
if (const AdBlockRule* rule = m_networkBlockTree.find(url, url_domain, url_string, referer, resource_type)) {
return rule;
}
for (int i = 0, count = m_networkBlockRules.size(); i < count; i++) {
const AdBlockRule *rule = m_networkBlockRules.at(i);
if (rule->networkMatch(request, url_domain, url_string)) {
if (rule->networkMatch(url, url_domain, url_string, referer, resource_type)) {
return rule;
}
}
@ -63,9 +64,10 @@ const AdBlockRule *AdBlockMatcher::match(const QNetworkRequest &request, const Q
return NULL;
}
bool AdBlockMatcher::adBlockDisabledForUrl(const QUrl &url) const {
bool AdBlockMatcher::adBlockDisabledForUrl(const QUrl &url, const QString &referer,
QWebEngineUrlRequestInfo::ResourceType resource_type) const {
for (int i = 0, count = m_documentRules.size(); i < count; i++) {
if (m_documentRules.at(i)->urlMatch(url)) {
if (m_documentRules.at(i)->urlMatch(url, referer, resource_type)) {
return true;
}
}
@ -73,60 +75,9 @@ bool AdBlockMatcher::adBlockDisabledForUrl(const QUrl &url) const {
return false;
}
bool AdBlockMatcher::elemHideDisabledForUrl(const QUrl &url) const {
if (adBlockDisabledForUrl(url)) {
return true;
}
for (int i = 0, count = m_elemhideRules.size(); 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 added_rules_count = 0;
for (int i = 0, count = m_domainRestrictedCssRules.size(); i < count; i++) {
const AdBlockRule *rule = m_domainRestrictedCssRules.at(i);
if (!rule->matchDomain(domain)) {
continue;
}
if (added_rules_count == 1000) {
rules.append(rule->cssSelector());
rules.append(QL1S("{display:none !important;}\n"));
added_rules_count = 0;
}
else {
rules.append(rule->cssSelector() + QL1C(','));
added_rules_count++;
}
}
if (added_rules_count != 0) {
rules = rules.left(rules.size() - 1);
rules.append(QLatin1String("{display:none !important;}\n"));
}
return rules;
}
void AdBlockMatcher::update() {
clear();
QHash<QString, const AdBlockRule*> css_rules_hash;
QVector<const AdBlockRule*> exception_css_rules;
foreach (const AdBlockSubscription *subscription, m_manager->subscriptions()) {
foreach (const AdBlockRule *rule, subscription->allRules()) {
// Don't add internally disabled rules to cache
@ -134,26 +85,9 @@ void AdBlockMatcher::update() {
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()) {
exception_css_rules.append(rule);
}
else {
css_rules_hash.insert(rule->cssSelector(), rule);
}
}
else if (rule->isDocument()) {
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);
@ -166,52 +100,6 @@ void AdBlockMatcher::update() {
}
}
}
foreach (const AdBlockRule *rule, exception_css_rules) {
const AdBlockRule *original_rule = css_rules_hash.value(rule->cssSelector());
// If we don't have this selector, the exception does nothing.
if (original_rule == NULL) {
continue;
}
AdBlockRule *copied_rule = original_rule->copy();
copied_rule->m_options |= AdBlockRule::DomainRestrictedOption;
copied_rule->m_blockedDomains.append(rule->m_allowedDomains);
css_rules_hash[rule->cssSelector()] = copied_rule;
m_createdRules.append(copied_rule);
}
// 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 hiding_rules_count = 0;
QHashIterator<QString,const AdBlockRule*> it(css_rules_hash);
while (it.hasNext()) {
it.next();
const AdBlockRule *rule = it.value();
if (rule->isDomainRestricted()) {
m_domainRestrictedCssRules.append(rule);
}
else if (hiding_rules_count == 1000) {
m_elementHidingRules.append(rule->cssSelector());
m_elementHidingRules.append(QL1S("{display:none !important;} "));
hiding_rules_count = 0;
}
else {
m_elementHidingRules.append(rule->cssSelector() + QL1C(','));
hiding_rules_count++;
}
}
if (hiding_rules_count != 0) {
m_elementHidingRules = m_elementHidingRules.left(m_elementHidingRules.size() - 1);
m_elementHidingRules.append(QLatin1String("{display:none !important;} "));
}
}
void AdBlockMatcher::clear() {
@ -222,12 +110,7 @@ void AdBlockMatcher::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) {

View File

@ -37,13 +37,10 @@ class AdBlockMatcher : public QObject {
explicit AdBlockMatcher(AdBlockManager *manager);
virtual ~AdBlockMatcher();
const AdBlockRule *match(const QNetworkRequest &request, const QString &url_domain, const QString &url_string) const;
const AdBlockRule *match(const QUrl &url, const QString &url_domain, const QString &url_string,
const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type) const;
bool adBlockDisabledForUrl(const QUrl &url) const;
bool elemHideDisabledForUrl(const QUrl &url) const;
QString elementHidingRules() const;
QString elementHidingRulesForDomain(const QString &domain) const;
bool adBlockDisabledForUrl(const QUrl &url, const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type) const;
public slots:
void update();
@ -55,14 +52,11 @@ class AdBlockMatcher : public QObject {
private:
AdBlockManager *m_manager;
QVector<AdBlockRule*> m_createdRules;
QVector<const AdBlockRule*> m_networkExceptionRules;
QVector<const AdBlockRule*> m_networkBlockRules;
QVector<const AdBlockRule*> m_domainRestrictedCssRules;
QVector<const AdBlockRule*> m_documentRules;
QVector<const AdBlockRule*> m_elemhideRules;
QString m_elementHidingRules;
AdBlockSearchTree m_networkBlockTree;
AdBlockSearchTree m_networkExceptionTree;
};

View File

@ -111,14 +111,6 @@ void AdBlockRule::setFilter(const QString &filter) {
parseFilter();
}
bool AdBlockRule::isCssRule() const {
return m_type == CssRule;
}
QString AdBlockRule::cssSelector() const {
return m_matchString;
}
bool AdBlockRule::isDocument() const {
return hasOption(DocumentOption);
}
@ -155,17 +147,19 @@ bool AdBlockRule::isInternalDisabled() const {
return m_isInternalDisabled;
}
bool AdBlockRule::urlMatch(const QUrl &url) const {
bool AdBlockRule::urlMatch(const QUrl &url, const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type) const {
if (!hasOption(DocumentOption) && !hasOption(ElementHideOption)) {
return false;
}
else {
return networkMatch(QNetworkRequest(url), url.host(), url.toEncoded());
return networkMatch(url, url.host(), url.toEncoded(), referer, resource_type);
}
}
bool AdBlockRule::networkMatch(const QNetworkRequest &request, const QString &domain, const QString &encoded_url) const {
if (m_type == CssRule || !m_isEnabled || m_isInternalDisabled) {
bool AdBlockRule::networkMatch(const QUrl &url, const QString &domain,
const QString &encoded_url, const QString &referer,
QWebEngineUrlRequestInfo::ResourceType resource_type) const {
if (!m_isEnabled || m_isInternalDisabled) {
return false;
}
@ -195,22 +189,22 @@ bool AdBlockRule::networkMatch(const QNetworkRequest &request, const QString &do
}
// Check third-party restriction.
if (hasOption(ThirdPartyOption) && !matchThirdParty(request)) {
if (hasOption(ThirdPartyOption) && !matchThirdParty(referer, url)) {
return false;
}
// Check object restrictions.
if (hasOption(ObjectOption) && !matchObject(request)) {
if (hasOption(ObjectOption) && !matchObject(resource_type)) {
return false;
}
// Check subdocument restriction.
if (hasOption(SubdocumentOption) && !matchSubdocument(request)) {
if (hasOption(SubdocumentOption)) {
return false;
}
// Check xmlhttprequest restriction
if (hasOption(XMLHttpRequestOption) && !matchXmlHttpRequest(request)) {
if (hasOption(XMLHttpRequestOption)) {
return false;
}
@ -265,38 +259,26 @@ bool AdBlockRule::matchDomain(const QString &domain) const {
return false;
}
bool AdBlockRule::matchThirdParty(const QNetworkRequest &request) const {
const QString referer = request.attribute(QNetworkRequest::Attribute(QNetworkRequest::User + 151), QString()).toString();
bool AdBlockRule::matchThirdParty(const QString &referer, const QUrl &url) const {
if (referer.isEmpty()) {
return false;
}
// Third-party matching should be performed on second-level domains.
const QString refererHost = WebFactory::instance()->toSecondLevelDomain(QUrl(referer));
const QString host = WebFactory::instance()->toSecondLevelDomain(request.url());
const QString host = WebFactory::instance()->toSecondLevelDomain(url);
bool match = refererHost != host;
return hasException(ThirdPartyOption) ? !match : match;
}
bool AdBlockRule::matchObject(const QNetworkRequest &request) const {
bool match = request.attribute(QNetworkRequest::Attribute(QNetworkRequest::User + 150)).toString() == QL1S("object");
bool AdBlockRule::matchObject(QWebEngineUrlRequestInfo::ResourceType type) const {
bool match = type == QWebEngineUrlRequestInfo::ResourceTypeObject;
return hasException(ObjectOption) ? !match : match;
}
bool AdBlockRule::matchSubdocument(const QNetworkRequest &request) const {
return false;
}
bool AdBlockRule::matchXmlHttpRequest(const QNetworkRequest &request) const {
bool match = request.rawHeader("X-Requested-With") == QByteArray("XMLHttpRequest");
return hasException(XMLHttpRequestOption) ? !match : match;
}
bool AdBlockRule::matchImage(const QString &encoded_url) const {
bool match = encoded_url.endsWith(QL1S(".png")) ||
encoded_url.endsWith(QL1S(".jpg")) ||
@ -321,19 +303,7 @@ void AdBlockRule::parseFilter() {
// CSS Element hiding rule.
if (parsed_line.contains(QL1S("##")) || parsed_line.contains(QL1S("#@#"))) {
m_type = CssRule;
int pos = parsed_line.indexOf(QL1C('#'));
// Domain restricted rule
if (!parsed_line.startsWith(QL1S("##"))) {
QString domains = parsed_line.left(pos);
parseDomains(domains, QL1C(','));
}
m_isException = parsed_line.at(pos + 1) == QL1C('@');
m_matchString = parsed_line.mid(m_isException ? pos + 3 : pos + 2);
// CSS rule cannot have more options -> stop parsing.
// Do not parse CSS rules.
return;
}

View File

@ -49,6 +49,7 @@
#include <QObject>
#include <QStringList>
#include <QWebEngineUrlRequestInfo>
class QNetworkRequest;
class QUrl;
@ -72,9 +73,6 @@ class AdBlockRule {
QString filter() const;
void setFilter(const QString &filter);
bool isCssRule() const;
QString cssSelector() const;
bool isDocument() const;
bool isElemhide() const;
@ -88,14 +86,13 @@ class AdBlockRule {
bool isSlow() const;
bool isInternalDisabled() const;
bool urlMatch(const QUrl &url) const;
bool networkMatch(const QNetworkRequest &request, const QString &domain, const QString &encoded_url) const;
bool urlMatch(const QUrl &url, const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type) const;
bool networkMatch(const QUrl &url, const QString &domain, const QString &encoded_url,
const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type) const;
bool matchDomain(const QString &domain) const;
bool matchThirdParty(const QNetworkRequest &request) const;
bool matchObject(const QNetworkRequest &request) const;
bool matchSubdocument(const QNetworkRequest &request) const;
bool matchXmlHttpRequest(const QNetworkRequest &request) const;
bool matchThirdParty(const QString &referer, const QUrl &url) const;
bool matchObject(QWebEngineUrlRequestInfo::ResourceType type) const;
bool matchImage(const QString &encoded_url) const;
protected:
@ -105,7 +102,6 @@ class AdBlockRule {
private:
enum RuleType {
CssRule = 0,
DomainMatchRule = 1,
RegExpMatchRule = 2,
StringEndsMatchRule = 3,

View File

@ -65,8 +65,9 @@ bool AdBlockSearchTree::add(const AdBlockRule *rule) {
return true;
}
const AdBlockRule *AdBlockSearchTree::find(const QNetworkRequest &request, const QString &domain,
const QString &url_string) const {
const AdBlockRule *AdBlockSearchTree::find(const QUrl &url, const QString &domain,
const QString &url_string, const QString &referer,
QWebEngineUrlRequestInfo::ResourceType resource_type) const {
const int len = url_string.size();
if (len <= 0) {
@ -76,7 +77,7 @@ const AdBlockRule *AdBlockSearchTree::find(const QNetworkRequest &request, const
const QChar *string = url_string.constData();
for (int i = 0; i < len; i++) {
const AdBlockRule *rule = prefixSearch(request, domain, url_string, string++, len - i);
const AdBlockRule *rule = prefixSearch(url, domain, url_string, string++, referer, resource_type, len - i);
if (rule != NULL) {
return rule;
@ -86,8 +87,10 @@ const AdBlockRule *AdBlockSearchTree::find(const QNetworkRequest &request, const
return NULL;
}
const AdBlockRule *AdBlockSearchTree::prefixSearch(const QNetworkRequest &request, const QString &domain,
const QString &url_string, const QChar* string, int len) const {
const AdBlockRule *AdBlockSearchTree::prefixSearch(const QUrl &url, const QString &domain,
const QString &url_string, const QChar* string,
const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type,
int len) const {
if (len <= 0) {
return NULL;
}
@ -103,7 +106,7 @@ const AdBlockRule *AdBlockSearchTree::prefixSearch(const QNetworkRequest &reques
for (int i = 1; i < len; i++) {
const QChar c = (++string)[0];
if (node->rule && node->rule->networkMatch(request, domain, url_string)) {
if (node->rule && node->rule->networkMatch(url, domain, url_string, referer, resource_type)) {
return node->rule;
}
@ -114,7 +117,7 @@ const AdBlockRule *AdBlockSearchTree::prefixSearch(const QNetworkRequest &reques
node = node->children[c];
}
if (node->rule && node->rule->networkMatch(request, domain, url_string)) {
if (node->rule && node->rule->networkMatch(url, domain, url_string, referer, resource_type)) {
return node->rule;
}

View File

@ -21,6 +21,8 @@
#include <QChar>
#include <QHash>
#include <QUrl>
#include <QWebEngineUrlRequestInfo>
class QNetworkRequest;
@ -34,7 +36,8 @@ class AdBlockSearchTree {
void clear();
bool add(const AdBlockRule *rule);
const AdBlockRule *find(const QNetworkRequest &request, const QString &domain, const QString &url_string) const;
const AdBlockRule *find(const QUrl &url, const QString &domain, const QString &url_string,
const QString &referer, QWebEngineUrlRequestInfo::ResourceType resource_type) const;
private:
struct Node {
@ -48,8 +51,9 @@ class AdBlockSearchTree {
};
void deleteNode(Node *node);
const AdBlockRule *prefixSearch(const QNetworkRequest &request, const QString &domain,
const QString &url_string, const QChar* string, int len) const;
const AdBlockRule *prefixSearch(const QUrl &url, const QString &domain,
const QString &url_string, const QChar* string, const QString &referer,
QWebEngineUrlRequestInfo::ResourceType resource_type, int len) const;
Node *m_root;
};

View File

@ -203,10 +203,6 @@ void AdBlockTreeWidget::adjustItemFeatures(QTreeWidgetItem *item, const AdBlockR
item->setForeground(0, QColor(Qt::darkGreen));
item->setFont(0, QFont());
}
else if (rule->isCssRule()) {
item->setForeground(0, QColor(Qt::darkBlue));
item->setFont(0, QFont());
}
else {
item->setForeground(0, QColor());
item->setFont(0, QFont());

View File

@ -1,5 +1,41 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2016 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard 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 3 of the License, or
// (at your option) any later version.
//
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "network-web/adblock/requestinterceptor.h"
#include "network-web/adblock/adblockmanager.h"
#include "miscellaneous/application.h"
RequestInterceptor::RequestInterceptor(QObject *p) : QWebEngineUrlRequestInterceptor(p) {
RequestInterceptor::RequestInterceptor(QObject *parent) : QWebEngineUrlRequestInterceptor(parent) {
}
RequestInterceptor::~RequestInterceptor() {
}
void RequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) {
if (AdBlockManager::instance()->shouldBlock(info.requestUrl(), info.firstPartyUrl().toString(), info.resourceType())) {
info.block(true);
qWarning("%s just blocked network resource:\n URL: '%s'.", APP_NAME, qPrintable(info.requestUrl().toString()));
/*
qApp->showGuiMessage(tr("Network resource blocked"),
tr("%1 just blocked network resource:\n URL: %2").arg(APP_NAME, info.requestUrl().toString()),
QSystemTrayIcon::Information);
*/
}
}

View File

@ -1,10 +1,33 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2016 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard 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 3 of the License, or
// (at your option) any later version.
//
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#ifndef REQUESTINTERCEPTOR_H
#define REQUESTINTERCEPTOR_H
#include <QWebEngineUrlRequestInterceptor>
class RequestInterceptor : public QWebEngineUrlRequestInterceptor {
public:
RequestInterceptor();
explicit RequestInterceptor(QObject *parent = 0);
virtual ~RequestInterceptor();
void interceptRequest(QWebEngineUrlRequestInfo &info);
};
#endif // REQUESTINTERCEPTOR_H

View File

@ -1,70 +0,0 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2016 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard 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 3 of the License, or
// (at your option) any later version.
//
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#include "network-web/webbrowsernetworkaccessmanager.h"
#include "miscellaneous/application.h"
#include "network-web/adblock/adblockmanager.h"
#include <QNetworkReply>
QPointer<WebBrowserNetworkAccessManager> WebBrowserNetworkAccessManager::s_instance;
WebBrowserNetworkAccessManager::WebBrowserNetworkAccessManager(WebPage *page, QObject *parent)
: BaseNetworkAccessManager(parent), m_page(page) {
connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
this, SLOT(onAuthenticationRequired(QNetworkReply*,QAuthenticator*)));
}
WebBrowserNetworkAccessManager::~WebBrowserNetworkAccessManager() {
qDebug("Destroying WebBrowserNetworkAccessManager instance.");
}
void WebBrowserNetworkAccessManager::onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator) {
Q_UNUSED(authenticator);
// FIXME: Support authentication for web pages.
qDebug("URL '%s' requested authentication but username/password is not available.", qPrintable(reply->url().toString()));
}
QNetworkReply *WebBrowserNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData) {
if (m_page != NULL) {
QNetworkRequest page_request = request;
m_page->populateNetworkRequest(page_request);
return WebBrowserNetworkAccessManager::instance()->createRequest(op, page_request, outgoingData);
}
if (op == QNetworkAccessManager::GetOperation) {
QNetworkReply *reply = AdBlockManager::instance()->block(request);
if (reply != NULL) {
return reply;
}
}
return BaseNetworkAccessManager::createRequest(op, request, outgoingData);
}
WebBrowserNetworkAccessManager *WebBrowserNetworkAccessManager::instance() {
if (s_instance.isNull()) {
s_instance = new WebBrowserNetworkAccessManager(0, qApp);
}
return s_instance;
}

View File

@ -1,53 +0,0 @@
// This file is part of RSS Guard.
//
// Copyright (C) 2011-2016 by Martin Rotter <rotter.martinos@gmail.com>
//
// RSS Guard 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 3 of the License, or
// (at your option) any later version.
//
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
#ifndef WEBBROWSERNETWORKACCESSMANAGER_H
#define WEBBROWSERNETWORKACCESSMANAGER_H
#include "network-web/basenetworkaccessmanager.h"
#include "webpage.h"
#include <QPointer>
// This is network access manager for web browsers.
class WebBrowserNetworkAccessManager : public BaseNetworkAccessManager {
Q_OBJECT
public:
// Constructors and destructors.
explicit WebBrowserNetworkAccessManager(WebPage *page = 0, QObject *parent = 0);
virtual ~WebBrowserNetworkAccessManager();
// Returns pointer to global network access manager
// used by ALL web browsers and download manager.
static WebBrowserNetworkAccessManager *instance();
protected:
QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData);
protected slots:
void onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
private:
WebPage *m_page;
static QPointer<WebBrowserNetworkAccessManager> s_instance;
};
#endif // WEBBROWSERNETWORKACCESSMANAGER_H

View File

@ -20,24 +20,14 @@
#include "network-web/webbrowser.h"
#include "miscellaneous/application.h"
#include "network-web/adblock/adblockmanager.h"
#include <QNetworkReply>
QList<WebPage*> WebPage::s_livingPages;
WebPage::WebPage(QObject *parent)
: QWebEnginePage(parent), m_loadProgress(-1) {
connect(this, SIGNAL(loadProgress(int)), this, SLOT(progress(int)));
connect(this, SIGNAL(loadFinished(bool)), this, SLOT(finished()));
connect(this, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl)));
s_livingPages.append(this);
}
WebPage::~WebPage() {
s_livingPages.removeOne(this);
}
bool WebPage::isLoading() const {
@ -52,44 +42,6 @@ void WebPage::finished() {
progress(100);
}
void WebPage::urlChanged(const QUrl &url) {
Q_UNUSED(url)
if (isLoading()) {
m_adBlockedEntries.clear();
}
}
void WebPage::addAdBlockRule(const AdBlockRule *rule, const QUrl &url) {
AdBlockedEntry entry;
entry.rule = rule;
entry.url = url;
if (!m_adBlockedEntries.contains(entry)) {
m_adBlockedEntries.append(entry);
}
}
QVector<WebPage::AdBlockedEntry> WebPage::adBlockedEntries() const {
return m_adBlockedEntries;
}
bool WebPage::isPointerSafeToUse(WebPage *page) {
// Pointer to WebPage is passed with every QNetworkRequest casted to void*
// So there is no way to test whether pointer is still valid or not, except
// this hack.
return page == 0 ? false : s_livingPages.contains(page);
}
void WebPage::populateNetworkRequest(QNetworkRequest &request) {
WebPage *page_pointer = this;
QVariant variant = QVariant::fromValue((void*) page_pointer);
request.setAttribute((QNetworkRequest::Attribute)(QNetworkRequest::User + 100), variant);
}
QString WebPage::toHtml() const {
return QString();
// TODO: TODO

View File

@ -28,35 +28,18 @@ class WebPage : public QWebEnginePage {
Q_OBJECT
public:
struct AdBlockedEntry {
const AdBlockRule *rule;
QUrl url;
bool operator==(const AdBlockedEntry &other) const {
return (this->rule == other.rule && this->url == other.url);
}
};
// Constructors and destructors.
explicit WebPage(QObject *parent = 0);
virtual ~WebPage();
QString toHtml() const;
bool isLoading() const;
QVector<AdBlockedEntry> adBlockedEntries() const;
void populateNetworkRequest(QNetworkRequest &request);
void addAdBlockRule(const AdBlockRule *rule, const QUrl &url);
static bool isPointerSafeToUse(WebPage *page);
private slots:
void progress(int prog);
void finished();
void urlChanged(const QUrl &url);
private:
QVector<AdBlockedEntry> m_adBlockedEntries;
int m_loadProgress;
static QList<WebPage*> s_livingPages;