Commit e1867a99 authored by Max Kellermann's avatar Max Kellermann

Merge tag 'v0.21.16'

release v0.21.16
parents b2c4a5db 9b95e65b
......@@ -32,6 +32,17 @@ ver 0.22 (not yet released)
* switch to C++17
- GCC 7 or clang 4 (or newer) recommended
ver 0.21.16 (2019/10/16)
* queue
- fix relative destination offset when moving a range
* storage
- curl: request the "resourcetype" property to fix database update
- curl: URL-encode more paths
- curl: follow redirects for collections without trailing slash
* update
- fix crash when music_directory is not a directory
* fix build with iconv() instead of ICU
ver 0.21.15 (2019/09/25)
* decoder
- dsdiff, dsf: fix displayed bit rate
......
......@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd"
android:installLocation="auto"
android:versionCode="38"
android:versionName="0.21.15">
android:versionCode="39"
android:versionName="0.21.16">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/>
......
......@@ -475,6 +475,12 @@ UpdateWalk::Walk(Directory &root, const char *path, bool discard) noexcept
if (!GetInfo(storage, "", info))
return false;
if (!info.IsDirectory()) {
FormatError(update_domain, "Not a directory: %s",
storage.MapUTF8("").c_str());
return false;
}
ExcludeList exclude_list;
UpdateDirectory(root, exclude_list, info);
......
......@@ -30,6 +30,7 @@
#ifndef CURL_EASY_HXX
#define CURL_EASY_HXX
#include "String.hxx"
#include "util/Compiler.h"
#include <curl/curl.h>
......@@ -208,8 +209,8 @@ public:
return ::curl_easy_pause(handle, CURLPAUSE_CONT) == CURLE_OK;
}
char *Escape(const char *string, int length=0) const noexcept {
return curl_easy_escape(handle, string, length);
CurlString Escape(const char *string, int length=0) const noexcept {
return CurlString(curl_easy_escape(handle, string, length));
}
};
......
/*
* Copyright (C) 2018 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Escape.hxx"
#include "Easy.hxx"
#include "String.hxx"
#include "util/IterableSplitString.hxx"
std::string
CurlEscapeUriPath(CURL *curl, StringView src) noexcept
{
std::string dest;
for (const auto i : IterableSplitString(src, '/')) {
CurlString escaped(curl_easy_escape(curl, i.data, i.size));
if (!dest.empty())
dest.push_back('/');
dest += escaped.c_str();
}
return dest;
}
std::string
CurlEscapeUriPath(StringView src) noexcept
{
CurlEasy easy;
return CurlEscapeUriPath(easy.Get(), src);
}
std::string
CurlUnescape(CURL *curl, StringView src) noexcept
{
int outlength;
CurlString tmp(curl_easy_unescape(curl, src.data, src.size,
&outlength));
return std::string(tmp.c_str(), outlength);
}
std::string
CurlUnescape(StringView src) noexcept
{
CurlEasy easy;
return CurlUnescape(easy.Get(), src);
}
/*
* Copyright (C) 2018 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CURL_ESCAPE_HXX
#define CURL_ESCAPE_HXX
#include <curl/curl.h>
#include <string>
struct StringView;
std::string
CurlEscapeUriPath(CURL *curl, StringView src) noexcept;
std::string
CurlEscapeUriPath(StringView src) noexcept;
std::string
CurlUnescape(CURL *curl, StringView src) noexcept;
std::string
CurlUnescape(StringView src) noexcept;
#endif
......@@ -28,6 +28,7 @@
*/
#include "Form.hxx"
#include "String.hxx"
std::string
EncodeForm(CURL *curl,
......@@ -43,12 +44,10 @@ EncodeForm(CURL *curl,
result.push_back('=');
if (!i.second.empty()) {
char *value = curl_easy_escape(curl, i.second.data(),
i.second.length());
if (value != nullptr) {
CurlString value(curl_easy_escape(curl, i.second.data(),
i.second.length()));
if (value)
result.append(value);
curl_free(value);
}
}
}
......
/*
* Copyright 2019 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CURL_STRING_HXX
#define CURL_STRING_HXX
#include <curl/curl.h>
#include <utility>
/**
* An OO wrapper for an allocated string to be freed with curl_free().
*/
class CurlString {
char *p = nullptr;
public:
CurlString() noexcept = default;
CurlString(std::nullptr_t) noexcept {}
explicit CurlString(char *_p) noexcept
:p(_p) {}
CurlString(CurlString &&src) noexcept
:p(std::exchange(src.p, nullptr)) {}
~CurlString() noexcept {
if (p != nullptr)
curl_free(p);
}
CurlString &operator=(CurlString &&src) noexcept {
using std::swap;
swap(p, src.p);
return *this;
}
operator bool() const noexcept {
return p != nullptr;
}
operator const char *() const noexcept {
return p;
}
const char *c_str() const noexcept {
return p;
}
};
#endif
......@@ -11,6 +11,7 @@ curl = static_library(
'Init.cxx',
'Global.cxx',
'Request.cxx',
'Escape.cxx',
'Form.cxx',
include_directories: inc,
dependencies: [
......
......@@ -20,7 +20,7 @@ if icu_dep.found()
elif not get_option('iconv').disabled()
have_iconv = compiler.has_function('iconv')
conf.set('HAVE_ICONV', have_iconv)
if get_option('iconv').enabled()
if not have_iconv and get_option('iconv').enabled()
error('iconv() not available')
endif
endif
......
......@@ -352,7 +352,7 @@ playlist::MoveRange(PlayerControl &pc,
return;
to = (currentSong + abs(to)) % GetLength();
if (start < (unsigned)to)
to--;
to -= end - start;
}
queue.MoveRange(start, end, to);
......
......@@ -25,8 +25,10 @@
#include "lib/curl/Init.hxx"
#include "lib/curl/Global.hxx"
#include "lib/curl/Slist.hxx"
#include "lib/curl/String.hxx"
#include "lib/curl/Request.hxx"
#include "lib/curl/Handler.hxx"
#include "lib/curl/Escape.hxx"
#include "lib/expat/ExpatParser.hxx"
#include "fs/Traits.hxx"
#include "event/DeferEvent.hxx"
......@@ -34,7 +36,6 @@
#include "thread/Cond.hxx"
#include "time/Parser.hxx"
#include "util/ASCII.hxx"
#include "util/IterableSplitString.hxx"
#include "util/RuntimeError.hxx"
#include "util/StringCompare.hxx"
#include "util/StringFormat.hxx"
......@@ -74,26 +75,15 @@ CurlStorage::MapUTF8(const char *uri_utf8) const noexcept
if (StringIsEmpty(uri_utf8))
return base;
CurlEasy easy;
std::string path_esc;
for (auto elt: IterableSplitString(uri_utf8, '/')) {
char *elt_esc = easy.Escape(elt.data, elt.size);
if (!path_esc.empty())
path_esc.push_back('/');
path_esc += elt_esc;
curl_free(elt_esc);
}
std::string path_esc = CurlEscapeUriPath(uri_utf8);
return PathTraitsUTF8::Build(base.c_str(), path_esc.c_str());
}
const char *
CurlStorage::MapToRelativeUTF8(const char *uri_utf8) const noexcept
{
// TODO: escape/unescape?
return PathTraitsUTF8::Relative(base.c_str(), uri_utf8);
return PathTraitsUTF8::Relative(base.c_str(),
CurlUnescape(uri_utf8).c_str());
}
class BlockingHttpRequest : protected CurlResponseHandler {
......@@ -128,6 +118,10 @@ public:
std::rethrow_exception(postponed_error);
}
CURL *GetEasy() noexcept {
return request.Get();
}
protected:
void SetDone() {
assert(!done);
......@@ -265,6 +259,8 @@ public:
CommonExpatParser(ExpatNamespaceSeparator{'|'})
{
request.SetOption(CURLOPT_CUSTOMREQUEST, "PROPFIND");
request.SetOption(CURLOPT_FOLLOWLOCATION, 1l);
request.SetOption(CURLOPT_MAXREDIRS, 1l);
request_headers.Append(StringFormat<40>("depth: %u", depth));
......@@ -273,6 +269,7 @@ public:
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:propfind>");
......@@ -280,6 +277,7 @@ public:
// TODO: send request body
}
using BlockingHttpRequest::GetEasy;
using BlockingHttpRequest::Wait;
protected:
......@@ -450,9 +448,7 @@ CurlStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow)
{
// TODO: escape the given URI
std::string uri = base;
uri += uri_utf8;
const auto uri = MapUTF8(uri_utf8);
return HttpGetInfoOperation(*curl, uri.c_str()).Perform();
}
......@@ -499,7 +495,11 @@ private:
if (path == nullptr)
return nullptr;
path = StringAfterPrefix(path, base_path.c_str());
/* kludge: ignoring case in this comparison to avoid
false negatives if the web server uses a different
case in hex digits in escaped characters; TODO:
implement properly */
path = StringAfterPrefixIgnoreCase(path, base_path.c_str());
if (path == nullptr || *path == 0)
return nullptr;
......@@ -525,10 +525,7 @@ protected:
if (escaped_name.IsNull())
return;
// TODO: unescape
const auto name = escaped_name;
entries.emplace_front(std::string(name.data, name.size));
entries.emplace_front(CurlUnescape(GetEasy(), escaped_name));
auto &info = entries.front().info;
info = StorageFileInfo(r.collection
......@@ -542,10 +539,7 @@ protected:
std::unique_ptr<StorageDirectoryReader>
CurlStorage::OpenDirectory(const char *uri_utf8)
{
// TODO: escape the given URI
std::string uri = base;
uri += uri_utf8;
std::string uri = MapUTF8(uri_utf8);
/* collection URIs must end with a slash */
if (uri.back() != '/')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment