#include "networkaccess.h"
-#include "Constants.h"
+#include "constants.h"
#include <QtGui>
namespace The {
- NetworkAccess* http();
+NetworkAccess* http();
}
-NetworkReply::NetworkReply(QNetworkReply *networkReply) : QObject(networkReply) {
- this->networkReply = networkReply;
-}
-
-void NetworkReply::finished() {
+/*
+const QString USER_AGENT = QString(Constants::NAME)
+ + " " + Constants::VERSION
+ + " (" + Constants::WEBSITE + ")";
+*/
- QUrl redirection = networkReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
- if (redirection.isValid()) {
+const QString USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11";
- // 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(10000);
+ 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 qWarning() << "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) {
+ qDebug() << networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()
+ << networkReply->errorString() << code;
emit error(networkReply);
}
+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)));
+ }
+}
+
+void NetworkReply::readTimeout() {
+ networkReply->disconnect();
+ networkReply->abort();
+ networkReply->deleteLater();
+
+ if (networkReply->operation() != QNetworkAccessManager::GetOperation
+ || networkReply->operation() != QNetworkAccessManager::HeadOperation) {
+ emit error(networkReply);
+ return;
+ }
+
+ 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 ) {}
-QNetworkReply* NetworkAccess::simpleGet(QUrl url, int operation) {
+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) {
QNetworkAccessManager *manager = The::networkAccessManager();
- QNetworkRequest request(url);
- request.setRawHeader("User-Agent", Constants::USER_AGENT.toUtf8());
- request.setRawHeader("Connection", "Keep-Alive");
+ QNetworkRequest request = buildRequest(url);
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)));
-
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;
-
+ QNetworkReply *networkReply = request(url, QNetworkAccessManager::HeadOperation);
+ return new NetworkReply(networkReply);
}
-/*** 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* 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())
+ + '&';
}
-
- networkReply->deleteLater();
- return 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);
- */
- }
-
-}
-
-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);
}