]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: server: Implemented blocking response output stream.
authorStephan Bosch <stephan@rename-it.nl>
Wed, 10 Feb 2016 21:30:22 +0000 (22:30 +0100)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 11 Feb 2016 10:00:42 +0000 (12:00 +0200)
src/lib-http/http-server-private.h
src/lib-http/http-server-response.c
src/lib-http/http-server.h

index e831aaeb050bb900d4f0b9b77565ecd748ff8f2f..65a0503972cb818c1b4c199a053be96fdceae22c 100644 (file)
@@ -53,6 +53,8 @@ struct http_server_response {
        uoff_t payload_size, payload_offset;
        struct ostream *payload_output;
 
+       struct ostream *blocking_output;
+
        http_server_tunnel_callback_t tunnel_callback;
        void *tunnel_context;
 
index 1599a8a84450429fdf3c3d6397845afa23e2bc4a..af4ed9bf61e6db6c8ef406acff2a271873ab8ded 100644 (file)
@@ -125,6 +125,7 @@ void http_server_response_set_payload(struct http_server_response *resp,
        int ret;
 
        i_assert(!resp->submitted);
+       i_assert(resp->blocking_output == NULL);
        i_assert(resp->payload_input == NULL);
 
        i_stream_ref(input);
@@ -411,6 +412,8 @@ int http_server_response_send_payload(struct http_server_response **_resp,
        struct http_server_response *resp = *_resp;
        struct const_iovec iov;
 
+       i_assert(resp->blocking_output == NULL);
+
        resp->payload_corked = TRUE;
 
        i_assert(data != NULL);
@@ -423,6 +426,10 @@ int http_server_response_send_payload(struct http_server_response **_resp,
 
 int http_server_response_finish_payload(struct http_server_response **_resp)
 {
+       struct http_server_response *resp = *_resp;
+
+       i_assert(resp->blocking_output == NULL);
+
        return http_server_response_output_payload(_resp, NULL, 0);
 }
 
@@ -664,3 +671,99 @@ int http_server_response_send(struct http_server_response *resp,
        i_free(errstr);
        return ret;
 }
+
+/*
+ * Payload output stream
+ */
+
+struct http_server_ostream {
+       struct ostream_private ostream;
+
+       struct http_server_response *resp;
+};
+
+static ssize_t
+http_server_ostream_sendv(struct ostream_private *stream,
+                   const struct const_iovec *iov, unsigned int iov_count)
+{
+       struct http_server_ostream *hsostream =
+               (struct http_server_ostream *)stream;
+       unsigned int i;
+       ssize_t ret;
+
+       if (http_server_response_output_payload
+               (&hsostream->resp, iov, iov_count) < 0) {
+               if (stream->parent->stream_errno != 0) {
+                       o_stream_copy_error_from_parent(stream);
+               } else {
+                       io_stream_set_error(&stream->iostream,
+                   "HTTP connection broke while sending payload");
+                       stream->ostream.stream_errno = EIO;
+               }
+               return -1;
+       }
+
+       ret = 0;
+       for (i = 0; i < iov_count; i++)
+               ret += iov[i].iov_len;
+       stream->ostream.offset += ret;
+       return ret;
+}
+
+static void http_server_ostream_close(struct iostream_private *stream,
+                                 bool close_parent ATTR_UNUSED)
+{
+       struct http_server_ostream *hsostream =
+               (struct http_server_ostream *)stream;
+       struct ostream_private *ostream = &hsostream->ostream;
+
+       if (hsostream->resp == NULL)
+               return;
+       hsostream->resp->blocking_output = NULL;
+
+       if (http_server_response_output_payload
+               (&hsostream->resp, NULL, 0) < 0) {
+               if (ostream->parent->stream_errno != 0) {
+                       o_stream_copy_error_from_parent(ostream);
+               } else {
+                       io_stream_set_error(&ostream->iostream,
+                   "HTTP connection broke while sending payload");
+                       ostream->ostream.stream_errno = EIO;
+               }
+       }
+       hsostream->resp = NULL;
+}
+
+static void http_server_ostream_destroy(struct iostream_private *stream)
+{
+       struct http_server_ostream *hsostream =
+               (struct http_server_ostream *)stream;
+
+       if (hsostream->resp != NULL) {
+               hsostream->resp->blocking_output = NULL;
+               http_server_response_abort_payload(&hsostream->resp);
+       }
+}
+
+struct ostream *
+http_server_response_get_payload_output(struct http_server_response *resp,
+       bool blocking)
+{
+       struct http_server_connection *conn = resp->request->conn;
+       struct http_server_ostream *hsostream;
+
+       i_assert(resp->payload_input == NULL);
+       i_assert(resp->blocking_output == NULL);
+
+       i_assert(blocking == TRUE); // FIXME: support non-blocking
+
+       hsostream = i_new(struct http_server_ostream, 1);
+       hsostream->ostream.sendv = http_server_ostream_sendv;
+       hsostream->ostream.iostream.close = http_server_ostream_close;
+       hsostream->ostream.iostream.destroy = http_server_ostream_destroy;
+       hsostream->resp = resp;
+
+       resp->blocking_output =
+               o_stream_create(&hsostream->ostream, conn->conn.output, -1);
+       return resp->blocking_output;
+}
index e88297e7770192237003aa95985160d1265d1c91..552d2c0da399dfb543c737250fba8dd81c9a552d 100644 (file)
@@ -154,6 +154,10 @@ void http_server_response_set_payload(struct http_server_response *resp,
 void http_server_response_set_payload_data(struct http_server_response *resp,
                                     const unsigned char *data, size_t size);
 
+struct ostream *
+http_server_response_get_payload_output(struct http_server_response *resp,
+       bool blocking);
+
 void http_server_response_add_auth(
        struct http_server_response *resp,
        const struct http_auth_challenge *chlng);