Migrate to QtNetwork for HTTP(s) requests (#344)

* Migrate to QtNetwork for HTTP(s) requests

* Fix

* Cleanup

* Fix linux build
This commit is contained in:
parhelia512 2025-04-07 16:56:09 +08:00 committed by Nova
parent 19cbfe0754
commit c43d11cb7b
8 changed files with 90 additions and 113 deletions

View File

@ -37,7 +37,6 @@ list(APPEND CMAKE_PREFIX_PATH ${NKR_LIBS})
if(WIN32)
list(APPEND CMAKE_PREFIX_PATH "libs/deps/built/x64-windows-static")
endif ()
add_definitions(-DCURL_STATICLIB)
message("[CMAKE_PREFIX_PATH] ${CMAKE_PREFIX_PATH}")
@ -66,9 +65,6 @@ list(APPEND NKR_EXTERNAL_TARGETS yaml-cpp)
find_package(ZXing CONFIG REQUIRED)
list(APPEND NKR_EXTERNAL_TARGETS ZXing::ZXing)
find_package(cpr REQUIRED)
list(APPEND NKR_EXTERNAL_TARGETS cpr::cpr)
set(BUILD_SHARED_LIBS OFF)
list(APPEND NKR_EXTERNAL_TARGETS qhotkey)

View File

@ -1,7 +1,5 @@
#pragma once
#ifndef NKR_NO_GRPC
#include "core/server/gen/libcore.pb.h"
#include <QString>
@ -54,4 +52,3 @@ namespace NekoGui_rpc {
inline Client *defaultClient;
} // namespace NekoGui_rpc
#endif

View File

@ -1,8 +1,5 @@
#pragma once
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QObject>
#include <functional>
@ -26,7 +23,7 @@ namespace NekoGui_network {
static QString GetHeader(const QList<QPair<QByteArray, QByteArray>> &header, const QString &name);
static QString DownloadAsset(const QString &url, const QString &fileName, bool isTemp);
static QString DownloadAsset(const QString &url, const QString &fileName);
};
} // namespace NekoGui_network

View File

@ -19,7 +19,7 @@ mkdir -p $INSTALL_PREFIX
#### clean ####
clean() {
rm -rf dl.zip yaml-* zxing-* protobuf curl cpr libpsl* zlib vcpkg
rm -rf dl.zip yaml-* zxing-* protobuf
}
#### ZXing v2.3.0 ####
@ -69,46 +69,5 @@ ninja && ninja install
cd ../..
if [[ "$(uname -s)" == *"NT"* ]]; then
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
export VCPKG_BUILD_TYPE="release"
export VCPKG_LIBRARY_LINKAGE="static"
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install curl:x64-windows-static --x-install-root=$INSTALL_PREFIX
cd ..
git clone https://github.com/libcpr/cpr.git
cd cpr
git checkout bb01c8db702fb41e5497aee9c0559ddf4bf13749
sed -i 's/find_package(CURL COMPONENTS HTTP HTTPS)/find_package(CURL REQUIRED)/g' CMakeLists.txt
mkdir build && cd build
cmake -GNinja .. -DCMAKE_BUILD_TYPE=Release -DCPR_USE_SYSTEM_CURL=ON -DBUILD_SHARED_LIBS=OFF -DCURL_STATICLIB=ON -DCMAKE_OSX_ARCHITECTURES=$1 -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCURL_LIBRARY=../../built/x64-windows-static/lib -DCURL_INCLUDE_DIR=../../built/x64-windows-static/include -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX
ninja && ninja install
cd ../..
else
git clone https://github.com/curl/curl.git
cd curl
git checkout 7eb8c048470ed2cc14dca75be9c1cdae7ac8498b
mkdir build && cd build
cmake -GNinja .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DCMAKE_OSX_ARCHITECTURES=$1 -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX -DCURL_STATICLIB=ON -DUSE_LIBIDN2=OFF
ninja && ninja install
cd ../..
git clone https://github.com/libcpr/cpr.git
cd cpr
git checkout bb01c8db702fb41e5497aee9c0559ddf4bf13749
mkdir build && cd build
cmake -GNinja .. -DCMAKE_BUILD_TYPE=Release -DCPR_USE_SYSTEM_CURL=ON -DBUILD_SHARED_LIBS=OFF -DCURL_STATICLIB=ON -DCMAKE_OSX_ARCHITECTURES=$1 -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX
ninja && ninja install
cd ../..
fi
####
clean

View File

@ -53,7 +53,7 @@ patchelf --set-rpath '$ORIGIN/../../lib' ./usr/plugins/platformthemes/libqxdgdes
# fix extra libs...
mkdir ./usr/lib2
ls ./usr/lib/
cp ./usr/lib/libQt* ./usr/lib/libxcb-util* ./usr/lib/libicuuc* ./usr/lib/libicui18n* ./usr/lib/libicudata* ./usr/lib/libssl* ./usr/lib/libcrypto* ./usr/lib2
cp ./usr/lib/libQt* ./usr/lib/libxcb-util* ./usr/lib/libicuuc* ./usr/lib/libicui18n* ./usr/lib/libicudata* ./usr/lib2
rm -r ./usr/lib
mv ./usr/lib2 ./usr/lib

View File

@ -1,42 +1,67 @@
#include "include/global/HTTPRequestHelper.hpp"
#include <QByteArray>
#include <QMetaEnum>
#include <QNetworkProxy>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QTimer>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>
#include <QDir>
#include <QApplication>
#include "cpr/cpr.h"
#include "include/global/NekoGui.hpp"
namespace NekoGui_network {
NekoHTTPResponse NetworkRequestHelper::HttpGet(const QString &url) {
cpr::Session session;
QNetworkRequest request;
QNetworkAccessManager accessManager;
request.setUrl(url);
if (NekoGui::dataStore->sub_use_proxy || NekoGui::dataStore->spmode_system_proxy) {
session.SetProxies({{"http", "127.0.0.1:" + QString(Int2String(NekoGui::dataStore->inbound_socks_port)).toStdString()},
{"https", "127.0.0.1:" + QString(Int2String(NekoGui::dataStore->inbound_socks_port)).toStdString()}});
if (NekoGui::dataStore->started_id < 0 && NekoGui::dataStore->sub_use_proxy) {
QNetworkProxy p;
p.setType(QNetworkProxy::HttpProxy);
p.setHostName("127.0.0.1");
p.setPort(NekoGui::dataStore->inbound_socks_port);
accessManager.setProxy(p);
if (NekoGui::dataStore->started_id < 0) {
return NekoHTTPResponse{QObject::tr("Request with proxy but no profile started.")};
}
}
// Set attribute
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, NekoGui::dataStore->GetUserAgent());
if (NekoGui::dataStore->sub_insecure) {
session.SetVerifySsl(cpr::VerifySsl{false});
QSslConfiguration c;
c.setPeerVerifyMode(QSslSocket::PeerVerifyMode::VerifyNone);
request.setSslConfiguration(c);
}
session.SetUserAgent(cpr::UserAgent{NekoGui::dataStore->GetUserAgent().toStdString()});
session.SetTimeout(cpr::Timeout(10000));
session.SetUrl(cpr::Url(url.toStdString()));
auto resp = session.Get();
auto headerPairs = QList<QPair<QByteArray, QByteArray>>();
for (const auto &item: resp.header) {
headerPairs.append(std::pair<QByteArray, QByteArray>(QByteArray(item.first.c_str()), QByteArray(item.second.c_str())));
//
auto _reply = accessManager.get(request);
connect(_reply, &QNetworkReply::sslErrors, _reply, [](const QList<QSslError> &errors) {
QStringList error_str;
for (const auto &err: errors) {
error_str << err.errorString();
}
MW_show_log(QString("SSL Errors: %1 %2").arg(error_str.join(","), NekoGui::dataStore->sub_insecure ? "(Ignored)" : ""));
});
// Wait for response
auto abortTimer = new QTimer;
abortTimer->setSingleShot(true);
abortTimer->setInterval(10000);
connect(abortTimer, &QTimer::timeout, _reply, &QNetworkReply::abort);
abortTimer->start();
{
QEventLoop loop;
connect(_reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
}
auto err = resp.error.message.empty() ? (resp.status_code == 200 ? "" : resp.status_line) : resp.error.message;
auto result = NekoHTTPResponse{ err.c_str(),
resp.text.c_str(), headerPairs};
if (abortTimer != nullptr) {
abortTimer->stop();
abortTimer->deleteLater();
}
//
auto result = NekoHTTPResponse{_reply->error() == QNetworkReply::NetworkError::NoError ? "" : _reply->errorString(),
_reply->readAll(), _reply->rawHeaderPairs()};
_reply->deleteLater();
return result;
}
@ -47,38 +72,46 @@ namespace NekoGui_network {
return "";
}
QString NetworkRequestHelper::DownloadAsset(const QString &url, const QString &fileName, bool isTemp) {
cpr::Session session;
session.SetUrl(cpr::Url{url.toStdString()});
QString NetworkRequestHelper::DownloadAsset(const QString &url, const QString &fileName) {
QNetworkRequest request;
QNetworkAccessManager accessManager;
request.setUrl(url);
if (NekoGui::dataStore->spmode_system_proxy) {
session.SetProxies({{"http", "127.0.0.1:" + QString(Int2String(NekoGui::dataStore->inbound_socks_port)).toStdString()},
{"https", "127.0.0.1:" + QString(Int2String(NekoGui::dataStore->inbound_socks_port)).toStdString()}});
QNetworkProxy p;
p.setType(QNetworkProxy::HttpProxy);
p.setHostName("127.0.0.1");
p.setPort(NekoGui::dataStore->inbound_socks_port);
accessManager.setProxy(p);
if (NekoGui::dataStore->started_id < 0) {
return QObject::tr("Request with proxy but no profile started.");
}
}
auto _reply = accessManager.get(request);
connect(_reply, &QNetworkReply::sslErrors, _reply, [](const QList<QSslError> &errors) {
QStringList error_str;
for (const auto &err: errors) {
error_str << err.errorString();
}
MW_show_log(QString("SSL Errors: %1").arg(error_str.join(",")));
});
QEventLoop loop;
connect(_reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
if(_reply->error() != QNetworkReply::NetworkError::NoError) {
return _reply->errorString();
}
auto filePath = NekoGui::GetBasePath()+ "/" + fileName;
auto tempFilePath = QString(filePath);
if(isTemp) tempFilePath += ".1";
QFile::remove(tempFilePath);
std::ofstream fout;
fout.open(tempFilePath.toStdString(), std::ios::trunc | std::ios::out | std::ios::binary);
auto r = session.Download(fout);
fout.close();
auto tmpFile = QFile(tempFilePath);
if (r.status_code != 200) {
tmpFile.remove();
if (r.status_code == 0) {
return "Please check the URL and your network Connectivity";
}
return r.status_line.c_str();
auto file = QFile(filePath);
if (file.exists()) {
file.remove();
}
if(isTemp) {
QFile(filePath).remove();
if (!tmpFile.rename(filePath)) {
tmpFile.remove();
return tmpFile.errorString();
}
if (!file.open(QIODevice::WriteOnly)) {
return QObject::tr("Could not open file.");
}
file.write(_reply->readAll());
file.close();
return "";
}

View File

@ -19,11 +19,6 @@
#include "include/sys/windows/MiniDump.h"
#include "include/sys/windows/vcCheck.h"
#include "include/sys/windows/eventHandler.h"
#pragma comment (lib, "cpr.lib")
#pragma comment (lib, "libcurl.lib")
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Wldap32.lib")
#pragma comment (lib, "Crypt32.lib")
#endif
void signal_handler(int signum) {

View File

@ -2094,14 +2094,14 @@ void MainWindow::DownloadAssets(const QString &geoipUrl, const QString &geositeU
MW_show_log("Start downloading...");
QString errors;
if (!geoipUrl.isEmpty()) {
auto resp = NetworkRequestHelper::DownloadAsset(geoipUrl, "geoip.db", true);
auto resp = NetworkRequestHelper::DownloadAsset(geoipUrl, "geoip.db");
if (!resp.isEmpty()) {
MW_show_log(QString(tr("Failed to download geoip: %1")).arg(resp));
errors += "geoip: " + resp;
}
}
if (!geositeUrl.isEmpty()) {
auto resp = NetworkRequestHelper::DownloadAsset(geositeUrl, "geosite.db", true);
auto resp = NetworkRequestHelper::DownloadAsset(geositeUrl, "geosite.db");
if (!resp.isEmpty()) {
MW_show_log(QString(tr("Failed to download geosite: %1")).arg(resp));
errors += "\ngeosite: " + resp;
@ -2252,7 +2252,7 @@ void MainWindow::CheckUpdate() {
}
QString errors;
if (!release_download_url.isEmpty()) {
auto res = NetworkRequestHelper::DownloadAsset(release_download_url, "nekoray.zip", false);
auto res = NetworkRequestHelper::DownloadAsset(release_download_url, "nekoray.zip");
if (!res.isEmpty()) {
errors += res;
}