]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: http-server-response - Properly finish the payload output stream asynchrono...
authorStephan Bosch <stephan.bosch@open-xchange.com>
Sat, 9 Nov 2019 12:31:52 +0000 (13:31 +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-server-private.h
src/lib-http/http-server-response.c

index afc25e5064f6c6c89876c30145d016e10e8d6b20..e939ab5051cdf3ceeb12792cd3fc3a3ee87ff077 100644 (file)
@@ -88,6 +88,7 @@ struct http_server_response {
 
        bool payload_chunked:1;
        bool payload_blocking:1;
+       bool payload_finished:1;
        bool payload_direct:1;
        bool payload_corked:1;
        bool submitted:1;
index b930bc753f011a306808591ce2d554037d68680b..242c534f80007d55487827fa0441e132f18925e7 100644 (file)
@@ -235,12 +235,40 @@ void http_server_response_submit_tunnel(struct http_server_response *resp,
        http_server_response_do_submit(resp);
 }
 
-static void
+static int
+http_server_response_flush_payload(struct http_server_response *resp)
+{
+       struct http_server_request *req = resp->request;
+       struct http_server_connection *conn = req->conn;
+       int ret;
+
+       if (resp->payload_output != conn->conn.output &&
+           (ret = o_stream_finish(resp->payload_output)) <= 0) {
+               if (ret < 0)
+                       http_server_connection_handle_output_error(conn);
+               return ret;
+       }
+
+       return 1;
+}
+
+static int
 http_server_response_finish_payload_out(struct http_server_response *resp)
 {
        struct http_server_connection *conn = resp->request->conn;
+       int ret;
+
+       resp->payload_finished = TRUE;
 
        if (resp->payload_output != NULL) {
+               ret = http_server_response_flush_payload(resp);
+               if (ret < 0)
+                       return -1;
+               if (ret == 0) {
+                       e_debug(resp->event,
+                               "Not quite finished sending payload");
+                       return 0;
+               }
                o_stream_unref(&resp->payload_output);
                resp->payload_output = NULL;
        }
@@ -260,6 +288,7 @@ http_server_response_finish_payload_out(struct http_server_response *resp)
 
        http_server_request_finished(resp->request);
        http_server_connection_unref(&conn);
+       return 1;
 }
 
 static int
@@ -338,7 +367,7 @@ http_server_response_output_payload(struct http_server_response **_resp,
        if (iov == NULL) {
                resp->payload_direct = FALSE;
                if (req->state == HTTP_SERVER_REQUEST_STATE_PAYLOAD_OUT)
-                       http_server_response_finish_payload_out(resp);
+                       (void)http_server_response_finish_payload_out(resp);
        } else {
                resp->payload_direct = TRUE;
                rpay.iov = i_new(struct const_iovec, iov_count);
@@ -492,6 +521,9 @@ int http_server_response_send_more(struct http_server_response *resp)
        i_assert(resp->payload_input != NULL);
        i_assert(resp->payload_output != NULL);
 
+       if (resp->payload_finished)
+               return http_server_response_finish_payload_out(resp);
+
        io_remove(&conn->io_resp_payload);
 
        /* Chunked ostream needs to write to the parent stream's buffer */
@@ -546,7 +578,8 @@ int http_server_response_send_more(struct http_server_response *resp)
 
        if (ret != 0) {
                /* Finished sending payload (or error) */
-               http_server_response_finish_payload_out(resp);
+               if (http_server_response_finish_payload_out(resp) < 0)
+                       return -1;
        }
        return ret < 0 ? -1 : 0;
 }