changeset 22665:2cd3df7171e1

lib-http: client: Send empty payload (Content-Length: 0) for requests that normally expect a payload. This includes the standard POST and PUT methods. Others need to use the new http_client_request_set_payload_empty() function to force sending an empty payload.
author Stephan Bosch <stephan.bosch@dovecot.fi>
date Thu, 21 Sep 2017 00:38:33 +0200
parents fea53c2725c0
children 0b8c69533353
files src/lib-http/http-client-private.h src/lib-http/http-client-request.c src/lib-http/http-client.h
diffstat 3 files changed, 30 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-http/http-client-private.h	Thu Nov 09 12:24:16 2017 +0200
+++ b/src/lib-http/http-client-private.h	Thu Sep 21 00:38:33 2017 +0200
@@ -134,6 +134,7 @@
 	unsigned int payload_sync_continue:1;
 	unsigned int payload_chunked:1;
 	unsigned int payload_wait:1;
+	unsigned int payload_empty:1;
 	unsigned int urgent:1;
 	unsigned int submitted:1;
 	unsigned int listed:1;
--- a/src/lib-http/http-client-request.c	Thu Nov 09 12:24:16 2017 +0200
+++ b/src/lib-http/http-client-request.c	Thu Sep 21 00:38:33 2017 +0200
@@ -463,6 +463,11 @@
 	i_stream_unref(&input);
 }
 
+void http_client_request_set_payload_empty(struct http_client_request *req)
+{
+	req->payload_empty = TRUE;
+}
+
 void http_client_request_set_timeout_msecs(struct http_client_request *req,
 	unsigned int msecs)
 {
@@ -1161,20 +1166,25 @@
 	if (!req->have_hdr_expect && req->payload_sync) {
 		str_append(rtext, "Expect: 100-continue\r\n");
 	}
-	if (req->payload_input != NULL) {
-		if (req->payload_chunked) {
-			// FIXME: can't do this for a HTTP/1.0 server
-			if (!req->have_hdr_body_spec)
-				str_append(rtext, "Transfer-Encoding: chunked\r\n");
-			req->payload_output =
-				http_transfer_chunked_ostream_create(output);
-		} else {
-			/* send Content-Length if we have specified a payload,
-				 even if it's 0 bytes. */
-			if (!req->have_hdr_body_spec) {
-				str_printfa(rtext, "Content-Length: %"PRIuUOFF_T"\r\n",
-					req->payload_size);
-			}
+	if (req->payload_input != NULL && req->payload_chunked) {
+		// FIXME: can't do this for a HTTP/1.0 server
+		if (!req->have_hdr_body_spec)
+			str_append(rtext, "Transfer-Encoding: chunked\r\n");
+		req->payload_output =
+			http_transfer_chunked_ostream_create(output);
+	} else if (req->payload_input != NULL ||
+		req->payload_empty ||
+		strcasecmp(req->method, "POST") == 0 ||
+		strcasecmp(req->method, "PUT") == 0) {
+
+		/* send Content-Length if we have specified a payload
+		   or when one is normally expected, even if it's 0 bytes. */
+		i_assert(req->payload_input != NULL || req->payload_size == 0);
+		if (!req->have_hdr_body_spec) {
+			str_printfa(rtext, "Content-Length: %"PRIuUOFF_T"\r\n",
+				req->payload_size);
+		}
+		if (req->payload_input != NULL) {
 			req->payload_output = output;
 			o_stream_ref(output);
 		}
--- a/src/lib-http/http-client.h	Thu Nov 09 12:24:16 2017 +0200
+++ b/src/lib-http/http-client.h	Thu Sep 21 00:38:33 2017 +0200
@@ -311,6 +311,11 @@
  */
 void http_client_request_set_payload_data(struct http_client_request *req,
 				     const unsigned char *data, size_t size);
+/* send an empty payload for this request. This means that a Content-Length 
+   header is generated with zero size. Calling this function is not necessary
+   for the standard POST and PUT methods, for which this is done implicitly if
+   there is no payload set. */
+void http_client_request_set_payload_empty(struct http_client_request *req);
 
 /* set an absolute timeout for this request specifically, overriding the
    default client-wide absolute request timeout */