+/* $BEGIN_LICENSE
+
+This file is part of Minitube.
+Copyright 2009, Flavio Tordini <flavio.tordini@gmail.com>
+
+Minitube is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Minitube is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Minitube. If not, see <http://www.gnu.org/licenses/>.
+
+$END_LICENSE */
+
#include "networkaccess.h"
#include "constants.h"
#include <QtGui>
+#if QT_VERSION >= 0x050000
+#include <QtWidgets>
+#endif
namespace The {
- NetworkAccess* http();
+NetworkAccess* http();
}
-const QString USER_AGENT = QString(Constants::APP_NAME)
+/*
+const QString USER_AGENT = QString(Constants::NAME)
+ " " + Constants::VERSION
+ " (" + Constants::WEBSITE + ")";
+*/
-NetworkReply::NetworkReply(QNetworkReply *networkReply) : QObject(networkReply) {
- this->networkReply = networkReply;
-}
-
-void NetworkReply::finished() {
+const QString USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36";
- QUrl redirection = networkReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
- if (redirection.isValid()) {
-
- // qDebug() << "Redirect!"; // << redirection;
+NetworkReply::NetworkReply(QNetworkReply *networkReply) :
+ QObject(networkReply),
+ networkReply(networkReply),
+ retryCount(0) {
- QNetworkReply *redirectReply = The::http()->simpleGet(redirection, networkReply->operation());
+ setupReply();
- setParent(redirectReply);
- networkReply->deleteLater();
- networkReply = redirectReply;
+ readTimeoutTimer = new QTimer(this);
+ readTimeoutTimer->setInterval(25000);
+ readTimeoutTimer->setSingleShot(true);
+ connect(readTimeoutTimer, SIGNAL(timeout()), SLOT(readTimeout()), Qt::UniqueConnection);
+ readTimeoutTimer->start();
+}
- // when the request is finished we'll invoke the target method
- connect(networkReply, SIGNAL(finished()), this, SLOT(finished()), Qt::AutoConnection);
+void NetworkReply::setupReply() {
+ connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
+ SLOT(requestError(QNetworkReply::NetworkError)), Qt::UniqueConnection);
+ connect(networkReply, SIGNAL(finished()),
+ SLOT(finished()), Qt::UniqueConnection);
+ connect(networkReply, SIGNAL(downloadProgress(qint64,qint64)),
+ SLOT(downloadProgress(qint64,qint64)), Qt::UniqueConnection);
+}
- return;
+void NetworkReply::finished() {
+ QUrl redirection = networkReply->attribute(
+ QNetworkRequest::RedirectionTargetAttribute).toUrl();
+ if (redirection.isValid()) {
+ if (networkReply->operation() == QNetworkAccessManager::GetOperation
+ || networkReply->operation() == QNetworkAccessManager::HeadOperation) {
+ QNetworkReply *redirectReply =
+ The::http()->request(redirection, networkReply->operation());
+ setParent(redirectReply);
+ networkReply->deleteLater();
+ networkReply = redirectReply;
+ setupReply();
+ readTimeoutTimer->start();
+ return;
+ } else qDebug() << "Redirection not supported" << networkReply->url().toEncoded();
}
+ if (receivers(SIGNAL(data(QByteArray))) > 0)
+ emit data(networkReply->readAll());
+ else if (receivers(SIGNAL(finished(QNetworkReply*))) > 0)
+ emit finished(networkReply);
- emit finished(networkReply);
-
- // get the HTTP response body
- QByteArray bytes = networkReply->readAll();
-
- emit data(bytes);
+#ifndef QT_NO_DEBUG_OUTPUT
+ if (!networkReply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool())
+ qDebug() << networkReply->url().toEncoded();
+#endif
// bye bye my reply
// this will also delete this NetworkReply as the QNetworkReply is its parent
}
void NetworkReply::requestError(QNetworkReply::NetworkError code) {
+ qWarning() << networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()
+ << networkReply->errorString() << code;
emit error(networkReply);
}
-/* --- NetworkAccess --- */
+void NetworkReply::downloadProgress(qint64 bytesReceived, qint64 /* bytesTotal */) {
+ // qDebug() << "Downloading" << bytesReceived << bytesTotal << networkReply->url();
+ if (bytesReceived > 0 && readTimeoutTimer->isActive()) {
+ readTimeoutTimer->stop();
+ disconnect(networkReply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(downloadProgress(qint64,qint64)));
+ }
+}
-NetworkAccess::NetworkAccess( QObject* parent) : QObject( parent ) {}
+void NetworkReply::readTimeout() {
+ networkReply->disconnect();
+ networkReply->abort();
+ networkReply->deleteLater();
-QNetworkReply* NetworkAccess::simpleGet(QUrl url, int operation) {
+ if (networkReply->operation() != QNetworkAccessManager::GetOperation
+ || networkReply->operation() != QNetworkAccessManager::HeadOperation) {
+ emit error(networkReply);
+ return;
+ }
- QNetworkAccessManager *manager = The::networkAccessManager();
+ if (retryCount > 3) {
+ emit error(networkReply);
+ return;
+ }
+ QNetworkReply *retryReply = The::http()->request(networkReply->url(), networkReply->operation());
+ setParent(retryReply);
+ networkReply = retryReply;
+ setupReply();
+ retryCount++;
+ readTimeoutTimer->start();
+}
+
+/* --- NetworkAccess --- */
+
+NetworkAccess::NetworkAccess( QObject* parent) : QObject( parent ) {}
+QNetworkRequest NetworkAccess::buildRequest(QUrl url) {
QNetworkRequest request(url);
request.setRawHeader("User-Agent", USER_AGENT.toUtf8());
+ request.setRawHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
+ request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+ request.setRawHeader("Accept-Language", "en-us,en;q=0.5");
request.setRawHeader("Connection", "Keep-Alive");
+ return request;
+}
+
+QNetworkReply* NetworkAccess::request(QUrl url, int operation, const QByteArray& body, uint offset) {
+ QNetworkAccessManager *manager = The::networkAccessManager();
+
+ QNetworkRequest request = buildRequest(url);
+
+ if (offset > 0)
+ request.setRawHeader("Range", QString("bytes=%1-").arg(offset).toUtf8());
QNetworkReply *networkReply;
switch (operation) {
case QNetworkAccessManager::GetOperation:
- qDebug() << "GET" << url.toString();
networkReply = manager->get(request);
break;
case QNetworkAccessManager::HeadOperation:
- qDebug() << "HEAD" << url.toString();
networkReply = manager->head(request);
break;
+ case QNetworkAccessManager::PostOperation:
+ if (!body.isEmpty())
+ request.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
+ networkReply = manager->post(request, body);
+ break;
+
default:
- qDebug() << "Unknown operation:" << operation;
+ qWarning() << "Unknown operation:" << operation;
return 0;
-
}
- // error handling
- connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
- this, SLOT(error(QNetworkReply::NetworkError)));
-
+#ifdef APP_MAC
+ networkReply->ignoreSslErrors();
+#endif
return networkReply;
-
}
NetworkReply* NetworkAccess::get(const QUrl url) {
-
- QNetworkReply *networkReply = simpleGet(url);
- NetworkReply *reply = new NetworkReply(networkReply);
-
- // error signal
- connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
- reply, SLOT(requestError(QNetworkReply::NetworkError)));
-
- // when the request is finished we'll invoke the target method
- connect(networkReply, SIGNAL(finished()), reply, SLOT(finished()), Qt::AutoConnection);
-
- return reply;
-
+ QNetworkReply *networkReply = request(url);
+ return new NetworkReply(networkReply);
}
NetworkReply* NetworkAccess::head(const QUrl url) {
-
- QNetworkReply *networkReply = simpleGet(url, QNetworkAccessManager::HeadOperation);
- NetworkReply *reply = new NetworkReply(networkReply);
-
- // error signal
- connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
- reply, SLOT(requestError(QNetworkReply::NetworkError)));
-
- // when the request is finished we'll invoke the target method
- connect(networkReply, SIGNAL(finished()), reply, SLOT(finished()), Qt::AutoConnection);
-
- return reply;
-
-}
-
-/*** sync ***/
-
-
-QNetworkReply* NetworkAccess::syncGet(QUrl url) {
-
- working = true;
-
- networkReply = simpleGet(url);
- connect(networkReply, SIGNAL(metaDataChanged()),
- this, SLOT(syncMetaDataChanged()), Qt::AutoConnection);
- connect(networkReply, SIGNAL(finished()),
- this, SLOT(syncFinished()), Qt::AutoConnection);
- connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
- this, SLOT(error(QNetworkReply::NetworkError)));
-
- // A little trick to make this function blocking
- while (working) {
- // Do something else, maybe even network processing events
- qApp->processEvents();
- }
-
- networkReply->deleteLater();
- return networkReply;
-
+ QNetworkReply *networkReply = request(url, QNetworkAccessManager::HeadOperation);
+ return new NetworkReply(networkReply);
}
-void NetworkAccess::syncMetaDataChanged() {
-
- QUrl redirection = networkReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
- if (redirection.isValid()) {
-
- qDebug() << "Redirect" << redirection;
- networkReply->deleteLater();
- syncGet(redirection);
-
- /*
- QNetworkAccessManager *manager = The::networkAccessManager();
- networkReply->deleteLater();
- networkReply = manager->get(QNetworkRequest(redirection));
- connect(networkReply, SIGNAL(metaDataChanged()),
- this, SLOT(metaDataChanged()), Qt::AutoConnection);
- connect(networkReply, SIGNAL(finished()),
- this, SLOT(finished()), Qt::AutoConnection);
- */
+NetworkReply* NetworkAccess::post(const QUrl url, const QMap<QString, QString>& params) {
+ QByteArray body;
+ QMapIterator<QString, QString> i(params);
+ while (i.hasNext()) {
+ i.next();
+ body += QUrl::toPercentEncoding(i.key())
+ + '='
+ + QUrl::toPercentEncoding(i.value())
+ + '&';
}
-
-}
-
-void NetworkAccess::syncFinished() {
- // got it!
- working = false;
-}
-
-void NetworkAccess::error(QNetworkReply::NetworkError code) {
- // get the QNetworkReply that sent the signal
- QNetworkReply *networkReply = static_cast<QNetworkReply *>(sender());
- if (!networkReply) {
- qDebug() << "Cannot get sender";
- return;
- }
-
- // Ignore HEADs
- if (networkReply->operation() == QNetworkAccessManager::HeadOperation)
- return;
-
- // report the error in the status bar
- QMainWindow* mainWindow = dynamic_cast<QMainWindow*>(qApp->topLevelWidgets().first());
- if (mainWindow) mainWindow->statusBar()->showMessage(
- tr("Network error: %1").arg(networkReply->errorString()));
-
- qDebug() << "Network error:" << networkReply->errorString() << code;
-
- networkReply->deleteLater();
-}
-
-QByteArray NetworkAccess::syncGetBytes(QUrl url) {
- return syncGet(url)->readAll();
-}
-
-QString NetworkAccess::syncGetString(QUrl url) {
- return QString::fromUtf8(syncGetBytes(url));
+ QNetworkReply *networkReply = request(url, QNetworkAccessManager::PostOperation, body);
+ return new NetworkReply(networkReply);
}