]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: http-client-request - Properly finish the payload output stream asynchronously.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Tue, 20 Mar 2018 19:42:17 +0000 (20:42 +0100)
committermartti.rannanjarvi <martti.rannanjarvi@open-xchange.com>
Sat, 18 Apr 2020 14:55:11 +0000 (14:55 +0000)
Payload output handling is finished only after the stream is finished and
flushed completely.

src/lib-http/http-client-private.h
src/lib-http/http-client-request.c

index 18a1613cd676c76a7521ffb6015729237b51ad5b..90aa8f9c62b25f9c08743afeb5a4bce936a5fcb5 100644 (file)
@@ -162,6 +162,7 @@ struct http_client_request {
        bool payload_sync_continue:1;
        bool payload_chunked:1;
        bool payload_wait:1;
+       bool payload_finished:1;
        bool payload_empty:1;
        bool urgent:1;
        bool submitted:1;
index 7760a90a7ed25d8b4217239ae81baf94215deb2f..a5e77ebac9d5220d23fad5c05cbd4542f0fc194e 100644 (file)
@@ -985,15 +985,41 @@ http_client_request_get_peer_addr(const struct http_client_request *req,
        }
 }
 
-static void
+static int
+http_client_request_flush_payload(struct http_client_request *req)
+{
+       struct http_client_connection *conn = req->conn;
+       int ret;
+
+       if (req->payload_output != conn->conn.output &&
+           (ret=o_stream_finish(req->payload_output)) <= 0) {
+               if (ret < 0)
+                       http_client_connection_handle_output_error(conn);
+               return ret;
+       }
+
+       return 1;
+}
+
+static int
 http_client_request_finish_payload_out(struct http_client_request *req)
 {
        struct http_client_connection *conn = req->conn;
+       int ret;
 
        i_assert(conn != NULL);
+       req->payload_finished = TRUE;
 
        /* drop payload output stream */
        if (req->payload_output != NULL) {
+               ret = http_client_request_flush_payload(req);
+               if (ret < 0)
+                       return -1;
+               if (ret == 0) {
+                       e_debug(req->event,
+                               "Not quite finished sending payload");
+                       return 0;
+               }
                o_stream_unref(&req->payload_output);
                req->payload_output = NULL;
        }
@@ -1015,6 +1041,7 @@ http_client_request_finish_payload_out(struct http_client_request *req)
 
        e_debug(req->event, "Finished sending%s payload",
                (req->state == HTTP_REQUEST_STATE_ABORTED ? " aborted" : ""));
+       return 1;
 }
 
 static int
@@ -1040,7 +1067,7 @@ http_client_request_continue_payload(struct http_client_request **_req,
        if (data == NULL) {
                req->payload_input = NULL;
                if (req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT)
-                       http_client_request_finish_payload_out(req);
+                       (void)http_client_request_finish_payload_out(req);
        } else { 
                req->payload_input = i_stream_create_from_data(data, size);
                i_stream_set_name(req->payload_input, "<HTTP request payload>");
@@ -1186,6 +1213,9 @@ int http_client_request_send_more(struct http_client_request *req,
        i_assert(req->payload_input != NULL);
        i_assert(req->payload_output != NULL);
 
+       if (req->payload_finished)
+               return http_client_request_finish_payload_out(req);
+
        io_remove(&conn->io_req_payload);
 
        /* chunked ostream needs to write to the parent stream's buffer */
@@ -1223,7 +1253,8 @@ int http_client_request_send_more(struct http_client_request *req,
                                io_loop_stop(req->client->ioloop);
                } else {
                        /* finished sending payload */
-                       http_client_request_finish_payload_out(req);
+                       if (http_client_request_finish_payload_out(req) < 0)
+                               return -1;
                }
                return 0;
        case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT: