File indexing completed on 2024-04-14 14:16:51

0001 /*
0002     This file is part of KDE.
0003 
0004     SPDX-FileCopyrightText: 2008 Cornelius Schumacher <schumacher@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "atticabasejob.h"
0010 
0011 #include <QAuthenticator>
0012 #include <QDebug>
0013 #include <QNetworkReply>
0014 #include <QTimer>
0015 
0016 #include "platformdependent.h"
0017 #include <attica_debug.h>
0018 #include <atticautils.h>
0019 
0020 using namespace Attica;
0021 
0022 class Q_DECL_HIDDEN BaseJob::Private
0023 {
0024 public:
0025     Metadata m_metadata;
0026     PlatformDependent *m_internals;
0027     QNetworkReply *m_reply;
0028     bool aborted{false};
0029     bool started = false;
0030 
0031     Private(PlatformDependent *internals)
0032         : m_internals(internals)
0033         , m_reply(nullptr)
0034     {
0035     }
0036 
0037     bool redirection(QUrl &newUrl) const
0038     {
0039         if (m_reply == nullptr || m_reply->error() != QNetworkReply::NoError) {
0040             return false;
0041         }
0042 
0043         const int httpStatusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
0044         if (httpStatusCode == 301 // Moved Permanently
0045             || httpStatusCode == 302 // Found
0046             || httpStatusCode == 303 // See Other
0047             || httpStatusCode == 307) { // Temporary Redirect
0048             QNetworkRequest request = m_reply->request();
0049             QUrl redirectUrl(m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl());
0050             if (redirectUrl.isRelative()) {
0051                 QUrl baseUrl(request.url());
0052                 newUrl = baseUrl.resolved(redirectUrl);
0053                 qCDebug(ATTICA) << "resolving relative URL redirection to" << newUrl.toString();
0054             } else {
0055                 newUrl = redirectUrl;
0056                 qCDebug(ATTICA) << "resolving absolute URL redirection to" << newUrl.toString();
0057             }
0058             return true;
0059         }
0060 
0061         return false;
0062     }
0063 };
0064 
0065 BaseJob::BaseJob(PlatformDependent *internals)
0066     : d(new Private(internals))
0067 {
0068 }
0069 
0070 BaseJob::~BaseJob()
0071 {
0072     delete d;
0073 }
0074 
0075 void BaseJob::dataFinished()
0076 {
0077     if (!d->m_reply) {
0078         return;
0079     }
0080 
0081     bool error = d->m_reply->error() != QNetworkReply::NoError && d->m_reply->error() != QNetworkReply::OperationCanceledError;
0082 
0083     // handle redirections automatically
0084     QUrl newUrl;
0085     if (d->redirection(newUrl)) {
0086         // qCDebug(ATTICA) << "BaseJob::dataFinished" << newUrl;
0087         QNetworkRequest request = d->m_reply->request();
0088         QNetworkAccessManager::Operation operation = d->m_reply->operation();
0089         if (newUrl.isValid() && operation == QNetworkAccessManager::GetOperation) {
0090             d->m_reply->deleteLater();
0091             // reissue same request with different Url
0092             request.setUrl(newUrl);
0093             d->m_reply = internals()->get(request);
0094             connect(d->m_reply, &QNetworkReply::finished, this, &BaseJob::dataFinished);
0095             return;
0096         } else {
0097             error = true;
0098         }
0099     }
0100 
0101     if (error) {
0102         d->m_metadata.setError(Metadata::NetworkError);
0103         d->m_metadata.setStatusCode(d->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
0104         d->m_metadata.setStatusString(d->m_reply->errorString());
0105         d->m_metadata.setHeaders(d->m_reply->rawHeaderPairs());
0106     } else {
0107         QByteArray data = d->m_reply->readAll();
0108         // qCDebug(ATTICA) << "XML Returned:\n" << data;
0109         parse(QString::fromUtf8(data.constData()));
0110         if (d->m_metadata.statusCode() >= 100 && d->m_metadata.statusCode() < 200) {
0111             d->m_metadata.setError(Metadata::NoError);
0112         } else {
0113             d->m_metadata.setError(Metadata::OcsError);
0114         }
0115     }
0116     Q_EMIT finished(this);
0117 
0118     d->m_reply->deleteLater();
0119     deleteLater();
0120 }
0121 
0122 void BaseJob::start()
0123 {
0124     if (!d->started) {
0125         d->started = true;
0126         QTimer::singleShot(0, this, &BaseJob::doWork);
0127     }
0128 }
0129 
0130 void BaseJob::doWork()
0131 {
0132     if (d->aborted) {
0133         return;
0134     }
0135     d->m_reply = executeRequest();
0136     qCDebug(ATTICA) << "executing" << Utils::toString(d->m_reply->operation()) << "request for" << d->m_reply->url();
0137     connect(d->m_reply, &QNetworkReply::finished, this, &BaseJob::dataFinished);
0138     connect(d->m_reply->manager(), &QNetworkAccessManager::authenticationRequired, this, &BaseJob::authenticationRequired);
0139     connect(d->m_reply, &QNetworkReply::errorOccurred, [](QNetworkReply::NetworkError code) {
0140         qCDebug(ATTICA) << "error found" << code;
0141     });
0142 }
0143 
0144 void BaseJob::authenticationRequired(QNetworkReply *reply, QAuthenticator *auth)
0145 {
0146     auth->setUser(reply->request().attribute((QNetworkRequest::Attribute)BaseJob::UserAttribute).toString());
0147     auth->setPassword(reply->request().attribute((QNetworkRequest::Attribute)BaseJob::PasswordAttribute).toString());
0148 }
0149 
0150 void BaseJob::abort()
0151 {
0152     d->aborted = true;
0153     if (d->m_reply) {
0154         d->m_reply->abort();
0155         d->m_reply->deleteLater();
0156     }
0157     deleteLater();
0158 }
0159 
0160 bool BaseJob::isAborted() const
0161 {
0162     return d->aborted;
0163 }
0164 
0165 PlatformDependent *BaseJob::internals()
0166 {
0167     return d->m_internals;
0168 }
0169 
0170 Metadata BaseJob::metadata() const
0171 {
0172     return d->m_metadata;
0173 }
0174 
0175 void BaseJob::setMetadata(const Attica::Metadata &data) const
0176 {
0177     d->m_metadata = data;
0178 }
0179 
0180 #include "moc_atticabasejob.cpp"