File indexing completed on 2023-09-24 04:08:41
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2000 Stephan Kulow <coolo@kde.org> 0004 SPDX-FileCopyrightText: 2000-2009 David Faure <faure@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "multigetjob.h" 0010 #include "job_p.h" 0011 #include "scheduler.h" 0012 #include "slave.h" 0013 #include <kurlauthorized.h> 0014 0015 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 84) 0016 0017 using namespace KIO; 0018 0019 class KIO::MultiGetJobPrivate : public KIO::TransferJobPrivate 0020 { 0021 public: 0022 explicit MultiGetJobPrivate(const QUrl &url) 0023 : TransferJobPrivate(url, 0, QByteArray(), QByteArray()) 0024 , m_currentEntry(0, QUrl(), MetaData()) 0025 { 0026 } 0027 struct GetRequest { 0028 GetRequest(long _id, const QUrl &_url, const MetaData &_metaData) 0029 : id(_id) 0030 , url(_url) 0031 , metaData(_metaData) 0032 { 0033 } 0034 long id; 0035 QUrl url; 0036 MetaData metaData; 0037 0038 inline bool operator==(const GetRequest &req) const 0039 { 0040 return req.id == id; 0041 } 0042 }; 0043 typedef std::list<GetRequest> RequestQueue; 0044 0045 RequestQueue m_waitQueue; 0046 RequestQueue m_activeQueue; 0047 GetRequest m_currentEntry; 0048 bool b_multiGetActive; 0049 0050 /** 0051 * @internal 0052 * Called by the scheduler when a @p slave gets to 0053 * work on this job. 0054 * @param slave the slave that starts working on this job 0055 */ 0056 void start(Slave *slave) override; 0057 0058 bool findCurrentEntry(); 0059 void flushQueue(RequestQueue &queue); 0060 0061 Q_DECLARE_PUBLIC(MultiGetJob) 0062 0063 static inline MultiGetJob *newJob(const QUrl &url) 0064 { 0065 MultiGetJob *job = new MultiGetJob(*new MultiGetJobPrivate(url)); 0066 job->setUiDelegate(KIO::createDefaultJobUiDelegate()); 0067 return job; 0068 } 0069 }; 0070 0071 MultiGetJob::MultiGetJob(MultiGetJobPrivate &dd) 0072 : TransferJob(dd) 0073 { 0074 } 0075 0076 MultiGetJob::~MultiGetJob() 0077 { 0078 } 0079 0080 void MultiGetJob::get(long id, const QUrl &url, const MetaData &metaData) 0081 { 0082 Q_D(MultiGetJob); 0083 MultiGetJobPrivate::GetRequest entry(id, url, metaData); 0084 entry.metaData[QStringLiteral("request-id")] = QString::number(id); 0085 d->m_waitQueue.push_back(entry); 0086 } 0087 0088 void MultiGetJobPrivate::flushQueue(RequestQueue &queue) 0089 { 0090 // Use multi-get 0091 // Scan all jobs in m_waitQueue 0092 auto wqIt = m_waitQueue.begin(); 0093 while (wqIt != m_waitQueue.end()) { 0094 const GetRequest &entry = *wqIt; 0095 if (m_url.scheme() == entry.url.scheme() // clang-format off 0096 && m_url.host() == entry.url.host() 0097 && m_url.port() == entry.url.port() 0098 && m_url.userName() == entry.url.userName()) { // clang-format on 0099 queue.push_back(entry); 0100 wqIt = m_waitQueue.erase(wqIt); 0101 } else { 0102 ++wqIt; 0103 } 0104 } 0105 // Send number of URLs, (URL, metadata)* 0106 KIO_ARGS << (qint32)queue.size(); 0107 for (const GetRequest &entry : queue) { 0108 stream << entry.url << entry.metaData; 0109 } 0110 m_packedArgs = packedArgs; 0111 m_command = CMD_MULTI_GET; 0112 m_outgoingMetaData.clear(); 0113 } 0114 0115 void MultiGetJobPrivate::start(Slave *slave) 0116 { 0117 if (m_waitQueue.empty()) { 0118 return; 0119 } 0120 // Get the first entry from m_waitQueue and add it to m_activeQueue 0121 const GetRequest entry = m_waitQueue.front(); 0122 m_activeQueue.push_back(entry); 0123 // then remove it from m_waitQueue 0124 m_waitQueue.pop_front(); 0125 0126 m_url = entry.url; 0127 0128 if (!entry.url.scheme().startsWith(QLatin1String("http"))) { 0129 // Use normal get 0130 KIO_ARGS << entry.url; 0131 m_packedArgs = packedArgs; 0132 m_outgoingMetaData = entry.metaData; 0133 m_command = CMD_GET; 0134 b_multiGetActive = false; 0135 } else { 0136 flushQueue(m_activeQueue); 0137 b_multiGetActive = true; 0138 } 0139 0140 TransferJobPrivate::start(slave); // Anything else to do?? 0141 } 0142 0143 bool MultiGetJobPrivate::findCurrentEntry() 0144 { 0145 if (b_multiGetActive) { 0146 const long id = m_incomingMetaData.value(QStringLiteral("request-id")).toLong(); 0147 for (const GetRequest &entry : m_activeQueue) { 0148 if (entry.id == id) { 0149 m_currentEntry = entry; 0150 return true; 0151 } 0152 } 0153 0154 m_currentEntry.id = 0; 0155 return false; 0156 } else { 0157 if (m_activeQueue.empty()) { 0158 return false; 0159 } 0160 m_currentEntry = m_activeQueue.front(); 0161 return true; 0162 } 0163 } 0164 0165 void MultiGetJob::slotRedirection(const QUrl &url) 0166 { 0167 Q_D(MultiGetJob); 0168 if (!d->findCurrentEntry()) { 0169 return; // Error 0170 } 0171 if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("redirect"), d->m_url, url)) { 0172 qCWarning(KIO_CORE) << "Redirection from" << d->m_currentEntry.url << "to" << url << "REJECTED!"; 0173 return; 0174 } 0175 d->m_redirectionURL = url; 0176 get(d->m_currentEntry.id, d->m_redirectionURL, d->m_currentEntry.metaData); // Try again 0177 } 0178 0179 void MultiGetJob::slotFinished() 0180 { 0181 Q_D(MultiGetJob); 0182 if (!d->findCurrentEntry()) { 0183 return; 0184 } 0185 if (d->m_redirectionURL.isEmpty()) { 0186 // No redirection, tell the world that we are finished. 0187 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 79) 0188 Q_EMIT result(d->m_currentEntry.id); 0189 #endif 0190 Q_EMIT fileTransferred(d->m_currentEntry.id); 0191 } 0192 d->m_redirectionURL = QUrl(); 0193 setError(0); 0194 d->m_incomingMetaData.clear(); 0195 d->m_activeQueue.remove(d->m_currentEntry); 0196 if (d->m_activeQueue.empty()) { 0197 if (d->m_waitQueue.empty()) { 0198 // All done 0199 TransferJob::slotFinished(); 0200 } else { 0201 // return slave to pool 0202 // fetch new slave for first entry in d->m_waitQueue and call start 0203 // again. 0204 d->slaveDone(); 0205 0206 d->m_url = d->m_waitQueue.front().url; 0207 if ((d->m_extraFlags & JobPrivate::EF_KillCalled) == 0) { 0208 Scheduler::doJob(this); 0209 } 0210 } 0211 } 0212 } 0213 0214 void MultiGetJob::slotData(const QByteArray &_data) 0215 { 0216 Q_D(MultiGetJob); 0217 if (d->m_redirectionURL.isEmpty() || !d->m_redirectionURL.isValid() || error()) { 0218 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 79) 0219 Q_EMIT data(d->m_currentEntry.id, _data); 0220 #endif 0221 Q_EMIT dataReceived(d->m_currentEntry.id, _data); 0222 } 0223 } 0224 0225 void MultiGetJob::slotMimetype(const QString &_mimetype) 0226 { 0227 Q_D(MultiGetJob); 0228 if (d->b_multiGetActive) { 0229 MultiGetJobPrivate::RequestQueue newQueue; 0230 d->flushQueue(newQueue); 0231 if (!newQueue.empty()) { 0232 d->m_activeQueue.splice(d->m_activeQueue.cend(), newQueue); 0233 d->m_slave->send(d->m_command, d->m_packedArgs); 0234 } 0235 } 0236 if (!d->findCurrentEntry()) { 0237 return; // Error, unknown request! 0238 } 0239 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 78) 0240 Q_EMIT mimetype(d->m_currentEntry.id, _mimetype); 0241 #endif 0242 Q_EMIT mimeTypeFound(d->m_currentEntry.id, _mimetype); 0243 } 0244 0245 MultiGetJob *KIO::multi_get(long id, const QUrl &url, const MetaData &metaData) 0246 { 0247 MultiGetJob *job = MultiGetJobPrivate::newJob(url); 0248 job->get(id, url, metaData); 0249 return job; 0250 } 0251 0252 #include "moc_multigetjob.cpp" 0253 0254 #endif // Deprecated since 5.84