File indexing completed on 2025-02-09 04:18:49
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"