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