changeset 18002:4dc3c0cacd25

lib-http: client: Handle situation in which server sends response before request payload is fully sent.
author Stephan Bosch <stephan@rename-it.nl>
date Sat, 25 Oct 2014 01:38:43 +0300
parents cffa8349f167
children 37a3c6c001b7
files src/lib-http/http-client-connection.c
diffstat 1 files changed, 23 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-http/http-client-connection.c	Sat Oct 25 01:38:42 2014 +0300
+++ b/src/lib-http/http-client-connection.c	Sat Oct 25 01:38:43 2014 +0300
@@ -632,10 +632,9 @@
 		return;
 	}
 
-	// FIXME: handle somehow if server replies before request->input is at EOF
 	while ((ret=http_response_parse_next
 		(conn->http_parser, payload_type, &response, &error)) > 0) {
-		bool aborted;
+		bool aborted, early = FALSE;
 
 		if (req == NULL) {
 			/* server sent response without any requests in the wait list */
@@ -687,6 +686,16 @@
 			http_client_connection_debug(conn,
 				"Got unexpected %u response; ignoring", response.status);
 			continue;
+		} else 	if (!req->payload_sync &&
+			req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT) {
+			/* got early response from server while we're still sending request
+			   payload. we cannot recover from this reliably, so we stop sending
+			   payload and close the connection once the response is processed */
+			http_client_connection_debug(conn,
+				"Got early input from server; "
+				"request payload not completely sent (will close connection)");
+			o_stream_unset_flush_callback(conn->conn.output);
+			conn->output_broken = early = TRUE;
 		}
 
 		http_client_connection_debug(conn,
@@ -710,6 +719,18 @@
 		if (!aborted) {
 			bool handled = FALSE;
 
+			/* response cannot be 2xx if request payload was not completely sent
+			 */
+			if (early && response.status / 100 == 2) {
+				http_client_request_error(req,
+					HTTP_CLIENT_REQUEST_ERROR_BAD_RESPONSE,
+					"Server responded with success response "
+					"before all payload was sent");
+				http_client_request_unref(&req);
+				http_client_connection_close(&conn);
+				return;
+			} 
+
 			/* don't redirect/retry if we're sending data in small
 			   blocks via http_client_request_send_payload()
 			   and we're not waiting for 100 continue */