request body support: unfinished version with read callback v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Tue, 05 Apr 2022 00:06:12 +0200
branchv_0
changeset 25 dbeae485a3fd
parent 24 4f96098f7c57
child 26 53c6f76603f6
request body support: unfinished version with read callback
src/HTTPClient.cpp
src/HTTPHandler.h
--- a/src/HTTPClient.cpp	Mon Apr 04 23:07:31 2022 +0200
+++ b/src/HTTPClient.cpp	Tue Apr 05 00:06:12 2022 +0200
@@ -32,6 +32,7 @@
 public:
 	CURL* curl;
 	char curlErrorBuffer[CURL_ERROR_SIZE];
+	std::stringstream requestBody;
 	std::stringstream responseBody;
 	std::stringstream responseHeaders;
 
@@ -93,8 +94,17 @@
 HTTPClient* HTTPClient::open() {
 	HTTPClient::HTTPClientImpl* impl = new HTTPClient::HTTPClientImpl(curl_easy_init());
 
+	typedef size_t(*CurlReadCallback)(char*, size_t, size_t, HTTPClient::HTTPClientImpl*);
 	typedef size_t(*CurlWriteCallback)(char*, size_t, size_t, HTTPClient::HTTPClientImpl*);
 
+	// set request body callback
+	curl_easy_setopt(impl->curl, CURLOPT_READDATA, impl);
+	curl_easy_setopt(impl->curl, CURLOPT_READFUNCTION, (CurlReadCallback)[](char* buffer, size_t size, size_t nmemb, HTTPClient::HTTPClientImpl * impl) {
+		size_t r = size * nmemb;
+		ssize_t bytesRead = impl->requestBody.readsome(buffer, r);
+		return (size_t) bytesRead;
+	});
+
 	// set response body callback
 	curl_easy_setopt(impl->curl, CURLOPT_WRITEDATA, impl);
 	curl_easy_setopt(impl->curl, CURLOPT_WRITEFUNCTION, (CurlWriteCallback)[](char* buffer, size_t size, size_t nmemb, HTTPClient::HTTPClientImpl * impl)->size_t {
@@ -156,6 +166,14 @@
 	for (size_t i = 0; i < request.headers.size(); i += 2) requestHeders.append(request.headers[i] + ": " + request.headers[i + 1]); // TODO: validate, no CR/LF...
 	curl_easy_setopt(impl->curl, CURLOPT_HTTPHEADER, requestHeders.getList());
 
+	// store request body
+	if (request.body.size()) {
+		impl->requestBody = std::stringstream(request.body);
+		curl_easy_setopt(impl->curl, CURLOPT_UPLOAD, 1L);
+		curl_easy_setopt(impl->curl, CURLOPT_EXPECT_100_TIMEOUT_MS, 0);
+	}
+
+
 	// clear the error buffer
 	impl->curlErrorBuffer[0] = 0;
 
--- a/src/HTTPHandler.h	Mon Apr 04 23:07:31 2022 +0200
+++ b/src/HTTPHandler.h	Tue Apr 05 00:06:12 2022 +0200
@@ -212,6 +212,8 @@
 		if (attributeName == L"id") requestId = value;
 		else if (attributeName == L"url") request.url = convertor.to_bytes(value);
 		else if (attributeName == L"method") request.method = parseMethod(value);
+		else if (attributeName == L"text") request.body = convertor.to_bytes(value);
+		else if (attributeName == L"data") request.body = "TODO: read binary data: " + convertor.to_bytes(value); // TODO: read hex/binary request body
 		else if (isHeaderAttribute(attributeName)) appendRequestHeader(fetchHeaderName(attributeName), value);
 		else throw std::invalid_argument("Unsupported attribute in the header relation: " + convertor.to_bytes(attributeName + L" = " + value));