]> git.sur5r.net Git - minitube/blob - src/networkaccess.cpp
Imported Upstream version 2.4
[minitube] / src / networkaccess.cpp
1 /* $BEGIN_LICENSE
2
3 This file is part of Minitube.
4 Copyright 2009, Flavio Tordini <flavio.tordini@gmail.com>
5
6 Minitube is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Minitube is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Minitube.  If not, see <http://www.gnu.org/licenses/>.
18
19 $END_LICENSE */
20
21 #include "networkaccess.h"
22 #include "constants.h"
23 #include <QtGui>
24 #if QT_VERSION >= 0x050000
25 #include <QtWidgets>
26 #endif
27
28 namespace The {
29 NetworkAccess* http();
30 }
31
32 /*
33 const QString USER_AGENT = QString(Constants::NAME)
34                            + " " + Constants::VERSION
35                            + " (" + Constants::WEBSITE + ")";
36 */
37
38 const QString USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36";
39
40 NetworkReply::NetworkReply(QNetworkReply *networkReply) :
41     QObject(networkReply),
42     networkReply(networkReply),
43     retryCount(0) {
44
45     setupReply();
46
47     readTimeoutTimer = new QTimer(this);
48     readTimeoutTimer->setInterval(25000);
49     readTimeoutTimer->setSingleShot(true);
50     connect(readTimeoutTimer, SIGNAL(timeout()), SLOT(readTimeout()), Qt::UniqueConnection);
51     readTimeoutTimer->start();
52 }
53
54 void NetworkReply::setupReply() {
55     connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
56             SLOT(requestError(QNetworkReply::NetworkError)), Qt::UniqueConnection);
57     connect(networkReply, SIGNAL(finished()),
58             SLOT(finished()), Qt::UniqueConnection);
59     connect(networkReply, SIGNAL(downloadProgress(qint64,qint64)),
60             SLOT(downloadProgress(qint64,qint64)), Qt::UniqueConnection);
61 }
62
63 void NetworkReply::finished() {
64     QUrl redirection = networkReply->attribute(
65                 QNetworkRequest::RedirectionTargetAttribute).toUrl();
66     if (redirection.isValid()) {
67         if (networkReply->operation() == QNetworkAccessManager::GetOperation
68                 || networkReply->operation() == QNetworkAccessManager::HeadOperation) {
69             QNetworkReply *redirectReply =
70                     The::http()->request(redirection, networkReply->operation());
71             setParent(redirectReply);
72             networkReply->deleteLater();
73             networkReply = redirectReply;
74             setupReply();
75             readTimeoutTimer->start();
76             return;
77         } else qDebug() << "Redirection not supported" << networkReply->url().toEncoded();
78     }
79
80     if (receivers(SIGNAL(data(QByteArray))) > 0)
81         emit data(networkReply->readAll());
82     else if (receivers(SIGNAL(finished(QNetworkReply*))) > 0)
83         emit finished(networkReply);
84
85 #ifndef QT_NO_DEBUG_OUTPUT
86     if (!networkReply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool())
87         qDebug() << networkReply->url().toEncoded();
88 #endif
89
90     // bye bye my reply
91     // this will also delete this NetworkReply as the QNetworkReply is its parent
92     networkReply->deleteLater();
93 }
94
95 void NetworkReply::requestError(QNetworkReply::NetworkError code) {
96     qWarning() << networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()
97              << networkReply->errorString() << code;
98     emit error(networkReply);
99 }
100
101 void NetworkReply::downloadProgress(qint64 bytesReceived, qint64 /* bytesTotal */) {
102     // qDebug() << "Downloading" << bytesReceived << bytesTotal << networkReply->url();
103     if (bytesReceived > 0 && readTimeoutTimer->isActive()) {
104         readTimeoutTimer->stop();
105         disconnect(networkReply, SIGNAL(downloadProgress(qint64,qint64)),
106                    this, SLOT(downloadProgress(qint64,qint64)));
107     }
108 }
109
110 void NetworkReply::readTimeout() {
111     networkReply->disconnect();
112     networkReply->abort();
113     networkReply->deleteLater();
114
115     if (networkReply->operation() != QNetworkAccessManager::GetOperation
116             || networkReply->operation() != QNetworkAccessManager::HeadOperation) {
117         emit error(networkReply);
118         return;
119     }
120
121     if (retryCount > 3) {
122         emit error(networkReply);
123         return;
124     }
125     QNetworkReply *retryReply = The::http()->request(networkReply->url(), networkReply->operation());
126     setParent(retryReply);
127     networkReply = retryReply;
128     setupReply();
129     retryCount++;
130     readTimeoutTimer->start();
131 }
132
133 /* --- NetworkAccess --- */
134
135 NetworkAccess::NetworkAccess( QObject* parent) : QObject( parent ) {}
136
137 QNetworkRequest NetworkAccess::buildRequest(QUrl url) {
138     QNetworkRequest request(url);
139     request.setRawHeader("User-Agent", USER_AGENT.toUtf8());
140     request.setRawHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
141     request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
142     request.setRawHeader("Accept-Language", "en-us,en;q=0.5");
143     request.setRawHeader("Connection", "Keep-Alive");
144     return request;
145 }
146
147 QNetworkReply* NetworkAccess::request(QUrl url, int operation, const QByteArray& body, uint offset) {
148     QNetworkAccessManager *manager = The::networkAccessManager();
149
150     QNetworkRequest request = buildRequest(url);
151
152     if (offset > 0)
153         request.setRawHeader("Range", QString("bytes=%1-").arg(offset).toUtf8());
154
155     QNetworkReply *networkReply;
156     switch (operation) {
157
158     case QNetworkAccessManager::GetOperation:
159         networkReply = manager->get(request);
160         break;
161
162     case QNetworkAccessManager::HeadOperation:
163         networkReply = manager->head(request);
164         break;
165
166     case QNetworkAccessManager::PostOperation:
167         if (!body.isEmpty())
168             request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
169         networkReply = manager->post(request, body);
170         break;
171
172     default:
173         qWarning() << "Unknown operation:" << operation;
174         return 0;
175     }
176
177     return networkReply;
178 }
179
180 NetworkReply* NetworkAccess::get(const QUrl url) {
181     QNetworkReply *networkReply = request(url);
182     return new NetworkReply(networkReply);
183 }
184
185 NetworkReply* NetworkAccess::head(const QUrl url) {
186     QNetworkReply *networkReply = request(url, QNetworkAccessManager::HeadOperation);
187     return new NetworkReply(networkReply);
188 }
189
190 NetworkReply* NetworkAccess::post(const QUrl url, const QMap<QString, QString>& params) {
191     QByteArray body;
192     QMapIterator<QString, QString> i(params);
193     while (i.hasNext()) {
194         i.next();
195         body += QUrl::toPercentEncoding(i.key())
196                 + '='
197                 + QUrl::toPercentEncoding(i.value())
198                 + '&';
199     }
200     QNetworkReply *networkReply = request(url, QNetworkAccessManager::PostOperation, body);
201     return new NetworkReply(networkReply);
202 }