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

@@ -46,7 +46,8 @@
CurlRequest::CurlRequest(CurlGlobal &_global, const char *url,
CurlResponseHandler &_handler)
:global(_global), handler(_handler)
:DeferredMonitor(_global.GetEventLoop()),
global(_global), handler(_handler)
{
error_buffer[0] = 0;
@@ -226,8 +227,11 @@ CurlRequest::DataReceived(const void *ptr, size_t received_size)
return CURL_WRITEFUNC_PAUSE;
} catch (...) {
state = State::CLOSED;
handler.OnError(std::current_exception());
return 0;
/* move the CurlResponseHandler::OnError() call into a
"safe" stack frame */
postponed_error = std::current_exception();
DeferredMonitor::Schedule();
return CURL_WRITEFUNC_PAUSE;
}
}
@@ -243,3 +247,11 @@ CurlRequest::WriteFunction(void *ptr, size_t size, size_t nmemb, void *stream)
return c.DataReceived(ptr, size);
}
void
CurlRequest::RunDeferred()
{
assert(postponed_error);
handler.OnError(postponed_error);
}