MythTV master
mythsingledownload.cpp
Go to the documentation of this file.
1
3#include "mythversion.h"
4#include "mythlogging.h"
5
6/*
7 * For simple one-at-a-time downloads, this routine (found at
8 * http://www.insanefactory.com/2012/08/qt-http-request-in-a-single-function/
9 * ) works well.
10 */
11
12#define LOC QString("MythSingleDownload: ")
13
14bool MythSingleDownload::DownloadURL(const QUrl &url, QByteArray *buffer,
15 std::chrono::seconds timeout,
16 uint redirs, qint64 maxsize, QString *final_url)
17{
18 m_lock.lock();
19
20 QEventLoop event_loop;
21 m_buffer = buffer;
22
23 // the HTTP request
24 QNetworkRequest req(url);
25 req.setRawHeader("User-Agent",
26 "MythTV v" + QByteArray(MYTH_BINARY_VERSION) + " MythSingleDownload");
27 m_replylock.lock();
28 m_reply = m_mgr.get(req);
29 m_replylock.unlock();
30
31 req.setAttribute(QNetworkRequest::CacheLoadControlAttribute,
32 QNetworkRequest::AlwaysNetwork);
33
34 // "quit()" the event-loop, when the network request "finished()"
35 connect(&m_timer, &QTimer::timeout, &event_loop, &QEventLoop::quit);
36 connect(m_reply, &QNetworkReply::finished, &event_loop, &QEventLoop::quit);
37 connect(m_reply, &QNetworkReply::downloadProgress, this, &MythSingleDownload::Progress);
38
39 // Configure timeout and size limit
40 m_maxsize = maxsize;
41 m_timer.setSingleShot(true);
42 m_timer.start(timeout); // 30 secs. by default
43
44 bool ret = event_loop.exec() != 0; // blocks stack until quit() is called
45
46 disconnect(&m_timer, &QTimer::timeout, &event_loop, &QEventLoop::quit);
47 disconnect(m_reply, &QNetworkReply::finished, &event_loop, &QEventLoop::quit);
48 disconnect(m_reply, &QNetworkReply::downloadProgress, this, &MythSingleDownload::Progress);
49
50 if (ret)
51 {
52 LOG(VB_GENERAL, LOG_ERR, LOC + "eventloop failed");
53 }
54
55 m_replylock.lock();
56 if (!m_timer.isActive())
57 {
58 m_errorstring = "timed-out";
59 m_reply->abort();
60 ret = false;
61 }
62 else
63 {
64 m_timer.stop();
65 m_errorcode = m_reply->error();
66
67 QString redir = m_reply->attribute(
68 QNetworkRequest::RedirectionTargetAttribute).toUrl().toString();
69
70 if (!redir.isEmpty())
71 {
72 if (redirs <= 3)
73 {
74 QUrl redirUrl { redir };
75 if (redirUrl.isValid())
76 {
77 LOG(VB_GENERAL, LOG_INFO, QString("%1 -> %2").arg(url.toString(), redir));
78 m_replylock.unlock();
79 m_lock.unlock();
80 return DownloadURL(redirUrl, buffer, timeout, redirs + 1, maxsize, final_url);
81 }
82 LOG(VB_GENERAL, LOG_INFO, QString("%1 -> %2 (invalid)").arg(url.toString(), redir));
83 m_errorstring = QString("invalid redirect: %1").arg(redir);
84 ret = false;
85 }
86 else
87 {
88 LOG(VB_GENERAL, LOG_ERR, QString("%1: too many redirects").arg(url.toString()));
89 ret = false;
90 }
91 }
92 else if (m_errorcode == QNetworkReply::NoError)
93 {
94 if (final_url != nullptr)
95 *final_url = url.toString();
96 *m_buffer += m_reply->readAll();
97 m_errorstring.clear();
98 ret = true;
99 }
100 else
101 {
102 m_errorstring = m_reply->errorString();
103 ret = false;
104 }
105 }
106
107 m_replylock.unlock();
108 m_lock.unlock();
109
110 delete m_reply;
111 m_reply = nullptr;
112 m_buffer = nullptr;
113
114 return ret;
115}
116
118{
119 QMutexLocker replylock(&m_replylock);
120 if (m_reply)
121 {
122 LOG(VB_GENERAL, LOG_INFO, LOC + "Aborting download");
123 m_reply->abort();
124 }
125}
126
127void MythSingleDownload::Progress(qint64 bytesRead, qint64 /*totalBytes*/)
128{
129 if (m_maxsize && bytesRead>=m_maxsize)
130 {
131 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Reached specified max file size (%1 bytes)").arg(m_maxsize));
132 {
133 QMutexLocker replylock(&m_replylock);
134 *m_buffer += m_reply->read(m_maxsize);
135 }
136 m_maxsize=0;
137 Cancel();
138 }
139}
QNetworkAccessManager m_mgr
bool DownloadURL(const QUrl &url, QByteArray *buffer, std::chrono::seconds timeout=30s, uint redirs=0, qint64 maxsize=0, QString *final_url=nullptr)
QNetworkReply * m_reply
QNetworkReply::NetworkError m_errorcode
void Progress(qint64 bytesRead, qint64 totalBytes)
unsigned int uint
Definition: compat.h:60
@ quit
Definition: lirc_client.h:31
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define LOC