Skip to content

Commit

Permalink
lib-http: server: Implemented blocking response output stream.
Browse files Browse the repository at this point in the history
  • Loading branch information
stephanbosch authored and sirainen committed Feb 11, 2016
1 parent ee26330 commit 7c7117e
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/lib-http/http-server-private.h
Expand Up @@ -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;

Expand Down
103 changes: 103 additions & 0 deletions src/lib-http/http-server-response.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

Expand Down Expand Up @@ -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;
}
4 changes: 4 additions & 0 deletions src/lib-http/http-server.h
Expand Up @@ -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);
Expand Down

0 comments on commit 7c7117e

Please sign in to comment.