Merge branch 'v0.22.x'
This commit is contained in:
commit
81ea749248
2
NEWS
2
NEWS
@ -3,6 +3,8 @@ ver 0.23 (not yet released)
|
|||||||
- new command "getvol"
|
- new command "getvol"
|
||||||
|
|
||||||
ver 0.22.4 (not yet released)
|
ver 0.22.4 (not yet released)
|
||||||
|
* storage
|
||||||
|
- curl: fix several WebDAV protocol bugs
|
||||||
* decoder
|
* decoder
|
||||||
- dsdiff: apply padding to odd-sized chunks
|
- dsdiff: apply padding to odd-sized chunks
|
||||||
* filter
|
* filter
|
||||||
|
@ -243,6 +243,7 @@ class PropfindOperation : BlockingHttpRequest, CommonExpatParser {
|
|||||||
enum class State {
|
enum class State {
|
||||||
ROOT,
|
ROOT,
|
||||||
RESPONSE,
|
RESPONSE,
|
||||||
|
PROPSTAT,
|
||||||
HREF,
|
HREF,
|
||||||
STATUS,
|
STATUS,
|
||||||
TYPE,
|
TYPE,
|
||||||
@ -262,18 +263,19 @@ public:
|
|||||||
request.SetOption(CURLOPT_MAXREDIRS, 1L);
|
request.SetOption(CURLOPT_MAXREDIRS, 1L);
|
||||||
|
|
||||||
request_headers.Append(StringFormat<40>("depth: %u", depth));
|
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_HTTPHEADER, request_headers.Get());
|
||||||
|
|
||||||
request.SetOption(CURLOPT_POSTFIELDS,
|
request.SetOption(CURLOPT_POSTFIELDS,
|
||||||
"<?xml version=\"1.0\"?>\n"
|
"<?xml version=\"1.0\"?>\n"
|
||||||
"<a:propfind xmlns:a=\"DAV:\">"
|
"<a:propfind xmlns:a=\"DAV:\">"
|
||||||
"<a:prop><a:resourcetype/></a:prop>"
|
"<a:prop>"
|
||||||
"<a:prop><a:getcontenttype/></a:prop>"
|
"<a:resourcetype/>"
|
||||||
"<a:prop><a:getcontentlength/></a:prop>"
|
"<a:getcontenttype/>"
|
||||||
|
"<a:getcontentlength/>"
|
||||||
|
"</a:prop>"
|
||||||
"</a:propfind>");
|
"</a:propfind>");
|
||||||
|
|
||||||
// TODO: send request body
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using BlockingHttpRequest::GetEasy;
|
using BlockingHttpRequest::GetEasy;
|
||||||
@ -321,9 +323,13 @@ private:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case State::RESPONSE:
|
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;
|
state = State::HREF;
|
||||||
else if (strcmp(name, "DAV:|status") == 0)
|
break;
|
||||||
|
case State::PROPSTAT:
|
||||||
|
if (strcmp(name, "DAV:|status") == 0)
|
||||||
state = State::STATUS;
|
state = State::STATUS;
|
||||||
else if (strcmp(name, "DAV:|resourcetype") == 0)
|
else if (strcmp(name, "DAV:|resourcetype") == 0)
|
||||||
state = State::TYPE;
|
state = State::TYPE;
|
||||||
@ -353,9 +359,15 @@ private:
|
|||||||
|
|
||||||
case State::RESPONSE:
|
case State::RESPONSE:
|
||||||
if (strcmp(name, "DAV:|response") == 0) {
|
if (strcmp(name, "DAV:|response") == 0) {
|
||||||
FinishResponse();
|
|
||||||
state = State::ROOT;
|
state = State::ROOT;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State::PROPSTAT:
|
||||||
|
if (strcmp(name, "DAV:|propstat") == 0) {
|
||||||
|
FinishResponse();
|
||||||
|
state = State::RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -366,22 +378,22 @@ private:
|
|||||||
|
|
||||||
case State::STATUS:
|
case State::STATUS:
|
||||||
if (strcmp(name, "DAV:|status") == 0)
|
if (strcmp(name, "DAV:|status") == 0)
|
||||||
state = State::RESPONSE;
|
state = State::PROPSTAT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::TYPE:
|
case State::TYPE:
|
||||||
if (strcmp(name, "DAV:|resourcetype") == 0)
|
if (strcmp(name, "DAV:|resourcetype") == 0)
|
||||||
state = State::RESPONSE;
|
state = State::PROPSTAT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::MTIME:
|
case State::MTIME:
|
||||||
if (strcmp(name, "DAV:|getlastmodified") == 0)
|
if (strcmp(name, "DAV:|getlastmodified") == 0)
|
||||||
state = State::RESPONSE;
|
state = State::PROPSTAT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::LENGTH:
|
case State::LENGTH:
|
||||||
if (strcmp(name, "DAV:|getcontentlength") == 0)
|
if (strcmp(name, "DAV:|getcontentlength") == 0)
|
||||||
state = State::RESPONSE;
|
state = State::PROPSTAT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -389,6 +401,7 @@ private:
|
|||||||
void CharacterData(const XML_Char *s, int len) final {
|
void CharacterData(const XML_Char *s, int len) final {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case State::ROOT:
|
case State::ROOT:
|
||||||
|
case State::PROPSTAT:
|
||||||
case State::RESPONSE:
|
case State::RESPONSE:
|
||||||
case State::TYPE:
|
case State::TYPE:
|
||||||
break;
|
break;
|
||||||
@ -455,11 +468,19 @@ CurlStorage::GetInfo(std::string_view uri_utf8, [[maybe_unused]] bool follow)
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static std::string_view
|
static std::string_view
|
||||||
UriPathOrSlash(const char *uri) noexcept
|
UriPathOrSlash(const char *uri, bool relative) noexcept
|
||||||
{
|
{
|
||||||
auto path = uri_get_path(uri);
|
auto path = uri_get_path(uri);
|
||||||
if (path.data() == nullptr)
|
if (path.data() == nullptr)
|
||||||
path = "/";
|
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;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,13 +489,15 @@ UriPathOrSlash(const char *uri) noexcept
|
|||||||
*/
|
*/
|
||||||
class HttpListDirectoryOperation final : public PropfindOperation {
|
class HttpListDirectoryOperation final : public PropfindOperation {
|
||||||
const std::string base_path;
|
const std::string base_path;
|
||||||
|
const std::string base_path_relative;
|
||||||
|
|
||||||
MemoryStorageDirectoryReader::List entries;
|
MemoryStorageDirectoryReader::List entries;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HttpListDirectoryOperation(CurlGlobal &curl, const char *uri)
|
HttpListDirectoryOperation(CurlGlobal &curl, const char *uri)
|
||||||
:PropfindOperation(curl, uri, 1),
|
: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() {
|
std::unique_ptr<StorageDirectoryReader> Perform() {
|
||||||
DeferStart();
|
DeferStart();
|
||||||
@ -500,9 +523,15 @@ private:
|
|||||||
/* kludge: ignoring case in this comparison to avoid
|
/* kludge: ignoring case in this comparison to avoid
|
||||||
false negatives if the web server uses a different
|
false negatives if the web server uses a different
|
||||||
case */
|
case */
|
||||||
path = StringAfterPrefixIgnoreCase(path, base_path.c_str());
|
if (uri_has_scheme(path)) {
|
||||||
if (path == nullptr || path.empty())
|
path = StringAfterPrefixIgnoreCase(path, base_path.c_str());
|
||||||
|
} else {
|
||||||
|
path = StringAfterPrefixIgnoreCase(path, base_path_relative.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path == nullptr || path.empty()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
const char *slash = path.Find('/');
|
const char *slash = path.Find('/');
|
||||||
if (slash == nullptr)
|
if (slash == nullptr)
|
||||||
|
@ -85,7 +85,7 @@ uri_after_scheme(std::string_view uri) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
uri_has_scheme(const char *uri) noexcept
|
uri_has_scheme(std::string_view uri) noexcept
|
||||||
{
|
{
|
||||||
return !uri_get_scheme(uri).empty();
|
return !uri_get_scheme(uri).empty();
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool
|
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.
|
* Returns the scheme name of the specified URI, or an empty string.
|
||||||
|
Loading…
Reference in New Issue
Block a user