]> git.sur5r.net Git - minitube/blob - lib/http/src/networkhttpreply.cpp
New upstream version 3.4
[minitube] / lib / http / src / networkhttpreply.cpp
1 #include "networkhttpreply.h"
2
3 NetworkHttpReply::NetworkHttpReply(const HttpRequest &req, Http &http)
4     : http(http), req(req), retryCount(0) {
5     if (req.url.isEmpty()) {
6         qWarning() << "Empty URL";
7     }
8
9     networkReply = http.networkReply(req);
10     setParent(networkReply);
11     setupReply();
12
13     readTimeoutTimer = new QTimer(this);
14     readTimeoutTimer->setInterval(http.getReadTimeout());
15     readTimeoutTimer->setSingleShot(true);
16     connect(readTimeoutTimer, SIGNAL(timeout()), SLOT(readTimeout()), Qt::UniqueConnection);
17     readTimeoutTimer->start();
18 }
19
20 void NetworkHttpReply::setupReply() {
21     connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
22             SLOT(replyError(QNetworkReply::NetworkError)), Qt::UniqueConnection);
23     connect(networkReply, SIGNAL(finished()), SLOT(replyFinished()), Qt::UniqueConnection);
24     connect(networkReply, SIGNAL(downloadProgress(qint64, qint64)),
25             SLOT(downloadProgress(qint64, qint64)), Qt::UniqueConnection);
26 }
27
28 QString NetworkHttpReply::errorMessage() {
29     return url().toString() + QLatin1Char(' ') + QString::number(statusCode()) + QLatin1Char(' ') +
30            reasonPhrase();
31 }
32
33 void NetworkHttpReply::emitError() {
34     const QString msg = errorMessage();
35 #ifndef QT_NO_DEBUG_OUTPUT
36     qDebug() << "Http:" << msg;
37     if (!req.body.isEmpty()) qDebug() << "Http:" << req.body;
38 #endif
39     emit error(msg);
40     emitFinished();
41 }
42
43 void NetworkHttpReply::emitFinished() {
44     readTimeoutTimer->stop();
45
46     // disconnect to avoid replyFinished() from being called
47     networkReply->disconnect();
48
49     emit finished(*this);
50
51     // bye bye my reply
52     // this will also delete this object and HttpReply as the QNetworkReply is their parent
53     networkReply->deleteLater();
54 }
55
56 void NetworkHttpReply::replyFinished() {
57     QUrl redirection = networkReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
58     if (redirection.isValid()) {
59         HttpRequest redirectReq;
60         if (redirection.isRelative()) redirection = networkReply->url().resolved(redirection);
61         redirectReq.url = redirection;
62         qDebug() << "Redirected to" << redirectReq.url;
63         redirectReq.operation = req.operation;
64         redirectReq.body = req.body;
65         redirectReq.offset = req.offset;
66         QNetworkReply *redirectReply = http.networkReply(redirectReq);
67         setParent(redirectReply);
68         networkReply->deleteLater();
69         networkReply = redirectReply;
70         setupReply();
71         readTimeoutTimer->start();
72         return;
73     }
74
75     if (isSuccessful()) {
76         bytes = networkReply->readAll();
77         emit data(bytes);
78
79 #ifndef QT_NO_DEBUG_OUTPUT
80         if (!networkReply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool())
81             qDebug() << statusCode() << networkReply->url().toString();
82         else
83             qDebug() << "CACHE" << networkReply->url().toString();
84 #endif
85     }
86
87     emitFinished();
88 }
89
90 void NetworkHttpReply::replyError(QNetworkReply::NetworkError code) {
91     Q_UNUSED(code);
92     const int status = statusCode();
93     if (retryCount <= http.getMaxRetries() && status >= 500 && status < 600 &&
94         (networkReply->operation() == QNetworkAccessManager::GetOperation ||
95          networkReply->operation() == QNetworkAccessManager::HeadOperation)) {
96         qDebug() << "Retrying" << status << QVariant(req.operation).toString() << req.url;
97         networkReply->disconnect();
98         networkReply->deleteLater();
99         QNetworkReply *retryReply = http.networkReply(req);
100         setParent(retryReply);
101         networkReply = retryReply;
102         setupReply();
103         retryCount++;
104         readTimeoutTimer->start();
105     } else {
106         emitError();
107         return;
108     }
109 }
110
111 void NetworkHttpReply::downloadProgress(qint64 bytesReceived, qint64 /* bytesTotal */) {
112     // qDebug() << "Downloading" << bytesReceived << bytesTotal << networkReply->url();
113     if (bytesReceived > 0 && readTimeoutTimer->isActive()) {
114         readTimeoutTimer->stop();
115         disconnect(networkReply, SIGNAL(downloadProgress(qint64, qint64)), this,
116                    SLOT(downloadProgress(qint64, qint64)));
117     }
118 }
119
120 void NetworkHttpReply::readTimeout() {
121     qDebug() << "Timeout" << req.url;
122
123     if (!networkReply) return;
124
125     bool shouldRetry = (networkReply->operation() == QNetworkAccessManager::GetOperation ||
126                         networkReply->operation() == QNetworkAccessManager::HeadOperation) &&
127                        retryCount < http.getMaxRetries();
128
129     networkReply->disconnect();
130     networkReply->abort();
131     networkReply->deleteLater();
132
133     if (!shouldRetry) {
134         emitError();
135         emit finished(*this);
136         return;
137     }
138
139     retryCount++;
140     QNetworkReply *retryReply = http.networkReply(req);
141     setParent(retryReply);
142     networkReply = retryReply;
143     setupReply();
144     readTimeoutTimer->start();
145 }
146
147 QUrl NetworkHttpReply::url() const {
148     return networkReply->url();
149 }
150
151 int NetworkHttpReply::statusCode() const {
152     return networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
153 }
154
155 QString NetworkHttpReply::reasonPhrase() const {
156     return networkReply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
157 }
158
159 const QList<QNetworkReply::RawHeaderPair> NetworkHttpReply::headers() const {
160     return networkReply->rawHeaderPairs();
161 }
162
163 QByteArray NetworkHttpReply::header(const QByteArray &headerName) const {
164     return networkReply->rawHeader(headerName);
165 }
166
167 QByteArray NetworkHttpReply::body() const {
168     return bytes;
169 }