#include "http.h"
-namespace {
+#include "networkhttpreply.h"
-QNetworkAccessManager *createNetworkAccessManager() {
- QNetworkAccessManager *nam = new QNetworkAccessManager();
- return nam;
-}
+namespace {
QNetworkAccessManager *networkAccessManager() {
- static QMap<QThread *, QNetworkAccessManager *> nams;
- QThread *t = QThread::currentThread();
- QMap<QThread *, QNetworkAccessManager *>::const_iterator i = nams.constFind(t);
- if (i != nams.constEnd()) return i.value();
- QNetworkAccessManager *nam = createNetworkAccessManager();
- nams.insert(t, nam);
+ static thread_local QNetworkAccessManager *nam = new QNetworkAccessManager();
return nam;
}
int defaultReadTimeout = 10000;
+int defaultMaxRetries = 3;
} // namespace
-Http::Http() : requestHeaders(getDefaultRequestHeaders()), readTimeout(defaultReadTimeout) {}
+Http::Http()
+ : requestHeaders(getDefaultRequestHeaders()), readTimeout(defaultReadTimeout),
+ maxRetries(defaultMaxRetries) {}
void Http::setRequestHeaders(const QMap<QByteArray, QByteArray> &headers) {
requestHeaders = headers;
request.setRawHeader(it.key(), it.value());
if (req.offset > 0)
- request.setRawHeader("Range", QString("bytes=%1-").arg(req.offset).toUtf8());
+ request.setRawHeader("Range", QStringLiteral("bytes=%1-").arg(req.offset).toUtf8());
QNetworkAccessManager *manager = networkAccessManager();
return request(req);
}
-NetworkHttpReply::NetworkHttpReply(const HttpRequest &req, Http &http)
- : http(http), req(req), retryCount(0) {
- if (req.url.isEmpty()) {
- qWarning() << "Empty URL";
- }
-
- networkReply = http.networkReply(req);
- setParent(networkReply);
- setupReply();
-
- readTimeoutTimer = new QTimer(this);
- readTimeoutTimer->setInterval(http.getReadTimeout());
- readTimeoutTimer->setSingleShot(true);
- connect(readTimeoutTimer, SIGNAL(timeout()), SLOT(readTimeout()), Qt::UniqueConnection);
- readTimeoutTimer->start();
-}
-
-void NetworkHttpReply::setupReply() {
- connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)),
- SLOT(replyError(QNetworkReply::NetworkError)), Qt::UniqueConnection);
- connect(networkReply, SIGNAL(finished()), SLOT(replyFinished()), Qt::UniqueConnection);
- connect(networkReply, SIGNAL(downloadProgress(qint64, qint64)),
- SLOT(downloadProgress(qint64, qint64)), Qt::UniqueConnection);
-}
-
-QString NetworkHttpReply::errorMessage() {
- return url().toString() + QLatin1Char(' ') + QString::number(statusCode()) + QLatin1Char(' ') +
- reasonPhrase();
-}
-
-void NetworkHttpReply::emitError() {
- const QString msg = errorMessage();
-#ifndef QT_NO_DEBUG_OUTPUT
- qDebug() << "Http:" << msg;
- if (!req.body.isEmpty()) qDebug() << "Http:" << req.body;
-#endif
- emit error(msg);
- emitFinished();
-}
-
-void NetworkHttpReply::emitFinished() {
- readTimeoutTimer->stop();
-
- // disconnect to avoid replyFinished() from being called
- networkReply->disconnect();
-
- emit finished(*this);
-
- // bye bye my reply
- // this will also delete this object and HttpReply as the QNetworkReply is their parent
- networkReply->deleteLater();
-}
-
-void NetworkHttpReply::replyFinished() {
- QUrl redirection = networkReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
- if (redirection.isValid()) {
- HttpRequest redirectReq;
- redirectReq.url = redirection;
- redirectReq.operation = req.operation;
- redirectReq.body = req.body;
- redirectReq.offset = req.offset;
- QNetworkReply *redirectReply = http.networkReply(redirectReq);
- setParent(redirectReply);
- networkReply->deleteLater();
- networkReply = redirectReply;
- setupReply();
- readTimeoutTimer->start();
- return;
- }
-
- if (isSuccessful()) {
- bytes = networkReply->readAll();
- emit data(bytes);
-
-#ifndef QT_NO_DEBUG_OUTPUT
- if (!networkReply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool())
- qDebug() << networkReply->url().toString() << statusCode();
- else
- qDebug() << "CACHE" << networkReply->url().toString();
-#endif
- }
-
- emitFinished();
-}
-
-void NetworkHttpReply::replyError(QNetworkReply::NetworkError code) {
- Q_UNUSED(code);
- const int status = statusCode();
- if (retryCount <= 3 && status >= 500 && status < 600) {
- qDebug() << "Retrying" << req.url;
- networkReply->disconnect();
- networkReply->deleteLater();
- QNetworkReply *retryReply = http.networkReply(req);
- setParent(retryReply);
- networkReply = retryReply;
- setupReply();
- retryCount++;
- readTimeoutTimer->start();
- } else {
- emitError();
- return;
- }
-}
-
-void NetworkHttpReply::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 NetworkHttpReply::readTimeout() {
- if (!networkReply) return;
- networkReply->disconnect();
- networkReply->abort();
- networkReply->deleteLater();
-
- if (retryCount > 3 && (networkReply->operation() != QNetworkAccessManager::GetOperation &&
- networkReply->operation() != QNetworkAccessManager::HeadOperation)) {
- emitError();
- emit finished(*this);
- return;
- }
-
- qDebug() << "Timeout" << req.url;
- QNetworkReply *retryReply = http.networkReply(req);
- setParent(retryReply);
- networkReply = retryReply;
- setupReply();
- retryCount++;
- readTimeoutTimer->start();
-}
-
-QUrl NetworkHttpReply::url() const {
- return networkReply->url();
-}
-
-int NetworkHttpReply::statusCode() const {
- return networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
-}
-
-QString NetworkHttpReply::reasonPhrase() const {
- return networkReply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
-}
-
-const QList<QNetworkReply::RawHeaderPair> NetworkHttpReply::headers() const {
- return networkReply->rawHeaderPairs();
-}
-
-QByteArray NetworkHttpReply::header(const QByteArray &headerName) const {
- return networkReply->rawHeader(headerName);
+int Http::getMaxRetries() const
+{
+ return maxRetries;
}
-QByteArray NetworkHttpReply::body() const {
- return bytes;
+void Http::setMaxRetries(int value)
+{
+ maxRetries = value;
}