diff --git a/src/core/NetworkRequest.cpp b/src/core/NetworkRequest.cpp index 38707c725..4e4e941bb 100644 --- a/src/core/NetworkRequest.cpp +++ b/src/core/NetworkRequest.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace { @@ -23,6 +24,12 @@ void NetworkRequest::fetch(const QUrl& url) reset(); QNetworkRequest request(url); + + // Set headers + for(const auto &[header, value] : qAsConst(m_headers)) { + request.setRawHeader(header.toUtf8(), value.toUtf8()); + } + m_reply = m_manager->get(request); connect(m_reply, &QNetworkReply::finished, this, &NetworkRequest::fetchFinished); @@ -115,7 +122,9 @@ void NetworkRequest::setMaxRedirects(int maxRedirects) m_maxRedirects = std::max(0, maxRedirects); } -NetworkRequest::NetworkRequest(int maxRedirects, std::chrono::milliseconds timeoutDuration, QNetworkAccessManager* manager) : m_reply(nullptr), m_maxRedirects(maxRedirects), m_redirects(0), m_timeoutDuration(timeoutDuration) +NetworkRequest::NetworkRequest(int maxRedirects, std::chrono::milliseconds timeoutDuration, + QList> headers, QNetworkAccessManager* manager) + : m_reply(nullptr), m_maxRedirects(maxRedirects), m_redirects(0), m_timeoutDuration(timeoutDuration), m_headers(headers) { m_manager = manager ? manager : getNetMgr(); connect(&m_timeout, &QTimer::timeout, this, &NetworkRequest::fetchTimeout); @@ -141,3 +150,16 @@ void NetworkRequest::fetchTimeout() // Cancel request on timeout cancel(); } +NetworkRequest createRequest(int maxRedirects, + std::chrono::milliseconds timeoutDuration, + QList> additionalHeaders, + QNetworkAccessManager* manager) +{ + // Append user agent unless given + if(std::none_of(additionalHeaders.begin(), additionalHeaders.end(), [](const auto& pair) { + return pair.first == "User-Agent"; + })) { + additionalHeaders.append(QPair{"User-Agent", "KeePassXC"}); + } + return NetworkRequest(maxRedirects, timeoutDuration, additionalHeaders, manager); +} diff --git a/src/core/NetworkRequest.h b/src/core/NetworkRequest.h index f6e6e8261..9249aafb0 100644 --- a/src/core/NetworkRequest.h +++ b/src/core/NetworkRequest.h @@ -1,13 +1,37 @@ - +/* + * Copyright (C) 2023 Patrick Sean Klein + * + * This program 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 2 or (at your option) + * version 3 of the License. + * + * This program 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 this program. If not, see . + */ #ifndef KEEPASSXC_NETWORKREQUEST_H #define KEEPASSXC_NETWORKREQUEST_H #include +#include +#include #include #include class QNetworkReply; class QNetworkAccessManager; +/** + * Implements a simple HTTP request with a timeout and a maximum number of redirects. + * The result of the request is emitted as a signal, specifically success() or failure(). + * The result is a QByteArray containing the response body. Further information about the + * response can be obtained by calling the url(), ContentType(), and ContentTypeParameters() + * methods. + */ class NetworkRequest : public QObject { Q_OBJECT @@ -15,29 +39,35 @@ class NetworkRequest : public QObject { QNetworkReply* m_reply; QByteArray m_bytes; + // Response information QString m_content_type; QHash m_content_type_parameters; - QTimer m_timeout; + // Request parameters + QTimer m_timeout; int m_maxRedirects; int m_redirects; std::chrono::milliseconds m_timeoutDuration; + QList> m_headers; public: - explicit NetworkRequest(int maxRedirects, std::chrono::milliseconds timeoutDuration, QNetworkAccessManager* manager = nullptr); + // TODO Disallow insecure connections by default? + explicit NetworkRequest(int maxRedirects, std::chrono::milliseconds timeoutDuration, + QList> headers, QNetworkAccessManager* manager = nullptr); ~NetworkRequest() override; void setMaxRedirects(int maxRedirects); void setTimeout(std::chrono::milliseconds timeoutDuration); + // TODO Should it be single shot vs multiple shot? void fetch(const QUrl& url); void cancel(); QUrl url() const; - /*** + /** * @return The MIME Type set in the Content-Type header. Empty string if Content-Type was not set. */ const QString& ContentType() const; - /*** + /** * @return Any parameters set in the Content-Type header. */ const QHash& ContentTypeParameters() const; @@ -53,4 +83,16 @@ class NetworkRequest : public QObject { void failure(); }; + /** + * Creates a NetworkRequest with default parameters. + * @param maxRedirects + * @param timeoutDuration + * @param headers + * @param manager + * @return + */ + NetworkRequest createRequest(int maxRedirects = 5, + std::chrono::milliseconds timeoutDuration = std::chrono::milliseconds(5000), + QList> additionalHeaders = {}, QNetworkAccessManager* manager = nullptr); + #endif // KEEPASSXC_NETWORKREQUEST_H