From 1f312b2e42714ee80bec75a59662c448a8db1ed4 Mon Sep 17 00:00:00 2001
From: Max Kellermann <mk@cm4all.com>
Date: Fri, 11 Dec 2020 14:13:53 +0100
Subject: [PATCH] curl/Handler: disallow OnData() to throw

This eliminates some complexity from class CurlRequest.
---
 src/lib/curl/Handler.hxx |  2 +-
 src/lib/curl/Request.cxx | 19 +------------------
 src/lib/curl/Request.hxx | 16 ----------------
 test/RunCurl.cxx         |  8 ++++++--
 4 files changed, 8 insertions(+), 37 deletions(-)

diff --git a/src/lib/curl/Handler.hxx b/src/lib/curl/Handler.hxx
index ad5001e11..1259c4b3a 100644
--- a/src/lib/curl/Handler.hxx
+++ b/src/lib/curl/Handler.hxx
@@ -59,7 +59,7 @@ public:
 	/**
 	 * Response body data has been received.
 	 *
-	 * May throw #Pause.
+	 * May throw #Pause (but nothing else).
 	 */
 	virtual void OnData(ConstBuffer<void> data) = 0;
 
diff --git a/src/lib/curl/Request.cxx b/src/lib/curl/Request.cxx
index 1f1c59940..d174fdb80 100644
--- a/src/lib/curl/Request.cxx
+++ b/src/lib/curl/Request.cxx
@@ -47,9 +47,7 @@
 
 CurlRequest::CurlRequest(CurlGlobal &_global,
 			 CurlResponseHandler &_handler)
-	:global(_global), handler(_handler),
-	 postpone_error_event(global.GetEventLoop(),
-			      BIND_THIS_METHOD(OnPostponeError))
+	:global(_global), handler(_handler)
 {
 	error_buffer[0] = 0;
 
@@ -243,13 +241,6 @@ CurlRequest::DataReceived(const void *ptr, size_t received_size) noexcept
 		return received_size;
 	} catch (CurlResponseHandler::Pause) {
 		return CURL_WRITEFUNC_PAUSE;
-	} catch (...) {
-		state = State::CLOSED;
-		/* move the CurlResponseHandler::OnError() call into a
-		   "safe" stack frame */
-		postponed_error = std::current_exception();
-		postpone_error_event.Schedule();
-		return CURL_WRITEFUNC_PAUSE;
 	}
 
 }
@@ -266,11 +257,3 @@ CurlRequest::WriteFunction(char *ptr, size_t size, size_t nmemb,
 
 	return c.DataReceived(ptr, size);
 }
-
-void
-CurlRequest::OnPostponeError() noexcept
-{
-	assert(postponed_error);
-
-	handler.OnError(postponed_error);
-}
diff --git a/src/lib/curl/Request.hxx b/src/lib/curl/Request.hxx
index abc2a46a7..654f3f179 100644
--- a/src/lib/curl/Request.hxx
+++ b/src/lib/curl/Request.hxx
@@ -31,11 +31,9 @@
 #define CURL_REQUEST_HXX
 
 #include "Easy.hxx"
-#include "event/DeferEvent.hxx"
 
 #include <map>
 #include <string>
-#include <exception>
 
 struct StringView;
 class CurlGlobal;
@@ -57,18 +55,6 @@ class CurlRequest final {
 
 	std::multimap<std::string, std::string> headers;
 
-	/**
-	 * An exception caught by DataReceived(), which will be
-	 * forwarded into a "safe" stack frame by
-	 * #postpone_error_event.  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;
-
-	DeferEvent postpone_error_event;
-
 	/** error message provided by libcurl */
 	char error_buffer[CURL_ERROR_SIZE];
 
@@ -167,8 +153,6 @@ private:
 
 	void HeaderFunction(StringView s) noexcept;
 
-	void OnPostponeError() noexcept;
-
 	/** called by curl when new data is available */
 	static size_t _HeaderFunction(char *ptr, size_t size, size_t nmemb,
 				      void *stream) noexcept;
diff --git a/test/RunCurl.cxx b/test/RunCurl.cxx
index f81e8097e..6f5ce1a1f 100644
--- a/test/RunCurl.cxx
+++ b/test/RunCurl.cxx
@@ -50,8 +50,12 @@ public:
 	}
 
 	void OnData(ConstBuffer<void> data) override {
-		if (fwrite(data.data, data.size, 1, stdout) != 1)
-			throw std::runtime_error("Failed to write");
+		try {
+			if (fwrite(data.data, data.size, 1, stdout) != 1)
+				throw std::runtime_error("Failed to write");
+		} catch (...) {
+			OnError(std::current_exception());
+		}
 	}
 
 	void OnEnd() override {