From 0bffa066db7c228ef4da666f7eae33582c4dd480 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (qlassez)" Date: Fri, 18 Dec 2015 14:30:31 +0300 Subject: [PATCH 1/4] Make DownloadManager to save/load cookies --- src/app/application.cpp | 2 +- src/base/net/downloadmanager.cpp | 81 +++++++++++++++++++++++++++++--- src/base/net/downloadmanager.h | 8 ++-- src/base/preferences.cpp | 29 ++++++++++-- src/base/preferences.h | 4 ++ 5 files changed, 108 insertions(+), 16 deletions(-) diff --git a/src/app/application.cpp b/src/app/application.cpp index 9bdb62713..624bcb664 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -462,10 +462,10 @@ void Application::cleanup() #ifndef DISABLE_COUNTRIES_RESOLUTION Net::GeoIPManager::freeInstance(); #endif + Net::DownloadManager::freeInstance(); Preferences::freeInstance(); Logger::freeInstance(); IconProvider::freeInstance(); - Net::DownloadManager::freeInstance(); #ifndef DISABLE_GUI #ifdef Q_OS_WIN typedef BOOL (WINAPI *PSHUTDOWNBRDESTROY)(HWND); diff --git a/src/base/net/downloadmanager.cpp b/src/base/net/downloadmanager.cpp index c21fb813a..21672274d 100644 --- a/src/base/net/downloadmanager.cpp +++ b/src/base/net/downloadmanager.cpp @@ -27,11 +27,13 @@ * exception statement from your version. */ +#include #include #include #include #include #include +#include #include #include #include @@ -40,6 +42,71 @@ #include "downloadhandler.h" #include "downloadmanager.h" +namespace +{ + class NetworkCookieJar: public QNetworkCookieJar + { + public: + explicit NetworkCookieJar(QObject *parent = 0) + : QNetworkCookieJar(parent) + { + QDateTime now = QDateTime::currentDateTime(); + QList cookies = Preferences::instance()->getNetworkCookies(); + foreach (const QNetworkCookie &cookie, Preferences::instance()->getNetworkCookies()) { + if (cookie.isSessionCookie() || (cookie.expirationDate() <= now)) + cookies.removeAll(cookie); + } + + setAllCookies(cookies); + } + + ~NetworkCookieJar() + { + QDateTime now = QDateTime::currentDateTime(); + QList cookies = allCookies(); + foreach (const QNetworkCookie &cookie, allCookies()) { + if (cookie.isSessionCookie() || (cookie.expirationDate() <= now)) + cookies.removeAll(cookie); + } + + Preferences::instance()->setNetworkCookies(cookies); + } + +#ifndef QBT_USES_QT5 + virtual bool deleteCookie(const QNetworkCookie &cookie) + { + auto myCookies = allCookies(); + myCookies.removeAll(cookie); + setAllCookies(myCookies); + } +#endif + + QList cookiesForUrl(const QUrl &url) const override + { + QDateTime now = QDateTime::currentDateTime(); + QList cookies = QNetworkCookieJar::cookiesForUrl(url); + foreach (const QNetworkCookie &cookie, QNetworkCookieJar::cookiesForUrl(url)) { + if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now)) + cookies.removeAll(cookie); + } + + return cookies; + } + + bool setCookiesFromUrl(const QList &cookieList, const QUrl &url) override + { + QDateTime now = QDateTime::currentDateTime(); + QList cookies = cookieList; + foreach (const QNetworkCookie &cookie, cookieList) { + if (!cookie.isSessionCookie() && (cookie.expirationDate() <= now)) + cookies.removeAll(cookie); + } + + return QNetworkCookieJar::setCookiesFromUrl(cookies, url); + } + }; +} + using namespace Net; DownloadManager *DownloadManager::m_instance = 0; @@ -50,10 +117,7 @@ DownloadManager::DownloadManager(QObject *parent) #ifndef QT_NO_OPENSSL connect(&m_networkManager, SIGNAL(sslErrors(QNetworkReply *, QList)), this, SLOT(ignoreSslErrors(QNetworkReply *, QList))); #endif -} - -DownloadManager::~DownloadManager() -{ + m_networkManager.setCookieJar(new NetworkCookieJar(this)); } void DownloadManager::initInstance() @@ -92,22 +156,27 @@ DownloadHandler *DownloadManager::downloadUrl(const QString &url, bool saveToFil request.setRawHeader("Referer", request.url().toEncoded().data()); qDebug("Downloading %s...", request.url().toEncoded().data()); + qDebug() << "Cookies:" << m_networkManager.cookieJar()->cookiesForUrl(request.url()); // accept gzip request.setRawHeader("Accept-Encoding", "gzip"); return new DownloadHandler(m_networkManager.get(request), this, saveToFile, limit, handleRedirectToMagnet); } -QList DownloadManager::cookiesForUrl(const QString &url) const +QList DownloadManager::cookiesForUrl(const QUrl &url) const { return m_networkManager.cookieJar()->cookiesForUrl(url); } bool DownloadManager::setCookiesFromUrl(const QList &cookieList, const QUrl &url) { - qDebug("Setting %d cookies for url: %s", cookieList.size(), qPrintable(url.toString())); return m_networkManager.cookieJar()->setCookiesFromUrl(cookieList, url); } +bool DownloadManager::deleteCookie(const QNetworkCookie &cookie) +{ + return static_cast(m_networkManager.cookieJar())->deleteCookie(cookie); +} + void DownloadManager::applyProxySettings() { QNetworkProxy proxy; diff --git a/src/base/net/downloadmanager.h b/src/base/net/downloadmanager.h index d5fe6b367..8621f70bd 100644 --- a/src/base/net/downloadmanager.h +++ b/src/base/net/downloadmanager.h @@ -33,12 +33,10 @@ #include #include -QT_BEGIN_NAMESPACE class QNetworkReply; class QNetworkCookie; class QSslError; class QUrl; -QT_END_NAMESPACE namespace Net { @@ -54,8 +52,9 @@ namespace Net static DownloadManager *instance(); DownloadHandler *downloadUrl(const QString &url, bool saveToFile = false, qint64 limit = 0, bool handleRedirectToMagnet = false); - QList cookiesForUrl(const QString &url) const; + QList cookiesForUrl(const QUrl &url) const; bool setCookiesFromUrl(const QList &cookieList, const QUrl &url); + bool deleteCookie(const QNetworkCookie &cookie); private slots: #ifndef QT_NO_OPENSSL @@ -63,8 +62,7 @@ namespace Net #endif private: - DownloadManager(QObject *parent = 0); - ~DownloadManager(); + explicit DownloadManager(QObject *parent = 0); void applyProxySettings(); diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index 590039380..783fcc6a9 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -1027,12 +1027,12 @@ void Preferences::setFilteringEnabled(bool enabled) bool Preferences::isFilteringTrackerEnabled() const { - return value("Preferences/IPFilter/FilterTracker", false).toBool(); + return value("Preferences/IPFilter/FilterTracker", false).toBool(); } void Preferences::setFilteringTrackerEnabled(bool enabled) { - setValue("Preferences/IPFilter/FilterTracker", enabled); + setValue("Preferences/IPFilter/FilterTracker", enabled); } QString Preferences::getFilter() const @@ -2559,11 +2559,32 @@ void Preferences::setHostNameCookies(const QString &host_name, const QList Preferences::getNetworkCookies() const +{ + QList cookies; + QStringList rawCookies = value("Network/Cookies").toStringList(); + foreach (const QString &rawCookie, rawCookies) + cookies << QNetworkCookie::parseCookies(rawCookie.toUtf8()); + + return cookies; +} + +void Preferences::setNetworkCookies(const QList &cookies) +{ + QStringList rawCookies; + foreach (const QNetworkCookie &cookie, cookies) + rawCookies << cookie.toRawForm(); + + setValue("Network/Cookies", rawCookies); +} + +int Preferences::getSpeedWidgetPeriod() const +{ return value("SpeedWidget/period", 1).toInt(); } -void Preferences::setSpeedWidgetPeriod(const int period) { +void Preferences::setSpeedWidgetPeriod(const int period) +{ setValue("SpeedWidget/period", period); } diff --git a/src/base/preferences.h b/src/base/preferences.h index 4767a1d59..96fe22fb7 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -542,6 +542,10 @@ public: QList getHostNameQNetworkCookies(const QString& host_name) const; void setHostNameCookies(const QString &host_name, const QList &cookies); + // Network + QList getNetworkCookies() const; + void setNetworkCookies(const QList &cookies); + // SpeedWidget int getSpeedWidgetPeriod() const; void setSpeedWidgetPeriod(const int period); From 12c151eb69e2894e7542ef1e70ff6fc50caa79a2 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (qlassez)" Date: Fri, 18 Dec 2015 20:45:43 +0300 Subject: [PATCH 2/4] Save RSS cookies to common cookie storage Closes #4305 --- src/app/upgrade.h | 4 ++++ src/base/preferences.cpp | 47 +++++++++++++++----------------------- src/base/preferences.h | 5 ++-- src/gui/rss/cookiesdlg.cpp | 40 ++++++++++++++++++-------------- src/gui/rss/cookiesdlg.h | 12 ++++++---- src/gui/rss/rss_imp.cpp | 25 ++++++++++---------- 6 files changed, 68 insertions(+), 65 deletions(-) diff --git a/src/app/upgrade.h b/src/app/upgrade.h index 0a9ff75c8..1f6366210 100644 --- a/src/app/upgrade.h +++ b/src/app/upgrade.h @@ -45,6 +45,7 @@ #include "base/utils/misc.h" #include "base/utils/string.h" #include "base/qinisettings.h" +#include "base/preferences.h" bool userAcceptsUpgrade() { @@ -114,6 +115,9 @@ bool upgradeResumeFile(const QString &filepath, const QVariantHash &oldTorrent, bool upgrade(bool ask = true) { + // Move RSS cookies to common storage + Preferences::instance()->moveRSSCookies(); + QIniSettings *oldResumeSettings = new QIniSettings("qBittorrent", "qBittorrent-resume"); QString oldResumeFilename = oldResumeSettings->fileName(); QVariantHash oldResumeData = oldResumeSettings->value("torrents").toHash(); diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index 783fcc6a9..9aab3ad9b 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -2525,38 +2525,29 @@ void Preferences::setToolbarTextPosition(const int position) setValue("Toolbar/textPosition", position); } -QList Preferences::getHostNameCookies(const QString &host_name) const +void Preferences::moveRSSCookies() { - QMap hosts_table = value("Rss/hosts_cookies").toMap(); - if (!hosts_table.contains(host_name)) return QList(); - QByteArray raw_cookies = hosts_table.value(host_name).toByteArray(); - return raw_cookies.split(':'); -} - -QList Preferences::getHostNameQNetworkCookies(const QString& host_name) const -{ - QList cookies; - const QList raw_cookies = getHostNameCookies(host_name); - foreach (const QByteArray& raw_cookie, raw_cookies) { - QList cookie_parts = raw_cookie.split('='); - if (cookie_parts.size() == 2) { - qDebug("Loading cookie: %s = %s", cookie_parts.first().constData(), cookie_parts.last().constData()); - cookies << QNetworkCookie(cookie_parts.first(), cookie_parts.last()); + QList cookies = getNetworkCookies(); + QVariantMap hostsTable = value("Rss/hosts_cookies").toMap(); + foreach (const QString &key, hostsTable.keys()) { + QVariant value = hostsTable[key]; + QList rawCookies = value.toByteArray().split(':'); + foreach (const QByteArray &rawCookie, rawCookies) { + foreach (QNetworkCookie cookie, QNetworkCookie::parseCookies(rawCookie)) { + cookie.setDomain(key); + cookie.setPath("/"); + cookie.setExpirationDate(QDateTime::currentDateTime().addYears(10)); + cookies << cookie; + } } } - return cookies; -} -void Preferences::setHostNameCookies(const QString &host_name, const QList &cookies) -{ - QMap hosts_table = value("Rss/hosts_cookies").toMap(); - QByteArray raw_cookies = ""; - foreach (const QByteArray& cookie, cookies) - raw_cookies += cookie + ":"; - if (raw_cookies.endsWith(":")) - raw_cookies.chop(1); - hosts_table.insert(host_name, raw_cookies); - setValue("Rss/hosts_cookies", hosts_table); + setNetworkCookies(cookies); + + QWriteLocker locker(&lock); + dirty = true; + timer.start(); + m_data.remove("Rss/hosts_cookies"); } QList Preferences::getNetworkCookies() const diff --git a/src/base/preferences.h b/src/base/preferences.h index 96fe22fb7..23047ed4d 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -538,13 +538,12 @@ public: void setRssFeedsUrls(const QStringList &rssFeeds); QStringList getRssFeedsAliases() const; void setRssFeedsAliases(const QStringList &rssAliases); - QList getHostNameCookies(const QString &host_name) const; - QList getHostNameQNetworkCookies(const QString& host_name) const; - void setHostNameCookies(const QString &host_name, const QList &cookies); // Network QList getNetworkCookies() const; void setNetworkCookies(const QList &cookies); + // Temporary method for upgrade purposes + void moveRSSCookies(); // SpeedWidget int getSpeedWidgetPeriod() const; diff --git a/src/gui/rss/cookiesdlg.cpp b/src/gui/rss/cookiesdlg.cpp index e5662d2fc..ed4ce9c41 100644 --- a/src/gui/rss/cookiesdlg.cpp +++ b/src/gui/rss/cookiesdlg.cpp @@ -31,12 +31,14 @@ #include "cookiesdlg.h" #include "ui_cookiesdlg.h" #include "guiiconprovider.h" +#include "base/net/downloadmanager.h" #include +#include enum CookiesCols { COOKIE_KEY, COOKIE_VALUE}; -CookiesDlg::CookiesDlg(QWidget *parent, const QList &raw_cookies) : +CookiesDlg::CookiesDlg(const QUrl &url, QWidget *parent) : QDialog(parent), ui(new Ui::CookiesDlg) { @@ -46,13 +48,13 @@ CookiesDlg::CookiesDlg(QWidget *parent, const QList &raw_cookies) : ui->del_btn->setIcon(GuiIconProvider::instance()->getIcon("list-remove")); ui->infos_lbl->setText(tr("Common keys for cookies are: '%1', '%2'.\nYou should get this information from your Web browser preferences.").arg("uid").arg("pass")); - foreach (const QByteArray &raw_cookie, raw_cookies) { - QList cookie_parts = raw_cookie.split('='); - if (cookie_parts.size() != 2) continue; + + QList cookies = Net::DownloadManager::instance()->cookiesForUrl(url); + foreach (const QNetworkCookie &cookie, cookies) { const int i = ui->cookiesTable->rowCount(); ui->cookiesTable->setRowCount(i+1); - ui->cookiesTable->setItem(i, COOKIE_KEY, new QTableWidgetItem(cookie_parts.first().data())); - ui->cookiesTable->setItem(i, COOKIE_VALUE, new QTableWidgetItem(cookie_parts.last().data())); + ui->cookiesTable->setItem(i, COOKIE_KEY, new QTableWidgetItem(QString(cookie.name()))); + ui->cookiesTable->setItem(i, COOKIE_VALUE, new QTableWidgetItem(QString(cookie.value()))); } } @@ -75,8 +77,9 @@ void CookiesDlg::on_del_btn_clicked() { } } -QList CookiesDlg::getCookies() const { - QList ret; +QList CookiesDlg::getCookies() const { + QList ret; + auto now = QDateTime::currentDateTime(); for (int i=0; icookiesTable->rowCount(); ++i) { QString key; if (ui->cookiesTable->item(i, COOKIE_KEY)) @@ -85,20 +88,23 @@ QList CookiesDlg::getCookies() const { if (ui->cookiesTable->item(i, COOKIE_VALUE)) value = ui->cookiesTable->item(i, COOKIE_VALUE)->text().trimmed(); if (!key.isEmpty() && !value.isEmpty()) { - const QString raw_cookie = key+"="+value; - qDebug("Cookie: %s", qPrintable(raw_cookie)); - ret << raw_cookie.toLocal8Bit(); + QNetworkCookie cookie(key.toUtf8(), value.toUtf8()); + // TODO: Delete this hack when advanced Cookie dialog will be implemented. + cookie.setExpirationDate(now.addYears(10)); + qDebug("Cookie: %s", cookie.toRawForm().data()); + ret << cookie; } } return ret; } -QList CookiesDlg::askForCookies(QWidget *parent, const QList &raw_cookies, bool *ok) { - CookiesDlg dlg(parent, raw_cookies); +bool CookiesDlg::askForCookies(QWidget *parent, const QUrl &url, QList &out) +{ + CookiesDlg dlg(url, parent); if (dlg.exec()) { - *ok = true; - return dlg.getCookies(); + out = dlg.getCookies(); + return true; } - *ok = false; - return QList(); + + return false; } diff --git a/src/gui/rss/cookiesdlg.h b/src/gui/rss/cookiesdlg.h index 3e7469973..e9e6fc733 100644 --- a/src/gui/rss/cookiesdlg.h +++ b/src/gui/rss/cookiesdlg.h @@ -32,22 +32,24 @@ #define COOKIESDLG_H #include +#include + +class QNetworkCookie; +class QUrl; -QT_BEGIN_NAMESPACE namespace Ui { class CookiesDlg; } -QT_END_NAMESPACE class CookiesDlg : public QDialog { Q_OBJECT public: - explicit CookiesDlg(QWidget *parent = 0, const QList &raw_cookies = QList()); + explicit CookiesDlg(const QUrl &url, QWidget *parent = 0); ~CookiesDlg(); - QList getCookies() const; - static QList askForCookies(QWidget *parent, const QList &raw_cookies, bool *ok); + QList getCookies() const; + static bool askForCookies(QWidget *parent, const QUrl &url, QList &out); protected slots: void on_add_btn_clicked(); diff --git a/src/gui/rss/rss_imp.cpp b/src/gui/rss/rss_imp.cpp index 2cda0096c..106b7cb30 100644 --- a/src/gui/rss/rss_imp.cpp +++ b/src/gui/rss/rss_imp.cpp @@ -142,18 +142,19 @@ void RSSImp::displayItemsListMenu(const QPoint&) void RSSImp::on_actionManage_cookies_triggered() { Q_ASSERT(!m_feedList->selectedItems().empty()); - // Get feed hostname - QString feed_url = m_feedList->getItemID(m_feedList->selectedItems().first()); - QString feed_hostname = QUrl::fromEncoded(feed_url.toUtf8()).host(); - qDebug("RSS Feed hostname is: %s", qPrintable(feed_hostname)); - Q_ASSERT(!feed_hostname.isEmpty()); - bool ok = false; - Preferences* const pref = Preferences::instance(); - QList raw_cookies = CookiesDlg::askForCookies(this, pref->getHostNameCookies(feed_hostname), &ok); - if (ok) { - qDebug() << "Settings cookies for host name: " << feed_hostname; - pref->setHostNameCookies(feed_hostname, raw_cookies); - Net::DownloadManager::instance()->setCookiesFromUrl(pref->getHostNameQNetworkCookies(feed_hostname), feed_hostname); + + // TODO: Create advanced application wide Cookie dialog and use it everywhere. + QUrl feedUrl = QUrl::fromEncoded(m_feedList->getItemID(m_feedList->selectedItems().first()).toUtf8()); + QList cookies; + if (CookiesDlg::askForCookies(this, feedUrl, cookies)) { + auto downloadManager = Net::DownloadManager::instance(); + QList oldCookies = downloadManager->cookiesForUrl(feedUrl); + foreach (const QNetworkCookie &oldCookie, oldCookies) { + if (!cookies.contains(oldCookie)) + downloadManager->deleteCookie(oldCookie); + } + + downloadManager->setCookiesFromUrl(cookies, feedUrl); } } From e378a65508b24b445c9360a1987e63a33c0bfe55 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (qlassez)" Date: Sat, 19 Dec 2015 09:48:46 +0300 Subject: [PATCH 3/4] Use DownloadManager by ProgramUpdater Closes #2023 --- src/base/net/downloadmanager.cpp | 11 ++- src/base/net/downloadmanager.h | 2 +- src/gui/programupdater.cpp | 133 ++++++++++++------------------- src/gui/programupdater.h | 19 ++--- 4 files changed, 69 insertions(+), 96 deletions(-) diff --git a/src/base/net/downloadmanager.cpp b/src/base/net/downloadmanager.cpp index 21672274d..fa8288f88 100644 --- a/src/base/net/downloadmanager.cpp +++ b/src/base/net/downloadmanager.cpp @@ -42,6 +42,9 @@ #include "downloadhandler.h" #include "downloadmanager.h" +// Spoof Firefox 38 user agent to avoid web server banning +const char DEFAULT_USER_AGENT[] = "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0"; + namespace { class NetworkCookieJar: public QNetworkCookieJar @@ -139,7 +142,7 @@ DownloadManager *DownloadManager::instance() return m_instance; } -DownloadHandler *DownloadManager::downloadUrl(const QString &url, bool saveToFile, qint64 limit, bool handleRedirectToMagnet) +DownloadHandler *DownloadManager::downloadUrl(const QString &url, bool saveToFile, qint64 limit, bool handleRedirectToMagnet, const QString &userAgent) { // Update proxy settings applyProxySettings(); @@ -149,8 +152,10 @@ DownloadHandler *DownloadManager::downloadUrl(const QString &url, bool saveToFil const QUrl qurl = QUrl::fromEncoded(url.toUtf8()); QNetworkRequest request(qurl); - // Spoof Firefox 38 user agent to avoid web server banning - request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; Linux i686; rv:38.0) Gecko/20100101 Firefox/38.0"); + if (userAgent.isEmpty()) + request.setRawHeader("User-Agent", DEFAULT_USER_AGENT); + else + request.setRawHeader("User-Agent", userAgent.toUtf8()); // Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents request.setRawHeader("Referer", request.url().toEncoded().data()); diff --git a/src/base/net/downloadmanager.h b/src/base/net/downloadmanager.h index 8621f70bd..9cd34151a 100644 --- a/src/base/net/downloadmanager.h +++ b/src/base/net/downloadmanager.h @@ -51,7 +51,7 @@ namespace Net static void freeInstance(); static DownloadManager *instance(); - DownloadHandler *downloadUrl(const QString &url, bool saveToFile = false, qint64 limit = 0, bool handleRedirectToMagnet = false); + DownloadHandler *downloadUrl(const QString &url, bool saveToFile = false, qint64 limit = 0, bool handleRedirectToMagnet = false, const QString &userAgent = ""); QList cookiesForUrl(const QUrl &url) const; bool setCookiesFromUrl(const QList &cookieList, const QUrl &url); bool deleteCookie(const QNetworkCookie &cookie); diff --git a/src/gui/programupdater.cpp b/src/gui/programupdater.cpp index 3514c6f0f..c722d8ec2 100644 --- a/src/gui/programupdater.cpp +++ b/src/gui/programupdater.cpp @@ -28,23 +28,20 @@ * Contact : chris@qbittorrent.org */ -#include -#include -#include #include -#include #include #include #include #include -#include "programupdater.h" #include "base/utils/fs.h" -#include "base/preferences.h" +#include "base/net/downloadmanager.h" +#include "base/net/downloadhandler.h" +#include "programupdater.h" namespace { - const QUrl RSS_URL("http://www.fosshub.com/software/feedqBittorent"); + const QString RSS_URL("http://www.fosshub.com/software/feedqBittorent"); #ifdef Q_OS_MAC const QString OS_TYPE("Mac OS X"); @@ -59,99 +56,73 @@ ProgramUpdater::ProgramUpdater(QObject *parent, bool invokedByUser) : QObject(parent) , m_invokedByUser(invokedByUser) { - m_networkManager = new QNetworkAccessManager(this); - Preferences* const pref = Preferences::instance(); - // Proxy support - if (pref->isProxyEnabled()) { - QNetworkProxy proxy; - switch(pref->getProxyType()) { - case Proxy::SOCKS4: - case Proxy::SOCKS5: - case Proxy::SOCKS5_PW: - proxy.setType(QNetworkProxy::Socks5Proxy); - default: - proxy.setType(QNetworkProxy::HttpProxy); - break; - } - proxy.setHostName(pref->getProxyIp()); - proxy.setPort(pref->getProxyPort()); - // Proxy authentication - if (pref->isProxyAuthEnabled()) { - proxy.setUser(pref->getProxyUsername()); - proxy.setPassword(pref->getProxyPassword()); - } - m_networkManager->setProxy(proxy); - } -} - -ProgramUpdater::~ProgramUpdater() -{ - delete m_networkManager; } void ProgramUpdater::checkForUpdates() { - // SIGNAL/SLOT - connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), - this, SLOT(rssDownloadFinished(QNetworkReply*))); - // Send the request - QNetworkRequest request(RSS_URL); - // Don't change this User-Agent. In case our updater goes haywire, the filehost can indetify it and contact us. - request.setRawHeader("User-Agent", QString("qBittorrent/%1 ProgramUpdater (www.qbittorrent.org)").arg(VERSION).toLocal8Bit()); - m_networkManager->get(request); + Net::DownloadHandler *handler = Net::DownloadManager::instance()->downloadUrl( + RSS_URL, false, 0, false, + // Don't change this User-Agent. In case our updater goes haywire, + // the filehost can identify it and contact us. + QString("qBittorrent/%1 ProgramUpdater (www.qbittorrent.org)").arg(VERSION)); + connect(handler, SIGNAL(downloadFinished(QString,QByteArray)), SLOT(rssDownloadFinished(QString,QByteArray))); + connect(handler, SIGNAL(downloadFailed(QString,QString)), SLOT(rssDownloadFailed(QString,QString))); } -void ProgramUpdater::rssDownloadFinished(QNetworkReply *reply) +void ProgramUpdater::rssDownloadFinished(const QString &url, const QByteArray &data) { - // Disconnect SIGNAL/SLOT - disconnect(m_networkManager, 0, this, 0); + Q_UNUSED(url); + qDebug("Finished downloading the new qBittorrent updates RSS"); QString version; - if (!reply->error()) { - qDebug("No download error, good."); - QXmlStreamReader xml(reply); - bool inItem = false; - QString updateLink; - QString type; + QXmlStreamReader xml(data); + bool inItem = false; + QString updateLink; + QString type; - while (!xml.atEnd()) { - xml.readNext(); + while (!xml.atEnd()) { + xml.readNext(); - if (xml.isStartElement()) { - if (xml.name() == "item") - inItem = true; - else if (inItem && xml.name() == "link") - updateLink = getStringValue(xml); - else if (inItem && xml.name() == "type") - type = getStringValue(xml); - else if (inItem && xml.name() == "version") - version = getStringValue(xml); - } - else if (xml.isEndElement()) { - if (inItem && xml.name() == "item") { - if (type.compare(OS_TYPE, Qt::CaseInsensitive) == 0) { - qDebug("The last update available is %s", qPrintable(version)); - if (!version.isEmpty()) { - qDebug("Detected version is %s", qPrintable(version)); - if (isVersionMoreRecent(version)) - m_updateUrl = updateLink; - } - break; + if (xml.isStartElement()) { + if (xml.name() == "item") + inItem = true; + else if (inItem && xml.name() == "link") + updateLink = getStringValue(xml); + else if (inItem && xml.name() == "type") + type = getStringValue(xml); + else if (inItem && xml.name() == "version") + version = getStringValue(xml); + } + else if (xml.isEndElement()) { + if (inItem && xml.name() == "item") { + if (type.compare(OS_TYPE, Qt::CaseInsensitive) == 0) { + qDebug("The last update available is %s", qPrintable(version)); + if (!version.isEmpty()) { + qDebug("Detected version is %s", qPrintable(version)); + if (isVersionMoreRecent(version)) + m_updateUrl = updateLink; } - - inItem = false; - updateLink.clear(); - type.clear(); - version.clear(); + break; } + + inItem = false; + updateLink.clear(); + type.clear(); + version.clear(); } } } emit updateCheckFinished(!m_updateUrl.isEmpty(), version, m_invokedByUser); - // Clean up - reply->deleteLater(); +} + +void ProgramUpdater::rssDownloadFailed(const QString &url, const QString &error) +{ + Q_UNUSED(url); + + qDebug() << "Downloading the new qBittorrent updates RSS failed:" << error; + emit updateCheckFinished(false, QString(), m_invokedByUser); } void ProgramUpdater::updateProgram() diff --git a/src/gui/programupdater.h b/src/gui/programupdater.h index ecf71bd7c..cda228bbb 100644 --- a/src/gui/programupdater.h +++ b/src/gui/programupdater.h @@ -34,30 +34,27 @@ #include #include -class QNetworkReply; -class QNetworkAccessManager; - class ProgramUpdater: public QObject { Q_OBJECT + public: explicit ProgramUpdater(QObject *parent = 0, bool invokedByUser = false); - ~ProgramUpdater(); + void checkForUpdates(); void updateProgram(); -protected: - bool isVersionMoreRecent(const QString &remoteVersion) const; - -protected slots: - void rssDownloadFinished(QNetworkReply* reply); - signals: void updateCheckFinished(bool updateAvailable, QString version, bool invokedByUser); +private slots: + void rssDownloadFinished(const QString &url, const QByteArray &data); + void rssDownloadFailed(const QString &url, const QString &error); + private: + bool isVersionMoreRecent(const QString &remoteVersion) const; + QString m_updateUrl; - QNetworkAccessManager *m_networkManager; bool m_invokedByUser; }; From 881108057de739a24c05c633b046615769758d43 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (qlassez)" Date: Sat, 19 Dec 2015 15:35:45 +0300 Subject: [PATCH 4/4] Use DownloadManager by DNSUpdater --- src/base/net/dnsupdater.cpp | 117 ++++++++++++++++++------------------ src/base/net/dnsupdater.h | 34 +++++------ 2 files changed, 77 insertions(+), 74 deletions(-) diff --git a/src/base/net/dnsupdater.cpp b/src/base/net/dnsupdater.cpp index c9aa6c2ca..6ef1dd98b 100644 --- a/src/base/net/dnsupdater.cpp +++ b/src/base/net/dnsupdater.cpp @@ -28,7 +28,6 @@ * Contact : chris@qbittorrent.org */ -#include #include #include #include @@ -37,6 +36,8 @@ #endif #include "base/logger.h" +#include "base/net/downloadmanager.h" +#include "base/net/downloadhandler.h" #include "dnsupdater.h" using namespace Net; @@ -76,65 +77,62 @@ DNSUpdater::~DNSUpdater() void DNSUpdater::checkPublicIP() { Q_ASSERT(m_state == OK); - QNetworkAccessManager *manager = new QNetworkAccessManager(this); - connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(ipRequestFinished(QNetworkReply *))); + + DownloadHandler *handler = DownloadManager::instance()->downloadUrl( + "http://checkip.dyndns.org", false, 0, false, + QString("qBittorrent/%1").arg(VERSION)); + connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(ipRequestFinished(QString, QByteArray))); + connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(ipRequestFailed(QString, QString))); + m_lastIPCheckTime = QDateTime::currentDateTime(); - QNetworkRequest request; - request.setUrl(QUrl("http://checkip.dyndns.org")); - request.setRawHeader("User-Agent", "qBittorrent/" VERSION); - manager->get(request); } -void DNSUpdater::ipRequestFinished(QNetworkReply *reply) +void DNSUpdater::ipRequestFinished(const QString &url, const QByteArray &data) { - qDebug() << Q_FUNC_INFO; - if (reply->error()) { - // Error - qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString(); - } - else { - // Parse response - QRegExp ipregex("Current IP Address:\\s+([^<]+)"); - QString ret = reply->readAll(); - if (ipregex.indexIn(ret) >= 0) { - QString ip_str = ipregex.cap(1); - qDebug() << Q_FUNC_INFO << "Regular expression captured the following IP:" << ip_str; - QHostAddress new_ip(ip_str); - if (!new_ip.isNull()) { - if (m_lastIP != new_ip) { - qDebug() << Q_FUNC_INFO << "The IP address changed, report the change to DynDNS..."; - qDebug() << m_lastIP.toString() << "->" << new_ip.toString(); - m_lastIP = new_ip; - updateDNSService(); - } - } - else { - qWarning() << Q_FUNC_INFO << "Failed to construct a QHostAddress from the IP string"; + Q_UNUSED(url); + + // Parse response + QRegExp ipregex("Current IP Address:\\s+([^<]+)"); + if (ipregex.indexIn(data) >= 0) { + QString ipStr = ipregex.cap(1); + qDebug() << Q_FUNC_INFO << "Regular expression captured the following IP:" << ipStr; + QHostAddress newIp(ipStr); + if (!newIp.isNull()) { + if (m_lastIP != newIp) { + qDebug() << Q_FUNC_INFO << "The IP address changed, report the change to DynDNS..."; + qDebug() << m_lastIP.toString() << "->" << newIp.toString(); + m_lastIP = newIp; + updateDNSService(); } } else { - qWarning() << Q_FUNC_INFO << "Regular expression failed to capture the IP address"; + qWarning() << Q_FUNC_INFO << "Failed to construct a QHostAddress from the IP string"; } } - // Clean up - reply->deleteLater(); - sender()->deleteLater(); + else { + qWarning() << Q_FUNC_INFO << "Regular expression failed to capture the IP address"; + } +} + +void DNSUpdater::ipRequestFailed(const QString &url, const QString &error) +{ + Q_UNUSED(url); + qWarning() << "IP request failed:" << error; } void DNSUpdater::updateDNSService() { qDebug() << Q_FUNC_INFO; - // Prepare request - QNetworkAccessManager *manager = new QNetworkAccessManager(this); - connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(ipUpdateFinished(QNetworkReply *))); + m_lastIPCheckTime = QDateTime::currentDateTime(); - QNetworkRequest request; - request.setUrl(getUpdateUrl()); - request.setRawHeader("User-Agent", "qBittorrent/" VERSION); - manager->get(request); + DownloadHandler *handler = DownloadManager::instance()->downloadUrl( + getUpdateUrl(), false, 0, false, + QString("qBittorrent/%1").arg(VERSION)); + connect(handler, SIGNAL(downloadFinished(QString, QByteArray)), SLOT(ipUpdateFinished(QString, QByteArray))); + connect(handler, SIGNAL(downloadFailed(QString, QString)), SLOT(ipUpdateFailed(QString, QString))); } -QUrl DNSUpdater::getUpdateUrl() const +QString DNSUpdater::getUpdateUrl() const { QUrl url; #ifdef QT_NO_OPENSSL @@ -172,22 +170,20 @@ QUrl DNSUpdater::getUpdateUrl() const Q_ASSERT(url.isValid()); qDebug() << Q_FUNC_INFO << url.toString(); - return url; + return url.toString(); } -void DNSUpdater::ipUpdateFinished(QNetworkReply *reply) +void DNSUpdater::ipUpdateFinished(const QString &url, const QByteArray &data) { - if (reply->error()) { - // Error - qWarning() << Q_FUNC_INFO << "Error:" << reply->errorString(); - } - else { - // Parse reply - processIPUpdateReply(reply->readAll()); - } - // Clean up - reply->deleteLater(); - sender()->deleteLater(); + Q_UNUSED(url); + // Parse reply + processIPUpdateReply(data); +} + +void DNSUpdater::ipUpdateFailed(const QString &url, const QString &error) +{ + Q_UNUSED(url); + qWarning() << "IP update failed:" << error; } void DNSUpdater::processIPUpdateReply(const QString &reply) @@ -196,16 +192,19 @@ void DNSUpdater::processIPUpdateReply(const QString &reply) qDebug() << Q_FUNC_INFO << reply; QString code = reply.split(" ").first(); qDebug() << Q_FUNC_INFO << "Code:" << code; - if (code == "good" || code == "nochg") { + + if ((code == "good") || (code == "nochg")) { logger->addMessage(tr("Your dynamic DNS was successfully updated."), Log::INFO); return; } + if ((code == "911") || (code == "dnserr")) { logger->addMessage(tr("Dynamic DNS error: The service is temporarily unavailable, it will be retried in 30 minutes."), Log::CRITICAL); m_lastIP.clear(); // It will retry in 30 minutes because the timer was not stopped return; } + // Everything bellow is an error, stop updating until the user updates something m_ipCheckTimer.stop(); m_lastIP.clear(); @@ -214,23 +213,27 @@ void DNSUpdater::processIPUpdateReply(const QString &reply) m_state = INVALID_CREDS; return; } + if (code == "badauth") { logger->addMessage(tr("Dynamic DNS error: Invalid username/password."), Log::CRITICAL); m_state = INVALID_CREDS; return; } + if (code == "badagent") { logger->addMessage(tr("Dynamic DNS error: qBittorrent was blacklisted by the service, please report a bug at http://bugs.qbittorrent.org."), Log::CRITICAL); m_state = FATAL; return; } + if (code == "!donator") { logger->addMessage(tr("Dynamic DNS error: %1 was returned by the service, please report a bug at http://bugs.qbittorrent.org.").arg("!donator"), Log::CRITICAL); m_state = FATAL; return; } + if (code == "abuse") { logger->addMessage(tr("Dynamic DNS error: Your username was blocked due to abuse."), Log::CRITICAL); m_state = FATAL; diff --git a/src/base/net/dnsupdater.h b/src/base/net/dnsupdater.h index 49afc4623..2c3cb6c38 100644 --- a/src/base/net/dnsupdater.h +++ b/src/base/net/dnsupdater.h @@ -33,15 +33,15 @@ #include #include -#include #include #include + #include "base/preferences.h" namespace Net -{ +{ // Based on http://www.dyndns.com/developers/specs/ - class DNSUpdater : public QObject + class DNSUpdater: public QObject { Q_OBJECT @@ -56,15 +56,25 @@ namespace Net private slots: void checkPublicIP(); - void ipRequestFinished(QNetworkReply *reply); + void ipRequestFinished(const QString &url, const QByteArray &data); + void ipRequestFailed(const QString &url, const QString &error); void updateDNSService(); - void ipUpdateFinished(QNetworkReply *reply); + void ipUpdateFinished(const QString &url, const QByteArray &data); + void ipUpdateFailed(const QString &url, const QString &error); private: - QUrl getUpdateUrl() const; + enum State + { + OK, + INVALID_CREDS, + FATAL + }; + + static const int IP_CHECK_INTERVAL_MS = 1800000; // 30 min + + QString getUpdateUrl() const; void processIPUpdateReply(const QString &reply); - private: QHostAddress m_lastIP; QDateTime m_lastIPCheckTime; QTimer m_ipCheckTimer; @@ -74,16 +84,6 @@ namespace Net QString m_domain; QString m_username; QString m_password; - - private: - static const int IP_CHECK_INTERVAL_MS = 1800000; // 30 min - - enum State - { - OK, - INVALID_CREDS, - FATAL - }; }; }