Attempt to solve WebDAV redirection issue on Windows.

This commit is contained in:
Matthias Koefferlein 2021-01-23 20:40:25 +01:00
parent 372a42e84a
commit fdd5671602
4 changed files with 104 additions and 33 deletions

View File

@ -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;

View File

@ -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<QNetworkReply::RawHeaderPair> &raw_headers = reply->rawHeaderPairs ();
for (QList<QNetworkReply::RawHeaderPair>::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);
}

View File

@ -30,6 +30,7 @@
#include <QObject>
#include <QBuffer>
#include <QByteArray>
#include <QTimer>
#include <memory>
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<std::string, std::string> m_headers;
tl::Event m_ready;
QTimer *mp_resend_timer;
void issue_request (const QUrl &url);
};

View File

@ -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 \
}