diff options
author | Max Kellermann <max@musicpd.org> | 2021-01-05 13:08:39 +0100 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2021-01-05 13:09:15 +0100 |
commit | e99f6b5b388a0480686c0659f8dfe07f5f9b61d0 (patch) | |
tree | bafce25950a8db72b9910ee7146486785c31d123 | |
parent | 5348f8c9c88b930d06042e5103ffb617d2c09d75 (diff) | |
parent | 74b2fc7fdca9be13cbbe4cb52b2fab573b3cf82c (diff) |
Merge branch 'bugfix/1039/fix-webdav' of git://github.com/PVince81/MPD into v0.22.x
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1039
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | src/storage/plugins/CurlStorage.cxx | 61 | ||||
-rw-r--r-- | src/util/UriExtract.cxx | 2 | ||||
-rw-r--r-- | src/util/UriExtract.hxx | 2 |
4 files changed, 49 insertions, 18 deletions
@@ -1,4 +1,6 @@ ver 0.22.4 (not yet released) +* storage + - curl: fix several WebDAV protocol bugs * decoder - dsdiff: apply padding to odd-sized chunks * filter diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx index ccfb0bf12..d717a824c 100644 --- a/src/storage/plugins/CurlStorage.cxx +++ b/src/storage/plugins/CurlStorage.cxx @@ -243,6 +243,7 @@ class PropfindOperation : BlockingHttpRequest, CommonExpatParser { enum class State { ROOT, RESPONSE, + PROPSTAT, HREF, STATUS, TYPE, @@ -262,18 +263,19 @@ public: request.SetOption(CURLOPT_MAXREDIRS, 1L); request_headers.Append(StringFormat<40>("depth: %u", depth)); + request_headers.Append("content-type: text/xml"); request.SetOption(CURLOPT_HTTPHEADER, request_headers.Get()); request.SetOption(CURLOPT_POSTFIELDS, "<?xml version=\"1.0\"?>\n" "<a:propfind xmlns:a=\"DAV:\">" - "<a:prop><a:resourcetype/></a:prop>" - "<a:prop><a:getcontenttype/></a:prop>" - "<a:prop><a:getcontentlength/></a:prop>" + "<a:prop>" + "<a:resourcetype/>" + "<a:getcontenttype/>" + "<a:getcontentlength/>" + "</a:prop>" "</a:propfind>"); - - // TODO: send request body } using BlockingHttpRequest::GetEasy; @@ -321,9 +323,13 @@ private: break; case State::RESPONSE: - if (strcmp(name, "DAV:|href") == 0) + if (strcmp(name, "DAV:|propstat") == 0) + state = State::PROPSTAT; + else if (strcmp(name, "DAV:|href") == 0) state = State::HREF; - else if (strcmp(name, "DAV:|status") == 0) + break; + case State::PROPSTAT: + if (strcmp(name, "DAV:|status") == 0) state = State::STATUS; else if (strcmp(name, "DAV:|resourcetype") == 0) state = State::TYPE; @@ -353,9 +359,15 @@ private: case State::RESPONSE: if (strcmp(name, "DAV:|response") == 0) { - FinishResponse(); state = State::ROOT; } + break; + + case State::PROPSTAT: + if (strcmp(name, "DAV:|propstat") == 0) { + FinishResponse(); + state = State::RESPONSE; + } break; @@ -366,22 +378,22 @@ private: case State::STATUS: if (strcmp(name, "DAV:|status") == 0) - state = State::RESPONSE; + state = State::PROPSTAT; break; case State::TYPE: if (strcmp(name, "DAV:|resourcetype") == 0) - state = State::RESPONSE; + state = State::PROPSTAT; break; case State::MTIME: if (strcmp(name, "DAV:|getlastmodified") == 0) - state = State::RESPONSE; + state = State::PROPSTAT; break; case State::LENGTH: if (strcmp(name, "DAV:|getcontentlength") == 0) - state = State::RESPONSE; + state = State::PROPSTAT; break; } } @@ -389,6 +401,7 @@ private: void CharacterData(const XML_Char *s, int len) final { switch (state) { case State::ROOT: + case State::PROPSTAT: case State::RESPONSE: case State::TYPE: break; @@ -455,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; } @@ -468,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<StorageDirectoryReader> Perform() { DeferStart(); @@ -500,9 +523,15 @@ 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()) + if (uri_has_scheme(path)) { + path = StringAfterPrefixIgnoreCase(path, base_path.c_str()); + } else { + path = StringAfterPrefixIgnoreCase(path, base_path_relative.c_str()); + } + + if (path == nullptr || path.empty()) { return nullptr; + } const char *slash = path.Find('/'); if (slash == nullptr) diff --git a/src/util/UriExtract.cxx b/src/util/UriExtract.cxx index 053c20cc7..ab8a7244a 100644 --- a/src/util/UriExtract.cxx +++ b/src/util/UriExtract.cxx @@ -85,7 +85,7 @@ uri_after_scheme(std::string_view uri) noexcept } bool -uri_has_scheme(const char *uri) noexcept +uri_has_scheme(std::string_view uri) noexcept { return !uri_get_scheme(uri).empty(); } diff --git a/src/util/UriExtract.hxx b/src/util/UriExtract.hxx index 05e288b30..5f17910ea 100644 --- a/src/util/UriExtract.hxx +++ b/src/util/UriExtract.hxx @@ -40,7 +40,7 @@ */ gcc_pure bool -uri_has_scheme(const char *uri) noexcept; +uri_has_scheme(std::string_view uri) noexcept; /** * Returns the scheme name of the specified URI, or an empty string. |