diff --git a/deploy/FortFirewall.iss b/deploy/FortFirewall.iss index 0ff43b11..7b7c9481 100644 --- a/deploy/FortFirewall.iss +++ b/deploy/FortFirewall.iss @@ -91,6 +91,7 @@ Filename: "{app}\driver\scripts\uninstall.bat"; RunOnceId: "DelDriver" Type: filesandordirs; Name: "{app}\driver" Type: filesandordirs; Name: "{app}\i18n" Type: filesandordirs; Name: "{app}\plugins" +; TODO: COMPAT: Remove the following line after v4.1.0 Type: files; Name: "{app}\curl*.*" Type: files; Name: "{app}\qt*.*" Type: files; Name: "{app}\README*.*" diff --git a/deploy/qt-build.bat b/deploy/qt-build.bat index 60374df9..3b81b674 100644 --- a/deploy/qt-build.bat +++ b/deploy/qt-build.bat @@ -47,8 +47,7 @@ cd %TARGET_PATH% -no-feature-mimetype-database -no-feature-sql -no-feature-sql-odbc ^ ^ -no-feature-getifaddrs -no-feature-ipv6ifname -no-feature-libproxy ^ - -no-feature-openssl -no-feature-schannel -no-feature-ssl -no-feature-sctp ^ - -no-feature-system-proxies -no-feature-http -no-feature-udpsocket ^ + -no-feature-openssl -schannel -ssl -no-feature-sctp -no-feature-udpsocket ^ -no-feature-networkproxy -no-feature-socks5 -no-feature-networkdiskcache ^ -no-feature-dnslookup -no-feature-sspi -no-feature-networklistmanager ^ ^ diff --git a/src/ui/util/net/netdownloader.cpp b/src/ui/util/net/netdownloader.cpp index 9eff8e9f..8a21ab0e 100644 --- a/src/ui/util/net/netdownloader.cpp +++ b/src/ui/util/net/netdownloader.cpp @@ -1,51 +1,80 @@ #include "netdownloader.h" #include +#include +#include -#define DOWNLOAD_TIMEOUT 30 // 30 seconds timeout -#define DOWNLOAD_MAXSIZE (64 * 1024) +#define DOWNLOAD_TIMEOUT (30 * 1000) // 30 milliseconds timeout +#define DOWNLOAD_MAXSIZE (8 * 1024 * 1024) -NetDownloader::NetDownloader(QObject *parent) : QObject(parent), m_started(false), m_aborted(false) +NetDownloader::NetDownloader(QObject *parent) : + QObject(parent), m_started(false), m_aborted(false), m_manager(new QNetworkAccessManager(this)) { - setupProcess(); -} + m_downloadTimer.setInterval(DOWNLOAD_TIMEOUT); -void NetDownloader::setupProcess() -{ - connect(&m_process, &QProcess::readyReadStandardOutput, this, &NetDownloader::processReadyRead); - connect(&m_process, &QProcess::errorOccurred, this, &NetDownloader::processError); - connect(&m_process, QOverload::of(&QProcess::finished), this, - &NetDownloader::processFinished); + connect(&m_downloadTimer, &QTimer::timeout, this, [&] { + qDebug() << "NetDownloader: Error: Download timed out"; + + finish(); + }); } void NetDownloader::start() { - QStringList args; - - args.append("--max-time"); - args.append(QString::number(DOWNLOAD_TIMEOUT)); - - if (!m_data.isEmpty()) { - args.append("--data"); - args.append(QString::fromLatin1(m_data.constData())); - } - - args.append(m_url); + qDebug() << "NetDownloader: Start:" << url() << data(); m_started = true; m_aborted = false; m_buffer.clear(); - m_process.start("curl", args, QIODevice::ReadOnly); + m_downloadTimer.start(); - qDebug() << "NetDownloader: Run `curl`:" << args; + QNetworkRequest request(url()); - if (!m_process.waitForStarted(1000)) { - qWarning() << "NetDownloader: Cannot start `curl`:" << m_process.errorString(); + if (!m_data.isEmpty()) { + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + m_reply = m_manager->post(request, data()); + } else { + m_reply = m_manager->get(request); + } + + connect(m_reply, &QNetworkReply::downloadProgress, this, + [&](qint64 bytesReceived, qint64 /*bytesTotal*/) { + if (m_aborted || bytesReceived == 0) + return; + + const QByteArray data = m_reply->read(DOWNLOAD_MAXSIZE - m_buffer.size()); + + m_buffer.append(data); + if (m_buffer.size() >= DOWNLOAD_MAXSIZE) { + qWarning() << "NetDownloader: Error: Too big file"; + finish(); + } + }); + connect(m_reply, &QNetworkReply::finished, this, [&] { + const bool success = (m_reply->error() == QNetworkReply::NoError); + + finish(success && !m_buffer.isEmpty()); + }); + connect(m_reply, &QNetworkReply::errorOccurred, this, [&](QNetworkReply::NetworkError error) { + if (m_aborted) + return; + + qWarning() << "NetDownloader: Error:" << error << m_reply->errorString(); finish(); - } + }); + connect(m_reply, &QNetworkReply::sslErrors, this, [&](const QList &errors) { + if (m_aborted) + return; + + for (const QSslError &error : errors) { + qWarning() << "NetDownloader: SSL Error:" << error.errorString(); + } + + finish(); + }); } void NetDownloader::finish(bool success) @@ -56,38 +85,15 @@ void NetDownloader::finish(bool success) m_started = false; m_aborted = true; - m_process.kill(); - m_process.waitForFinished(); + m_downloadTimer.stop(); + + if (m_reply) { + m_reply->abort(); + m_reply->close(); + + m_reply->deleteLater(); + m_reply = nullptr; + } emit finished(success); } - -void NetDownloader::processReadyRead() -{ - const QByteArray data = m_process.read(DOWNLOAD_MAXSIZE - m_buffer.size()); - m_buffer.append(data); - - if (m_buffer.size() > DOWNLOAD_MAXSIZE) { - finish(true); // try to use the partial loaded data - } -} - -void NetDownloader::processError(QProcess::ProcessError error) -{ - if (m_aborted) - return; - - qWarning() << "NetDownloader: Cannot run `curl`:" << error << m_process.errorString(); - - finish(); -} - -void NetDownloader::processFinished(int exitCode, QProcess::ExitStatus exitStatus) -{ - const bool success = (exitCode == 0 && exitStatus == QProcess::NormalExit); - if (!success) { - qWarning() << "NetDownloader: `curl` error code:" << exitCode; - } - - finish(success && !m_buffer.isEmpty()); -} diff --git a/src/ui/util/net/netdownloader.h b/src/ui/util/net/netdownloader.h index 92fe9642..1186854d 100644 --- a/src/ui/util/net/netdownloader.h +++ b/src/ui/util/net/netdownloader.h @@ -1,7 +1,11 @@ #ifndef NETDOWNLOADER_H #define NETDOWNLOADER_H -#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QNetworkAccessManager) +QT_FORWARD_DECLARE_CLASS(QNetworkReply) class NetDownloader : public QObject { @@ -10,7 +14,10 @@ class NetDownloader : public QObject public: explicit NetDownloader(QObject *parent = nullptr); + QString url() const { return m_url; } void setUrl(const QString &url) { m_url = url; } + + QByteArray data() const { return m_data; } void setData(const QByteArray &data) { m_data = data; } QByteArray buffer() const { return m_buffer; } @@ -23,14 +30,6 @@ public slots: void start(); void finish(bool success = false); -private slots: - void processReadyRead(); - void processError(QProcess::ProcessError error); - void processFinished(int exitCode, QProcess::ExitStatus exitStatus); - -private: - void setupProcess(); - private: bool m_started : 1; bool m_aborted : 1; @@ -38,9 +37,12 @@ private: QString m_url; QByteArray m_data; - QProcess m_process; - QByteArray m_buffer; + + QTimer m_downloadTimer; + + QNetworkAccessManager *m_manager = nullptr; + QNetworkReply *m_reply = nullptr; }; #endif // NETDOWNLOADER_H