From 216f62ea1468933f4a78f17885b27e37e1393d8c Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Mon, 4 Jan 2021 21:50:03 +0100 Subject: [PATCH] Webdav href in response can be relative Fixed Webdav base path stripping in cases where href is a relative path. Signed-off-by: Vincent Petry --- src/storage/plugins/CurlStorage.cxx | 35 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx index c986a8a49..298d70967 100644 --- a/src/storage/plugins/CurlStorage.cxx +++ b/src/storage/plugins/CurlStorage.cxx @@ -468,11 +468,19 @@ CurlStorage::GetInfo(std::string_view uri_utf8, [[maybe_unused]] bool follow) gcc_pure static std::string_view -UriPathOrSlash(const char *uri) noexcept +UriPathOrSlash(const char *uri, bool relative) noexcept { auto path = uri_get_path(uri); if (path.data() == nullptr) path = "/"; + else if (relative) { + // search after first slash + path = path.substr(1); + auto slash = path.find('/'); + if (slash != std::string_view::npos) + path = path.substr(slash); + } + return path; } @@ -481,13 +489,15 @@ UriPathOrSlash(const char *uri) noexcept */ class HttpListDirectoryOperation final : public PropfindOperation { const std::string base_path; + const std::string base_path_relative; MemoryStorageDirectoryReader::List entries; public: HttpListDirectoryOperation(CurlGlobal &curl, const char *uri) :PropfindOperation(curl, uri, 1), - base_path(CurlUnescape(GetEasy(), UriPathOrSlash(uri))) {} + base_path(CurlUnescape(GetEasy(), UriPathOrSlash(uri, false))), + base_path_relative(CurlUnescape(GetEasy(), UriPathOrSlash(uri, true))) {} std::unique_ptr Perform() { DeferStart(); @@ -506,6 +516,7 @@ private: */ gcc_pure StringView HrefToEscapedName(const char *href) const noexcept { + StringView relative_path; StringView path = uri_get_path(href); if (path == nullptr) return nullptr; @@ -513,17 +524,23 @@ private: /* kludge: ignoring case in this comparison to avoid false negatives if the web server uses a different case */ - path = StringAfterPrefixIgnoreCase(path, base_path.c_str()); - if (path == nullptr || path.empty()) - return nullptr; + relative_path = StringAfterPrefixIgnoreCase(path, base_path.c_str()); + if (relative_path == nullptr || relative_path.empty()) { + // try relative base path + relative_path = StringAfterPrefixIgnoreCase(path, base_path_relative.c_str()); + } - const char *slash = path.Find('/'); + if (relative_path == nullptr || relative_path.empty()) { + return nullptr; + } + + const char *slash = relative_path.Find('/'); if (slash == nullptr) /* regular file */ - return path; - else if (slash == &path.back()) + return relative_path; + else if (slash == &relative_path.back()) /* trailing slash: collection; strip the slash */ - return {path.data, slash}; + return {relative_path.data, slash}; else /* strange, better ignore it */ return nullptr;