3#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
4#include <QtSystemDetection>
6#include <QCoreApplication>
12#include <QNetworkCookie>
13#include <QAuthenticator>
16#include <QNetworkProxy>
17#include <QMutexLocker>
30#include "mythversion.h"
38#define LOC QString("DownloadManager: ")
53 qRegisterMetaType<QNetworkReply::NetworkError>(
"QNetworkReply::NetworkError");
65 QMutexLocker lock(&
m_lock);
71 QMutexLocker lock(&
m_lock);
95 const QHash<QByteArray, QByteArray> *
m_headers {
nullptr};
97 QNetworkReply::NetworkError
m_errorCode {QNetworkReply::NoError};
163 while (!tmpDLM->getQueueThread())
164 std::this_thread::sleep_for(10ms);
166 tmpDLM->moveToThread(tmpDLM->getQueueThread());
167 tmpDLM->setRunThread();
169 while (!tmpDLM->isRunning())
170 std::this_thread::sleep_for(10ms);
199 bool downloading =
false;
200 bool itemsInQueue =
false;
201 bool itemsInCancellationQueue =
false;
202 bool waitAnyway =
false;
207 std::this_thread::sleep_for(50ms);
209 m_manager =
new QNetworkAccessManager(
this);
213 QCoreApplication::applicationName() +
"-" +
223 m_manager->cookieJar()->setParent(
nullptr);
225 QObject::connect(
m_manager, &QNetworkAccessManager::finished,
233 LOG(VB_GENERAL, LOG_DEBUG,
"Updating DLManager's Cookie Jar");
243 if (itemsInCancellationQueue)
248 QCoreApplication::processEvents();
254 if (!itemsInQueue || waitAnyway)
261 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"waiting 200ms"));
266 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"waiting for more items to download"));
298 if (dlInfo->
m_url.startsWith(
"myth://"))
328 const QString &
dest, QByteArray *data,
335 dlInfo->m_request = req;
336 dlInfo->m_outFile =
dest;
337 dlInfo->m_data = data;
338 dlInfo->m_caller = caller;
339 dlInfo->m_requestType = reqType;
340 dlInfo->m_reload = reload;
360 const QString &
dest, QByteArray *data,
364 const QHash<QByteArray, QByteArray> *
headers,
370 dlInfo->m_request = req;
371 dlInfo->m_outFile =
dest;
372 dlInfo->m_data = data;
373 dlInfo->m_requestType = reqType;
374 dlInfo->m_reload = reload;
375 dlInfo->m_syncMode =
true;
376 dlInfo->m_authCallback = authCallbackFn;
377 dlInfo->m_authArg = authArg;
379 dlInfo->m_finalUrl = finalUrl;
389 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"preCache('%1')").arg(url));
390 queueItem(url,
nullptr, QString(),
nullptr,
nullptr);
404 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"queueDownload('%1', '%2', %3)")
405 .arg(url,
dest, QString::number((
long long)caller)));
419 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"queueDownload('%1', '%2', %3)")
420 .arg(req->url().toString()).arg((
long long)data)
421 .arg((
long long)caller));
423 queueItem(req->url().toString(), req, QString(), data, caller,
425 (QNetworkRequest::AlwaysNetwork == req->attribute(
426 QNetworkRequest::CacheLoadControlAttribute,
427 QNetworkRequest::PreferNetwork).toInt()));
449 const bool reload, QString *finalUrl)
453 nullptr,
nullptr,
nullptr, &redirected))
455 if (!redirected.isEmpty() && finalUrl !=
nullptr)
456 *finalUrl = redirected;
470 QNetworkReply *reply =
nullptr;
473 dlInfo->m_reload = reload;
474 dlInfo->m_syncMode =
true;
475 dlInfo->m_processReply =
false;
481 reply = dlInfo->m_reply;
483 dlInfo->m_reply =
nullptr;
503 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"download('%1', '%2')")
504 .arg(req->url().toString()).arg((
long long)data));
505 return processItem(req->url().toString(), req, QString(), data,
507 (QNetworkRequest::AlwaysNetwork == req->attribute(
508 QNetworkRequest::CacheLoadControlAttribute,
509 QNetworkRequest::PreferNetwork).toInt()));
522 const bool reload,
AuthCallback authCallbackFn,
void *authArg,
523 const QHash<QByteArray, QByteArray> *
headers)
539 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"queuePost('%1', '%2')")
540 .arg(url).arg((
long long)data));
544 LOG(VB_GENERAL, LOG_ERR,
LOC +
"queuePost(), data is NULL!");
560 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"queuePost('%1', '%2')")
561 .arg(req->url().toString()).arg((
long long)data));
565 LOG(VB_GENERAL, LOG_ERR,
LOC +
"queuePost(), data is NULL!");
569 queueItem(req->url().toString(), req, QString(), data, caller,
571 (QNetworkRequest::AlwaysNetwork == req->attribute(
572 QNetworkRequest::CacheLoadControlAttribute,
573 QNetworkRequest::PreferNetwork).toInt()));
584 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"post('%1', '%2')")
585 .arg(url).arg((
long long)data));
589 LOG(VB_GENERAL, LOG_ERR,
LOC +
"post(), data is NULL!");
603 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"post('%1', '%2')")
604 .arg(req->url().toString()).arg((
long long)data));
608 LOG(VB_GENERAL, LOG_ERR,
LOC +
"post(), data is NULL!");
612 return processItem(req->url().toString(), req, QString(), data,
614 (QNetworkRequest::AlwaysNetwork == req->attribute(
615 QNetworkRequest::CacheLoadControlAttribute,
616 QNetworkRequest::PreferNetwork).toInt()));
630 const QHash<QByteArray, QByteArray> *
headers)
632 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"postAuth('%1', '%2')")
633 .arg(url).arg((
long long)data));
637 LOG(VB_GENERAL, LOG_ERR,
LOC +
"postAuth(), data is NULL!");
662 static const QString kDateFormat =
"ddd, dd MMM yyyy hh:mm:ss 'GMT'";
663 QUrl qurl(dlInfo->
m_url);
664 QNetworkRequest request;
674 request.setUrl(qurl);
679 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
680 QNetworkRequest::AlwaysNetwork);
691 while (!(redirectLoc =
getHeader(qurl,
"Location")).isNull())
695 LOG(VB_GENERAL, LOG_WARNING, QString(
"Cache Redirection limit "
697 .arg(qurl.toString()));
700 qurl.setUrl(redirectLoc);
704 LOG(VB_NETWORK, LOG_DEBUG, QString(
"Checking cache for %1")
705 .arg(qurl.toString()));
708 QNetworkCacheMetaData urlData =
m_manager->cache()->metaData(qurl);
710 if ((urlData.isValid()) &&
711 ((!urlData.expirationDate().isValid()) ||
712 (urlData.expirationDate().toUTC().secsTo(now) < 10)))
714 QString dateString =
getHeader(urlData,
"Date");
716 if (!dateString.isNull())
720#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
721 loadDate.setTimeSpec(Qt::UTC);
723 loadDate.setTimeZone(QTimeZone(QTimeZone::UTC));
725 if (loadDate.secsTo(now) <= 720)
728 LOG(VB_NETWORK, LOG_DEBUG, QString(
"Preferring cache for %1")
729 .arg(qurl.toString()));
736 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
737 QNetworkRequest::PreferCache);
739 if (!request.hasRawHeader(
"User-Agent"))
741 request.setRawHeader(
"User-Agent",
742 QByteArray(
"MythTV v") + MYTH_BINARY_VERSION +
743 " MythDownloadManager");
748 QHash<QByteArray, QByteArray>::const_iterator it =
750 for ( ; it != dlInfo->
m_headers->constEnd(); ++it )
752 if (!it.key().isEmpty() && !it.value().isEmpty())
754 request.setRawHeader(it.key(), it.value());
777 connect(
m_manager, &QNetworkAccessManager::authenticationRequired,
781 connect(dlInfo->
m_reply, &QNetworkReply::errorOccurred,
783 connect(dlInfo->
m_reply, &QNetworkReply::downloadProgress,
792 QAuthenticator *authenticator)
804 LOG(VB_FILE, LOG_DEBUG,
"Calling auth callback");
826 if (dlInfo->
m_url.startsWith(
"http://[fe80::",Qt::CaseInsensitive))
827 return downloadNowLinkLocal(dlInfo, deleteInfo);
839 while ((!dlInfo->
IsDone()) &&
841 (((!dlInfo->
m_url.startsWith(
"myth://")) &&
843 ((dlInfo->
m_url.startsWith(
"myth://")) &&
852 bool done = dlInfo->
IsDone();
854 done && (dlInfo->
m_errorCode == QNetworkReply::NoError);
863 LOG(VB_FILE, LOG_DEBUG,
864 LOC + QString(
"Aborting download - lack of data transfer"));
899bool MythDownloadManager::downloadNowLinkLocal(
MythDownloadInfo *dlInfo,
bool deleteInfo)
906 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"No data buffer provided for %1").arg(dlInfo->
m_url));
913 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unsupported authentication for %1").arg(dlInfo->
m_url));
919 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unsupported File output %1 for %2")
928 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Unsupported link-local operation %1")
929 .arg(dlInfo->
m_url));
933 QUrl url(dlInfo->
m_url);
934 QString host(url.host());
935 int port(url.port(80));
949 QByteArray* buffer = dlInfo->
m_data;
950 QHash<QByteArray, QByteArray>
headers;
953 if (!
headers.contains(
"User-Agent"))
954 headers.insert(
"User-Agent", QByteArray(
"MythDownloadManager v") +
955 MYTH_BINARY_VERSION);
956 headers.insert(
"Connection",
"close");
957 headers.insert(
"Accept-Encoding",
"identity");
958 if (!buffer->isEmpty())
959 headers.insert(
"Content-Length", QString::number(buffer->size()).toUtf8());
960 headers.insert(
"Host", (url.host() +
":" + QString::number(port)).toUtf8());
962 QByteArray requestMessage;
963 QString path (url.path());
964 requestMessage.append(
"POST ");
965 requestMessage.append(path.toLatin1());
966 requestMessage.append(
" HTTP/1.1\r\n");
969 requestMessage.append(it.key());
970 requestMessage.append(
": ");
971 requestMessage.append(it.value());
972 requestMessage.append(
"\r\n");
974 requestMessage.append(
"\r\n");
975 if (!buffer->isEmpty())
976 requestMessage.append(*buffer);
979 socket.connectToHost(host,
static_cast<uint16_t>(port));
981 if (!socket.waitForConnected(5000))
984 ok = socket.write(requestMessage) > 0;
987 ok = socket.waitForDisconnected(5000);
990 *buffer = socket.readAll();
992 QByteArray delim(
"\r\n\r\n");
993 int delimLoc = buffer->indexOf(delim);
995 *buffer = buffer->right(buffer->size() - delimLoc - 4);
1012 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Link Local request failed: %1").arg(url.toString()));
1033 for (
const auto& url : std::as_const(urls))
1040 if (dlInfo->
m_url == url)
1067 if (QThread::currentThread() == this->thread())
1081 std::this_thread::sleep_for(50ms);
1098 LOG(VB_FILE, LOG_DEBUG,
1099 LOC + QString(
"Aborting download - user request"));
1108 dlInfo->
m_errorCode = QNetworkReply::OperationCanceledError;
1130 dlInfo->
m_data =
nullptr;
1134 QMap <QString, MythDownloadInfo*>::iterator mit =
m_downloadInfos.begin();
1142 dlInfo->
m_data =
nullptr;
1152 auto *reply = qobject_cast<QNetworkReply *>(sender());
1153 if (reply ==
nullptr)
1156 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"downloadError %1 ")
1157 .arg(errorCode) + reply->errorString() );
1162 reply->deleteLater();
1180 const QUrl& oldRedirectUrl)
1182 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"redirectUrl()"));
1185 if(!possibleRedirectUrl.isEmpty() && possibleRedirectUrl != oldRedirectUrl)
1196 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"downloadFinished(%1)")
1197 .arg((
long long)reply));
1202 reply->deleteLater();
1208 if (!dlInfo || !dlInfo->
m_reply)
1222 int statusCode = -1;
1223 static const QString kDateFormat =
"ddd, dd MMM yyyy hh:mm:ss 'GMT'";
1224 QNetworkReply *reply = dlInfo->
m_reply;
1228 QUrl possibleRedirectUrl =
1229 reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
1231 if (!possibleRedirectUrl.isEmpty() &&
1232 possibleRedirectUrl.isValid() &&
1233 possibleRedirectUrl.isRelative())
1234 possibleRedirectUrl = reply->url().resolved(possibleRedirectUrl);
1236 if (!possibleRedirectUrl.isEmpty() && dlInfo->
m_finalUrl !=
nullptr)
1237 *dlInfo->
m_finalUrl = QString(possibleRedirectUrl.toString());
1243 reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
1244 if (status.isValid())
1245 statusCode = status.toInt();
1250 (statusCode == 301 || statusCode == 302 ||
1251 statusCode == 303)))
1253 LOG(VB_FILE, LOG_DEBUG,
LOC +
1254 QString(
"downloadFinished(%1): Redirect: %2 -> %3")
1255 .arg(QString::number((
long long)dlInfo),
1256 reply->url().toString(),
1257 dlInfo->m_redirectedTo.toString()));
1260 dlInfo->m_data->clear();
1262 dlInfo->m_bytesReceived = 0;
1263 dlInfo->m_bytesTotal = 0;
1265 QNetworkRequest request(dlInfo->m_redirectedTo);
1267 if (dlInfo->m_reload)
1269 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
1270 QNetworkRequest::AlwaysNetwork);
1272 else if (dlInfo->m_preferCache)
1274 request.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
1275 QNetworkRequest::PreferCache);
1278 request.setRawHeader(
"User-Agent",
1279 "MythDownloadManager v" +
1280 QByteArray(MYTH_BINARY_VERSION));
1282 switch (dlInfo->m_requestType)
1285 dlInfo->m_reply =
m_manager->head(request);
1289 dlInfo->m_reply =
m_manager->get(request);
1295 connect(dlInfo->m_reply, &QNetworkReply::errorOccurred,
1297 connect(dlInfo->m_reply, &QNetworkReply::downloadProgress,
1301 reply->deleteLater();
1305 LOG(VB_FILE, LOG_DEBUG, QString(
"downloadFinished(%1): COMPLETE: %2")
1306 .arg((
long long)dlInfo).arg(dlInfo->m_url));
1310 QUrl fileUrl { dlInfo->m_url };
1311 QString redirectLoc;
1313 while (!(redirectLoc =
getHeader(fileUrl,
"Location")).isNull())
1315 QUrl redirUrl { redirectLoc };
1316 if (!redirUrl.isValid())
1318 LOG(VB_GENERAL, LOG_WARNING, QString(
"Invalid redirect %1 for %2")
1319 .arg(redirectLoc, fileUrl.toString()));
1324 LOG(VB_GENERAL, LOG_WARNING, QString(
"Cache Redirection limit "
1326 .arg(fileUrl.toString()));
1329 fileUrl.setUrl(redirectLoc);
1334 QNetworkCacheMetaData urlData =
m_manager->cache()->metaData(fileUrl);
1336 if (
getHeader(urlData,
"Date").isNull())
1338 QNetworkCacheMetaData::RawHeaderList
headers = urlData.rawHeaders();
1339 QNetworkCacheMetaData::RawHeader newheader;
1341 newheader = QNetworkCacheMetaData::RawHeader(
"Date",
1342 now.toString(kDateFormat).toLatin1());
1344 urlData.setRawHeaders(
headers);
1346 m_manager->cache()->updateMetaData(urlData);
1351 dlInfo->m_redirectedTo.clear();
1357 if (reply && dlInfo->m_processReply)
1359 bool append = (!dlInfo->m_syncMode && dlInfo->m_caller);
1360 QByteArray data = reply->readAll();
1361 dataSize = data.size();
1364 dlInfo->m_bytesReceived += dataSize;
1366 dlInfo->m_bytesReceived = dataSize;
1368 dlInfo->m_bytesTotal = dlInfo->m_bytesReceived;
1373 dlInfo->m_data->append(data);
1375 *dlInfo->m_data = data;
1377 else if (!dlInfo->m_outFile.isEmpty())
1379 saveFile(dlInfo->m_outFile, data, append);
1386 (*dlInfo->m_data) = dlInfo->m_privData;
1388 else if (!dlInfo->m_outFile.isEmpty())
1390 saveFile(dlInfo->m_outFile, dlInfo->m_privData);
1392 dlInfo->m_bytesReceived += dataSize;
1393 dlInfo->m_bytesTotal = dlInfo->m_bytesReceived;
1401 LOG(VB_GENERAL, LOG_ERR,
LOC +
1402 QString(
"ERROR download finished but failed to remove url: %1")
1403 .arg(dlInfo->m_url));
1410 dlInfo->SetDone(
true);
1412 if (!dlInfo->m_syncMode)
1414 if (dlInfo->m_caller)
1416 LOG(VB_FILE, LOG_DEBUG, QString(
"downloadFinished(%1): "
1417 "COMPLETE: %2, sending event to caller")
1418 .arg((
long long)dlInfo).arg(dlInfo->m_url));
1421 args << dlInfo->m_url;
1422 args << dlInfo->m_outFile;
1423 args << QString::number(dlInfo->m_bytesTotal);
1425 args << (reply ? reply->errorString() : QString());
1426 args << QString::number((
int)(reply ? reply->error() :
1427 dlInfo->m_errorCode));
1429 QCoreApplication::postEvent(dlInfo->m_caller,
1448 auto *reply = qobject_cast<QNetworkReply *>(sender());
1449 if (reply ==
nullptr)
1452 LOG(VB_FILE, LOG_DEBUG,
LOC +
1453 QString(
"downloadProgress(%1, %2) (for reply %3)")
1454 .arg(bytesReceived).arg(bytesTotal).arg((
long long)reply));
1467 LOG(VB_FILE, LOG_DEBUG,
LOC +
1468 QString(
"downloadProgress: %1 to %2 is at %3 of %4 bytes downloaded")
1470 .arg(bytesReceived).arg(bytesTotal));
1474 LOG(VB_FILE, LOG_DEBUG, QString(
"downloadProgress(%1): "
1475 "sending event to caller")
1476 .arg(reply->url().toString()));
1479 QByteArray data = reply->readAll();
1484 dlInfo->
m_data->append(data);
1492 args << QString::number(bytesReceived);
1493 args << QString::number(bytesTotal);
1495 QCoreApplication::postEvent(dlInfo->
m_caller,
1508 const QByteArray &data,
1511 if (outFile.isEmpty() || data.isEmpty())
1514 QFile
file(outFile);
1515 QFileInfo fileInfo(outFile);
1516 QDir qdir(fileInfo.absolutePath());
1518 if (!qdir.exists() && !qdir.mkpath(fileInfo.absolutePath()))
1520 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to create: '%1'")
1521 .arg(fileInfo.absolutePath()));
1525 QIODevice::OpenMode mode = QIODevice::Unbuffered|QIODevice::WriteOnly;
1527 mode |= QIODevice::Append;
1529 if (!
file.open(mode))
1531 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to open: '%1'") .arg(outFile));
1536 size_t remaining = data.size();
1537 uint failure_cnt = 0;
1538 while ((remaining > 0) && (failure_cnt < 5))
1540 ssize_t written =
file.write(data.data() + offset, remaining);
1544 std::this_thread::sleep_for(50ms);
1550 remaining -= written;
1553 return remaining <= 0;
1567 static const QString kDateFormat =
"ddd, dd MMM yyyy hh:mm:ss 'GMT'";
1568 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"GetLastModified('%1')").arg(url));
1573 QUrl cacheUrl = QUrl(url);
1576 QString redirectLoc;
1578 while (!(redirectLoc =
getHeader(cacheUrl,
"Location")).isNull())
1582 LOG(VB_GENERAL, LOG_WARNING, QString(
"Cache Redirection limit "
1584 .arg(cacheUrl.toString()));
1587 cacheUrl.setUrl(redirectLoc);
1592 QNetworkCacheMetaData urlData =
m_manager->cache()->metaData(cacheUrl);
1595 if (urlData.isValid() &&
1596 ((!urlData.expirationDate().isValid()) ||
1597 (urlData.expirationDate().secsTo(now) < 0)))
1599 if (urlData.lastModified().toUTC().secsTo(now) <= 3600)
1601 result = urlData.lastModified().toUTC();
1605 QString date =
getHeader(urlData,
"Date");
1608 QDateTime loadDate =
1610#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
1611 loadDate.setTimeSpec(Qt::UTC);
1613 loadDate.setTimeZone(QTimeZone(QTimeZone::UTC));
1615 if (loadDate.secsTo(now) <= 1200)
1617 result = urlData.lastModified().toUTC();
1623 if (!result.isValid())
1626 dlInfo->
m_url = url;
1637 QNetworkRequest::LastModifiedHeader);
1638 if (lastMod.isValid())
1639 result = lastMod.toDateTime().toUTC();
1648 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"GetLastModified('%1'): Result %2")
1649 .arg(url, result.toString()));
1677 auto *jar = qobject_cast<MythCookieJar *>(
m_manager->cookieJar());
1699 auto *inJar = qobject_cast<MythCookieJar *>(
m_manager->cookieJar());
1700 if (inJar ==
nullptr)
1716 auto *inJar = qobject_cast<MythCookieJar *>(jar);
1717 if (inJar ==
nullptr)
1735 if (inJar !=
nullptr)
1752 QNetworkCacheMetaData metadata =
m_manager->cache()->metaData(url);
1764 const QString& header)
1766 auto headers = cacheData.rawHeaders();
1767 for (
const auto& rh : std::as_const(
headers))
1768 if (QString(rh.first) == header)
1779 const QList<QNetworkCookie> cookieList = old.allCookies();
1780 setAllCookies(cookieList);
1788 LOG(VB_GENERAL, LOG_DEBUG, QString(
"MythCookieJar: loading cookies from: %1").arg(
filename));
1791 if (!f.open(QIODevice::ReadOnly))
1793 LOG(VB_GENERAL, LOG_WARNING, QString(
"MythCookieJar::load() failed to open file for reading: %1").arg(
filename));
1797 QList<QNetworkCookie> cookieList;
1798 QTextStream stream(&f);
1799 while (!stream.atEnd())
1801 QString cookie = stream.readLine();
1802 cookieList << QNetworkCookie::parseCookies(cookie.toLocal8Bit());
1805 setAllCookies(cookieList);
1813 LOG(VB_GENERAL, LOG_DEBUG, QString(
"MythCookieJar: saving cookies to: %1").arg(
filename));
1816 if (!f.open(QIODevice::WriteOnly))
1818 LOG(VB_GENERAL, LOG_ERR, QString(
"MythCookieJar::save() failed to open file for writing: %1").arg(
filename));
1822 QList<QNetworkCookie> cookieList = allCookies();
1823 QTextStream stream(&f);
1825 for (
const auto& cookie : std::as_const(cookieList))
1826 stream << cookie.toRawForm() << Qt::endl;
1829#include "moc_mythdownloadmanager.cpp"
static MThreadPool * globalInstance(void)
void start(QRunnable *runnable, const QString &debugName, int priority=0)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
A subclassed QNetworkCookieJar that allows for reading and writing cookie files that contain raw form...
void load(const QString &filename)
Loads the cookie jar from a cookie file.
void save(const QString &filename)
Saves the cookie jar to a cookie file.
void copyAllCookies(MythCookieJar &old)
Copies all cookies from one MythCookieJar to another.
QString GetHostName(void)
const QHash< QByteArray, QByteArray > * m_headers
QNetworkReply::NetworkError m_errorCode
AuthCallback m_authCallback
MRequestType m_requestType
QNetworkRequest * m_request
QNetworkCookieJar * copyCookieJar(void)
Copy from one cookie jar to another.
void preCache(const QString &url)
Downloads a URL but doesn't store the resulting data anywhere.
QMap< QString, MythDownloadInfo * > m_downloadInfos
void downloadRemoteFile(MythDownloadInfo *dlInfo)
Triggers a myth:// URI download in the background via RemoteFile.
void queueItem(const QString &url, QNetworkRequest *req, const QString &dest, QByteArray *data, QObject *caller, MRequestType reqType=kRequestGet, bool reload=false)
Adds a request to the download queue.
~MythDownloadManager() override
Destructor for MythDownloadManager.
bool postAuth(const QString &url, QByteArray *data, AuthCallback authCallback, void *authArg, const QHash< QByteArray, QByteArray > *headers=nullptr)
Posts data to a url via the QNetworkAccessManager.
QNetworkCookieJar * m_inCookieJar
QNetworkDiskCache * m_diskCache
static bool saveFile(const QString &outFile, const QByteArray &data, bool append=false)
Saves a QByteArray of data to a given filename.
QWaitCondition m_queueWaitCond
bool downloadNow(MythDownloadInfo *dlInfo, bool deleteInfo=true)
Download helper for download() blocking methods.
QString getHeader(const QUrl &url, const QString &header)
void downloadQNetworkRequest(MythDownloadInfo *dlInfo)
Downloads a QNetworkRequest via the QNetworkAccessManager.
void queuePost(const QString &url, QByteArray *data, QObject *caller)
Queues a post to a URL via the QNetworkAccessManager.
void loadCookieJar(const QString &filename)
Loads the cookie jar from a cookie file.
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
Slot to process download update events.
void updateCookieJar(void)
Update the cookie jar from the temporary cookie jar.
bool post(const QString &url, QByteArray *data)
Posts data to a url via the QNetworkAccessManager.
bool processItem(const QString &url, QNetworkRequest *req, const QString &dest, QByteArray *data, MRequestType reqType=kRequestGet, bool reload=false, AuthCallback authCallback=nullptr, void *authArg=nullptr, const QHash< QByteArray, QByteArray > *headers=nullptr, QString *finalUrl=nullptr)
Processes a network request immediately and waits for a response.
QList< MythDownloadInfo * > m_cancellationQueue
QRecursiveMutex * m_infoLock
void downloadCanceled(void)
static QUrl redirectUrl(const QUrl &possibleRedirectUrl, const QUrl &oldRedirectUrl)
Checks whether we were redirected to the given URL.
friend class RemoteFileDownloadThread
QMap< QNetworkReply *, MythDownloadInfo * > m_downloadReplies
void authCallback(QNetworkReply *reply, QAuthenticator *authenticator)
Signal handler for authentication requests.
QList< MythDownloadInfo * > m_downloadQueue
void saveCookieJar(const QString &filename)
Saves the cookie jar to a cookie file.
bool downloadAuth(const QString &url, const QString &dest, bool reload=false, AuthCallback authCallback=nullptr, void *authArg=nullptr, const QHash< QByteArray, QByteArray > *headers=nullptr)
Downloads a URL to a file in blocking mode.
QNetworkAccessManager * m_manager
void setCookieJar(QNetworkCookieJar *cookieJar)
void run(void) override
Runs a loop to process incoming download requests and triggers download events to be processed.
void cancelDownload(const QString &url, bool block=true)
Cancel a queued or current download.
void removeListener(QObject *caller)
Disconnects the specified caller from any existing MythDownloadInfo instances.
void refreshCookieJar(QNetworkCookieJar *jar)
Refresh the temporary cookie jar from another cookie jar.
void queueDownload(const QString &url, const QString &dest, QObject *caller, bool reload=false)
Adds a url to the download queue.
QDateTime GetLastModified(const QString &url)
Gets the Last Modified timestamp for a URI.
void downloadError(QNetworkReply::NetworkError errorCode)
Slot to process download error events.
void downloadFinished(QNetworkReply *reply)
Slot to process download finished events.
bool download(const QString &url, const QString &dest, bool reload=false)
Downloads a URL to a file in blocking mode.
This class is used as a container for messages.
Small class to handle TCP port checking and finding link-local context.
bool resolveLinkLocal(QString &host, int port, std::chrono::milliseconds timeLimit=30s)
Convenience method to resolve link-local address.
MythDownloadManager * m_parent
RemoteFileDownloadThread(MythDownloadManager *parent, MythDownloadInfo *dlInfo)
MythDownloadInfo * m_dlInfo
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static constexpr int CACHE_REDIRECTION_LIMIT
void ShutdownMythDownloadManager(void)
Deletes the running MythDownloadManager at program exit.
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
MythDownloadManager * downloadManager
void(*)(QNetworkReply *, QAuthenticator *, void *) AuthCallback
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
std::chrono::seconds secsInPast(const QDateTime &past)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.