mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-26 23:28:14 +03:00
Added new state and new job to check if /index.php/204 is being redirected.
Signed-off-by: alex-z <blackslayer4@gmail.com>
This commit is contained in:
parent
6c12a221ff
commit
71f1d1aad4
9 changed files with 113 additions and 9 deletions
|
@ -1233,6 +1233,9 @@ void AccountSettings::slotAccountStateChanged()
|
|||
case AccountState::MaintenanceMode:
|
||||
showConnectionLabel(tr("Server %1 is currently in maintenance mode.").arg(server));
|
||||
break;
|
||||
case AccountState::RedirectDetected:
|
||||
showConnectionLabel(tr("Server %1 is currently being redirected, or your connection is behind a captive portal.").arg(server));
|
||||
break;
|
||||
case AccountState::SignedOut:
|
||||
showConnectionLabel(tr("Signed out from %1.").arg(serverWithUser));
|
||||
break;
|
||||
|
|
|
@ -118,10 +118,10 @@ void AccountState::setState(State state)
|
|||
// If we stop being voluntarily signed-out, try to connect and
|
||||
// auth right now!
|
||||
checkConnectivity();
|
||||
} else if (_state == ServiceUnavailable) {
|
||||
// Check if we are actually down for maintenance.
|
||||
} else if (_state == ServiceUnavailable || _state == RedirectDetected) {
|
||||
// Check if we are actually down for maintenance/in a redirect state (captive portal?).
|
||||
// To do this we must clear the connection validator that just
|
||||
// produced the 503. It's finished anyway and will delete itself.
|
||||
// produced the 503/302. It's finished anyway and will delete itself.
|
||||
_connectionValidator.clear();
|
||||
checkConnectivity();
|
||||
}
|
||||
|
@ -150,6 +150,8 @@ QString AccountState::stateString(State state)
|
|||
return tr("Service unavailable");
|
||||
case MaintenanceMode:
|
||||
return tr("Maintenance mode");
|
||||
case RedirectDetected:
|
||||
return tr("Redirect detected");
|
||||
case NetworkError:
|
||||
return tr("Network error");
|
||||
case ConfigurationError:
|
||||
|
@ -342,10 +344,11 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
|||
|
||||
_lastConnectionValidatorStatus = status;
|
||||
|
||||
// Come online gradually from 503 or maintenance mode
|
||||
// Come online gradually from 503, captive portal(redirection) or maintenance mode
|
||||
if (status == ConnectionValidator::Connected
|
||||
&& (_connectionStatus == ConnectionValidator::ServiceUnavailable
|
||||
|| _connectionStatus == ConnectionValidator::MaintenanceMode)) {
|
||||
|| _connectionStatus == ConnectionValidator::MaintenanceMode
|
||||
|| _connectionStatus == ConnectionValidator::StatusRedirect)) {
|
||||
if (!_timeSinceMaintenanceOver.isValid()) {
|
||||
qCInfo(lcAccountState) << "AccountState reconnection: delaying for"
|
||||
<< _maintenanceToConnectedDelay << "ms";
|
||||
|
@ -411,6 +414,10 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
|||
_timeSinceMaintenanceOver.invalidate();
|
||||
setState(MaintenanceMode);
|
||||
break;
|
||||
case ConnectionValidator::StatusRedirect:
|
||||
_timeSinceMaintenanceOver.invalidate();
|
||||
setState(RedirectDetected);
|
||||
break;
|
||||
case ConnectionValidator::Timeout:
|
||||
setState(NetworkError);
|
||||
updateRetryCount();
|
||||
|
|
|
@ -65,6 +65,10 @@ public:
|
|||
/// don't bother the user too much and try again.
|
||||
ServiceUnavailable,
|
||||
|
||||
/// Connection is being redirected (likely a captive portal is in effect)
|
||||
/// Do not proceed with connecting and check back later
|
||||
RedirectDetected,
|
||||
|
||||
/// Similar to ServiceUnavailable, but we know the server is down
|
||||
/// for maintenance
|
||||
MaintenanceMode,
|
||||
|
|
|
@ -63,7 +63,7 @@ void ConnectionValidator::checkServerAndAuth()
|
|||
// We want to reset the QNAM proxy so that the global proxy settings are used (via ClientProxy settings)
|
||||
_account->networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy));
|
||||
// use a queued invocation so we're as asynchronous as with the other code path
|
||||
QMetaObject::invokeMethod(this, "slotCheckServerAndAuth", Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(this, "slotCheckRedirectCostFreeUrl", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,10 +81,21 @@ void ConnectionValidator::systemProxyLookupDone(const QNetworkProxy &proxy)
|
|||
}
|
||||
_account->networkAccessManager()->setProxy(proxy);
|
||||
|
||||
slotCheckServerAndAuth();
|
||||
slotCheckRedirectCostFreeUrl();
|
||||
}
|
||||
|
||||
// The actual check
|
||||
|
||||
void ConnectionValidator::slotCheckRedirectCostFreeUrl()
|
||||
{
|
||||
const auto checkJob = new CheckRedirectCostFreeUrlJob(_account, this);
|
||||
checkJob->setTimeout(timeoutToUseMsec);
|
||||
checkJob->setIgnoreCredentialFailure(true);
|
||||
connect(checkJob, &CheckRedirectCostFreeUrlJob::timeout, this, &ConnectionValidator::slotJobTimeout);
|
||||
connect(checkJob, &CheckRedirectCostFreeUrlJob::jobFinished, this, &ConnectionValidator::slotCheckRedirectCostFreeUrlFinished);
|
||||
checkJob->start();
|
||||
}
|
||||
|
||||
void ConnectionValidator::slotCheckServerAndAuth()
|
||||
{
|
||||
auto *checkJob = new CheckServerJob(_account, this);
|
||||
|
@ -96,6 +107,15 @@ void ConnectionValidator::slotCheckServerAndAuth()
|
|||
checkJob->start();
|
||||
}
|
||||
|
||||
void ConnectionValidator::slotCheckRedirectCostFreeUrlFinished(int statusCode)
|
||||
{
|
||||
if (statusCode >= 301 && statusCode <= 307) {
|
||||
reportResult(StatusRedirect);
|
||||
return;
|
||||
}
|
||||
slotCheckServerAndAuth();
|
||||
}
|
||||
|
||||
void ConnectionValidator::slotStatusFound(const QUrl &url, const QJsonObject &info)
|
||||
{
|
||||
// Newer servers don't disclose any version in status.php anymore
|
||||
|
|
|
@ -90,6 +90,7 @@ public:
|
|||
CredentialsWrong, // AuthenticationRequiredError
|
||||
SslError, // SSL handshake error, certificate rejected by user?
|
||||
StatusNotFound, // Error retrieving status.php
|
||||
StatusRedirect, // 204 URL received one of redirect HTTP codes (301-307), possibly a captive portal
|
||||
ServiceUnavailable, // 503 on authed request
|
||||
MaintenanceMode, // maintenance enabled in status.php
|
||||
Timeout // actually also used for other errors on the authed request
|
||||
|
@ -111,8 +112,12 @@ signals:
|
|||
void connectionResult(OCC::ConnectionValidator::Status status, const QStringList &errors);
|
||||
|
||||
protected slots:
|
||||
void slotCheckRedirectCostFreeUrl();
|
||||
|
||||
void slotCheckServerAndAuth();
|
||||
|
||||
void slotCheckRedirectCostFreeUrlFinished(int statusCode);
|
||||
|
||||
void slotStatusFound(const QUrl &url, const QJsonObject &info);
|
||||
void slotNoStatusFound(QNetworkReply *reply);
|
||||
void slotJobTimeout(const QUrl &url);
|
||||
|
|
|
@ -47,7 +47,7 @@ Q_LOGGING_CATEGORY(lcNetworkJob, "nextcloud.sync.networkjob", QtInfoMsg)
|
|||
// If not set, it is overwritten by the Application constructor with the value from the config
|
||||
int AbstractNetworkJob::httpTimeout = qEnvironmentVariableIntValue("OWNCLOUD_TIMEOUT");
|
||||
|
||||
AbstractNetworkJob::AbstractNetworkJob(AccountPtr account, const QString &path, QObject *parent)
|
||||
AbstractNetworkJob::AbstractNetworkJob(const AccountPtr &account, const QString &path, QObject *parent)
|
||||
: QObject(parent)
|
||||
, _account(account)
|
||||
, _reply(nullptr)
|
||||
|
|
|
@ -40,7 +40,7 @@ class OWNCLOUDSYNC_EXPORT AbstractNetworkJob : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AbstractNetworkJob(AccountPtr account, const QString &path, QObject *parent = nullptr);
|
||||
explicit AbstractNetworkJob(const AccountPtr &account, const QString &path, QObject *parent = nullptr);
|
||||
~AbstractNetworkJob() override;
|
||||
|
||||
virtual void start();
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace OCC {
|
|||
Q_LOGGING_CATEGORY(lcEtagJob, "nextcloud.sync.networkjob.etag", QtInfoMsg)
|
||||
Q_LOGGING_CATEGORY(lcLsColJob, "nextcloud.sync.networkjob.lscol", QtInfoMsg)
|
||||
Q_LOGGING_CATEGORY(lcCheckServerJob, "nextcloud.sync.networkjob.checkserver", QtInfoMsg)
|
||||
Q_LOGGING_CATEGORY(lcCheckRedirectCostFreeUrlJob, "nextcloud.sync.networkjob.checkredirectcostfreeurl", QtInfoMsg)
|
||||
Q_LOGGING_CATEGORY(lcPropfindJob, "nextcloud.sync.networkjob.propfind", QtInfoMsg)
|
||||
Q_LOGGING_CATEGORY(lcAvatarJob, "nextcloud.sync.networkjob.avatar", QtInfoMsg)
|
||||
Q_LOGGING_CATEGORY(lcMkColJob, "nextcloud.sync.networkjob.mkcol", QtInfoMsg)
|
||||
|
@ -554,6 +555,42 @@ bool CheckServerJob::finished()
|
|||
|
||||
/*********************************************************************************************/
|
||||
|
||||
CheckRedirectCostFreeUrlJob::CheckRedirectCostFreeUrlJob(const AccountPtr &account, QObject *parent)
|
||||
: AbstractNetworkJob(account, QLatin1String(statusphpC), parent)
|
||||
{
|
||||
setIgnoreCredentialFailure(true);
|
||||
}
|
||||
|
||||
void CheckRedirectCostFreeUrlJob::start()
|
||||
{
|
||||
setFollowRedirects(false);
|
||||
sendRequest("GET", Utility::concatUrlPath(account()->url(), QStringLiteral("/index.php/204")));
|
||||
AbstractNetworkJob::start();
|
||||
}
|
||||
|
||||
void CheckRedirectCostFreeUrlJob::onTimedOut()
|
||||
{
|
||||
qCDebug(lcCheckRedirectCostFreeUrlJob) << "TIMEOUT";
|
||||
if (reply() && reply()->isRunning()) {
|
||||
emit timeout(reply()->url());
|
||||
} else if (!reply()) {
|
||||
qCDebug(lcCheckRedirectCostFreeUrlJob) << "Timeout without a reply?";
|
||||
}
|
||||
AbstractNetworkJob::onTimedOut();
|
||||
}
|
||||
|
||||
bool CheckRedirectCostFreeUrlJob::finished()
|
||||
{
|
||||
const auto statusCode = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if (statusCode >= 301 && statusCode <= 307) {
|
||||
const auto redirectionTarget = reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||
qCDebug(lcCheckRedirectCostFreeUrlJob) << "Redirecting cost-free URL" << reply()->url() << " to" << redirectionTarget;
|
||||
}
|
||||
emit jobFinished(statusCode);
|
||||
return true;
|
||||
}
|
||||
/*********************************************************************************************/
|
||||
|
||||
PropfindJob::PropfindJob(AccountPtr account, const QString &path, QObject *parent)
|
||||
: AbstractNetworkJob(account, path, parent)
|
||||
{
|
||||
|
|
|
@ -364,6 +364,34 @@ private:
|
|||
int _permanentRedirects = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The CheckRedirectCostFreeUrlJob class
|
||||
* @ingroup libsync
|
||||
*/
|
||||
class OWNCLOUDSYNC_EXPORT CheckRedirectCostFreeUrlJob : public AbstractNetworkJob
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CheckRedirectCostFreeUrlJob(const AccountPtr &account, QObject *parent = nullptr);
|
||||
void start() override;
|
||||
|
||||
signals:
|
||||
/**
|
||||
* a check is finished
|
||||
* \a statusCode cost-free URL GET HTTP response code
|
||||
*/
|
||||
void jobFinished(int statusCode);
|
||||
/** A timeout occurred.
|
||||
*
|
||||
* \a url The specific url where the timeout happened.
|
||||
*/
|
||||
void timeout(const QUrl &url);
|
||||
|
||||
private:
|
||||
bool finished() override;
|
||||
void onTimedOut() override;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The RequestEtagJob class
|
||||
|
|
Loading…
Reference in a new issue