From 2a5ea0269a1f9511c51d661a6c7d7bdc7d0176fa Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Sun, 7 Oct 2018 13:20:54 +0200 Subject: Expand HTTP header settings #4 - add doc/Usage/Filter.asciidoc to explain the usage of the filter headers - add HTTP headers to Profile (section "headers") - Use request interceptor to apply filter headers, then profile headers - add insert/delete actions to ProfileEditor --- doc/Usage/Filter.asciidoc | 12 ++ lib/configuration/configuration.h | 7 ++ lib/web/profilemanager.cpp | 13 +++ lib/web/webprofile.cpp | 14 +++ lib/web/webprofile.h | 9 ++ plugins/ProfileEditor/CMakeLists.txt | 3 + .../ProfileEditor/forms/newhttpheaderdialog.cpp | 32 ++++++ plugins/ProfileEditor/forms/newhttpheaderdialog.h | 33 ++++++ plugins/ProfileEditor/forms/newhttpheaderdialog.ui | 84 ++++++++++++++ plugins/ProfileEditor/forms/profileview.cpp | 46 ++++++++ plugins/ProfileEditor/forms/profileview.h | 3 + plugins/ProfileEditor/forms/profileview.ui | 68 ++++++++++- src/CMakeLists.txt | 2 + src/browser.cpp | 6 +- src/browser.h | 4 +- src/webengine/filter.cpp | 116 +++++++++++++++++++ src/webengine/filter.h | 45 ++++++++ src/webengine/urlinterceptor.cpp | 127 +++------------------ src/webengine/urlinterceptor.h | 18 +-- 19 files changed, 512 insertions(+), 130 deletions(-) create mode 100644 doc/Usage/Filter.asciidoc create mode 100644 plugins/ProfileEditor/forms/newhttpheaderdialog.cpp create mode 100644 plugins/ProfileEditor/forms/newhttpheaderdialog.h create mode 100644 plugins/ProfileEditor/forms/newhttpheaderdialog.ui create mode 100644 src/webengine/filter.cpp create mode 100644 src/webengine/filter.h diff --git a/doc/Usage/Filter.asciidoc b/doc/Usage/Filter.asciidoc new file mode 100644 index 0000000..d23d57a --- /dev/null +++ b/doc/Usage/Filter.asciidoc @@ -0,0 +1,12 @@ +== Url Request Filter +smolbote has a singular URL request filter that is installed onto all profiles. +Any setting applied to it will be applied to all profiles. + +=== filter.header + A list of header-value pairs, separated by a colon (':'). + +You can specify multiple headers by using --filter.header multiple times: +[source, sh] +---- +poi --filter.header "Dnt:1" --filter.header "Accept:text/html" +---- diff --git a/lib/configuration/configuration.h b/lib/configuration/configuration.h index d4770ae..1524536 100644 --- a/lib/configuration/configuration.h +++ b/lib/configuration/configuration.h @@ -56,6 +56,13 @@ public: return std::optional(QString::fromStdString(this->value(path).value())); //return std::optional(vm[path].as()); + } else if constexpr(std::is_same_v) { + QStringList r; + for(const std::string &item : this->value>(path).value()) { + r.append(QString::fromStdString(item)); + } + return std::optional(r); + } else if constexpr(std::is_same_v) { if(vm[path].value().type() == typeid(int)) { diff --git a/lib/web/profilemanager.cpp b/lib/web/profilemanager.cpp index 74ddc75..17435e8 100644 --- a/lib/web/profilemanager.cpp +++ b/lib/web/profilemanager.cpp @@ -73,6 +73,19 @@ WebProfile *ProfileManager::loadProfile(const QString &path) this->m_profiles.at(id)->settings.setValue("attributes/" + QString::number(attr), value); }); + // headers + ptr->settings.beginGroup("headers"); + for(const QString &key : ptr->settings.childKeys()) { + ptr->profile->setHttpHeader(key.toLatin1(), ptr->settings.value(key).toString().toLatin1()); + } + ptr->settings.endGroup(); + connect(ptr->profile, &WebProfile::headerChanged, ptr->profile, [this, id](const QString &name, const QString &value) { + this->m_profiles.at(id)->settings.setValue("headers/" + name, value); + }); + connect(ptr->profile, &WebProfile::headerRemoved, ptr->profile, [this, id](const QString &name) { + this->m_profiles.at(id)->settings.remove("headers/" + name); + }); + m_profiles[id] = std::move(ptr); return m_profiles.at(id)->profile; } diff --git a/lib/web/webprofile.cpp b/lib/web/webprofile.cpp index bd84d38..16c12b7 100644 --- a/lib/web/webprofile.cpp +++ b/lib/web/webprofile.cpp @@ -135,6 +135,20 @@ void WebProfile::setHttpUserAgent(const QString &userAgent) emit propertyChanged("httpUserAgent", userAgent); } +void WebProfile::setHttpHeader(const QString& name, const QString& value) +{ + m_headers[name.toLatin1()] = value.toLatin1(); + emit headerChanged(name, value); +} + +void WebProfile::removeHttpHeader(const QString& name) +{ + if(m_headers.contains(name.toLatin1())) { + m_headers.remove(name.toLatin1()); + emit headerRemoved(name); + } +} + void WebProfile::setSpellCheckEnabled(bool enable) { QWebEngineProfile::setSpellCheckEnabled(enable); diff --git a/lib/web/webprofile.h b/lib/web/webprofile.h index b58fad7..269989b 100644 --- a/lib/web/webprofile.h +++ b/lib/web/webprofile.h @@ -65,6 +65,10 @@ public: { return qAsConst(m_cookies); } + const QMap headers() const + { + return qAsConst(m_headers); + } // search url QString search() const; @@ -86,6 +90,8 @@ public: void setHttpCacheMaximumSize(int maxSize); void setHttpCacheType(int type); void setHttpUserAgent(const QString &userAgent); + void setHttpHeader(const QString &name, const QString &value); + void removeHttpHeader(const QString &name); void setSpellCheckEnabled(bool enable); @@ -97,6 +103,8 @@ signals: void propertyChanged(const QString &name, const QVariant &value); void attributeChanged(const QWebEngineSettings::WebAttribute attribute, const bool value); + void headerChanged(const QString &name, const QString &value); + void headerRemoved(const QString &name); private: static WebProfile *profile; @@ -107,6 +115,7 @@ private: QUrl m_newtab = QUrl("about:blank"); QVector m_cookies; + QMap m_headers; }; #endif // SMOLBOTE_WEBENGINEPROFILE_H diff --git a/plugins/ProfileEditor/CMakeLists.txt b/plugins/ProfileEditor/CMakeLists.txt index d22d3d6..7c9a774 100644 --- a/plugins/ProfileEditor/CMakeLists.txt +++ b/plugins/ProfileEditor/CMakeLists.txt @@ -20,6 +20,9 @@ add_library(ProfileEditorPlugin SHARED forms/newprofiledialog.cpp forms/newprofiledialog.h forms/newprofiledialog.ui + forms/newhttpheaderdialog.cpp + forms/newhttpheaderdialog.h + forms/newhttpheaderdialog.ui ) target_include_directories(ProfileEditorPlugin diff --git a/plugins/ProfileEditor/forms/newhttpheaderdialog.cpp b/plugins/ProfileEditor/forms/newhttpheaderdialog.cpp new file mode 100644 index 0000000..3978c4e --- /dev/null +++ b/plugins/ProfileEditor/forms/newhttpheaderdialog.cpp @@ -0,0 +1,32 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#include "newhttpheaderdialog.h" +#include "ui_newhttpheaderdialog.h" + +NewHttpHeaderDialog::NewHttpHeaderDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::NewHttpHeaderDialog) +{ + ui->setupUi(this); +} + +NewHttpHeaderDialog::~NewHttpHeaderDialog() +{ + delete ui; +} + +QString NewHttpHeaderDialog::header() const +{ + return ui->header->text(); +} + +QString NewHttpHeaderDialog::value() const +{ + return ui->value->text(); +} diff --git a/plugins/ProfileEditor/forms/newhttpheaderdialog.h b/plugins/ProfileEditor/forms/newhttpheaderdialog.h new file mode 100644 index 0000000..53a2a80 --- /dev/null +++ b/plugins/ProfileEditor/forms/newhttpheaderdialog.h @@ -0,0 +1,33 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#ifndef NEWHTTPHEADERDIALOG_H +#define NEWHTTPHEADERDIALOG_H + +#include + +namespace Ui { +class NewHttpHeaderDialog; +} + +class NewHttpHeaderDialog : public QDialog +{ + Q_OBJECT + +public: + explicit NewHttpHeaderDialog(QWidget *parent = nullptr); + ~NewHttpHeaderDialog(); + + QString header() const; + QString value() const; + +private: + Ui::NewHttpHeaderDialog *ui; +}; + +#endif // NEWHTTPHEADERDIALOG_H diff --git a/plugins/ProfileEditor/forms/newhttpheaderdialog.ui b/plugins/ProfileEditor/forms/newhttpheaderdialog.ui new file mode 100644 index 0000000..a457ba6 --- /dev/null +++ b/plugins/ProfileEditor/forms/newhttpheaderdialog.ui @@ -0,0 +1,84 @@ + + + NewHttpHeaderDialog + + + + 0 + 0 + 320 + 108 + + + + Dialog + + + + + + Header + + + + + + + + + + Value + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + NewHttpHeaderDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + NewHttpHeaderDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/plugins/ProfileEditor/forms/profileview.cpp b/plugins/ProfileEditor/forms/profileview.cpp index ccb4ae5..4a89af6 100644 --- a/plugins/ProfileEditor/forms/profileview.cpp +++ b/plugins/ProfileEditor/forms/profileview.cpp @@ -13,6 +13,7 @@ #include #include #include +#include "newhttpheaderdialog.h" inline void connectSetting(QCheckBox *checkBox, WebProfile *profile, QWebEngineSettings::WebAttribute attr) { @@ -86,6 +87,28 @@ ProfileView::ProfileView(WebProfile *profile, QWidget *parent) ui->storagePath_lineEdit->setText(m_profile->persistentStoragePath()); ui->cachePath_lineEdit->setText(m_profile->cachePath()); + // headers tab + for(auto i = m_profile->headers().constBegin(); i != m_profile->headers().constEnd(); ++i) { + //ui->httpHeaders->addItem(); + headerChanged(i.key(), i.value()); + } + connect(m_profile, &WebProfile::headerChanged, this, &ProfileView::headerChanged); + connect(m_profile, &WebProfile::headerRemoved, this, &ProfileView::headerRemoved); + connect(ui->headers_insert, &QPushButton::clicked, m_profile, [this]() { + auto *dlg = new NewHttpHeaderDialog(this); + if(dlg->exec() == QDialog::Accepted) { + m_profile->setHttpHeader(dlg->header(), dlg->value()); + } + delete dlg; + }); + connect(ui->headers_delete, &QPushButton::clicked, m_profile, [this]() { + for(auto &list : ui->httpHeaders->selectedRanges()) { + for(int i = list.bottomRow(); i >= list.topRow(); --i) { + m_profile->removeHttpHeader(ui->httpHeaders->item(i, 0)->text()); + } + } + }); + // settings tab connectSetting(ui->autoloadImages, m_profile, QWebEngineSettings::AutoLoadImages); connectSetting(ui->autoloadIcons, m_profile, QWebEngineSettings::AutoLoadIconsForPage); @@ -157,6 +180,29 @@ void ProfileView::loadCookies(QWebEngineCookieStore *store) connect(ui->cookies_deleteAll, &QPushButton::clicked, store, &QWebEngineCookieStore::deleteAllCookies); } +void ProfileView::headerChanged(const QString &name, const QString &value) +{ + const auto items = ui->httpHeaders->findItems(name, Qt::MatchExactly); + if(!items.isEmpty()) { + QTableWidgetItem *valueItem = ui->httpHeaders->item(items.constFirst()->row(), 1); + valueItem->setText(value); + } else { + // new header + const int index = ui->httpHeaders->rowCount(); + ui->httpHeaders->setRowCount(index + 1); + ui->httpHeaders->setItem(index, 0, new QTableWidgetItem(name)); + ui->httpHeaders->setItem(index, 1, new QTableWidgetItem(value)); + } +} + +void ProfileView::headerRemoved(const QString& name) +{ + const auto items = ui->httpHeaders->findItems(name, Qt::MatchExactly); + if(!items.isEmpty()) { + ui->httpHeaders->removeRow(items.constFirst()->row()); + } +} + void ProfileView::cookieAdded(const QNetworkCookie &cookie) { auto index = ui->cookies->rowCount(); diff --git a/plugins/ProfileEditor/forms/profileview.h b/plugins/ProfileEditor/forms/profileview.h index 5ff472b..d05b0f1 100644 --- a/plugins/ProfileEditor/forms/profileview.h +++ b/plugins/ProfileEditor/forms/profileview.h @@ -33,6 +33,9 @@ public: private slots: void loadCookies(QWebEngineCookieStore *store); + void headerChanged(const QString &name, const QString &value); + void headerRemoved(const QString &name); + void cookieAdded(const QNetworkCookie &cookie); void cookieRemoved(const QNetworkCookie &cookie); diff --git a/plugins/ProfileEditor/forms/profileview.ui b/plugins/ProfileEditor/forms/profileview.ui index 74b6d5d..630e53d 100644 --- a/plugins/ProfileEditor/forms/profileview.ui +++ b/plugins/ProfileEditor/forms/profileview.ui @@ -234,6 +234,70 @@ + + + Headers + + + + + + 200 + + + 100 + + + true + + + false + + + + Name + + + + + Value + + + + + + + + + + Insert + + + + + + + Delete + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Settings @@ -249,8 +313,8 @@ 0 0 - 276 - 855 + 584 + 797 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 45a4c06..e8f2794 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -38,6 +38,8 @@ set(srclist subwindow/tabwidget.h # webengine + webengine/filter.cpp + webengine/filter.h webengine/urlinterceptor.cpp webengine/urlinterceptor.h webengine/webpage.cpp diff --git a/src/browser.cpp b/src/browser.cpp index 7bf4adf..7295b56 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -27,6 +27,7 @@ #include #include #include +#include "webengine/filter.h" Browser::Browser(int &argc, char *argv[], bool allowSecondary) : SingleApplication(argc, argv, allowSecondary, SingleApplication::User | SingleApplication::SecondaryNotification | SingleApplication::ExcludeAppVersion) @@ -58,7 +59,8 @@ QPair Browser::loadProfile(const QString &id) { WebProfile *profile = m_profileManager->loadProfile(id); connect(profile, &WebProfile::downloadRequested, m_downloads.get(), &DownloadsWidget::addDownload); - profile->setRequestInterceptor(m_urlFilter.get()); + auto *interceptor = new UrlRequestInterceptor(m_urlFilter.get(), profile, profile); + profile->setRequestInterceptor(interceptor); return QPair(m_profileManager->id(profile), profile); } @@ -107,7 +109,7 @@ void Browser::setup() // downloads m_downloads = std::make_unique(m_config->value("downloads.path").value()); // url request filter - m_urlFilter = std::make_unique(m_config); + m_urlFilter = std::make_unique(m_config); // cookie request filter // load profiles diff --git a/src/browser.h b/src/browser.h index b4352a7..6731f59 100644 --- a/src/browser.h +++ b/src/browser.h @@ -20,7 +20,7 @@ class Configuration; class BookmarksWidget; class DownloadsWidget; -class UrlRequestInterceptor; +class Filter; class MainWindow; class WebProfile; class Browser : public SingleApplication, public BrowserInterface @@ -62,7 +62,7 @@ private: std::shared_ptr m_bookmarks; std::unique_ptr m_downloads; ProfileManager *m_profileManager; - std::unique_ptr m_urlFilter; + std::unique_ptr m_urlFilter; QVector m_windows; QVector m_plugins; diff --git a/src/webengine/filter.cpp b/src/webengine/filter.cpp new file mode 100644 index 0000000..b250843 --- /dev/null +++ b/src/webengine/filter.cpp @@ -0,0 +1,116 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#include "filter.h" +#include "urlinterceptor.h" +#include +#include +#include +#include +#include +#include "util.h" + + +QHash parseHostlist(const QString &filename) +{ + QHash rules; + + if(QFile hostfile(filename); hostfile.open(QIODevice::ReadOnly | QIODevice::Text)) { + + // with a QTextStream we can read lines without getting linebreaks at the end + QTextStream hostfile_stream(&hostfile); + + while(!hostfile_stream.atEnd()) { + + // read line and remove any whitespace at the end + const QString &line = hostfile_stream.readLine().trimmed(); + + // skip comments and empty lines + if(line.isEmpty() || line.startsWith('#')) + continue; + + // everything else should be a rule + // format is + // 0.0.0.0 hostname + const QStringList &parts = line.split(' '); + const QString &redirect = parts.at(0); + + for(auto i = parts.constBegin() + 1; i != parts.constEnd(); ++i) { + if(!rules.contains(*i)) { + Filter::HostRule rule{}; + rule.isBlocking = (redirect == "0.0.0.0"); + rules.insert(*i, rule); + } + } + + // for(const QString &host : parts.mid(1)) { + // if(!rules.contains(host)) { + // UrlRequestInterceptor::HostRule rule{}; + // rule.isBlocking = redirect == "0.0.0.0"; + // rules.insert(host, rule); + // } + // } + } + + hostfile.close(); + } + + return rules; +} +/* +inline std::vector parseAdBlockList(const QString &filename) +{ + std::vector rules; + QFile list(filename); + + if(list.open(QIODevice::ReadOnly | QIODevice::Text), true) { + QTextStream l(&list); + QString line; + while(l.readLineInto(&line)) { + AdBlockRule rule(line); + if(rule.isEnabled()) { + rules.emplace_back(std::move(rule)); + } + } + list.close(); + } + + return rules; +}*/ + +Filter::Filter::Filter(const std::unique_ptr &config, QObject* parent) + : QObject(parent) +{ + // parse headers + if(const auto headers = config->value("filter.header"); headers) { + for(const QString &header : headers.value()) { + const auto list = header.split(QLatin1Literal(":")); + if(list.length() == 2) + m_headers.insert(list.at(0).toLatin1(), list.at(1).toLatin1()); + } + } + + const QStringList hostfiles = Util::files(config->value("filter.path").value()); + for(const QString &hostfile : hostfiles) { + m_hostlist.unite(parseHostlist(hostfile)); + } + + /* + auto filtersPath = config->value("filter.adblock"); + if(filtersPath) + filters = parseAdBlockList(filtersPath.value()); + */ +} + +std::optional Filter::hostlistRule(const QString& url) const +{ + if(!m_hostlist.contains(url)) + return std::nullopt; + + return std::optional(m_hostlist.value(url)); +} diff --git a/src/webengine/filter.h b/src/webengine/filter.h new file mode 100644 index 0000000..3eac5ee --- /dev/null +++ b/src/webengine/filter.h @@ -0,0 +1,45 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#ifndef SMOLBOTE_FILTER_H +#define SMOLBOTE_FILTER_H + +#include "urlfilter/filterrule.h" +#include +#include +#include + +class Configuration; +class Filter : public QObject +{ + Q_OBJECT +public: + struct HostRule { + bool isBlocking; + }; + + explicit Filter(const std::unique_ptr &config, QObject *parent = nullptr); + ~Filter() override = default; + + const QHash hostlist() const + { + return qAsConst(m_hostlist); + } + std::optional hostlistRule(const QString &url) const; + + const QMap headers() const + { + return qAsConst(m_headers); + } + +private: + QHash m_hostlist; + QMap m_headers; +}; + +#endif // SMOLBOTE_FILTER_H diff --git a/src/webengine/urlinterceptor.cpp b/src/webengine/urlinterceptor.cpp index db4aea9..cf9b85f 100644 --- a/src/webengine/urlinterceptor.cpp +++ b/src/webengine/urlinterceptor.cpp @@ -14,127 +14,32 @@ #include #include #include +#include "filter.h" +#include -inline std::vector parseAdBlockList(const QString &filename) -{ - std::vector rules; - QFile list(filename); - - if(list.open(QIODevice::ReadOnly | QIODevice::Text), true) { - QTextStream l(&list); - QString line; - while(l.readLineInto(&line)) { - AdBlockRule rule(line); - if(rule.isEnabled()) { - rules.emplace_back(std::move(rule)); - } - } - list.close(); - } - - return rules; -} +// test DNT on https://browserleaks.com/donottrack -UrlRequestInterceptor::UrlRequestInterceptor(const std::unique_ptr &config, QObject *parent) +UrlRequestInterceptor::UrlRequestInterceptor(Filter* filter, WebProfile* profile, QObject* parent) : QWebEngineUrlRequestInterceptor(parent) { - QDir hostsD(config->value("filter.path").value()); - const QStringList hostFiles = hostsD.entryList(QDir::Files); - for(const QString &file : hostFiles) { - const QString absPath = hostsD.absoluteFilePath(file); - auto r = parse(absPath); -#ifdef QT_DEBUG - qDebug("Parsed %i rules from %s", r.count(), qUtf8Printable(absPath)); -#endif - - rules.unite(r); - } - - const auto header = config->value>("filter.header"); - if(header) { - for(const std::string &h : header.value()) { - std::vector s; - boost::split(s, h, boost::is_any_of(":=")); - auto pair = std::make_pair(s.at(0), s.at(1)); - m_headers.emplace_back(pair); - } - } - - auto filtersPath = config->value("filter.adblock"); - if(filtersPath) - filters = parseAdBlockList(filtersPath.value()); + Q_CHECK_PTR(filter); + m_filter = filter; + Q_CHECK_PTR(profile); + m_profile = profile; } -// test DNT on https://browserleaks.com/donottrack void UrlRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) { - for(const Header &header : m_headers) { - info.setHttpHeader(QByteArray::fromStdString(header.first), QByteArray::fromStdString(header.second)); + auto hostlistCheck = m_filter->hostlistRule(info.requestUrl().host()); + if(hostlistCheck) { + info.block(hostlistCheck.value().isBlocking); } - if(rules.contains(info.requestUrl().host())) { - info.block(rules.value(info.requestUrl().host()).isBlocking); - return; + // set headers + for(auto i = m_filter->headers().constBegin(); i != m_filter->headers().constEnd(); ++i) { + info.setHttpHeader(i.key(), i.value()); } - - const uint domainHash = qHash(info.firstPartyUrl().host()); - const QWebEngineUrlRequestInfo::ResourceType type = info.resourceType(); - const QUrl requestUrl = info.requestUrl(); - for(const FilterRule &rule : filters) { - if(rule.matchesDomain(domainHash) && rule.matchesType(type) && rule.matchesUrl(requestUrl)) { - info.block(rule.isBlocking()); -#ifdef QT_DEBUG - qDebug("--> blocked %s", qUtf8Printable(info.requestUrl().toString())); -#endif - break; - } + for(auto i = m_profile->headers().constBegin(); i != m_profile->headers().constEnd(); ++i) { + info.setHttpHeader(i.key(), i.value()); } } - -QHash parse(const QString &filename) -{ - QHash rules; - - QFile hostfile(filename); - if(hostfile.open(QIODevice::ReadOnly | QIODevice::Text)) { - - // with a QTextStream we can read lines without getting linebreaks at the end - QTextStream hostfile_stream(&hostfile); - - while(!hostfile_stream.atEnd()) { - - // read line and remove any whitespace at the end - const QString &line = hostfile_stream.readLine().trimmed(); - - // skip comments and empty lines - if(line.isEmpty() || line.startsWith('#')) - continue; - - // everything else should be a rule - // format is - // 0.0.0.0 hostname - const QStringList &parts = line.split(' '); - const QString &redirect = parts.at(0); - - for(auto i = parts.constBegin() + 1; i != parts.constEnd(); ++i) { - if(!rules.contains(*i)) { - UrlRequestInterceptor::HostRule rule{}; - rule.isBlocking = (redirect == "0.0.0.0"); - rules.insert(*i, rule); - } - } - - // for(const QString &host : parts.mid(1)) { - // if(!rules.contains(host)) { - // UrlRequestInterceptor::HostRule rule{}; - // rule.isBlocking = redirect == "0.0.0.0"; - // rules.insert(host, rule); - // } - // } - } - - hostfile.close(); - } - - return rules; -} diff --git a/src/webengine/urlinterceptor.h b/src/webengine/urlinterceptor.h index 575e0c9..420a161 100644 --- a/src/webengine/urlinterceptor.h +++ b/src/webengine/urlinterceptor.h @@ -15,29 +15,21 @@ #include #include -typedef std::pair Header; - +class Filter; +class WebProfile; class Configuration; class UrlRequestInterceptor : public QWebEngineUrlRequestInterceptor { Q_OBJECT public: - struct HostRule { - bool isBlocking; - }; - - explicit UrlRequestInterceptor(const std::unique_ptr &config, QObject *parent = nullptr); + explicit UrlRequestInterceptor(Filter *filter, WebProfile *profile, QObject *parent = nullptr); ~UrlRequestInterceptor() override = default; void interceptRequest(QWebEngineUrlRequestInfo &info) override; private: - QHash rules; - std::vector filters; - std::vector
m_headers; + Filter *m_filter; + WebProfile *m_profile; }; -QHash parse(const QString &filename); -inline std::vector parseAdBlockList(const QString &filename); - #endif // SMOLBOTE_URLREQUESTINTERCEPTOR_H -- cgit v1.2.1