From fdd56716028da93c7c516e3cccd99919ab88c651 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 Jan 2021 20:40:25 +0100 Subject: [PATCH] Attempt to solve WebDAV redirection issue on Windows. --- src/tl/tl/tlHttpStream.h | 8 +++- src/tl/tl/tlHttpStreamQt.cc | 70 ++++++++++++++++++++++++++++++-- src/tl/tl/tlHttpStreamQt.h | 3 ++ src/tl/unit_tests/unit_tests.pro | 56 ++++++++++++------------- 4 files changed, 104 insertions(+), 33 deletions(-) diff --git a/src/tl/tl/tlHttpStream.h b/src/tl/tl/tlHttpStream.h index c2acf7a18..cd2884657 100644 --- a/src/tl/tl/tlHttpStream.h +++ b/src/tl/tl/tlHttpStream.h @@ -28,6 +28,8 @@ #include "tlStream.h" #include "tlEvents.h" +class QNetworkReply; + namespace tl { @@ -54,9 +56,11 @@ class TL_PUBLIC HttpErrorException : public tl::Exception { public: - HttpErrorException (const std::string &f, int en, const std::string &url) - : tl::Exception (tl::to_string (tr ("Error %d: %s, fetching %s")), en, f, url) + HttpErrorException (const std::string &f, int ec, QNetworkReply *reply) + : tl::Exception (format_error (f, ec, reply)) { } + + static std::string format_error (const std::string &em, int ec, QNetworkReply *reply); }; class InputHttpStreamPrivateData; diff --git a/src/tl/tl/tlHttpStreamQt.cc b/src/tl/tl/tlHttpStreamQt.cc index 8fb182be3..4d9008f98 100644 --- a/src/tl/tl/tlHttpStreamQt.cc +++ b/src/tl/tl/tlHttpStreamQt.cc @@ -123,6 +123,39 @@ AuthenticationHandler::proxyAuthenticationRequired (const QNetworkProxy &proxy, // --------------------------------------------------------------- // InputHttpStream implementation +std::string +HttpErrorException::format_error (const std::string &em, int ec, QNetworkReply *reply) +{ + std::string msg = tl::sprintf (tl::to_string (tr ("Error %d: %s, fetching %s")), ec, em, tl::to_string (reply->url ().toString ())); + + std::string data = tl::to_string (QString::fromUtf8 (reply->readAll ())); + if (data.size () > 1000) { + data = data.substr (0, size_t (1000)) + "..."; + } + + if (! data.empty ()) { + + msg += "\n\n"; + msg += tl::to_string (tr ("Reply body:")); + msg += "\n"; + msg += data; + + } + + std::string redirected = tl::to_string (reply->attribute (QNetworkRequest::RedirectionTargetAttribute).toString ()); + if (! redirected.empty ()) { + + msg += "\n\n"; + msg += tl::to_string (tr ("Redirected to: ")) + redirected; + + } + + return msg; +} + +// --------------------------------------------------------------- +// InputHttpStream implementation + InputHttpStream::InputHttpStream (const std::string &url) { mp_data = new InputHttpStreamPrivateData (url); @@ -237,7 +270,7 @@ static QNetworkAccessManager *s_network_manager (0); static AuthenticationHandler *s_auth_handler (0); InputHttpStreamPrivateData::InputHttpStreamPrivateData (const std::string &url) - : m_url (url), mp_reply (0), m_request ("GET"), mp_buffer (0) + : m_url (url), mp_reply (0), m_request ("GET"), mp_buffer (0), mp_resend_timer (new QTimer (this)) { if (! s_network_manager) { @@ -252,6 +285,7 @@ InputHttpStreamPrivateData::InputHttpStreamPrivateData (const std::string &url) } connect (s_network_manager, SIGNAL (finished (QNetworkReply *)), this, SLOT (finished (QNetworkReply *))); + connect (mp_resend_timer, SIGNAL (timeout ()), this, SLOT (resend ())); } InputHttpStreamPrivateData::~InputHttpStreamPrivateData () @@ -293,6 +327,12 @@ InputHttpStreamPrivateData::add_header (const std::string &name, const std::stri m_headers.insert (std::make_pair (name, value)); } +void +InputHttpStreamPrivateData::resend () +{ + issue_request (QUrl (tl::to_qstring (m_url))); +} + void InputHttpStreamPrivateData::finished (QNetworkReply *reply) { @@ -300,16 +340,32 @@ InputHttpStreamPrivateData::finished (QNetworkReply *reply) return; } + if (tl::verbosity() >= 40) { + const QList &raw_headers = reply->rawHeaderPairs (); + for (QList::const_iterator h = raw_headers.begin (); h != raw_headers.end (); ++h) { + tl::info << "HTTP response header: " << h->first.constData ()<< ": " << h->second.constData (); + } + } + QVariant redirect_target = reply->attribute (QNetworkRequest::RedirectionTargetAttribute); if (reply->error () == QNetworkReply::NoError && ! redirect_target.isNull ()) { + m_url = tl::to_string (redirect_target.toString ()); if (tl::verbosity() >= 30) { tl::info << "HTTP redirect to: " << m_url; } - issue_request (QUrl (redirect_target.toString ())); + + close (); + + mp_resend_timer->setSingleShot (true); + mp_resend_timer->setInterval (0); + mp_resend_timer->start (); + } else { + mp_reply = reply; m_ready (); + } } @@ -333,6 +389,14 @@ InputHttpStreamPrivateData::issue_request (const QUrl &url) request.setRawHeader (QByteArray (h->first.c_str ()), QByteArray (h->second.c_str ())); } +#if QT_VERSION >= 0x50600 +#if QT_VERSION >= 0x50900 + request.setAttribute (QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy); +#else + request.setAttribute (QNetworkRequest::FollowRedirectsAttribute, false); +#endif +#endif + #if QT_VERSION < 0x40700 if (m_request == "GET" && m_data.isEmpty ()) { mp_active_reply.reset (s_network_manager->get (request)); @@ -410,7 +474,7 @@ InputHttpStreamPrivateData::read (char *b, size_t n) ec = int (mp_reply->error ()); } - throw HttpErrorException (em, ec, m_url); + throw HttpErrorException (em, ec, mp_reply); } diff --git a/src/tl/tl/tlHttpStreamQt.h b/src/tl/tl/tlHttpStreamQt.h index 9b52d5de6..9fa000a22 100644 --- a/src/tl/tl/tlHttpStreamQt.h +++ b/src/tl/tl/tlHttpStreamQt.h @@ -30,6 +30,7 @@ #include #include #include +#include #include class QNetworkAccessManager; @@ -103,6 +104,7 @@ public: private slots: void finished (QNetworkReply *); + void resend (); private: std::string m_url; @@ -113,6 +115,7 @@ private: QBuffer *mp_buffer; std::map m_headers; tl::Event m_ready; + QTimer *mp_resend_timer; void issue_request (const QUrl &url); }; diff --git a/src/tl/unit_tests/unit_tests.pro b/src/tl/unit_tests/unit_tests.pro index 43ca72765..667e447bd 100644 --- a/src/tl/unit_tests/unit_tests.pro +++ b/src/tl/unit_tests/unit_tests.pro @@ -7,47 +7,47 @@ TARGET = tl_tests include($$PWD/../../lib_ut.pri) SOURCES = \ - tlAlgorithm.cc \ - tlClassRegistry.cc \ - tlCommandLineParser.cc \ + tlAlgorithmTests.cc \ + tlClassRegistryTests.cc \ + tlCommandLineParserTests.cc \ tlCopyOnWriteTests.cc \ - tlDataMapping.cc \ - tlDeflate.cc \ - tlEvents.cc \ - tlExpression.cc \ - tlFileUtils.cc \ + tlDataMappingTests.cc \ + tlDeferredExecutionTests.cc \ + tlDeflateTests.cc \ + tlEventsTests.cc \ + tlExpressionTests.cc \ + tlFileSystemWatcherTests.cc \ + tlFileUtilsTests.cc \ + tlHttpStreamTests.cc \ tlIncludeTests.cc \ - tlIntervalMap.cc \ - tlIntervalSet.cc \ - tlKDTree.cc \ - tlMath.cc \ - tlObject.cc \ - tlReuseVector.cc \ - tlStableVector.cc \ - tlString.cc \ - tlThreadedWorkers.cc \ - tlThreads.cc \ - tlUtils.cc \ - tlVariant.cc \ - tlXMLParser.cc \ + tlInt128SupportTests.cc \ + tlIntervalMapTests.cc \ + tlIntervalSetTests.cc \ + tlKDTreeTests.cc \ + tlLongIntTests.cc \ + tlMathTests.cc \ + tlObjectTests.cc \ + tlReuseVectorTests.cc \ + tlStableVectorTests.cc \ tlStreamTests.cc \ - tlWebDAV.cc \ - tlHttpStream.cc \ - tlInt128Support.cc \ - tlLongInt.cc \ + tlStringTests.cc \ + tlThreadedWorkersTests.cc \ + tlThreadsTests.cc \ tlUniqueIdTests.cc \ tlListTests.cc \ tlEquivalenceClustersTests.cc \ tlUniqueNameTests.cc \ tlGlobPatternTests.cc \ tlRecipeTests.cc \ - tlUriTests.cc + tlUriTests.cc \ + tlUtilsTests.cc \ + tlVariantTests.cc \ + tlWebDAVTests.cc \ + tlXMLParserTests.cc !equals(HAVE_QT, "0") { SOURCES += \ - tlDeferredExecution.cc \ - tlFileSystemWatcher.cc \ }