changeset 19747:36963988e4f8

lib-http: server: Implemented blocking response output stream.
author Stephan Bosch <stephan@rename-it.nl>
date Wed, 10 Feb 2016 22:30:22 +0100
parents 7527051eb56a
children b0ecdc6cb8c2
files src/lib-http/http-server-private.h src/lib-http/http-server-response.c src/lib-http/http-server.h
diffstat 3 files changed, 109 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-http/http-server-private.h	Wed Feb 10 22:25:07 2016 +0100
+++ b/src/lib-http/http-server-private.h	Wed Feb 10 22:30:22 2016 +0100
@@ -53,6 +53,8 @@
 	uoff_t payload_size, payload_offset;
 	struct ostream *payload_output;
 
+	struct ostream *blocking_output;
+
 	http_server_tunnel_callback_t tunnel_callback;
 	void *tunnel_context;
 
--- a/src/lib-http/http-server-response.c	Wed Feb 10 22:25:07 2016 +0100
+++ b/src/lib-http/http-server-response.c	Wed Feb 10 22:30:22 2016 +0100
@@ -125,6 +125,7 @@
 	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 @@
 	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_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 @@
 	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;
+}
--- a/src/lib-http/http-server.h	Wed Feb 10 22:25:07 2016 +0100
+++ b/src/lib-http/http-server.h	Wed Feb 10 22:30:22 2016 +0100
@@ -154,6 +154,10 @@
 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);