File indexing completed on 2025-01-19 03:55:40

0001 #include <cassert>
0002 
0003 #include <QDebug>
0004 #include <QTimer>
0005 #include <QBuffer>
0006 #if QT_VERSION >= 0x050000
0007 #include <QUrlQuery>
0008 #endif
0009 
0010 #include "o2requestor.h"
0011 #include "o2.h"
0012 #include "o0globals.h"
0013 
0014 O2Requestor::O2Requestor(QNetworkAccessManager *manager, O2 *authenticator, QObject *parent): QObject(parent), reply_(NULL), status_(Idle), addAccessTokenInQuery_(true), rawData_(false) {
0015     manager_ = manager;
0016     authenticator_ = authenticator;
0017     if (authenticator) {
0018         timedReplies_.setIgnoreSslErrors(authenticator->ignoreSslErrors());
0019     }
0020     qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
0021     connect(authenticator, SIGNAL(refreshFinished(QNetworkReply::NetworkError)), this, SLOT(onRefreshFinished(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0022 }
0023 
0024 O2Requestor::~O2Requestor() {
0025 }
0026 
0027 void O2Requestor::setAddAccessTokenInQuery(bool value) {
0028     addAccessTokenInQuery_ = value;
0029 }
0030 
0031 void O2Requestor::setAccessTokenInAuthenticationHTTPHeaderFormat(const QString &value) {
0032     accessTokenInAuthenticationHTTPHeaderFormat_ = value;
0033 }
0034 
0035 int O2Requestor::get(const QNetworkRequest &req, int timeout/* = 60*1000*/) {
0036     if (-1 == setup(req, QNetworkAccessManager::GetOperation)) {
0037         return -1;
0038     }
0039     reply_ = manager_->get(request_);
0040     timedReplies_.add(new O2Reply(reply_, timeout));
0041 
0042 #if QT_VERSION < 0x051500
0043     connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0044 #else
0045     connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0046 #endif
0047     connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
0048     return id_;
0049 }
0050 
0051 int O2Requestor::post(const QNetworkRequest &req, const QByteArray &data, int timeout/* = 60*1000*/) {
0052     if (-1 == setup(req, QNetworkAccessManager::PostOperation)) {
0053         return -1;
0054     }
0055     rawData_ = true;
0056     data_ = data;
0057     reply_ = manager_->post(request_, data_);
0058     timedReplies_.add(new O2Reply(reply_, timeout));
0059 #if QT_VERSION < 0x051500
0060     connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0061 #else
0062     connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0063 #endif
0064     connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
0065     connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
0066     return id_;
0067 }
0068 
0069 int O2Requestor::post(const QNetworkRequest & req, QHttpMultiPart* data, int timeout/* = 60*1000*/)
0070 {
0071     if (-1 == setup(req, QNetworkAccessManager::PostOperation)) {
0072         return -1;
0073     }
0074     rawData_ = false;
0075     multipartData_ = data;
0076     reply_ = manager_->post(request_, multipartData_);
0077     multipartData_->setParent(reply_);
0078     timedReplies_.add(new O2Reply(reply_, timeout));
0079 #if QT_VERSION < 0x051500
0080     connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0081 #else
0082     connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0083 #endif
0084     connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
0085     connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
0086     return id_;
0087 }
0088 
0089 int O2Requestor::put(const QNetworkRequest &req, const QByteArray &data, int timeout/* = 60*1000*/) {
0090     if (-1 == setup(req, QNetworkAccessManager::PutOperation)) {
0091         return -1;
0092     }
0093     rawData_ = true;
0094     data_ = data;
0095     reply_ = manager_->put(request_, data_);
0096     timedReplies_.add(new O2Reply(reply_, timeout));
0097 #if QT_VERSION < 0x051500
0098     connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0099 #else
0100     connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0101 #endif
0102     connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
0103     connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
0104     return id_;
0105 }
0106 
0107 int O2Requestor::put(const QNetworkRequest & req, QHttpMultiPart* data, int timeout/* = 60*1000*/)
0108 {
0109     if (-1 == setup(req, QNetworkAccessManager::PutOperation)) {
0110         return -1;
0111     }
0112     rawData_ = false;
0113     multipartData_ = data;
0114     reply_ = manager_->put(request_, multipartData_);
0115     multipartData_->setParent(reply_);
0116     timedReplies_.add(new O2Reply(reply_, timeout));
0117 #if QT_VERSION < 0x051500
0118     connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0119 #else
0120     connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0121 #endif
0122     connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
0123     connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
0124     return id_;
0125 }
0126 
0127 int O2Requestor::deleteResource(const QNetworkRequest & req, int timeout/* = 60*1000*/)
0128 {
0129     if (-1 == setup(req, QNetworkAccessManager::DeleteOperation)) {
0130         return -1;
0131     }
0132     rawData_ = false;
0133     reply_ = manager_->deleteResource(request_);
0134     timedReplies_.add(new O2Reply(reply_, timeout));
0135 #if QT_VERSION < 0x051500
0136     connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0137 #else
0138     connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0139 #endif
0140     connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
0141     return id_;
0142 }
0143 
0144 int O2Requestor::customRequest(const QNetworkRequest &req, const QByteArray &verb, const QByteArray &data, int timeout/* = 60*1000*/)
0145 {
0146     (void)timeout;
0147 
0148     if (-1 == setup(req, QNetworkAccessManager::CustomOperation, verb)) {
0149         return -1;
0150     }
0151     data_ = data;
0152     QBuffer * buffer = new QBuffer;
0153     buffer->setData(data_);
0154     reply_ = manager_->sendCustomRequest(request_, verb, buffer);
0155     buffer->setParent(reply_);
0156     timedReplies_.add(new O2Reply(reply_));
0157 #if QT_VERSION < 0x051500
0158     connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0159 #else
0160     connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0161 #endif
0162     connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
0163     connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
0164     return id_;
0165 }
0166 
0167 int O2Requestor::head(const QNetworkRequest &req, int timeout/* = 60*1000*/)
0168 {
0169     if (-1 == setup(req, QNetworkAccessManager::HeadOperation)) {
0170         return -1;
0171     }
0172     reply_ = manager_->head(request_);
0173     timedReplies_.add(new O2Reply(reply_, timeout));
0174 #if QT_VERSION < 0x051500
0175     connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0176 #else
0177     connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0178 #endif
0179     connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
0180     return id_;
0181 }
0182 
0183 void O2Requestor::onRefreshFinished(QNetworkReply::NetworkError error) {
0184     if (status_ != Requesting) {
0185         qWarning() << "O2Requestor::onRefreshFinished: No pending request";
0186         return;
0187     }
0188     if (QNetworkReply::NoError == error) {
0189         QTimer::singleShot(100, this, SLOT(retry()));
0190     } else {
0191         error_ = error;
0192         QTimer::singleShot(10, this, SLOT(finish()));
0193     }
0194 }
0195 
0196 void O2Requestor::onRequestFinished() {
0197     if (status_ == Idle) {
0198         return;
0199     }
0200     if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
0201         return;
0202     }
0203     if (reply_->error() == QNetworkReply::NoError) {
0204         QTimer::singleShot(10, this, SLOT(finish()));
0205     }
0206 }
0207 
0208 void O2Requestor::onRequestError(QNetworkReply::NetworkError error) {
0209     qWarning() << "O2Requestor::onRequestError: Error" << (int)error;
0210     if (status_ == Idle) {
0211         return;
0212     }
0213     if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
0214         return;
0215     }
0216     int httpStatus = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
0217     qWarning() << "O2Requestor::onRequestError: HTTP status" << httpStatus << reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
0218     if ((status_ == Requesting) && (httpStatus == 401)) {
0219         // Call O2::refresh. Note the O2 instance might live in a different thread
0220         if (QMetaObject::invokeMethod(authenticator_, "refresh")) {
0221             return;
0222         }
0223         qCritical() << "O2Requestor::onRequestError: Invoking remote refresh failed";
0224     }
0225     error_ = error;
0226     QTimer::singleShot(10, this, SLOT(finish()));
0227 }
0228 
0229 void O2Requestor::onUploadProgress(qint64 uploaded, qint64 total) {
0230     if (status_ == Idle) {
0231         qWarning() << "O2Requestor::onUploadProgress: No pending request";
0232         return;
0233     }
0234     if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
0235         return;
0236     }
0237     // Restart timeout because request in progress
0238     O2Reply *o2Reply = timedReplies_.find(reply_);
0239     if(o2Reply)
0240         o2Reply->start();
0241     Q_EMIT uploadProgress(id_, uploaded, total);
0242 }
0243 
0244 int O2Requestor::setup(const QNetworkRequest &req, QNetworkAccessManager::Operation operation, const QByteArray &verb) {
0245     static int currentId;
0246 
0247     if (status_ != Idle) {
0248         qWarning() << "O2Requestor::setup: Another request pending";
0249         return -1;
0250     }
0251 
0252     request_ = req;
0253     operation_ = operation;
0254     id_ = currentId++;
0255     url_ = req.url();
0256 
0257     QUrl url = url_;
0258     if (addAccessTokenInQuery_) {
0259 #if QT_VERSION < 0x050000
0260         url.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
0261 #else
0262         QUrlQuery query(url);
0263         query.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
0264         url.setQuery(query);
0265 #endif
0266     }
0267 
0268     request_.setUrl(url);
0269 
0270     // If the service require the access token to be sent as a Authentication HTTP header, we add the access token.
0271     if (!accessTokenInAuthenticationHTTPHeaderFormat_.isEmpty()) {
0272         request_.setRawHeader(O2_HTTP_AUTHORIZATION_HEADER, accessTokenInAuthenticationHTTPHeaderFormat_.arg(authenticator_->token()).toLatin1());
0273     }
0274 
0275     if (!verb.isEmpty()) {
0276         request_.setRawHeader(O2_HTTP_HTTP_HEADER, verb);
0277     }
0278 
0279     status_ = Requesting;
0280     error_ = QNetworkReply::NoError;
0281     return id_;
0282 }
0283 
0284 void O2Requestor::finish() {
0285     QByteArray data;
0286     if (status_ == Idle) {
0287         qWarning() << "O2Requestor::finish: No pending request";
0288         return;
0289     }
0290     data = reply_->readAll();
0291     status_ = Idle;
0292     timedReplies_.remove(reply_);
0293     reply_->disconnect(this);
0294     reply_->deleteLater();
0295     QList<QNetworkReply::RawHeaderPair> headers = reply_->rawHeaderPairs();
0296     Q_EMIT finished(id_, error_, data);
0297     Q_EMIT finished(id_, error_, reply_->errorString(), data);
0298     Q_EMIT finished(id_, error_, data, headers);
0299     Q_EMIT finished(id_, error_, reply_->errorString(), data, headers);
0300 }
0301 
0302 void O2Requestor::retry() {
0303     if (status_ != Requesting) {
0304         qWarning() << "O2Requestor::retry: No pending request";
0305         return;
0306     }
0307     timedReplies_.remove(reply_);
0308     reply_->disconnect(this);
0309     reply_->deleteLater();
0310     QUrl url = url_;
0311     if (addAccessTokenInQuery_) {
0312 #if QT_VERSION < 0x050000
0313         url.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
0314 #else
0315         QUrlQuery query(url);
0316         query.addQueryItem(O2_OAUTH2_ACCESS_TOKEN, authenticator_->token());
0317         url.setQuery(query);
0318 #endif
0319     }
0320     request_.setUrl(url);
0321 
0322     // If the service require the access token to be sent as a Authentication HTTP header,
0323     // we update the access token when retrying.
0324     if(!accessTokenInAuthenticationHTTPHeaderFormat_.isEmpty()) {
0325         request_.setRawHeader(O2_HTTP_AUTHORIZATION_HEADER, accessTokenInAuthenticationHTTPHeaderFormat_.arg(authenticator_->token()).toLatin1());
0326     }
0327 
0328     status_ = ReRequesting;
0329     switch (operation_) {
0330     case QNetworkAccessManager::GetOperation:
0331         reply_ = manager_->get(request_);
0332         break;
0333     case QNetworkAccessManager::PostOperation:
0334         reply_ = rawData_ ? manager_->post(request_, data_) : manager_->post(request_, multipartData_);
0335         break;
0336     case QNetworkAccessManager::CustomOperation:
0337     {
0338         QBuffer * buffer = new QBuffer;
0339         buffer->setData(data_);
0340         reply_ = manager_->sendCustomRequest(request_, request_.rawHeader(O2_HTTP_HTTP_HEADER), buffer);
0341         buffer->setParent(reply_);
0342     }
0343         break;
0344     case QNetworkAccessManager::PutOperation:
0345         reply_ = rawData_ ? manager_->post(request_, data_) : manager_->put(request_, multipartData_);
0346         break;
0347     case QNetworkAccessManager::HeadOperation:
0348         reply_ = manager_->head(request_);
0349         break;
0350     default:
0351         assert(!"Unspecified operation for request");
0352         reply_ = manager_->get(request_);
0353         break;
0354     }
0355     timedReplies_.add(reply_);
0356 #if QT_VERSION < 0x051500
0357     connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0358 #else
0359     connect(reply_, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
0360 #endif
0361     connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
0362     connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
0363 }
0364 
0365 #include "moc_o2requestor.cpp"