diff --git a/NEWS b/NEWS index 52aed4c63..7408df405 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,8 @@ ver 0.24 (not yet released) - GCC 10 or clang 11 (or newer) recommended ver 0.23.8 (not yet released) +* storage + - curl: fix crash if web server does not understand WebDAV ver 0.23.7 (2022/05/09) * database diff --git a/src/lib/curl/Adapter.cxx b/src/lib/curl/Adapter.cxx index 3beade3d0..f3c3c8489 100644 --- a/src/lib/curl/Adapter.cxx +++ b/src/lib/curl/Adapter.cxx @@ -85,6 +85,12 @@ CurlResponseHandlerAdapter::FinishBody() void CurlResponseHandlerAdapter::Done(CURLcode result) noexcept { + if (postponed_error) { + state = State::CLOSED; + handler.OnError(std::move(postponed_error)); + return; + } + try { if (result != CURLE_OK) { StripRight(error_buffer); @@ -174,6 +180,13 @@ CurlResponseHandlerAdapter::DataReceived(const void *ptr, return received_size; } catch (CurlResponseHandler::Pause) { return CURL_WRITEFUNC_PAUSE; + } catch (...) { + /* from inside this libCURL callback function, we + can't do much, so we remember the exception to be + handled later by Done(), and return 0, causing the + response to be aborted with CURLE_WRITE_ERROR */ + postponed_error = std::current_exception(); + return 0; } } diff --git a/src/lib/curl/Adapter.hxx b/src/lib/curl/Adapter.hxx index 40c174425..b49a95411 100644 --- a/src/lib/curl/Adapter.hxx +++ b/src/lib/curl/Adapter.hxx @@ -34,6 +34,7 @@ #include #include +#include #include class CurlEasy; @@ -46,6 +47,12 @@ class CurlResponseHandlerAdapter { Curl::Headers headers; + /** + * An exception caught from within the WriteFunction() which + * will later be handled by Done(). + */ + std::exception_ptr postponed_error; + /** error message provided by libcurl */ char error_buffer[CURL_ERROR_SIZE]; diff --git a/src/lib/curl/Handler.hxx b/src/lib/curl/Handler.hxx index eaad2a661..a338f2aa2 100644 --- a/src/lib/curl/Handler.hxx +++ b/src/lib/curl/Handler.hxx @@ -51,13 +51,19 @@ public: /** * Status line and headers have been received. + * + * Exceptions thrown by this method will be passed to + * OnError(), aborting the request. */ virtual void OnHeaders(unsigned status, Curl::Headers &&headers) = 0; /** * Response body data has been received. * - * May throw #Pause (but nothing else). + * May throw #Pause. + * + * Other exceptions thrown by this method will be passed to + * OnError(), aborting the request. */ virtual void OnData(std::span data) = 0;