File indexing completed on 2024-04-28 15:26:30

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