]> git.sur5r.net Git - minitube/blob - src/networkaccess.cpp
Imported Upstream version 2.1.3
[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
25 namespace The {
26 NetworkAccess* http();
27 }
28
29 /*
30 const QString USER_AGENT = QString(Constants::NAME)
31                            + " " + Constants::VERSION
32                            + " (" + Constants::WEBSITE + ")";
33 */
34
35 const QString USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.65 Safari/537.36";
36
37 NetworkReply::NetworkReply(QNetworkReply *networkReply) :
38     QObject(networkReply),
39     networkReply(networkReply),
40     retryCount(0) {
41
42     setupReply();
43
44     readTimeoutTimer = new QTimer(this);
45     readTimeoutTimer->setInterval(25000);
46     readTimeoutTimer->setSingleShot(true);
47     connect(readTimeoutTimer, SIGNAL(timeout()), SLOT(readTimeout()), Qt::UniqueConnection);
48     readTimeoutTimer->start();
49 }
50
51 void NetworkReply::setupReply() {
52     connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
53             SLOT(requestError(QNetworkReply::NetworkError)), Qt::UniqueConnection);
54     connect(networkReply, SIGNAL(finished()),
55             SLOT(finished()), Qt::UniqueConnection);
56     connect(networkReply, SIGNAL(downloadProgress(qint64,qint64)),
57             SLOT(downloadProgress(qint64,qint64)), Qt::UniqueConnection);
58 }
59
60 void NetworkReply::finished() {
61     QUrl redirection = networkReply->attribute(
62                 QNetworkRequest::RedirectionTargetAttribute).toUrl();
63     if (redirection.isValid()) {
64         if (networkReply->operation() == QNetworkAccessManager::GetOperation
65                 || networkReply->operation() == QNetworkAccessManager::HeadOperation) {
66             QNetworkReply *redirectReply =
67                     The::http()->request(redirection, networkReply->operation());
68             setParent(redirectReply);
69             networkReply->deleteLater();
70             networkReply = redirectReply;
71             setupReply();
72             readTimeoutTimer->start();
73             return;
74         } else qWarning() << "Redirection not supported" << networkReply->url().toEncoded();
75     }
76
77     if (receivers(SIGNAL(data(QByteArray))) > 0)
78         emit data(networkReply->readAll());
79     else if (receivers(SIGNAL(finished(QNetworkReply*))) > 0)
80         emit finished(networkReply);
81
82 #ifndef QT_NO_DEBUG_OUTPUT
83     if (!networkReply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool())
84         qDebug() << networkReply->url().toEncoded();
85 #endif
86
87     // bye bye my reply
88     // this will also delete this NetworkReply as the QNetworkReply is its parent
89     networkReply->deleteLater();
90 }
91
92 void NetworkReply::requestError(QNetworkReply::NetworkError code) {
93     qWarning() << networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()
94              << networkReply->errorString() << code;
95     emit error(networkReply);
96 }
97
98 void NetworkReply::downloadProgress(qint64 bytesReceived, qint64 /* bytesTotal */) {
99     // qDebug() << "Downloading" << bytesReceived << bytesTotal << networkReply->url();
100     if (bytesReceived > 0 && readTimeoutTimer->isActive()) {
101         readTimeoutTimer->stop();
102         disconnect(networkReply, SIGNAL(downloadProgress(qint64,qint64)),
103                    this, SLOT(downloadProgress(qint64,qint64)));
104     }
105 }
106
107 void NetworkReply::readTimeout() {
108     networkReply->disconnect();
109     networkReply->abort();
110     networkReply->deleteLater();
111
112     if (networkReply->operation() != QNetworkAccessManager::GetOperation
113             || networkReply->operation() != QNetworkAccessManager::HeadOperation) {
114         emit error(networkReply);
115         return;
116     }
117
118     if (retryCount > 3) {
119         emit error(networkReply);
120         return;
121     }
122     QNetworkReply *retryReply = The::http()->request(networkReply->url(), networkReply->operation());
123     setParent(retryReply);
124     networkReply = retryReply;
125     setupReply();
126     retryCount++;
127     readTimeoutTimer->start();
128 }
129
130 /* --- NetworkAccess --- */
131
132 NetworkAccess::NetworkAccess( QObject* parent) : QObject( parent ) {}
133
134 QNetworkRequest NetworkAccess::buildRequest(QUrl url) {
135     QNetworkRequest request(url);
136     request.setRawHeader("User-Agent", USER_AGENT.toUtf8());
137     request.setRawHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
138     request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
139     request.setRawHeader("Accept-Language", "en-us,en;q=0.5");
140     request.setRawHeader("Connection", "Keep-Alive");
141     return request;
142 }
143
144 QNetworkReply* NetworkAccess::request(QUrl url, int operation, const QByteArray& body, uint offset) {
145     QNetworkAccessManager *manager = The::networkAccessManager();
146
147     QNetworkRequest request = buildRequest(url);
148
149     if (offset > 0)
150         request.setRawHeader("Range", QString("bytes=%1-").arg(offset).toUtf8());
151
152     QNetworkReply *networkReply;
153     switch (operation) {
154
155     case QNetworkAccessManager::GetOperation:
156         networkReply = manager->get(request);
157         break;
158
159     case QNetworkAccessManager::HeadOperation:
160         networkReply = manager->head(request);
161         break;
162
163     case QNetworkAccessManager::PostOperation:
164         if (!body.isEmpty())
165             request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
166         networkReply = manager->post(request, body);
167         break;
168
169     default:
170         qWarning() << "Unknown operation:" << operation;
171         return 0;
172     }
173
174     return networkReply;
175 }
176
177 NetworkReply* NetworkAccess::get(const QUrl url) {
178     QNetworkReply *networkReply = request(url);
179     return new NetworkReply(networkReply);
180 }
181
182 NetworkReply* NetworkAccess::head(const QUrl url) {
183     QNetworkReply *networkReply = request(url, QNetworkAccessManager::HeadOperation);
184     return new NetworkReply(networkReply);
185 }
186
187 NetworkReply* NetworkAccess::post(const QUrl url, const QMap<QString, QString>& params) {
188     QByteArray body;
189     QMapIterator<QString, QString> i(params);
190     while (i.hasNext()) {
191         i.next();
192         body += QUrl::toPercentEncoding(i.key())
193                 + '='
194                 + QUrl::toPercentEncoding(i.value())
195                 + '&';
196     }
197     QNetworkReply *networkReply = request(url, QNetworkAccessManager::PostOperation, body);
198     return new NetworkReply(networkReply);
199 }