Mercurial > dovecot > core-2.2
changeset 18969:a08e79a3707f
lib-http: client: Fixed handling of request timeout.
It was inappropriately active when the client needed to take action.
This showed particularly with large payloads sent using
http_client_request_send_payload().
author | Stephan Bosch <stephan@rename-it.nl> |
---|---|
date | Tue, 18 Aug 2015 23:02:01 +0300 |
parents | 04be746494dc |
children | 9765b87823df |
files | src/lib-http/http-client-connection.c src/lib-http/http-client-private.h src/lib-http/http-client-request.c |
diffstat | 3 files changed, 55 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-http/http-client-connection.c Tue Aug 18 21:10:41 2015 +0300 +++ b/src/lib-http/http-client-connection.c Tue Aug 18 23:02:01 2015 +0300 @@ -266,6 +266,35 @@ msecs/1000, msecs%1000)); } +void http_client_connection_start_request_timeout( + struct http_client_connection *conn) +{ + unsigned int timeout_msecs = conn->client->set.request_timeout_msecs; + + if (timeout_msecs == 0) + ; + else if (conn->to_requests != NULL) + timeout_reset(conn->to_requests); + else { + conn->to_requests = timeout_add(timeout_msecs, + http_client_connection_request_timeout, conn); + } +} + +void http_client_connection_reset_request_timeout( + struct http_client_connection *conn) +{ + if (conn->to_requests != NULL) + timeout_reset(conn->to_requests); +} + +void http_client_connection_stop_request_timeout( + struct http_client_connection *conn) +{ + if (conn->to_requests != NULL) + timeout_remove(&conn->to_requests); +} + static void http_client_connection_continue_timeout(struct http_client_connection *conn) { @@ -316,14 +345,6 @@ if (conn->to_idle != NULL) timeout_remove(&conn->to_idle); - if (conn->client->set.request_timeout_msecs == 0) - ; - else if (conn->to_requests != NULL) - timeout_reset(conn->to_requests); - else { - conn->to_requests = timeout_add(conn->client->set.request_timeout_msecs, - http_client_connection_request_timeout, conn); - } req->conn = conn; conn->payload_continue = FALSE; if (conn->peer->no_payload_sync) @@ -489,8 +510,7 @@ io_remove(&conn->conn.io); /* we've received the request itself, and we can't reset the timeout during the payload reading. */ - if (conn->to_requests != NULL) - timeout_remove(&conn->to_requests); + http_client_connection_stop_request_timeout(conn); } conn->in_req_callback = TRUE; @@ -607,8 +627,9 @@ http_client_payload_finished(conn); finished++; } - if (conn->to_requests != NULL) - timeout_reset(conn->to_requests); + + /* we've seen activity from the server; reset request timeout */ + http_client_connection_reset_request_timeout(conn); /* get first waiting request */ reqs = array_get(&conn->request_wait_list, &count); @@ -786,8 +807,7 @@ payload_type = http_client_request_get_payload_type(req); } else { /* no more requests waiting for the connection */ - if (conn->to_requests != NULL) - timeout_remove(&conn->to_requests); + http_client_connection_stop_request_timeout(conn); req = NULL; payload_type = HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED; } @@ -839,8 +859,8 @@ const char *error; int ret; - if (conn->to_requests != NULL) - timeout_reset(conn->to_requests); + /* we've seen activity from the server; reset request timeout */ + http_client_connection_reset_request_timeout(conn); if ((ret = o_stream_flush(output)) <= 0) { if (ret < 0) {
--- a/src/lib-http/http-client-private.h Tue Aug 18 21:10:41 2015 +0300 +++ b/src/lib-http/http-client-private.h Tue Aug 18 23:02:01 2015 +0300 @@ -291,6 +291,12 @@ void http_client_connection_unref(struct http_client_connection **_conn); void http_client_connection_close(struct http_client_connection **_conn); int http_client_connection_output(struct http_client_connection *conn); +void http_client_connection_start_request_timeout( + struct http_client_connection *conn); +void http_client_connection_reset_request_timeout( + struct http_client_connection *conn); +void http_client_connection_stop_request_timeout( + struct http_client_connection *conn); unsigned int http_client_connection_count_pending(struct http_client_connection *conn); bool http_client_connection_is_ready(struct http_client_connection *conn); @@ -301,6 +307,7 @@ void http_client_connection_start_tunnel(struct http_client_connection **_conn, struct http_client_tunnel *tunnel); + unsigned int http_client_peer_addr_hash (const struct http_client_peer_addr *peer) ATTR_PURE; int http_client_peer_addr_cmp
--- a/src/lib-http/http-client-request.c Tue Aug 18 21:10:41 2015 +0300 +++ b/src/lib-http/http-client-request.c Tue Aug 18 23:02:01 2015 +0300 @@ -536,7 +536,10 @@ /* advance state only when request didn't get aborted in the mean time */ if (req->state != HTTP_REQUEST_STATE_ABORTED) { i_assert(req->state == HTTP_REQUEST_STATE_PAYLOAD_OUT); + + /* we're now waiting for a response from the server */ req->state = HTTP_REQUEST_STATE_WAITING; + http_client_connection_start_request_timeout(req->conn); } /* release connection */ @@ -703,6 +706,7 @@ i_assert(ret >= 0); if (i_stream_is_eof(req->payload_input)) { + /* finished sending */ if (!req->payload_chunked && req->payload_input->v_offset - req->payload_offset != req->payload_size) { *error_r = t_strdup_printf("BUG: stream '%s' input size changed: " @@ -714,20 +718,26 @@ } if (req->payload_wait) { + /* this chunk of input is finished + (client needs to act; disable timeout) */ conn->output_locked = TRUE; + http_client_connection_stop_request_timeout(conn); if (req->client->ioloop != NULL) io_loop_stop(req->client->ioloop); } else { + /* finished sending payload */ http_client_request_finish_payload_out(req); } } else if (i_stream_get_data_size(req->payload_input) > 0) { - /* output is blocking */ + /* output is blocking (server needs to act; enable timeout) */ conn->output_locked = TRUE; + http_client_connection_start_request_timeout(conn); o_stream_set_flush_pending(output, TRUE); http_client_request_debug(req, "Partially sent payload"); } else { - /* input is blocking */ + /* input is blocking (client needs to act; disable timeout) */ conn->output_locked = TRUE; + http_client_connection_stop_request_timeout(conn); conn->io_req_payload = io_add_istream(req->payload_input, http_client_request_payload_input, req); }