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:
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user