aboutsummaryrefslogtreecommitdiff
path: root/libraries/katabasis/src/Requestor.cpp
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2021-07-22 20:15:20 +0200
committerPetr Mrázek <peterix@gmail.com>2021-07-25 19:50:44 +0200
commitdd133680858351e3e07690e286882327a4f42ba5 (patch)
tree42ac11eb0d6cc58d3785c57f8571046cafe4b769 /libraries/katabasis/src/Requestor.cpp
parent2568752af57258a33f27f4c2d0b8fc486fb3d100 (diff)
downloadPrismLauncher-dd133680858351e3e07690e286882327a4f42ba5.tar.gz
PrismLauncher-dd133680858351e3e07690e286882327a4f42ba5.tar.bz2
PrismLauncher-dd133680858351e3e07690e286882327a4f42ba5.zip
NOISSUE bulk addition of code from Katabasis
Diffstat (limited to 'libraries/katabasis/src/Requestor.cpp')
-rw-r--r--libraries/katabasis/src/Requestor.cpp304
1 files changed, 304 insertions, 0 deletions
diff --git a/libraries/katabasis/src/Requestor.cpp b/libraries/katabasis/src/Requestor.cpp
new file mode 100644
index 00000000..7b6d2679
--- /dev/null
+++ b/libraries/katabasis/src/Requestor.cpp
@@ -0,0 +1,304 @@
+#include <cassert>
+
+#include <QDebug>
+#include <QTimer>
+#include <QBuffer>
+#include <QUrlQuery>
+
+#include "katabasis/Requestor.h"
+#include "katabasis/OAuth2.h"
+#include "katabasis/Globals.h"
+
+namespace Katabasis {
+
+Requestor::Requestor(QNetworkAccessManager *manager, OAuth2 *authenticator, QObject *parent): QObject(parent), reply_(NULL), status_(Idle), addAccessTokenInQuery_(true), rawData_(false) {
+ manager_ = manager;
+ authenticator_ = authenticator;
+ if (authenticator) {
+ timedReplies_.setIgnoreSslErrors(authenticator->ignoreSslErrors());
+ }
+ qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
+ connect(authenticator, &OAuth2::refreshFinished, this, &Requestor::onRefreshFinished, Qt::QueuedConnection);
+}
+
+Requestor::~Requestor() {
+}
+
+void Requestor::setAddAccessTokenInQuery(bool value) {
+ addAccessTokenInQuery_ = value;
+}
+
+void Requestor::setAccessTokenInAuthenticationHTTPHeaderFormat(const QString &value) {
+ accessTokenInAuthenticationHTTPHeaderFormat_ = value;
+}
+
+int Requestor::get(const QNetworkRequest &req, int timeout/* = 60*1000*/) {
+ if (-1 == setup(req, QNetworkAccessManager::GetOperation)) {
+ return -1;
+ }
+ reply_ = manager_->get(request_);
+ timedReplies_.add(new Reply(reply_, timeout));
+ connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
+ return id_;
+}
+
+int Requestor::post(const QNetworkRequest &req, const QByteArray &data, int timeout/* = 60*1000*/) {
+ if (-1 == setup(req, QNetworkAccessManager::PostOperation)) {
+ return -1;
+ }
+ rawData_ = true;
+ data_ = data;
+ reply_ = manager_->post(request_, data_);
+ timedReplies_.add(new Reply(reply_, timeout));
+ connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
+ return id_;
+}
+
+int Requestor::post(const QNetworkRequest & req, QHttpMultiPart* data, int timeout/* = 60*1000*/)
+{
+ if (-1 == setup(req, QNetworkAccessManager::PostOperation)) {
+ return -1;
+ }
+ rawData_ = false;
+ multipartData_ = data;
+ reply_ = manager_->post(request_, multipartData_);
+ multipartData_->setParent(reply_);
+ timedReplies_.add(new Reply(reply_, timeout));
+ connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
+ return id_;
+}
+
+int Requestor::put(const QNetworkRequest &req, const QByteArray &data, int timeout/* = 60*1000*/) {
+ if (-1 == setup(req, QNetworkAccessManager::PutOperation)) {
+ return -1;
+ }
+ rawData_ = true;
+ data_ = data;
+ reply_ = manager_->put(request_, data_);
+ timedReplies_.add(new Reply(reply_, timeout));
+ connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
+ return id_;
+}
+
+int Requestor::put(const QNetworkRequest & req, QHttpMultiPart* data, int timeout/* = 60*1000*/)
+{
+ if (-1 == setup(req, QNetworkAccessManager::PutOperation)) {
+ return -1;
+ }
+ rawData_ = false;
+ multipartData_ = data;
+ reply_ = manager_->put(request_, multipartData_);
+ multipartData_->setParent(reply_);
+ timedReplies_.add(new Reply(reply_, timeout));
+ connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
+ return id_;
+}
+
+int Requestor::customRequest(const QNetworkRequest &req, const QByteArray &verb, const QByteArray &data, int timeout/* = 60*1000*/)
+{
+ (void)timeout;
+
+ if (-1 == setup(req, QNetworkAccessManager::CustomOperation, verb)) {
+ return -1;
+ }
+ data_ = data;
+ QBuffer * buffer = new QBuffer;
+ buffer->setData(data_);
+ reply_ = manager_->sendCustomRequest(request_, verb, buffer);
+ buffer->setParent(reply_);
+ timedReplies_.add(new Reply(reply_));
+ connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
+ return id_;
+}
+
+int Requestor::head(const QNetworkRequest &req, int timeout/* = 60*1000*/)
+{
+ if (-1 == setup(req, QNetworkAccessManager::HeadOperation)) {
+ return -1;
+ }
+ reply_ = manager_->head(request_);
+ timedReplies_.add(new Reply(reply_, timeout));
+ connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
+ return id_;
+}
+
+void Requestor::onRefreshFinished(QNetworkReply::NetworkError error) {
+ if (status_ != Requesting) {
+ qWarning() << "O2Requestor::onRefreshFinished: No pending request";
+ return;
+ }
+ if (QNetworkReply::NoError == error) {
+ QTimer::singleShot(100, this, &Requestor::retry);
+ } else {
+ error_ = error;
+ QTimer::singleShot(10, this, &Requestor::finish);
+ }
+}
+
+void Requestor::onRequestFinished() {
+ if (status_ == Idle) {
+ return;
+ }
+ if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
+ return;
+ }
+ if (reply_->error() == QNetworkReply::NoError) {
+ QTimer::singleShot(10, this, SLOT(finish()));
+ }
+}
+
+void Requestor::onRequestError(QNetworkReply::NetworkError error) {
+ qWarning() << "O2Requestor::onRequestError: Error" << (int)error;
+ if (status_ == Idle) {
+ return;
+ }
+ if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
+ return;
+ }
+ int httpStatus = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ qWarning() << "O2Requestor::onRequestError: HTTP status" << httpStatus << reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
+ if ((status_ == Requesting) && (httpStatus == 401)) {
+ // Call OAuth2::refresh. Note the O2 instance might live in a different thread
+ if (QMetaObject::invokeMethod(authenticator_, "refresh")) {
+ return;
+ }
+ qCritical() << "O2Requestor::onRequestError: Invoking remote refresh failed";
+ }
+ error_ = error;
+ QTimer::singleShot(10, this, SLOT(finish()));
+}
+
+void Requestor::onUploadProgress(qint64 uploaded, qint64 total) {
+ if (status_ == Idle) {
+ qWarning() << "O2Requestor::onUploadProgress: No pending request";
+ return;
+ }
+ if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
+ return;
+ }
+ // Restart timeout because request in progress
+ Reply *o2Reply = timedReplies_.find(reply_);
+ if(o2Reply)
+ o2Reply->start();
+ emit uploadProgress(id_, uploaded, total);
+}
+
+int Requestor::setup(const QNetworkRequest &req, QNetworkAccessManager::Operation operation, const QByteArray &verb) {
+ static int currentId;
+
+ if (status_ != Idle) {
+ qWarning() << "O2Requestor::setup: Another request pending";
+ return -1;
+ }
+
+ request_ = req;
+ operation_ = operation;
+ id_ = currentId++;
+ url_ = req.url();
+
+ QUrl url = url_;
+ if (addAccessTokenInQuery_) {
+ QUrlQuery query(url);
+ query.addQueryItem(OAUTH2_ACCESS_TOKEN, authenticator_->token());
+ url.setQuery(query);
+ }
+
+ request_.setUrl(url);
+
+ // If the service require the access token to be sent as a Authentication HTTP header, we add the access token.
+ if (!accessTokenInAuthenticationHTTPHeaderFormat_.isEmpty()) {
+ request_.setRawHeader(HTTP_AUTHORIZATION_HEADER, accessTokenInAuthenticationHTTPHeaderFormat_.arg(authenticator_->token()).toLatin1());
+ }
+
+ if (!verb.isEmpty()) {
+ request_.setRawHeader(HTTP_HTTP_HEADER, verb);
+ }
+
+ status_ = Requesting;
+ error_ = QNetworkReply::NoError;
+ return id_;
+}
+
+void Requestor::finish() {
+ QByteArray data;
+ if (status_ == Idle) {
+ qWarning() << "O2Requestor::finish: No pending request";
+ return;
+ }
+ data = reply_->readAll();
+ status_ = Idle;
+ timedReplies_.remove(reply_);
+ reply_->disconnect(this);
+ reply_->deleteLater();
+ QList<QNetworkReply::RawHeaderPair> headers = reply_->rawHeaderPairs();
+ emit finished(id_, error_, data, headers);
+}
+
+void Requestor::retry() {
+ if (status_ != Requesting) {
+ qWarning() << "O2Requestor::retry: No pending request";
+ return;
+ }
+ timedReplies_.remove(reply_);
+ reply_->disconnect(this);
+ reply_->deleteLater();
+ QUrl url = url_;
+ if (addAccessTokenInQuery_) {
+ QUrlQuery query(url);
+ query.addQueryItem(OAUTH2_ACCESS_TOKEN, authenticator_->token());
+ url.setQuery(query);
+ }
+ request_.setUrl(url);
+
+ // If the service require the access token to be sent as a Authentication HTTP header,
+ // we update the access token when retrying.
+ if(!accessTokenInAuthenticationHTTPHeaderFormat_.isEmpty()) {
+ request_.setRawHeader(HTTP_AUTHORIZATION_HEADER, accessTokenInAuthenticationHTTPHeaderFormat_.arg(authenticator_->token()).toLatin1());
+ }
+
+ status_ = ReRequesting;
+ switch (operation_) {
+ case QNetworkAccessManager::GetOperation:
+ reply_ = manager_->get(request_);
+ break;
+ case QNetworkAccessManager::PostOperation:
+ reply_ = rawData_ ? manager_->post(request_, data_) : manager_->post(request_, multipartData_);
+ break;
+ case QNetworkAccessManager::CustomOperation:
+ {
+ QBuffer * buffer = new QBuffer;
+ buffer->setData(data_);
+ reply_ = manager_->sendCustomRequest(request_, request_.rawHeader(HTTP_HTTP_HEADER), buffer);
+ buffer->setParent(reply_);
+ }
+ break;
+ case QNetworkAccessManager::PutOperation:
+ reply_ = rawData_ ? manager_->post(request_, data_) : manager_->put(request_, multipartData_);
+ break;
+ case QNetworkAccessManager::HeadOperation:
+ reply_ = manager_->head(request_);
+ break;
+ default:
+ assert(!"Unspecified operation for request");
+ reply_ = manager_->get(request_);
+ break;
+ }
+ timedReplies_.add(reply_);
+ connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
+ connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
+}
+
+}