diff --git a/syncthingconnector/syncthingconnection.cpp b/syncthingconnector/syncthingconnection.cpp index c189ea3..f6a8023 100644 --- a/syncthingconnector/syncthingconnection.cpp +++ b/syncthingconnector/syncthingconnection.cpp @@ -778,13 +778,13 @@ void SyncthingConnection::continueConnecting() * only do the cleanup of previous certificates but not emit any errors. * \returns Returns whether a certificate could be loaded. */ -bool SyncthingConnection::loadSelfSignedCertificate() +bool SyncthingConnection::loadSelfSignedCertificate(const QUrl &url) { // ensure current exceptions for self-signed certificates are cleared m_expectedSslErrors.clear(); // not required when not using secure connection - const QUrl syncthingUrl(m_syncthingUrl); + const auto syncthingUrl = url.isEmpty() ? m_syncthingUrl : url; if (!syncthingUrl.scheme().endsWith(QChar('s'))) { return false; } diff --git a/syncthingconnector/syncthingconnection.h b/syncthingconnector/syncthingconnection.h index b6e7289..73ac8c3 100644 --- a/syncthingconnector/syncthingconnection.h +++ b/syncthingconnector/syncthingconnection.h @@ -180,7 +180,7 @@ public: const QList &expectedSslErrors() const; public Q_SLOTS: - bool loadSelfSignedCertificate(); + bool loadSelfSignedCertificate(const QUrl &url = QUrl()); bool applySettings(Data::SyncthingConnectionSettings &connectionSettings); // methods to initiate/close connection @@ -337,6 +337,7 @@ private Q_SLOTS: void handleFatalConnectionError(); void handleAdditionalRequestCanceled(); void handleSslErrors(const QList &errors); + void handleRedirection(const QUrl &url); void recalculateStatus(); QString configPath() const; QByteArray changeConfigVerb() const; diff --git a/syncthingconnector/syncthingconnection_requests.cpp b/syncthingconnector/syncthingconnection_requests.cpp index e489943..677a889 100644 --- a/syncthingconnector/syncthingconnection_requests.cpp +++ b/syncthingconnector/syncthingconnection_requests.cpp @@ -63,6 +63,7 @@ QNetworkReply *SyncthingConnection::requestData(const QString &path, const QUrlQ #ifndef LIB_SYNCTHING_CONNECTOR_CONNECTION_MOCKED auto *const reply = networkAccessManager().get(prepareRequest(path, query, rest, longPolling)); QObject::connect(reply, &QNetworkReply::sslErrors, this, &SyncthingConnection::handleSslErrors); + QObject::connect(reply, &QNetworkReply::redirected, this, &SyncthingConnection::handleRedirection); if (loggingFlags() & SyncthingConnectionLoggingFlags::ApiCalls) { cerr << Phrases::Info << "Querying API: GET " << reply->url().toString().toStdString() << Phrases::EndFlush; } @@ -188,6 +189,24 @@ void SyncthingConnection::handleSslErrors(const QList &errors) } } +/*! + * \brief Handles redirections. + * \remarks The redirect policy will decide whether to follow the redirection or not. + * This function merely handles logging and loading the certificate in case this + * hasn't happened before (e.g. a redirection from http to https). + */ +void SyncthingConnection::handleRedirection(const QUrl &url) +{ + if (m_loggingFlags & SyncthingConnectionLoggingFlags::ApiReplies) { + const auto urlStr = url.toString().toUtf8(); + cerr << Phrases::Info << "Got redirected to: " << std::string_view(urlStr.data(), static_cast(urlStr.size())) + << Phrases::EndFlush; + } + if (m_expectedSslErrors.isEmpty() && url.scheme().endsWith(QChar('s'))) { + loadSelfSignedCertificate(url); + } +} + /*! * \brief Handles the specified \a reply; invoked by the prepareReply() functions. */ diff --git a/syncthingconnector/tests/misctests.cpp b/syncthingconnector/tests/misctests.cpp index 4bda9fa..e875cc2 100644 --- a/syncthingconnector/tests/misctests.cpp +++ b/syncthingconnector/tests/misctests.cpp @@ -188,7 +188,7 @@ void MiscTests::testConnectionSettingsAndLoadingSelfSignedCert() bool errorOccured = false; const function errorHandler = [&errorOccured](const QString &message) { errorOccured |= message == QStringLiteral("Unable to load certificate used by Syncthing."); }; - waitForSignals(bind(&SyncthingConnection::loadSelfSignedCertificate, &connection), 1, + waitForSignals(bind(&SyncthingConnection::loadSelfSignedCertificate, &connection, QUrl()), 1, signalInfo(&connection, &SyncthingConnection::error, errorHandler, &errorOccured)); settings.expectedSslErrors.clear(); CPPUNIT_ASSERT(!connection.applySettings(settings));