lib/curl/Request: move exception handling out of the WRITEFUNCTION

libcurl's WRITEFUNCTION is pretty fragile; if we destroy the CURL*
instance or even unregister it using curl_multi_remove_handle(),
libcurl will crash instantly.  But still we need to be able to handle
exceptions from inside the WRITEFUNCTION, and call
CurlResponseHandler::OnError(), which may destroy the whole thing.  As
a workaround, I use DeferredMonitor to postpone the OnError() call
into a stack frame which is allowed to destroy the request.
This commit is contained in:
Max Kellermann
2017-01-08 14:28:58 +01:00
parent 1bab6d0dd7
commit 4297a7b0a4
2 changed files with 31 additions and 4 deletions

View File

@@ -31,15 +31,17 @@
#define CURL_REQUEST_HXX
#include "Easy.hxx"
#include "event/DeferredMonitor.hxx"
#include <map>
#include <string>
#include <exception>
struct StringView;
class CurlGlobal;
class CurlResponseHandler;
class CurlRequest {
class CurlRequest final : DeferredMonitor {
CurlGlobal &global;
CurlResponseHandler &handler;
@@ -55,6 +57,16 @@ class CurlRequest {
std::multimap<std::string, std::string> headers;
/**
* An exception caught by DataReceived(), which will be
* forwarded into a "safe" stack frame by
* DeferredMonitor::RunDeferred(). This works around the
* problem that libcurl crashes if you call
* curl_multi_remove_handle() from within the WRITEFUNCTION
* (i.e. DataReceived()).
*/
std::exception_ptr postponed_error;
/** error message provided by libcurl */
char error_buffer[CURL_ERROR_SIZE];
@@ -129,6 +141,9 @@ private:
/** called by curl when new data is available */
static size_t WriteFunction(void *ptr, size_t size, size_t nmemb,
void *stream);
/* virtual methods from class DeferredMonitor */
void RunDeferred() override;
};
#endif