MythTV  master
mythsingledownload.cpp
Go to the documentation of this file.
1 
2 #include "mythsingledownload.h"
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 
14 bool 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" 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  LOG(VB_GENERAL, LOG_INFO, QString("%1 -> %2").arg(url.toString(), redir));
75  m_replylock.unlock();
76  m_lock.unlock();
77  return DownloadURL(redir, buffer, timeout, redirs + 1, maxsize, final_url);
78  }
79 
80  LOG(VB_GENERAL, LOG_ERR, QString("%1: too many redirects").arg(url.toString()));
81  ret = false;
82  }
83  else if (m_errorcode == QNetworkReply::NoError)
84  {
85  if (final_url != nullptr)
86  *final_url = url.toString();
87  *m_buffer += m_reply->readAll();
88  m_errorstring.clear();
89  ret = true;
90  }
91  else
92  {
93  m_errorstring = m_reply->errorString();
94  ret = false;
95  }
96  }
97 
98  m_replylock.unlock();
99  m_lock.unlock();
100 
101  delete m_reply;
102  m_reply = nullptr;
103  m_buffer = nullptr;
104 
105  return ret;
106 }
107 
109 {
110  QMutexLocker replylock(&m_replylock);
111  if (m_reply)
112  {
113  LOG(VB_GENERAL, LOG_INFO, LOC + "Aborting download");
114  m_reply->abort();
115  }
116 }
117 
118 void MythSingleDownload::Progress(qint64 bytesRead, qint64 /*totalBytes*/)
119 {
120  if (m_maxsize && bytesRead>=m_maxsize)
121  {
122  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Reached specified max file size (%1 bytes)").arg(m_maxsize));
123  {
124  QMutexLocker replylock(&m_replylock);
125  *m_buffer += m_reply->read(m_maxsize);
126  }
127  m_maxsize=0;
128  Cancel();
129  }
130 }
MythSingleDownload::m_lock
QMutex m_lock
Definition: mythsingledownload.h:46
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
MythSingleDownload::Cancel
void Cancel(void)
Definition: mythsingledownload.cpp:108
LOC
#define LOC
Definition: mythsingledownload.cpp:12
MythSingleDownload::m_mgr
QNetworkAccessManager m_mgr
Definition: mythsingledownload.h:43
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
mythsingledownload.h
MythSingleDownload::m_reply
QNetworkReply * m_reply
Definition: mythsingledownload.h:45
MythSingleDownload::m_timer
QTimer m_timer
Definition: mythsingledownload.h:44
MythSingleDownload::m_errorstring
QString m_errorstring
Definition: mythsingledownload.h:49
mythversion.h
quit
@ quit
Definition: lirc_client.h:30
mythlogging.h
MythSingleDownload::DownloadURL
bool DownloadURL(const QUrl &url, QByteArray *buffer, std::chrono::seconds timeout=30s, uint redirs=0, qint64 maxsize=0, QString *final_url=nullptr)
Definition: mythsingledownload.cpp:14
MythSingleDownload::m_errorcode
QNetworkReply::NetworkError m_errorcode
Definition: mythsingledownload.h:50
uint
unsigned int uint
Definition: compat.h:140
MythSingleDownload::m_maxsize
qint64 m_maxsize
Definition: mythsingledownload.h:52
MYTH_BINARY_VERSION
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:15
MythSingleDownload::Progress
void Progress(qint64 bytesRead, qint64 totalBytes)
Definition: mythsingledownload.cpp:118
MythSingleDownload::m_replylock
QMutex m_replylock
Definition: mythsingledownload.h:47
MythSingleDownload::m_buffer
QByteArray * m_buffer
Definition: mythsingledownload.h:51