From fd9114e7e28048b499c036d8196af91539ceac02 Mon Sep 17 00:00:00 2001 From: Naglis Jonaitis Date: Thu, 26 May 2022 16:43:58 +0300 Subject: [PATCH 01/10] doc/user.rst: fix neighbor plugin config block name --- doc/user.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user.rst b/doc/user.rst index a3bbe1785..06d8e2924 100644 --- a/doc/user.rst +++ b/doc/user.rst @@ -301,7 +301,7 @@ Configuring neighbor plugins ---------------------------- All neighbor plugins are disabled by default to avoid unwanted -overhead. To enable (and configure) a plugin, add a :code:`neighbor` +overhead. To enable (and configure) a plugin, add a :code:`neighbors` block to :file:`mpd.conf`: .. code-block:: none From 8d8b77412d0c78f6775aa2495979cbecee1bffe4 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 7 Dec 2021 11:54:02 +0100 Subject: [PATCH 02/10] lib/curl/Request: add API docs --- src/lib/curl/Request.hxx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/lib/curl/Request.hxx b/src/lib/curl/Request.hxx index e08e58e8c..d18e06c4f 100644 --- a/src/lib/curl/Request.hxx +++ b/src/lib/curl/Request.hxx @@ -1,5 +1,5 @@ /* - * Copyright 2008-2018 Max Kellermann + * Copyright 2008-2021 Max Kellermann * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,6 +39,12 @@ struct StringView; class CurlGlobal; class CurlResponseHandler; +/** + * A non-blocking HTTP request integrated via #CurlGlobal into the + * #EventLoop. + * + * To start sending the request, call Start(). + */ class CurlRequest final { CurlGlobal &global; @@ -136,7 +142,7 @@ public: easy.SetPost(value); } - void SetRequestBody(const void *data, size_t size) { + void SetRequestBody(const void *data, std::size_t size) { easy.SetRequestBody(data, size); } From 5cf6032c90f1e3015797942e5e57ab31de2e1dd3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 7 Dec 2021 11:56:52 +0100 Subject: [PATCH 03/10] lib/curl/Request: move code to SetupEasy() --- src/lib/curl/Request.cxx | 18 ++++++++++++------ src/lib/curl/Request.hxx | 2 ++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/lib/curl/Request.cxx b/src/lib/curl/Request.cxx index de97f1555..45dd440ec 100644 --- a/src/lib/curl/Request.cxx +++ b/src/lib/curl/Request.cxx @@ -1,5 +1,5 @@ /* - * Copyright 2008-2018 Max Kellermann + * Copyright 2008-2021 Max Kellermann * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,6 +48,17 @@ CurlRequest::CurlRequest(CurlGlobal &_global, CurlResponseHandler &_handler) :global(_global), handler(_handler) +{ + SetupEasy(); +} + +CurlRequest::~CurlRequest() noexcept +{ + FreeEasy(); +} + +void +CurlRequest::SetupEasy() { error_buffer[0] = 0; @@ -65,11 +76,6 @@ CurlRequest::CurlRequest(CurlGlobal &_global, easy.SetOption(CURLOPT_HTTPAUTH, (long) CURLAUTH_ANY); } -CurlRequest::~CurlRequest() noexcept -{ - FreeEasy(); -} - void CurlRequest::Start() { diff --git a/src/lib/curl/Request.hxx b/src/lib/curl/Request.hxx index d18e06c4f..a43b29bf9 100644 --- a/src/lib/curl/Request.hxx +++ b/src/lib/curl/Request.hxx @@ -154,6 +154,8 @@ public: void Done(CURLcode result) noexcept; private: + void SetupEasy(); + /** * Frees the current "libcurl easy" handle, and everything * associated with it. From f8338d4f0082dde2b230a03da97f4ba306023a5f Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 7 Dec 2021 12:00:09 +0100 Subject: [PATCH 04/10] lib/curl/Request: use std::size_t --- src/lib/curl/Request.cxx | 12 ++++++------ src/lib/curl/Request.hxx | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/lib/curl/Request.cxx b/src/lib/curl/Request.cxx index 45dd440ec..9a287503f 100644 --- a/src/lib/curl/Request.cxx +++ b/src/lib/curl/Request.cxx @@ -224,8 +224,8 @@ CurlRequest::HeaderFunction(StringView s) noexcept headers.emplace(std::move(name), std::string(value, end)); } -size_t -CurlRequest::_HeaderFunction(char *ptr, size_t size, size_t nmemb, +std::size_t +CurlRequest::_HeaderFunction(char *ptr, std::size_t size, std::size_t nmemb, void *stream) noexcept { CurlRequest &c = *(CurlRequest *)stream; @@ -236,8 +236,8 @@ CurlRequest::_HeaderFunction(char *ptr, size_t size, size_t nmemb, return size; } -inline size_t -CurlRequest::DataReceived(const void *ptr, size_t received_size) noexcept +inline std::size_t +CurlRequest::DataReceived(const void *ptr, std::size_t received_size) noexcept { assert(received_size > 0); @@ -251,8 +251,8 @@ CurlRequest::DataReceived(const void *ptr, size_t received_size) noexcept } -size_t -CurlRequest::WriteFunction(char *ptr, size_t size, size_t nmemb, +std::size_t +CurlRequest::WriteFunction(char *ptr, std::size_t size, std::size_t nmemb, void *stream) noexcept { CurlRequest &c = *(CurlRequest *)stream; diff --git a/src/lib/curl/Request.hxx b/src/lib/curl/Request.hxx index a43b29bf9..67785b1df 100644 --- a/src/lib/curl/Request.hxx +++ b/src/lib/curl/Request.hxx @@ -165,17 +165,17 @@ private: void FinishHeaders(); void FinishBody(); - size_t DataReceived(const void *ptr, size_t size) noexcept; + std::size_t DataReceived(const void *ptr, std::size_t size) noexcept; void HeaderFunction(StringView s) noexcept; /** called by curl when new data is available */ - static size_t _HeaderFunction(char *ptr, size_t size, size_t nmemb, - void *stream) noexcept; + static std::size_t _HeaderFunction(char *ptr, std::size_t size, std::size_t nmemb, + void *stream) noexcept; /** called by curl when new data is available */ - static size_t WriteFunction(char *ptr, size_t size, size_t nmemb, - void *stream) noexcept; + static std::size_t WriteFunction(char *ptr, std::size_t size, std::size_t nmemb, + void *stream) noexcept; }; #endif From 47ca4246aabebc3eb31e80604fdab03cb73e007c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 7 Dec 2021 12:00:45 +0100 Subject: [PATCH 05/10] lib/curl/Request: add constructor with CurlEasy parameter --- src/lib/curl/Request.cxx | 7 +++++++ src/lib/curl/Request.hxx | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/lib/curl/Request.cxx b/src/lib/curl/Request.cxx index 9a287503f..6f041af7e 100644 --- a/src/lib/curl/Request.cxx +++ b/src/lib/curl/Request.cxx @@ -45,6 +45,13 @@ #include +CurlRequest::CurlRequest(CurlGlobal &_global, CurlEasy _easy, + CurlResponseHandler &_handler) + :global(_global), handler(_handler), easy(std::move(_easy)) +{ + SetupEasy(); +} + CurlRequest::CurlRequest(CurlGlobal &_global, CurlResponseHandler &_handler) :global(_global), handler(_handler) diff --git a/src/lib/curl/Request.hxx b/src/lib/curl/Request.hxx index 67785b1df..fae401a4e 100644 --- a/src/lib/curl/Request.hxx +++ b/src/lib/curl/Request.hxx @@ -67,9 +67,9 @@ class CurlRequest final { bool registered = false; public: - /** - * To start sending the request, call Start(). - */ + CurlRequest(CurlGlobal &_global, CurlEasy easy, + CurlResponseHandler &_handler); + CurlRequest(CurlGlobal &_global, CurlResponseHandler &_handler); From 5d08988ddae807438f2177744031bcde5aecabc7 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Dec 2021 19:41:37 +0100 Subject: [PATCH 06/10] lib/curl/Handler: fix typo --- src/lib/curl/Handler.hxx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/curl/Handler.hxx b/src/lib/curl/Handler.hxx index 1259c4b3a..14a928a80 100644 --- a/src/lib/curl/Handler.hxx +++ b/src/lib/curl/Handler.hxx @@ -1,5 +1,5 @@ /* - * Copyright 2008-2018 Max Kellermann + * Copyright 2008-2021 Max Kellermann * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -64,14 +64,14 @@ public: virtual void OnData(ConstBuffer data) = 0; /** - * The response has ended. The method is allowed delete the - * #CurlRequest here. + * The response has ended. The method is allowed to delete the + * #CurlRequest. */ virtual void OnEnd() = 0; /** - * An error has occurred. The method is allowed delete the - * #CurlRequest here. + * An error has occurred. The method is allowed to delete the + * #CurlRequest. */ virtual void OnError(std::exception_ptr e) noexcept = 0; }; From 252e9f736fe9a076024275dcc8de98ec0d353575 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Dec 2021 19:47:01 +0100 Subject: [PATCH 07/10] lib/curl/Request: move code to class CurlResponseHandlerAdapter --- src/lib/curl/Adapter.cxx | 191 +++++++++++++++++++++++++++++++++++++++ src/lib/curl/Adapter.hxx | 87 ++++++++++++++++++ src/lib/curl/Request.cxx | 142 +---------------------------- src/lib/curl/Request.hxx | 29 +----- src/lib/curl/meson.build | 1 + 5 files changed, 287 insertions(+), 163 deletions(-) create mode 100644 src/lib/curl/Adapter.cxx create mode 100644 src/lib/curl/Adapter.hxx diff --git a/src/lib/curl/Adapter.cxx b/src/lib/curl/Adapter.cxx new file mode 100644 index 000000000..e41587bff --- /dev/null +++ b/src/lib/curl/Adapter.cxx @@ -0,0 +1,191 @@ +/* + * Copyright 2008-2021 Max Kellermann + * + * 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 "Adapter.hxx" +#include "Easy.hxx" +#include "Handler.hxx" +#include "util/CharUtil.hxx" +#include "util/RuntimeError.hxx" +#include "util/StringStrip.hxx" +#include "util/StringView.hxx" + +#include +#include + +void +CurlResponseHandlerAdapter::Install(CurlEasy &easy) +{ + assert(state == State::UNINITIALISED); + + error_buffer[0] = 0; + easy.SetErrorBuffer(error_buffer); + + easy.SetHeaderFunction(_HeaderFunction, this); + easy.SetWriteFunction(WriteFunction, this); + + curl = easy.Get(); + + state = State::HEADERS; +} + +void +CurlResponseHandlerAdapter::FinishHeaders() +{ + assert(state >= State::HEADERS); + + if (state != State::HEADERS) + return; + + state = State::BODY; + + long status = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status); + + handler.OnHeaders(status, std::move(headers)); +} + +void +CurlResponseHandlerAdapter::FinishBody() +{ + FinishHeaders(); + + if (state != State::BODY) + return; + + state = State::CLOSED; + handler.OnEnd(); +} + +void +CurlResponseHandlerAdapter::Done(CURLcode result) noexcept +{ + try { + if (result != CURLE_OK) { + StripRight(error_buffer); + const char *msg = error_buffer; + if (*msg == 0) + msg = curl_easy_strerror(result); + throw FormatRuntimeError("CURL failed: %s", msg); + } + + FinishBody(); + } catch (...) { + state = State::CLOSED; + handler.OnError(std::current_exception()); + } +} + +[[gnu::pure]] +static bool +IsResponseBoundaryHeader(StringView s) noexcept +{ + return s.size > 5 && (s.StartsWith("HTTP/") || + /* the proprietary "ICY 200 OK" is + emitted by Shoutcast */ + s.StartsWith("ICY 2")); +} + +inline void +CurlResponseHandlerAdapter::HeaderFunction(StringView s) noexcept +{ + if (state > State::HEADERS) + return; + + if (IsResponseBoundaryHeader(s)) { + /* this is the boundary to a new response, for example + after a redirect */ + headers.clear(); + return; + } + + const char *header = s.data; + const char *end = StripRight(header, header + s.size); + + const char *value = s.Find(':'); + if (value == nullptr) + return; + + std::string name(header, value); + std::transform(name.begin(), name.end(), name.begin(), + static_cast(ToLowerASCII)); + + /* skip the colon */ + + ++value; + + /* strip the value */ + + value = StripLeft(value, end); + end = StripRight(value, end); + + headers.emplace(std::move(name), std::string(value, end)); +} + +std::size_t +CurlResponseHandlerAdapter::_HeaderFunction(char *ptr, std::size_t size, + std::size_t nmemb, + void *stream) noexcept +{ + CurlResponseHandlerAdapter &c = *(CurlResponseHandlerAdapter *)stream; + + size *= nmemb; + + c.HeaderFunction({ptr, size}); + return size; +} + +inline std::size_t +CurlResponseHandlerAdapter::DataReceived(const void *ptr, + std::size_t received_size) noexcept +{ + assert(received_size > 0); + + try { + FinishHeaders(); + handler.OnData({ptr, received_size}); + return received_size; + } catch (CurlResponseHandler::Pause) { + return CURL_WRITEFUNC_PAUSE; + } + +} + +std::size_t +CurlResponseHandlerAdapter::WriteFunction(char *ptr, std::size_t size, + std::size_t nmemb, + void *stream) noexcept +{ + CurlResponseHandlerAdapter &c = *(CurlResponseHandlerAdapter *)stream; + + size *= nmemb; + if (size == 0) + return 0; + + return c.DataReceived(ptr, size); +} diff --git a/src/lib/curl/Adapter.hxx b/src/lib/curl/Adapter.hxx new file mode 100644 index 000000000..1d26f46e6 --- /dev/null +++ b/src/lib/curl/Adapter.hxx @@ -0,0 +1,87 @@ +/* + * Copyright 2008-2021 Max Kellermann + * + * 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_ADAPTER_HXX +#define CURL_ADAPTER_HXX + +#include + +#include +#include +#include + +struct StringView; +class CurlEasy; +class CurlResponseHandler; + +class CurlResponseHandlerAdapter { + CURL *curl; + + CurlResponseHandler &handler; + + std::multimap headers; + + /** error message provided by libcurl */ + char error_buffer[CURL_ERROR_SIZE]; + + enum class State { + UNINITIALISED, + HEADERS, + BODY, + CLOSED, + } state = State::UNINITIALISED; + +public: + explicit CurlResponseHandlerAdapter(CurlResponseHandler &_handler) noexcept + :handler(_handler) {} + + void Install(CurlEasy &easy); + + void Done(CURLcode result) noexcept; + +private: + void FinishHeaders(); + void FinishBody(); + + void HeaderFunction(StringView s) noexcept; + + /** called by curl when a new header is available */ + static std::size_t _HeaderFunction(char *ptr, + std::size_t size, std::size_t nmemb, + void *stream) noexcept; + + std::size_t DataReceived(const void *ptr, std::size_t size) noexcept; + + /** called by curl when new data is available */ + static std::size_t WriteFunction(char *ptr, + std::size_t size, std::size_t nmemb, + void *stream) noexcept; +}; + +#endif diff --git a/src/lib/curl/Request.cxx b/src/lib/curl/Request.cxx index 6f041af7e..7cdd10b12 100644 --- a/src/lib/curl/Request.cxx +++ b/src/lib/curl/Request.cxx @@ -30,20 +30,15 @@ #include "config.h" #include "Request.hxx" #include "Global.hxx" -#include "Handler.hxx" #include "event/Call.hxx" -#include "util/RuntimeError.hxx" #include "util/StringStrip.hxx" -#include "util/StringView.hxx" -#include "util/CharUtil.hxx" #include "Version.h" #include -#include #include -#include +#include CurlRequest::CurlRequest(CurlGlobal &_global, CurlEasy _easy, CurlResponseHandler &_handler) @@ -67,16 +62,14 @@ CurlRequest::~CurlRequest() noexcept void CurlRequest::SetupEasy() { - error_buffer[0] = 0; - easy.SetPrivate((void *)this); + + handler.Install(easy); + easy.SetUserAgent("Music Player Daemon " VERSION); - easy.SetHeaderFunction(_HeaderFunction, this); - easy.SetWriteFunction(WriteFunction, this); #if !defined(ANDROID) && !defined(_WIN32) easy.SetOption(CURLOPT_NETRC, 1L); #endif - easy.SetErrorBuffer(error_buffer); easy.SetNoProgress(); easy.SetNoSignal(); easy.SetConnectTimeout(10); @@ -138,135 +131,10 @@ CurlRequest::Resume() noexcept global.InvalidateSockets(); } -void -CurlRequest::FinishHeaders() -{ - if (state != State::HEADERS) - return; - - state = State::BODY; - - long status = 0; - easy.GetInfo(CURLINFO_RESPONSE_CODE, &status); - - handler.OnHeaders(status, std::move(headers)); -} - -void -CurlRequest::FinishBody() -{ - FinishHeaders(); - - if (state != State::BODY) - return; - - state = State::CLOSED; - handler.OnEnd(); -} - void CurlRequest::Done(CURLcode result) noexcept { Stop(); - try { - if (result != CURLE_OK) { - StripRight(error_buffer); - const char *msg = error_buffer; - if (*msg == 0) - msg = curl_easy_strerror(result); - throw FormatRuntimeError("CURL failed: %s", msg); - } - - FinishBody(); - } catch (...) { - state = State::CLOSED; - handler.OnError(std::current_exception()); - } -} - -[[gnu::pure]] -static bool -IsResponseBoundaryHeader(StringView s) noexcept -{ - return s.size > 5 && (s.StartsWith("HTTP/") || - /* the proprietary "ICY 200 OK" is - emitted by Shoutcast */ - s.StartsWith("ICY 2")); -} - -inline void -CurlRequest::HeaderFunction(StringView s) noexcept -{ - if (state > State::HEADERS) - return; - - if (IsResponseBoundaryHeader(s)) { - /* this is the boundary to a new response, for example - after a redirect */ - headers.clear(); - return; - } - - const char *header = s.data; - const char *end = StripRight(header, header + s.size); - - const char *value = s.Find(':'); - if (value == nullptr) - return; - - std::string name(header, value); - std::transform(name.begin(), name.end(), name.begin(), - static_cast(ToLowerASCII)); - - /* skip the colon */ - - ++value; - - /* strip the value */ - - value = StripLeft(value, end); - end = StripRight(value, end); - - headers.emplace(std::move(name), std::string(value, end)); -} - -std::size_t -CurlRequest::_HeaderFunction(char *ptr, std::size_t size, std::size_t nmemb, - void *stream) noexcept -{ - CurlRequest &c = *(CurlRequest *)stream; - - size *= nmemb; - - c.HeaderFunction({ptr, size}); - return size; -} - -inline std::size_t -CurlRequest::DataReceived(const void *ptr, std::size_t received_size) noexcept -{ - assert(received_size > 0); - - try { - FinishHeaders(); - handler.OnData({ptr, received_size}); - return received_size; - } catch (CurlResponseHandler::Pause) { - return CURL_WRITEFUNC_PAUSE; - } - -} - -std::size_t -CurlRequest::WriteFunction(char *ptr, std::size_t size, std::size_t nmemb, - void *stream) noexcept -{ - CurlRequest &c = *(CurlRequest *)stream; - - size *= nmemb; - if (size == 0) - return 0; - - return c.DataReceived(ptr, size); + handler.Done(result); } diff --git a/src/lib/curl/Request.hxx b/src/lib/curl/Request.hxx index fae401a4e..fcd68ca8e 100644 --- a/src/lib/curl/Request.hxx +++ b/src/lib/curl/Request.hxx @@ -31,9 +31,9 @@ #define CURL_REQUEST_HXX #include "Easy.hxx" +#include "Adapter.hxx" -#include -#include +#include struct StringView; class CurlGlobal; @@ -48,22 +48,11 @@ class CurlResponseHandler; class CurlRequest final { CurlGlobal &global; - CurlResponseHandler &handler; + CurlResponseHandlerAdapter handler; /** the curl handle */ CurlEasy easy; - enum class State { - HEADERS, - BODY, - CLOSED, - } state = State::HEADERS; - - std::multimap headers; - - /** error message provided by libcurl */ - char error_buffer[CURL_ERROR_SIZE]; - bool registered = false; public: @@ -164,18 +153,6 @@ private: void FinishHeaders(); void FinishBody(); - - std::size_t DataReceived(const void *ptr, std::size_t size) noexcept; - - void HeaderFunction(StringView s) noexcept; - - /** called by curl when new data is available */ - static std::size_t _HeaderFunction(char *ptr, std::size_t size, std::size_t nmemb, - void *stream) noexcept; - - /** called by curl when new data is available */ - static std::size_t WriteFunction(char *ptr, std::size_t size, std::size_t nmemb, - void *stream) noexcept; }; #endif diff --git a/src/lib/curl/meson.build b/src/lib/curl/meson.build index 3433997e0..284c688d8 100644 --- a/src/lib/curl/meson.build +++ b/src/lib/curl/meson.build @@ -18,6 +18,7 @@ curl = static_library( 'Init.cxx', 'Global.cxx', 'Request.cxx', + 'Adapter.cxx', 'Escape.cxx', 'Form.cxx', include_directories: inc, From 29e3a17f261f992d3f6761031e90c66f0262505c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 8 Dec 2021 19:56:20 +0100 Subject: [PATCH 08/10] lib/curl/Request: move code from SetupEasy() to Setup.cxx --- src/lib/curl/Request.cxx | 15 ++---------- src/lib/curl/Setup.cxx | 51 ++++++++++++++++++++++++++++++++++++++++ src/lib/curl/Setup.hxx | 39 ++++++++++++++++++++++++++++++ src/lib/curl/meson.build | 1 + 4 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 src/lib/curl/Setup.cxx create mode 100644 src/lib/curl/Setup.hxx diff --git a/src/lib/curl/Request.cxx b/src/lib/curl/Request.cxx index 7cdd10b12..a5c30dd34 100644 --- a/src/lib/curl/Request.cxx +++ b/src/lib/curl/Request.cxx @@ -27,19 +27,15 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" #include "Request.hxx" +#include "Setup.hxx" #include "Global.hxx" #include "event/Call.hxx" -#include "util/StringStrip.hxx" -#include "Version.h" #include #include -#include - CurlRequest::CurlRequest(CurlGlobal &_global, CurlEasy _easy, CurlResponseHandler &_handler) :global(_global), handler(_handler), easy(std::move(_easy)) @@ -66,14 +62,7 @@ CurlRequest::SetupEasy() handler.Install(easy); - easy.SetUserAgent("Music Player Daemon " VERSION); -#if !defined(ANDROID) && !defined(_WIN32) - easy.SetOption(CURLOPT_NETRC, 1L); -#endif - easy.SetNoProgress(); - easy.SetNoSignal(); - easy.SetConnectTimeout(10); - easy.SetOption(CURLOPT_HTTPAUTH, (long) CURLAUTH_ANY); + Curl::Setup(easy); } void diff --git a/src/lib/curl/Setup.cxx b/src/lib/curl/Setup.cxx new file mode 100644 index 000000000..284b7ca79 --- /dev/null +++ b/src/lib/curl/Setup.cxx @@ -0,0 +1,51 @@ +/* + * Copyright 2008-2021 Max Kellermann + * + * 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 "Setup.hxx" +#include "Easy.hxx" +#include "Version.h" + +#include + +namespace Curl { + +void +Setup(CurlEasy &easy) +{ + easy.SetUserAgent("Music Player Daemon " VERSION); +#if !defined(ANDROID) && !defined(_WIN32) + easy.SetOption(CURLOPT_NETRC, 1L); +#endif + easy.SetNoProgress(); + easy.SetNoSignal(); + easy.SetConnectTimeout(10); + easy.SetOption(CURLOPT_HTTPAUTH, (long) CURLAUTH_ANY); +} + +} // namespace Curl diff --git a/src/lib/curl/Setup.hxx b/src/lib/curl/Setup.hxx new file mode 100644 index 000000000..8937d8924 --- /dev/null +++ b/src/lib/curl/Setup.hxx @@ -0,0 +1,39 @@ +/* + * Copyright 2008-2021 Max Kellermann + * + * 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. + */ + +#pragma once + +class CurlEasy; + +namespace Curl { + +void +Setup(CurlEasy &easy); + +} // namespace Curl diff --git a/src/lib/curl/meson.build b/src/lib/curl/meson.build index 284c688d8..a0f9647fb 100644 --- a/src/lib/curl/meson.build +++ b/src/lib/curl/meson.build @@ -18,6 +18,7 @@ curl = static_library( 'Init.cxx', 'Global.cxx', 'Request.cxx', + 'Setup.cxx', 'Adapter.cxx', 'Escape.cxx', 'Form.cxx', From 19d2864c34ebb04d5790578bd92854c7baa78f90 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 4 Feb 2022 11:11:38 +0100 Subject: [PATCH 09/10] lib/curl/Headers: central type definition for the header map --- src/input/plugins/CurlInputPlugin.cxx | 16 +++++----- src/input/plugins/CurlInputPlugin.hxx | 7 ++--- src/input/plugins/QobuzClient.cxx | 4 +-- src/input/plugins/QobuzClient.hxx | 6 ++-- src/input/plugins/QobuzErrorParser.cxx | 2 +- src/input/plugins/QobuzErrorParser.hxx | 7 ++--- src/input/plugins/QobuzLoginRequest.cxx | 7 ++--- src/input/plugins/QobuzLoginRequest.hxx | 2 +- src/input/plugins/QobuzTagScanner.cxx | 3 +- src/input/plugins/QobuzTagScanner.hxx | 2 +- src/input/plugins/QobuzTrackRequest.cxx | 2 +- src/input/plugins/QobuzTrackRequest.hxx | 2 +- src/lib/curl/Adapter.hxx | 13 +++----- src/lib/curl/Delegate.cxx | 5 ++- src/lib/curl/Delegate.hxx | 12 +++---- src/lib/curl/Form.cxx | 3 +- src/lib/curl/Form.hxx | 6 ++-- src/lib/curl/Handler.hxx | 11 ++----- src/lib/curl/Headers.hxx | 42 +++++++++++++++++++++++++ src/lib/upnp/Discovery.cxx | 2 +- src/lib/upnp/Discovery.hxx | 3 +- src/storage/plugins/CurlStorage.cxx | 5 ++- test/RunCurl.cxx | 3 +- 23 files changed, 90 insertions(+), 75 deletions(-) create mode 100644 src/lib/curl/Headers.hxx diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index be5efed91..cc2606714 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -82,7 +82,7 @@ class CurlInputStream final : public AsyncInputStream, CurlResponseHandler { public: template CurlInputStream(EventLoop &event_loop, const char *_url, - const std::multimap &headers, + const Curl::Headers &headers, I &&_icy, Mutex &_mutex); @@ -92,7 +92,7 @@ public: CurlInputStream &operator=(const CurlInputStream &) = delete; static InputStreamPtr Open(const char *url, - const std::multimap &headers, + const Curl::Headers &headers, Mutex &mutex); private: @@ -131,8 +131,7 @@ private: void SeekInternal(offset_type new_offset); /* virtual methods from CurlResponseHandler */ - void OnHeaders(unsigned status, - std::multimap &&headers) override; + void OnHeaders(unsigned status, Curl::Headers &&headers) override; void OnData(ConstBuffer data) override; void OnEnd() override; void OnError(std::exception_ptr e) noexcept override; @@ -227,7 +226,7 @@ WithConvertedTagValue(const char *uri, const char *value, F &&f) noexcept void CurlInputStream::OnHeaders(unsigned status, - std::multimap &&headers) + Curl::Headers &&headers) { assert(GetEventLoop().IsInside()); assert(!postponed_exception); @@ -391,7 +390,7 @@ input_curl_finish() noexcept template inline CurlInputStream::CurlInputStream(EventLoop &event_loop, const char *_url, - const std::multimap &headers, + const Curl::Headers &headers, I &&_icy, Mutex &_mutex) :AsyncInputStream(event_loop, _url, _mutex, @@ -491,7 +490,7 @@ CurlInputStream::DoSeek(offset_type new_offset) inline InputStreamPtr CurlInputStream::Open(const char *url, - const std::multimap &headers, + const Curl::Headers &headers, Mutex &mutex) { auto icy = std::make_shared(); @@ -510,8 +509,7 @@ CurlInputStream::Open(const char *url, } InputStreamPtr -OpenCurlInputStream(const char *uri, - const std::multimap &headers, +OpenCurlInputStream(const char *uri, const Curl::Headers &headers, Mutex &mutex) { return CurlInputStream::Open(uri, headers, mutex); diff --git a/src/input/plugins/CurlInputPlugin.hxx b/src/input/plugins/CurlInputPlugin.hxx index c3decf675..3595a84ea 100644 --- a/src/input/plugins/CurlInputPlugin.hxx +++ b/src/input/plugins/CurlInputPlugin.hxx @@ -20,12 +20,10 @@ #ifndef MPD_INPUT_CURL_HXX #define MPD_INPUT_CURL_HXX +#include "lib/curl/Headers.hxx" #include "input/Ptr.hxx" #include "thread/Mutex.hxx" -#include -#include - extern const struct InputPlugin input_plugin_curl; /** @@ -36,8 +34,7 @@ extern const struct InputPlugin input_plugin_curl; * Throws on error. */ InputStreamPtr -OpenCurlInputStream(const char *uri, - const std::multimap &headers, +OpenCurlInputStream(const char *uri, const Curl::Headers &headers, Mutex &mutex); #endif diff --git a/src/input/plugins/QobuzClient.cxx b/src/input/plugins/QobuzClient.cxx index 294456a5a..48f8d8ecd 100644 --- a/src/input/plugins/QobuzClient.cxx +++ b/src/input/plugins/QobuzClient.cxx @@ -164,7 +164,7 @@ QobuzClient::InvokeHandlers() noexcept std::string QobuzClient::MakeUrl(const char *object, const char *method, - const std::multimap &query) const noexcept + const Curl::Headers &query) const noexcept { assert(!query.empty()); @@ -183,7 +183,7 @@ QobuzClient::MakeUrl(const char *object, const char *method, std::string QobuzClient::MakeSignedUrl(const char *object, const char *method, - const std::multimap &query) const noexcept + const Curl::Headers &query) const noexcept { assert(!query.empty()); diff --git a/src/input/plugins/QobuzClient.hxx b/src/input/plugins/QobuzClient.hxx index 0fa00dce0..65c9ec49a 100644 --- a/src/input/plugins/QobuzClient.hxx +++ b/src/input/plugins/QobuzClient.hxx @@ -23,12 +23,12 @@ #include "QobuzSession.hxx" #include "QobuzLoginRequest.hxx" #include "lib/curl/Init.hxx" +#include "lib/curl/Headers.hxx" #include "thread/Mutex.hxx" #include "event/DeferEvent.hxx" #include "util/IntrusiveList.hxx" #include -#include #include class QobuzSessionHandler @@ -94,10 +94,10 @@ public: QobuzSession GetSession() const; std::string MakeUrl(const char *object, const char *method, - const std::multimap &query) const noexcept; + const Curl::Headers &query) const noexcept; std::string MakeSignedUrl(const char *object, const char *method, - const std::multimap &query) const noexcept; + const Curl::Headers &query) const noexcept; private: void StartLogin(); diff --git a/src/input/plugins/QobuzErrorParser.cxx b/src/input/plugins/QobuzErrorParser.cxx index 96ac1f743..ae19be5dc 100644 --- a/src/input/plugins/QobuzErrorParser.cxx +++ b/src/input/plugins/QobuzErrorParser.cxx @@ -38,7 +38,7 @@ static constexpr yajl_callbacks qobuz_error_parser_callbacks = { }; QobuzErrorParser::QobuzErrorParser(unsigned _status, - const std::multimap &headers) + const Curl::Headers &headers) :YajlResponseParser(&qobuz_error_parser_callbacks, nullptr, this), status(_status) { diff --git a/src/input/plugins/QobuzErrorParser.hxx b/src/input/plugins/QobuzErrorParser.hxx index 4f50f8265..23523af46 100644 --- a/src/input/plugins/QobuzErrorParser.hxx +++ b/src/input/plugins/QobuzErrorParser.hxx @@ -20,11 +20,9 @@ #ifndef QOBUZ_ERROR_PARSER_HXX #define QOBUZ_ERROR_PARSER_HXX +#include "lib/curl/Headers.hxx" #include "lib/yajl/ResponseParser.hxx" -#include -#include - template struct ConstBuffer; struct StringView; @@ -46,8 +44,7 @@ public: * May throw if there is a formal error in the response * headers. */ - QobuzErrorParser(unsigned status, - const std::multimap &headers); + QobuzErrorParser(unsigned status, const Curl::Headers &headers); protected: /* virtual methods from CurlResponseParser */ diff --git a/src/input/plugins/QobuzLoginRequest.cxx b/src/input/plugins/QobuzLoginRequest.cxx index 2a3e091d0..143c3f931 100644 --- a/src/input/plugins/QobuzLoginRequest.cxx +++ b/src/input/plugins/QobuzLoginRequest.cxx @@ -77,7 +77,7 @@ QobuzLoginRequest::ResponseParser::GetSession() return std::move(session); } -static std::multimap +static Curl::Headers MakeLoginForm(const char *app_id, const char *username, const char *email, const char *password, @@ -85,7 +85,7 @@ MakeLoginForm(const char *app_id, { assert(username != nullptr || email != nullptr); - std::multimap form{ + Curl::Headers form{ {"app_id", app_id}, {"password", password}, {"device_manufacturer_id", device_manufacturer_id}, @@ -134,8 +134,7 @@ QobuzLoginRequest::~QobuzLoginRequest() noexcept } std::unique_ptr -QobuzLoginRequest::MakeParser(unsigned status, - std::multimap &&headers) +QobuzLoginRequest::MakeParser(unsigned status, Curl::Headers &&headers) { if (status != 200) return std::make_unique(status, headers); diff --git a/src/input/plugins/QobuzLoginRequest.hxx b/src/input/plugins/QobuzLoginRequest.hxx index 189cb6896..1bf657ec6 100644 --- a/src/input/plugins/QobuzLoginRequest.hxx +++ b/src/input/plugins/QobuzLoginRequest.hxx @@ -56,7 +56,7 @@ public: private: /* virtual methods from DelegateCurlResponseHandler */ std::unique_ptr MakeParser(unsigned status, - std::multimap &&headers) override; + Curl::Headers &&headers) override; void FinishParser(std::unique_ptr p) override; /* virtual methods from CurlResponseHandler */ diff --git a/src/input/plugins/QobuzTagScanner.cxx b/src/input/plugins/QobuzTagScanner.cxx index 3629d9865..50a3f022b 100644 --- a/src/input/plugins/QobuzTagScanner.cxx +++ b/src/input/plugins/QobuzTagScanner.cxx @@ -99,8 +99,7 @@ QobuzTagScanner::~QobuzTagScanner() noexcept } std::unique_ptr -QobuzTagScanner::MakeParser(unsigned status, - std::multimap &&headers) +QobuzTagScanner::MakeParser(unsigned status, Curl::Headers &&headers) { if (status != 200) return std::make_unique(status, headers); diff --git a/src/input/plugins/QobuzTagScanner.hxx b/src/input/plugins/QobuzTagScanner.hxx index 3a8a3276e..ce596bc80 100644 --- a/src/input/plugins/QobuzTagScanner.hxx +++ b/src/input/plugins/QobuzTagScanner.hxx @@ -49,7 +49,7 @@ public: private: /* virtual methods from DelegateCurlResponseHandler */ std::unique_ptr MakeParser(unsigned status, - std::multimap &&headers) override; + Curl::Headers &&headers) override; void FinishParser(std::unique_ptr p) override; /* virtual methods from CurlResponseHandler */ diff --git a/src/input/plugins/QobuzTrackRequest.cxx b/src/input/plugins/QobuzTrackRequest.cxx index e48a3848e..b697d3ec3 100644 --- a/src/input/plugins/QobuzTrackRequest.cxx +++ b/src/input/plugins/QobuzTrackRequest.cxx @@ -93,7 +93,7 @@ QobuzTrackRequest::~QobuzTrackRequest() noexcept std::unique_ptr QobuzTrackRequest::MakeParser(unsigned status, - std::multimap &&headers) + Curl::Headers &&headers) { if (status != 200) return std::make_unique(status, headers); diff --git a/src/input/plugins/QobuzTrackRequest.hxx b/src/input/plugins/QobuzTrackRequest.hxx index 9de1890b6..a16ce760b 100644 --- a/src/input/plugins/QobuzTrackRequest.hxx +++ b/src/input/plugins/QobuzTrackRequest.hxx @@ -56,7 +56,7 @@ public: private: /* virtual methods from DelegateCurlResponseHandler */ std::unique_ptr MakeParser(unsigned status, - std::multimap &&headers) override; + Curl::Headers &&headers) override; void FinishParser(std::unique_ptr p) override; /* virtual methods from CurlResponseHandler */ diff --git a/src/lib/curl/Adapter.hxx b/src/lib/curl/Adapter.hxx index 1d26f46e6..fc4c946c3 100644 --- a/src/lib/curl/Adapter.hxx +++ b/src/lib/curl/Adapter.hxx @@ -1,5 +1,5 @@ /* - * Copyright 2008-2021 Max Kellermann + * Copyright 2008-2022 Max Kellermann * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,14 +27,13 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CURL_ADAPTER_HXX -#define CURL_ADAPTER_HXX +#pragma once + +#include "Headers.hxx" #include #include -#include -#include struct StringView; class CurlEasy; @@ -45,7 +44,7 @@ class CurlResponseHandlerAdapter { CurlResponseHandler &handler; - std::multimap headers; + Curl::Headers headers; /** error message provided by libcurl */ char error_buffer[CURL_ERROR_SIZE]; @@ -83,5 +82,3 @@ private: std::size_t size, std::size_t nmemb, void *stream) noexcept; }; - -#endif diff --git a/src/lib/curl/Delegate.cxx b/src/lib/curl/Delegate.cxx index a16793ed2..b6b6dc507 100644 --- a/src/lib/curl/Delegate.cxx +++ b/src/lib/curl/Delegate.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 Max Kellermann + * Copyright 2008-2022 Max Kellermann * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,8 +34,7 @@ #include void -DelegateCurlResponseHandler::OnHeaders(unsigned status, - std::multimap &&headers) +DelegateCurlResponseHandler::OnHeaders(unsigned status, Curl::Headers &&headers) { parser = MakeParser(status, std::move(headers)); assert(parser); diff --git a/src/lib/curl/Delegate.hxx b/src/lib/curl/Delegate.hxx index fe6a65f35..95c8576ce 100644 --- a/src/lib/curl/Delegate.hxx +++ b/src/lib/curl/Delegate.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 Max Kellermann + * Copyright 2008-2022 Max Kellermann * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,8 +27,7 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CURL_DELEGATE_HXX -#define CURL_DELEGATE_HXX +#pragma once #include "Handler.hxx" @@ -53,7 +52,7 @@ protected: * CurlResponseParser::OnError()). */ virtual std::unique_ptr MakeParser(unsigned status, - std::multimap &&headers) = 0; + Curl::Headers &&headers) = 0; /** * The parser has finished parsing the response body. This @@ -64,10 +63,7 @@ protected: virtual void FinishParser(std::unique_ptr p) = 0; public: - void OnHeaders(unsigned status, - std::multimap &&headers) final; + void OnHeaders(unsigned status, Curl::Headers &&headers) final; void OnData(ConstBuffer data) final; void OnEnd() final; }; - -#endif diff --git a/src/lib/curl/Form.cxx b/src/lib/curl/Form.cxx index 5b668ec46..5f45fdb56 100644 --- a/src/lib/curl/Form.cxx +++ b/src/lib/curl/Form.cxx @@ -31,8 +31,7 @@ #include "String.hxx" std::string -EncodeForm(CURL *curl, - const std::multimap &fields) noexcept +EncodeForm(CURL *curl, const Curl::Headers &fields) noexcept { std::string result; diff --git a/src/lib/curl/Form.hxx b/src/lib/curl/Form.hxx index 8c045ac22..1545d3e7d 100644 --- a/src/lib/curl/Form.hxx +++ b/src/lib/curl/Form.hxx @@ -30,17 +30,17 @@ #ifndef CURL_FORM_HXX #define CURL_FORM_HXX +#include "Headers.hxx" + #include #include -#include /** * Encode the given map of form fields to a * "application/x-www-form-urlencoded" string. */ std::string -EncodeForm(CURL *curl, - const std::multimap &fields) noexcept; +EncodeForm(CURL *curl, const Curl::Headers &fields) noexcept; #endif diff --git a/src/lib/curl/Handler.hxx b/src/lib/curl/Handler.hxx index 14a928a80..c0bdeced1 100644 --- a/src/lib/curl/Handler.hxx +++ b/src/lib/curl/Handler.hxx @@ -27,14 +27,12 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CURL_HANDLER_HXX -#define CURL_HANDLER_HXX +#pragma once +#include "Headers.hxx" #include "util/ConstBuffer.hxx" #include -#include -#include /** * Asynchronous response handler for a #CurlRequest. @@ -53,8 +51,7 @@ public: /** * Status line and headers have been received. */ - virtual void OnHeaders(unsigned status, - std::multimap &&headers) = 0; + virtual void OnHeaders(unsigned status, Curl::Headers &&headers) = 0; /** * Response body data has been received. @@ -75,5 +72,3 @@ public: */ virtual void OnError(std::exception_ptr e) noexcept = 0; }; - -#endif diff --git a/src/lib/curl/Headers.hxx b/src/lib/curl/Headers.hxx new file mode 100644 index 000000000..7ff04a6e4 --- /dev/null +++ b/src/lib/curl/Headers.hxx @@ -0,0 +1,42 @@ +/* + * Copyright 2020-2021 CM4all GmbH + * All rights reserved. + * + * author: Max Kellermann + * + * 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. + */ + +#pragma once + +#include +#include + +namespace Curl { + +using Headers = std::multimap; + +} // namespace Curl diff --git a/src/lib/upnp/Discovery.cxx b/src/lib/upnp/Discovery.cxx index 7bd8b8d90..e224b28bd 100644 --- a/src/lib/upnp/Discovery.cxx +++ b/src/lib/upnp/Discovery.cxx @@ -55,7 +55,7 @@ UPnPDeviceDirectory::Downloader::Destroy() noexcept void UPnPDeviceDirectory::Downloader::OnHeaders(unsigned status, - std::multimap &&) + Curl::Headers &&) { if (status != 200) { Destroy(); diff --git a/src/lib/upnp/Discovery.hxx b/src/lib/upnp/Discovery.hxx index 3391148dd..8052b1a31 100644 --- a/src/lib/upnp/Discovery.hxx +++ b/src/lib/upnp/Discovery.hxx @@ -113,8 +113,7 @@ class UPnPDeviceDirectory final : UpnpCallback { } /* virtual methods from CurlResponseHandler */ - void OnHeaders(unsigned status, - std::multimap &&headers) override; + void OnHeaders(unsigned status, Curl::Headers &&headers) override; void OnData(ConstBuffer data) override; void OnEnd() override; void OnError(std::exception_ptr e) noexcept override; diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx index d6f1a932d..4b5b84553 100644 --- a/src/storage/plugins/CurlStorage.cxx +++ b/src/storage/plugins/CurlStorage.cxx @@ -227,7 +227,7 @@ IsXmlContentType(const char *content_type) noexcept gcc_pure static bool -IsXmlContentType(const std::multimap &headers) noexcept +IsXmlContentType(const Curl::Headers &headers) noexcept { auto i = headers.find("content-type"); return i != headers.end() && IsXmlContentType(i->second.c_str()); @@ -297,8 +297,7 @@ private: } /* virtual methods from CurlResponseHandler */ - void OnHeaders(unsigned status, - std::multimap &&headers) final { + void OnHeaders(unsigned status, Curl::Headers &&headers) final { if (status != 207) throw FormatRuntimeError("Status %d from WebDAV server; expected \"207 Multi-Status\"", status); diff --git a/test/RunCurl.cxx b/test/RunCurl.cxx index 9d4874eb0..7ae233054 100644 --- a/test/RunCurl.cxx +++ b/test/RunCurl.cxx @@ -41,8 +41,7 @@ public: } /* virtual methods from CurlResponseHandler */ - void OnHeaders(unsigned status, - std::multimap &&headers) override { + void OnHeaders(unsigned status, Curl::Headers &&headers) override { fprintf(stderr, "status: %u\n", status); for (const auto &i : headers) fprintf(stderr, "%s: %s\n", From b88d1e68209eb4beacd94dbd3557111c0e9513e9 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 4 Feb 2022 11:24:25 +0100 Subject: [PATCH 10/10] lib/curl/Headers: make the comparison type "transparent" --- src/lib/curl/Headers.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/curl/Headers.hxx b/src/lib/curl/Headers.hxx index 7ff04a6e4..2d7168411 100644 --- a/src/lib/curl/Headers.hxx +++ b/src/lib/curl/Headers.hxx @@ -37,6 +37,6 @@ namespace Curl { -using Headers = std::multimap; +using Headers = std::multimap>; } // namespace Curl