mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-26 15:06:08 +03:00
AbstractNetworkJob: move to its own file
This commit is contained in:
parent
79cc902673
commit
dd5ddf2166
5 changed files with 415 additions and 349 deletions
|
@ -43,6 +43,7 @@ set(libsync_SRCS
|
|||
logger.cpp
|
||||
accessmanager.cpp
|
||||
configfile.cpp
|
||||
abstractnetworkjob.cpp
|
||||
networkjobs.cpp
|
||||
owncloudpropagator.cpp
|
||||
owncloudtheme.cpp
|
||||
|
|
284
src/libsync/abstractnetworkjob.cpp
Normal file
284
src/libsync/abstractnetworkjob.cpp
Normal file
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QSslConfiguration>
|
||||
#include <QBuffer>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QStringList>
|
||||
#include <QStack>
|
||||
#include <QTimer>
|
||||
#include <QMutex>
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "json.h"
|
||||
|
||||
#include "networkjobs.h"
|
||||
#include "account.h"
|
||||
#include "owncloudpropagator.h"
|
||||
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QTimer*)
|
||||
|
||||
namespace OCC {
|
||||
|
||||
|
||||
AbstractNetworkJob::AbstractNetworkJob(AccountPtr account, const QString &path, QObject *parent)
|
||||
: QObject(parent)
|
||||
, _timedout(false)
|
||||
, _followRedirects(false)
|
||||
, _ignoreCredentialFailure(false)
|
||||
, _reply(0)
|
||||
, _account(account)
|
||||
, _path(path)
|
||||
, _redirectCount(0)
|
||||
{
|
||||
_timer.setSingleShot(true);
|
||||
_timer.setInterval(OwncloudPropagator::httpTimeout() * 1000); // default to 5 minutes.
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
|
||||
|
||||
connect(this, SIGNAL(networkActivity()), SLOT(resetTimeout()));
|
||||
|
||||
// Network activity on the propagator jobs (GET/PUT) keeps all requests alive.
|
||||
// This is a workaround for OC instances which only support one
|
||||
// parallel up and download
|
||||
if (_account) {
|
||||
connect(_account.data(), SIGNAL(propagatorNetworkActivity()), SLOT(resetTimeout()));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setReply(QNetworkReply *reply)
|
||||
{
|
||||
if (reply)
|
||||
reply->setProperty("doNotHandleAuth", true);
|
||||
|
||||
QNetworkReply *old = _reply;
|
||||
_reply = reply;
|
||||
delete old;
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setTimeout(qint64 msec)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << msec;
|
||||
|
||||
_timer.start(msec);
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::resetTimeout()
|
||||
{
|
||||
qint64 interval = _timer.interval();
|
||||
_timer.stop();
|
||||
_timer.start(interval);
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setIgnoreCredentialFailure(bool ignore)
|
||||
{
|
||||
_ignoreCredentialFailure = ignore;
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setPath(const QString &path)
|
||||
{
|
||||
_path = path;
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setupConnections(QNetworkReply *reply)
|
||||
{
|
||||
connect(reply, SIGNAL(finished()), SLOT(slotFinished()));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
|
||||
connect(reply, SIGNAL(encrypted()), SIGNAL(networkActivity()));
|
||||
#endif
|
||||
connect(reply->manager(), SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), SIGNAL(networkActivity()));
|
||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SIGNAL(networkActivity()));
|
||||
connect(reply, SIGNAL(metaDataChanged()), SIGNAL(networkActivity()));
|
||||
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), SIGNAL(networkActivity()));
|
||||
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), SIGNAL(networkActivity()));
|
||||
}
|
||||
|
||||
QNetworkReply* AbstractNetworkJob::addTimer(QNetworkReply *reply)
|
||||
{
|
||||
reply->setProperty("timer", QVariant::fromValue(&_timer));
|
||||
return reply;
|
||||
}
|
||||
|
||||
QNetworkReply* AbstractNetworkJob::davRequest(const QByteArray &verb, const QString &relPath,
|
||||
QNetworkRequest req, QIODevice *data)
|
||||
{
|
||||
return addTimer(_account->davRequest(verb, relPath, req, data));
|
||||
}
|
||||
|
||||
QNetworkReply *AbstractNetworkJob::davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data)
|
||||
{
|
||||
return addTimer(_account->davRequest(verb, url, req, data));
|
||||
}
|
||||
|
||||
QNetworkReply* AbstractNetworkJob::getRequest(const QString &relPath)
|
||||
{
|
||||
return addTimer(_account->getRequest(relPath));
|
||||
}
|
||||
|
||||
QNetworkReply *AbstractNetworkJob::getRequest(const QUrl &url)
|
||||
{
|
||||
return addTimer(_account->getRequest(url));
|
||||
}
|
||||
|
||||
QNetworkReply *AbstractNetworkJob::headRequest(const QString &relPath)
|
||||
{
|
||||
return addTimer(_account->headRequest(relPath));
|
||||
}
|
||||
|
||||
QNetworkReply *AbstractNetworkJob::headRequest(const QUrl &url)
|
||||
{
|
||||
return addTimer(_account->headRequest(url));
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::slotFinished()
|
||||
{
|
||||
_timer.stop();
|
||||
|
||||
if( _reply->error() == QNetworkReply::SslHandshakeFailedError ) {
|
||||
qDebug() << "SslHandshakeFailedError: " << reply()->errorString() << " : can be caused by a webserver wanting SSL client certificates";
|
||||
}
|
||||
|
||||
if( _reply->error() != QNetworkReply::NoError ) {
|
||||
qDebug() << Q_FUNC_INFO << _reply->error() << _reply->errorString();
|
||||
if (_reply->error() == QNetworkReply::ProxyAuthenticationRequiredError) {
|
||||
qDebug() << Q_FUNC_INFO << _reply->rawHeader("Proxy-Authenticate");
|
||||
}
|
||||
emit networkError(_reply);
|
||||
}
|
||||
|
||||
// get the Date timestamp from reply
|
||||
_responseTimestamp = _reply->rawHeader("Date");
|
||||
_duration = _durationTimer.elapsed();
|
||||
|
||||
if (_followRedirects) {
|
||||
// ### the qWarnings here should be exported via displayErrors() so they
|
||||
// ### can be presented to the user if the job executor has a GUI
|
||||
QUrl requestedUrl = reply()->request().url();
|
||||
QUrl redirectUrl = reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||
if (!redirectUrl.isEmpty()) {
|
||||
_redirectCount++;
|
||||
if (requestedUrl.scheme() == QLatin1String("https") &&
|
||||
redirectUrl.scheme() == QLatin1String("http")) {
|
||||
qWarning() << this << "HTTPS->HTTP downgrade detected!";
|
||||
} else if (requestedUrl == redirectUrl || _redirectCount >= maxRedirects()) {
|
||||
qWarning() << this << "Redirect loop detected!";
|
||||
} else {
|
||||
resetTimeout();
|
||||
setReply(getRequest(redirectUrl));
|
||||
setupConnections(reply());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AbstractCredentials *creds = _account->credentials();
|
||||
if (!creds->stillValid(_reply) && ! _ignoreCredentialFailure) {
|
||||
_account->handleInvalidCredentials();
|
||||
}
|
||||
|
||||
bool discard = finished();
|
||||
if (discard) {
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
quint64 AbstractNetworkJob::duration()
|
||||
{
|
||||
return _duration;
|
||||
}
|
||||
|
||||
QByteArray AbstractNetworkJob::responseTimestamp()
|
||||
{
|
||||
return _responseTimestamp;
|
||||
}
|
||||
|
||||
AbstractNetworkJob::~AbstractNetworkJob()
|
||||
{
|
||||
setReply(0);
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::start()
|
||||
{
|
||||
_timer.start();
|
||||
_durationTimer.start();
|
||||
_duration = 0;
|
||||
|
||||
const QUrl url = account()->url();
|
||||
const QString displayUrl = QString( "%1://%2%3").arg(url.scheme()).arg(url.host()).arg(url.path());
|
||||
|
||||
qDebug() << "!!!" << metaObject()->className() << "created for" << displayUrl << "+" << path();
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::slotTimeout()
|
||||
{
|
||||
_timedout = true;
|
||||
qDebug() << this << "Timeout";
|
||||
if (reply()) {
|
||||
reply()->abort();
|
||||
} else {
|
||||
qDebug() << "reply was NULL";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NetworkJobTimeoutPauser::NetworkJobTimeoutPauser(QNetworkReply *reply)
|
||||
{
|
||||
_timer = reply->property("timer").value<QTimer*>();
|
||||
if(!_timer.isNull()) {
|
||||
_timer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
NetworkJobTimeoutPauser::~NetworkJobTimeoutPauser()
|
||||
{
|
||||
if(!_timer.isNull()) {
|
||||
_timer->start();
|
||||
}
|
||||
}
|
||||
|
||||
QString extractErrorMessage(const QByteArray& errorResponse)
|
||||
{
|
||||
QXmlStreamReader reader(errorResponse);
|
||||
reader.readNextStartElement();
|
||||
if (reader.name() != "error") {
|
||||
return QString::null;
|
||||
}
|
||||
|
||||
while (!reader.atEnd() && reader.error() == QXmlStreamReader::NoError) {
|
||||
reader.readNextStartElement();
|
||||
if (reader.name() == QLatin1String("message")) {
|
||||
return reader.readElementText();
|
||||
}
|
||||
}
|
||||
return QString::null;
|
||||
}
|
||||
|
||||
QString errorMessage(const QString& baseError, const QByteArray& body)
|
||||
{
|
||||
QString msg = baseError;
|
||||
QString extra = extractErrorMessage(body);
|
||||
if (!extra.isEmpty()) {
|
||||
msg += QString::fromLatin1(" (%1)").arg(extra);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
} // namespace OCC
|
129
src/libsync/abstractnetworkjob.h
Normal file
129
src/libsync/abstractnetworkjob.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||
* Copyright (C) by Daniel Molkentin <danimo@owncloud.com>
|
||||
*
|
||||
* This program 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 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "owncloudlib.h"
|
||||
#include <QObject>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QPointer>
|
||||
#include <QElapsedTimer>
|
||||
#include <QDateTime>
|
||||
#include <QTimer>
|
||||
#include "accountfwd.h"
|
||||
|
||||
class QUrl;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class AbstractSslErrorHandler;
|
||||
|
||||
/**
|
||||
* @brief The AbstractNetworkJob class
|
||||
*/
|
||||
class OWNCLOUDSYNC_EXPORT AbstractNetworkJob : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AbstractNetworkJob(AccountPtr account, const QString &path, QObject* parent = 0);
|
||||
virtual ~AbstractNetworkJob();
|
||||
|
||||
virtual void start();
|
||||
|
||||
AccountPtr account() const { return _account; }
|
||||
|
||||
void setPath(const QString &path);
|
||||
QString path() const { return _path; }
|
||||
|
||||
void setReply(QNetworkReply *reply);
|
||||
QNetworkReply* reply() const { return _reply; }
|
||||
|
||||
void setIgnoreCredentialFailure(bool ignore);
|
||||
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
|
||||
|
||||
QByteArray responseTimestamp();
|
||||
quint64 duration();
|
||||
|
||||
public slots:
|
||||
void setTimeout(qint64 msec);
|
||||
void resetTimeout();
|
||||
signals:
|
||||
void networkError(QNetworkReply *reply);
|
||||
void networkActivity();
|
||||
protected:
|
||||
void setupConnections(QNetworkReply *reply);
|
||||
QNetworkReply* davRequest(const QByteArray& verb, const QString &relPath,
|
||||
QNetworkRequest req = QNetworkRequest(),
|
||||
QIODevice *data = 0);
|
||||
QNetworkReply* davRequest(const QByteArray& verb, const QUrl &url,
|
||||
QNetworkRequest req = QNetworkRequest(),
|
||||
QIODevice *data = 0);
|
||||
QNetworkReply* getRequest(const QString &relPath);
|
||||
QNetworkReply* getRequest(const QUrl &url);
|
||||
QNetworkReply* headRequest(const QString &relPath);
|
||||
QNetworkReply* headRequest(const QUrl &url);
|
||||
|
||||
int maxRedirects() const { return 10; }
|
||||
virtual bool finished() = 0;
|
||||
QByteArray _responseTimestamp;
|
||||
QElapsedTimer _durationTimer;
|
||||
quint64 _duration;
|
||||
bool _timedout; // set to true when the timeout slot is recieved
|
||||
|
||||
// Automatically follows redirects. Note that this only works for
|
||||
// GET requests that don't set up any HTTP body or other flags.
|
||||
bool _followRedirects;
|
||||
|
||||
private slots:
|
||||
void slotFinished();
|
||||
virtual void slotTimeout();
|
||||
|
||||
private:
|
||||
QNetworkReply* addTimer(QNetworkReply *reply);
|
||||
bool _ignoreCredentialFailure;
|
||||
QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit)
|
||||
AccountPtr _account;
|
||||
QString _path;
|
||||
QTimer _timer;
|
||||
int _redirectCount;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Internal Helper class
|
||||
*/
|
||||
class NetworkJobTimeoutPauser {
|
||||
public:
|
||||
NetworkJobTimeoutPauser(QNetworkReply *reply);
|
||||
~NetworkJobTimeoutPauser();
|
||||
private:
|
||||
QPointer<QTimer> _timer;
|
||||
};
|
||||
|
||||
|
||||
/** Gets the SabreDAV-style error message from an error response.
|
||||
*
|
||||
* This assumes the response is XML with a 'error' tag that has a
|
||||
* 'message' tag that contains the data to extract.
|
||||
*
|
||||
* Returns a null string if no message was found.
|
||||
*/
|
||||
QString OWNCLOUDSYNC_EXPORT extractErrorMessage(const QByteArray& errorResponse);
|
||||
|
||||
/** Builds a error message based on the error and the reply body. */
|
||||
QString OWNCLOUDSYNC_EXPORT errorMessage(const QString& baseError, const QByteArray& body);
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
|
|
@ -35,211 +35,8 @@
|
|||
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QTimer*)
|
||||
|
||||
namespace OCC {
|
||||
|
||||
|
||||
AbstractNetworkJob::AbstractNetworkJob(AccountPtr account, const QString &path, QObject *parent)
|
||||
: QObject(parent)
|
||||
, _timedout(false)
|
||||
, _followRedirects(false)
|
||||
, _ignoreCredentialFailure(false)
|
||||
, _reply(0)
|
||||
, _account(account)
|
||||
, _path(path)
|
||||
, _redirectCount(0)
|
||||
{
|
||||
_timer.setSingleShot(true);
|
||||
_timer.setInterval(OwncloudPropagator::httpTimeout() * 1000); // default to 5 minutes.
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
|
||||
|
||||
connect(this, SIGNAL(networkActivity()), SLOT(resetTimeout()));
|
||||
|
||||
// Network activity on the propagator jobs (GET/PUT) keeps all requests alive.
|
||||
// This is a workaround for OC instances which only support one
|
||||
// parallel up and download
|
||||
if (_account) {
|
||||
connect(_account.data(), SIGNAL(propagatorNetworkActivity()), SLOT(resetTimeout()));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setReply(QNetworkReply *reply)
|
||||
{
|
||||
if (reply)
|
||||
reply->setProperty("doNotHandleAuth", true);
|
||||
|
||||
QNetworkReply *old = _reply;
|
||||
_reply = reply;
|
||||
delete old;
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setTimeout(qint64 msec)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << msec;
|
||||
|
||||
_timer.start(msec);
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::resetTimeout()
|
||||
{
|
||||
qint64 interval = _timer.interval();
|
||||
_timer.stop();
|
||||
_timer.start(interval);
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setIgnoreCredentialFailure(bool ignore)
|
||||
{
|
||||
_ignoreCredentialFailure = ignore;
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setPath(const QString &path)
|
||||
{
|
||||
_path = path;
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setupConnections(QNetworkReply *reply)
|
||||
{
|
||||
connect(reply, SIGNAL(finished()), SLOT(slotFinished()));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
|
||||
connect(reply, SIGNAL(encrypted()), SIGNAL(networkActivity()));
|
||||
#endif
|
||||
connect(reply->manager(), SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), SIGNAL(networkActivity()));
|
||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SIGNAL(networkActivity()));
|
||||
connect(reply, SIGNAL(metaDataChanged()), SIGNAL(networkActivity()));
|
||||
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), SIGNAL(networkActivity()));
|
||||
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), SIGNAL(networkActivity()));
|
||||
}
|
||||
|
||||
QNetworkReply* AbstractNetworkJob::addTimer(QNetworkReply *reply)
|
||||
{
|
||||
reply->setProperty("timer", QVariant::fromValue(&_timer));
|
||||
return reply;
|
||||
}
|
||||
|
||||
QNetworkReply* AbstractNetworkJob::davRequest(const QByteArray &verb, const QString &relPath,
|
||||
QNetworkRequest req, QIODevice *data)
|
||||
{
|
||||
return addTimer(_account->davRequest(verb, relPath, req, data));
|
||||
}
|
||||
|
||||
QNetworkReply *AbstractNetworkJob::davRequest(const QByteArray &verb, const QUrl &url, QNetworkRequest req, QIODevice *data)
|
||||
{
|
||||
return addTimer(_account->davRequest(verb, url, req, data));
|
||||
}
|
||||
|
||||
QNetworkReply* AbstractNetworkJob::getRequest(const QString &relPath)
|
||||
{
|
||||
return addTimer(_account->getRequest(relPath));
|
||||
}
|
||||
|
||||
QNetworkReply *AbstractNetworkJob::getRequest(const QUrl &url)
|
||||
{
|
||||
return addTimer(_account->getRequest(url));
|
||||
}
|
||||
|
||||
QNetworkReply *AbstractNetworkJob::headRequest(const QString &relPath)
|
||||
{
|
||||
return addTimer(_account->headRequest(relPath));
|
||||
}
|
||||
|
||||
QNetworkReply *AbstractNetworkJob::headRequest(const QUrl &url)
|
||||
{
|
||||
return addTimer(_account->headRequest(url));
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::slotFinished()
|
||||
{
|
||||
_timer.stop();
|
||||
|
||||
if( _reply->error() == QNetworkReply::SslHandshakeFailedError ) {
|
||||
qDebug() << "SslHandshakeFailedError: " << reply()->errorString() << " : can be caused by a webserver wanting SSL client certificates";
|
||||
}
|
||||
|
||||
if( _reply->error() != QNetworkReply::NoError ) {
|
||||
qDebug() << Q_FUNC_INFO << _reply->error() << _reply->errorString();
|
||||
if (_reply->error() == QNetworkReply::ProxyAuthenticationRequiredError) {
|
||||
qDebug() << Q_FUNC_INFO << _reply->rawHeader("Proxy-Authenticate");
|
||||
}
|
||||
emit networkError(_reply);
|
||||
}
|
||||
|
||||
// get the Date timestamp from reply
|
||||
_responseTimestamp = _reply->rawHeader("Date");
|
||||
_duration = _durationTimer.elapsed();
|
||||
|
||||
if (_followRedirects) {
|
||||
// ### the qWarnings here should be exported via displayErrors() so they
|
||||
// ### can be presented to the user if the job executor has a GUI
|
||||
QUrl requestedUrl = reply()->request().url();
|
||||
QUrl redirectUrl = reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||
if (!redirectUrl.isEmpty()) {
|
||||
_redirectCount++;
|
||||
if (requestedUrl.scheme() == QLatin1String("https") &&
|
||||
redirectUrl.scheme() == QLatin1String("http")) {
|
||||
qWarning() << this << "HTTPS->HTTP downgrade detected!";
|
||||
} else if (requestedUrl == redirectUrl || _redirectCount >= maxRedirects()) {
|
||||
qWarning() << this << "Redirect loop detected!";
|
||||
} else {
|
||||
resetTimeout();
|
||||
setReply(getRequest(redirectUrl));
|
||||
setupConnections(reply());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AbstractCredentials *creds = _account->credentials();
|
||||
if (!creds->stillValid(_reply) && ! _ignoreCredentialFailure) {
|
||||
_account->handleInvalidCredentials();
|
||||
}
|
||||
|
||||
bool discard = finished();
|
||||
if (discard) {
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
quint64 AbstractNetworkJob::duration()
|
||||
{
|
||||
return _duration;
|
||||
}
|
||||
|
||||
QByteArray AbstractNetworkJob::responseTimestamp()
|
||||
{
|
||||
return _responseTimestamp;
|
||||
}
|
||||
|
||||
AbstractNetworkJob::~AbstractNetworkJob()
|
||||
{
|
||||
setReply(0);
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::start()
|
||||
{
|
||||
_timer.start();
|
||||
_durationTimer.start();
|
||||
_duration = 0;
|
||||
|
||||
const QUrl url = account()->url();
|
||||
const QString displayUrl = QString( "%1://%2%3").arg(url.scheme()).arg(url.host()).arg(url.path());
|
||||
|
||||
qDebug() << "!!!" << metaObject()->className() << "created for" << displayUrl << "+" << path();
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::slotTimeout()
|
||||
{
|
||||
_timedout = true;
|
||||
qDebug() << this << "Timeout";
|
||||
if (reply()) {
|
||||
reply()->abort();
|
||||
} else {
|
||||
qDebug() << "reply was NULL";
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
RequestEtagJob::RequestEtagJob(AccountPtr account, const QString &path, QObject *parent)
|
||||
: AbstractNetworkJob(account, path, parent)
|
||||
{
|
||||
|
@ -806,21 +603,6 @@ bool CheckQuotaJob::finished()
|
|||
return true;
|
||||
}
|
||||
|
||||
NetworkJobTimeoutPauser::NetworkJobTimeoutPauser(QNetworkReply *reply)
|
||||
{
|
||||
_timer = reply->property("timer").value<QTimer*>();
|
||||
if(!_timer.isNull()) {
|
||||
_timer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
NetworkJobTimeoutPauser::~NetworkJobTimeoutPauser()
|
||||
{
|
||||
if(!_timer.isNull()) {
|
||||
_timer->start();
|
||||
}
|
||||
}
|
||||
|
||||
JsonApiJob::JsonApiJob(const AccountPtr &account, const QString& path, QObject* parent): AbstractNetworkJob(account, path, parent)
|
||||
{ }
|
||||
|
||||
|
@ -857,31 +639,4 @@ bool JsonApiJob::finished()
|
|||
return true;
|
||||
}
|
||||
|
||||
QString extractErrorMessage(const QByteArray& errorResponse)
|
||||
{
|
||||
QXmlStreamReader reader(errorResponse);
|
||||
reader.readNextStartElement();
|
||||
if (reader.name() != "error") {
|
||||
return QString::null;
|
||||
}
|
||||
|
||||
while (!reader.atEnd() && reader.error() == QXmlStreamReader::NoError) {
|
||||
reader.readNextStartElement();
|
||||
if (reader.name() == QLatin1String("message")) {
|
||||
return reader.readElementText();
|
||||
}
|
||||
}
|
||||
return QString::null;
|
||||
}
|
||||
|
||||
QString errorMessage(const QString& baseError, const QByteArray& body)
|
||||
{
|
||||
QString msg = baseError;
|
||||
QString extra = extractErrorMessage(body);
|
||||
if (!extra.isEmpty()) {
|
||||
msg += QString::fromLatin1(" (%1)").arg(extra);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
|
|
@ -16,103 +16,12 @@
|
|||
#ifndef NETWORKJOBS_H
|
||||
#define NETWORKJOBS_H
|
||||
|
||||
#include "owncloudlib.h"
|
||||
#include <QObject>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QPointer>
|
||||
#include <QElapsedTimer>
|
||||
#include <QDateTime>
|
||||
#include <QTimer>
|
||||
#include "accountfwd.h"
|
||||
#include "abstractnetworkjob.h"
|
||||
|
||||
class QUrl;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class AbstractSslErrorHandler;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Internal Helper class
|
||||
*/
|
||||
class NetworkJobTimeoutPauser {
|
||||
public:
|
||||
NetworkJobTimeoutPauser(QNetworkReply *reply);
|
||||
~NetworkJobTimeoutPauser();
|
||||
private:
|
||||
QPointer<QTimer> _timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The AbstractNetworkJob class
|
||||
*/
|
||||
class OWNCLOUDSYNC_EXPORT AbstractNetworkJob : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AbstractNetworkJob(AccountPtr account, const QString &path, QObject* parent = 0);
|
||||
virtual ~AbstractNetworkJob();
|
||||
|
||||
virtual void start();
|
||||
|
||||
AccountPtr account() const { return _account; }
|
||||
|
||||
void setPath(const QString &path);
|
||||
QString path() const { return _path; }
|
||||
|
||||
void setReply(QNetworkReply *reply);
|
||||
QNetworkReply* reply() const { return _reply; }
|
||||
|
||||
void setIgnoreCredentialFailure(bool ignore);
|
||||
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
|
||||
|
||||
QByteArray responseTimestamp();
|
||||
quint64 duration();
|
||||
|
||||
public slots:
|
||||
void setTimeout(qint64 msec);
|
||||
void resetTimeout();
|
||||
signals:
|
||||
void networkError(QNetworkReply *reply);
|
||||
void networkActivity();
|
||||
protected:
|
||||
void setupConnections(QNetworkReply *reply);
|
||||
QNetworkReply* davRequest(const QByteArray& verb, const QString &relPath,
|
||||
QNetworkRequest req = QNetworkRequest(),
|
||||
QIODevice *data = 0);
|
||||
QNetworkReply* davRequest(const QByteArray& verb, const QUrl &url,
|
||||
QNetworkRequest req = QNetworkRequest(),
|
||||
QIODevice *data = 0);
|
||||
QNetworkReply* getRequest(const QString &relPath);
|
||||
QNetworkReply* getRequest(const QUrl &url);
|
||||
QNetworkReply* headRequest(const QString &relPath);
|
||||
QNetworkReply* headRequest(const QUrl &url);
|
||||
|
||||
int maxRedirects() const { return 10; }
|
||||
virtual bool finished() = 0;
|
||||
QByteArray _responseTimestamp;
|
||||
QElapsedTimer _durationTimer;
|
||||
quint64 _duration;
|
||||
bool _timedout; // set to true when the timeout slot is recieved
|
||||
|
||||
// Automatically follows redirects. Note that this only works for
|
||||
// GET requests that don't set up any HTTP body or other flags.
|
||||
bool _followRedirects;
|
||||
|
||||
private slots:
|
||||
void slotFinished();
|
||||
virtual void slotTimeout();
|
||||
|
||||
private:
|
||||
QNetworkReply* addTimer(QNetworkReply *reply);
|
||||
bool _ignoreCredentialFailure;
|
||||
QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit)
|
||||
AccountPtr _account;
|
||||
QString _path;
|
||||
QTimer _timer;
|
||||
int _redirectCount;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The EntityExistsJob class
|
||||
*/
|
||||
|
@ -314,18 +223,6 @@ signals:
|
|||
void jsonRecieved(const QVariantMap &json);
|
||||
};
|
||||
|
||||
/** Gets the SabreDAV-style error message from an error response.
|
||||
*
|
||||
* This assumes the response is XML with a 'error' tag that has a
|
||||
* 'message' tag that contains the data to extract.
|
||||
*
|
||||
* Returns a null string if no message was found.
|
||||
*/
|
||||
QString OWNCLOUDSYNC_EXPORT extractErrorMessage(const QByteArray& errorResponse);
|
||||
|
||||
/** Builds a error message based on the error and the reply body. */
|
||||
QString OWNCLOUDSYNC_EXPORT errorMessage(const QString& baseError, const QByteArray& body);
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
#endif // NETWORKJOBS_H
|
||||
|
|
Loading…
Reference in a new issue