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"
24 #if QT_VERSION >= 0x050000
29 NetworkAccess* http();
33 const QString USER_AGENT = QString(Constants::NAME)
34 + " " + Constants::VERSION
35 + " (" + Constants::WEBSITE + ")";
38 const QString USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36";
40 NetworkReply::NetworkReply(QNetworkReply *networkReply) :
41 QObject(networkReply),
42 networkReply(networkReply),
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();
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);
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;
75 readTimeoutTimer->start();
77 } else qWarning() << "Redirection not supported" << networkReply->url().toEncoded();
80 if (receivers(SIGNAL(data(QByteArray))) > 0)
81 emit data(networkReply->readAll());
82 else if (receivers(SIGNAL(finished(QNetworkReply*))) > 0)
83 emit finished(networkReply);
85 #ifndef QT_NO_DEBUG_OUTPUT
86 if (!networkReply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool())
87 qDebug() << networkReply->url().toEncoded();
91 // this will also delete this NetworkReply as the QNetworkReply is its parent
92 networkReply->deleteLater();
95 void NetworkReply::requestError(QNetworkReply::NetworkError code) {
96 qWarning() << networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()
97 << networkReply->errorString() << code;
98 emit error(networkReply);
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)));
110 void NetworkReply::readTimeout() {
111 networkReply->disconnect();
112 networkReply->abort();
113 networkReply->deleteLater();
115 if (networkReply->operation() != QNetworkAccessManager::GetOperation
116 || networkReply->operation() != QNetworkAccessManager::HeadOperation) {
117 emit error(networkReply);
121 if (retryCount > 3) {
122 emit error(networkReply);
125 QNetworkReply *retryReply = The::http()->request(networkReply->url(), networkReply->operation());
126 setParent(retryReply);
127 networkReply = retryReply;
130 readTimeoutTimer->start();
133 /* --- NetworkAccess --- */
135 NetworkAccess::NetworkAccess( QObject* parent) : QObject( parent ) {}
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");
147 QNetworkReply* NetworkAccess::request(QUrl url, int operation, const QByteArray& body, uint offset) {
148 QNetworkAccessManager *manager = The::networkAccessManager();
150 QNetworkRequest request = buildRequest(url);
153 request.setRawHeader("Range", QString("bytes=%1-").arg(offset).toUtf8());
155 QNetworkReply *networkReply;
158 case QNetworkAccessManager::GetOperation:
159 networkReply = manager->get(request);
162 case QNetworkAccessManager::HeadOperation:
163 networkReply = manager->head(request);
166 case QNetworkAccessManager::PostOperation:
168 request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
169 networkReply = manager->post(request, body);
173 qWarning() << "Unknown operation:" << operation;
180 NetworkReply* NetworkAccess::get(const QUrl url) {
181 QNetworkReply *networkReply = request(url);
182 return new NetworkReply(networkReply);
185 NetworkReply* NetworkAccess::head(const QUrl url) {
186 QNetworkReply *networkReply = request(url, QNetworkAccessManager::HeadOperation);
187 return new NetworkReply(networkReply);
190 NetworkReply* NetworkAccess::post(const QUrl url, const QMap<QString, QString>& params) {
192 QMapIterator<QString, QString> i(params);
193 while (i.hasNext()) {
195 body += QUrl::toPercentEncoding(i.key())
197 + QUrl::toPercentEncoding(i.value())
200 QNetworkReply *networkReply = request(url, QNetworkAccessManager::PostOperation, body);
201 return new NetworkReply(networkReply);