3 This file is part of Minitube.
4 Copyright 2009, Flavio Tordini <flavio.tordini@gmail.com>
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.
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.
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/>.
21 #include "networkaccess.h"
22 #include "constants.h"
26 NetworkAccess* http();
30 const QString USER_AGENT = QString(Constants::NAME)
31 + " " + Constants::VERSION
32 + " (" + Constants::WEBSITE + ")";
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";
37 NetworkReply::NetworkReply(QNetworkReply *networkReply) :
38 QObject(networkReply),
39 networkReply(networkReply),
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();
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);
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;
72 readTimeoutTimer->start();
74 } else qWarning() << "Redirection not supported" << networkReply->url().toEncoded();
77 if (receivers(SIGNAL(data(QByteArray))) > 0)
78 emit data(networkReply->readAll());
79 else if (receivers(SIGNAL(finished(QNetworkReply*))) > 0)
80 emit finished(networkReply);
82 #ifndef QT_NO_DEBUG_OUTPUT
83 if (!networkReply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool())
84 qDebug() << networkReply->url().toEncoded();
88 // this will also delete this NetworkReply as the QNetworkReply is its parent
89 networkReply->deleteLater();
92 void NetworkReply::requestError(QNetworkReply::NetworkError code) {
93 qWarning() << networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()
94 << networkReply->errorString() << code;
95 emit error(networkReply);
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)));
107 void NetworkReply::readTimeout() {
108 networkReply->disconnect();
109 networkReply->abort();
110 networkReply->deleteLater();
112 if (networkReply->operation() != QNetworkAccessManager::GetOperation
113 || networkReply->operation() != QNetworkAccessManager::HeadOperation) {
114 emit error(networkReply);
118 if (retryCount > 3) {
119 emit error(networkReply);
122 QNetworkReply *retryReply = The::http()->request(networkReply->url(), networkReply->operation());
123 setParent(retryReply);
124 networkReply = retryReply;
127 readTimeoutTimer->start();
130 /* --- NetworkAccess --- */
132 NetworkAccess::NetworkAccess( QObject* parent) : QObject( parent ) {}
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");
144 QNetworkReply* NetworkAccess::request(QUrl url, int operation, const QByteArray& body, uint offset) {
145 QNetworkAccessManager *manager = The::networkAccessManager();
147 QNetworkRequest request = buildRequest(url);
150 request.setRawHeader("Range", QString("bytes=%1-").arg(offset).toUtf8());
152 QNetworkReply *networkReply;
155 case QNetworkAccessManager::GetOperation:
156 networkReply = manager->get(request);
159 case QNetworkAccessManager::HeadOperation:
160 networkReply = manager->head(request);
163 case QNetworkAccessManager::PostOperation:
165 request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
166 networkReply = manager->post(request, body);
170 qWarning() << "Unknown operation:" << operation;
177 NetworkReply* NetworkAccess::get(const QUrl url) {
178 QNetworkReply *networkReply = request(url);
179 return new NetworkReply(networkReply);
182 NetworkReply* NetworkAccess::head(const QUrl url) {
183 QNetworkReply *networkReply = request(url, QNetworkAccessManager::HeadOperation);
184 return new NetworkReply(networkReply);
187 NetworkReply* NetworkAccess::post(const QUrl url, const QMap<QString, QString>& params) {
189 QMapIterator<QString, QString> i(params);
190 while (i.hasNext()) {
192 body += QUrl::toPercentEncoding(i.key())
194 + QUrl::toPercentEncoding(i.value())
197 QNetworkReply *networkReply = request(url, QNetworkAccessManager::PostOperation, body);
198 return new NetworkReply(networkReply);