Mercurial > dovecot > core-2.2
changeset 17882:77c4b78a4fa2
lib-http: Fixed detecting disconnection when ioloop is running only intermittently.
This fix only applies to ioloops created and run by lib-http itself.
author | Stephan Bosch <stephan@rename-it.nl> |
---|---|
date | Sat, 04 Oct 2014 17:32:48 +0300 |
parents | 4f175c27bea5 |
children | 95ac50948e39 |
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, 62 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-http/http-client-connection.c Sat Oct 04 17:32:48 2014 +0300 +++ b/src/lib-http/http-client-connection.c Sat Oct 04 17:32:48 2014 +0300 @@ -58,23 +58,6 @@ return pending_count; } -bool http_client_connection_is_ready(struct http_client_connection *conn) -{ - if (conn->in_req_callback) { - /* this can happen when a nested ioloop is created inside request - callback. we currently don't reuse connections that are occupied - this way, but theoretically we could, although that would add - quite a bit of complexity. - */ - return FALSE; - } - - return (conn->connected && !conn->output_locked && - !conn->close_indicated && !conn->tunneling && - http_client_connection_count_pending(conn) < - conn->client->set.max_pipelined_requests); -} - bool http_client_connection_is_idle(struct http_client_connection *conn) { return (conn->to_idle != NULL); @@ -174,6 +157,48 @@ http_client_connection_unref(_conn); } +bool http_client_connection_is_ready(struct http_client_connection *conn) +{ + int ret; + + if (conn->in_req_callback) { + /* this can happen when a nested ioloop is created inside request + callback. we currently don't reuse connections that are occupied + this way, but theoretically we could, although that would add + quite a bit of complexity. + */ + return FALSE; + } + + if (!conn->connected || conn->output_locked || + conn->close_indicated || conn->tunneling || + http_client_connection_count_pending(conn) >= + conn->client->set.max_pipelined_requests) + return FALSE; + + if (conn->last_ioloop != NULL && conn->last_ioloop != current_ioloop) { + conn->last_ioloop = current_ioloop; + /* Active ioloop is different from what we saw earlier; + we may have missed a disconnection event on this connection. + Verify status by reading from connection. */ + if ((ret=i_stream_read(conn->conn.input)) < 0) { + int stream_errno = conn->conn.input->stream_errno; + + i_assert(ret != -2); + i_assert(conn->conn.input->stream_errno != 0 || conn->conn.input->eof); + http_client_connection_abort_temp_error(&conn, + HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST, + t_strdup_printf("Connection lost: read(%s) failed: %s", + i_stream_get_name(conn->conn.input), + stream_errno != 0 ? + i_stream_get_error(conn->conn.input) : + "EOF")); + return FALSE; + } + } + return TRUE; +} + static void http_client_connection_idle_timeout(struct http_client_connection *conn) { @@ -802,6 +827,7 @@ { /* connected */ conn->connected = TRUE; + conn->last_ioloop = current_ioloop; if (conn->to_connect != NULL && (conn->ssl_iostream == NULL || ssl_iostream_is_handshaked(conn->ssl_iostream)))
--- a/src/lib-http/http-client-private.h Sat Oct 04 17:32:48 2014 +0300 +++ b/src/lib-http/http-client-private.h Sat Oct 04 17:32:48 2014 +0300 @@ -131,6 +131,7 @@ struct http_client_request *pending_request; struct istream *incoming_payload; struct io *io_req_payload; + struct ioloop *last_ioloop; /* requests that have been sent, waiting for response */ ARRAY_TYPE(http_client_request) request_wait_list;
--- a/src/lib-http/http-client-request.c Sat Oct 04 17:32:48 2014 +0300 +++ b/src/lib-http/http-client-request.c Sat Oct 04 17:32:48 2014 +0300 @@ -792,21 +792,27 @@ o_stream_get_name(output), o_stream_get_error(output)); ret = -1; - } - - http_client_request_debug(req, "Sent header"); + } else { + http_client_request_debug(req, "Sent header"); - if (ret >= 0 && req->payload_output != NULL) { - if (!req->payload_sync) { - if (http_client_request_send_more(req, error_r) < 0) - ret = -1; + if (req->payload_output != NULL) { + if (!req->payload_sync) { + if (http_client_request_send_more(req, error_r) < 0) + ret = -1; + } else { + http_client_request_debug(req, "Waiting for 100-continue"); + conn->output_locked = TRUE; + } } else { - http_client_request_debug(req, "Waiting for 100-continue"); - conn->output_locked = TRUE; + req->state = HTTP_REQUEST_STATE_WAITING; + conn->output_locked = FALSE; } - } else { - req->state = HTTP_REQUEST_STATE_WAITING; - conn->output_locked = FALSE; + if (ret >= 0 && o_stream_flush(output) < 0) { + *error_r = t_strdup_printf("flush(%s) failed: %s", + o_stream_get_name(output), + o_stream_get_error(output)); + ret = -1; + } } o_stream_uncork(output); return ret;