Mercurial > dovecot > core-2.2
changeset 19812:899c7a0345dd
doveadm-http: Handle istreams correctly
Based on patch by Aki Tuomi
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Sat, 20 Feb 2016 23:16:52 +0200 |
parents | 13fdf8e6c7a3 |
children | 7e9b5db56a85 |
files | src/doveadm/client-connection-http.c |
diffstat | 1 files changed, 39 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/src/doveadm/client-connection-http.c Wed Feb 17 10:24:24 2016 +0200 +++ b/src/doveadm/client-connection-http.c Sat Feb 20 23:16:52 2016 +0200 @@ -41,6 +41,7 @@ struct json_parser *json_parser; const struct doveadm_cmd_ver2 *cmd; struct doveadm_cmd_param *cmd_param; + struct ioloop *ioloop; ARRAY_TYPE(doveadm_cmd_param_arr_t) pargv; int method_err; char *method_id; @@ -53,6 +54,7 @@ JSON_STATE_COMMAND_PARAMETERS, JSON_STATE_COMMAND_PARAMETER_KEY, JSON_STATE_COMMAND_PARAMETER_VALUE, + JSON_STATE_COMMAND_PARAMETER_VALUE_ISTREAM_CONSUME, JSON_STATE_COMMAND_ID, JSON_STATE_COMMAND_DONE, JSON_STATE_DONE @@ -171,6 +173,24 @@ o_stream_nsend_str(conn->client.output,"\"]"); } +static int doveadm_http_server_istream_read(struct client_connection_http *conn) +{ + while (i_stream_read(conn->cmd_param->value.v_istream) > 0) + i_stream_skip(conn->cmd_param->value.v_istream, i_stream_get_data_size(conn->cmd_param->value.v_istream)); + if (!conn->cmd_param->value.v_istream->eof) + return 0; + + if (conn->cmd_param->value.v_istream->stream_errno != 0) { + i_error("read(%s) failed: %s", + i_stream_get_name(conn->cmd_param->value.v_istream), + i_stream_get_error(conn->cmd_param->value.v_istream)); + conn->method_err = 400; + return -1; + } + return 1; +} + + /** * this is to ensure we can handle arrays and other special parameter types */ @@ -178,18 +198,24 @@ { int rc; const char *tmp; - if (conn->json_state == JSON_STATE_COMMAND_PARAMETER_VALUE) { + + if (conn->json_state == JSON_STATE_COMMAND_PARAMETER_VALUE_ISTREAM_CONSUME) { + rc = doveadm_http_server_istream_read(conn); + if (rc != 1) return rc; + conn->json_state = JSON_STATE_COMMAND_PARAMETER_KEY; + return json_parse_next(conn->json_parser, type, value); + } else if (conn->json_state == JSON_STATE_COMMAND_PARAMETER_VALUE) { if (conn->cmd_param->type == CMD_PARAM_ISTREAM) { if (conn->cmd_param->value_set == TRUE) return json_parse_next(conn->json_parser, type, value); struct istream* is[2] = {0}; rc = json_parse_next_stream(conn->json_parser, &is[0]); if (rc != 1) return rc; + conn->cmd_param->value.v_istream = i_stream_create_seekable_path(is, IO_BLOCK_SIZE, "/tmp/doveadm."); + i_stream_unref(&is[0]); conn->cmd_param->value_set = TRUE; - conn->cmd_param->value.v_istream = i_stream_create_seekable_path(is, IO_BLOCK_SIZE, "/tmp/doveadm."); - rc = json_parse_next(conn->json_parser, type, value); - conn->json_state = JSON_STATE_COMMAND_PARAMETER_KEY; - return rc; + conn->json_state = JSON_STATE_COMMAND_PARAMETER_VALUE_ISTREAM_CONSUME; + return doveadm_http_server_json_parse_next(conn, type, value); } rc = json_parse_next(conn->json_parser, type, value); if (rc != 1) return rc; @@ -459,6 +485,7 @@ } if (json_parser_deinit(&conn->json_parser, &error) != 0) { + // istream JSON parsing failures do not count as errors http_server_request_fail_close(conn->http_server_request, 400, "Invalid JSON input"); // FIXME: should be returned as error to client, not logged i_info("doveadm(%s): %s", i_stream_get_name(conn->client.input), error); @@ -612,10 +639,15 @@ i_info("doveadm(%s): error writing output: %s", net_ip2addr(&conn->client.remote_ip), o_stream_get_error(conn->client.output)); + o_stream_destroy(&conn->client.output); http_server_response_update_status(conn->http_response, 500, "Internal server error"); } else { - // read the response - http_server_response_set_payload(conn->http_response, iostream_temp_finish(&conn->client.output, IO_BLOCK_SIZE)); + // send the payload response + struct istream *is; + + is = iostream_temp_finish(&conn->client.output, IO_BLOCK_SIZE); + http_server_response_set_payload(conn->http_response, is); + i_stream_unref(&is); } } // submit response