dovecot-2.2: lib-http: client: Fixed handling of requests aborte...
dovecot at dovecot.org
dovecot at dovecot.org
Fri Oct 24 22:39:47 UTC 2014
details: http://hg.dovecot.org/dovecot-2.2/rev/cffa8349f167
changeset: 18001:cffa8349f167
user: Stephan Bosch <stephan at rename-it.nl>
date: Sat Oct 25 01:38:42 2014 +0300
description:
lib-http: client: Fixed handling of requests aborted while still sending payload to server.
diffstat:
src/lib-http/http-client-connection.c | 79 +++++++++++++++++++++++++++-------
src/lib-http/http-client-private.h | 1 +
2 files changed, 63 insertions(+), 17 deletions(-)
diffs (200 lines):
diff -r 84b5e075c62c -r cffa8349f167 src/lib-http/http-client-connection.c
--- a/src/lib-http/http-client-connection.c Sat Oct 25 01:38:42 2014 +0300
+++ b/src/lib-http/http-client-connection.c Sat Oct 25 01:38:42 2014 +0300
@@ -165,7 +165,7 @@
return FALSE;
}
- if (!conn->connected || conn->output_locked ||
+ if (!conn->connected || conn->output_locked || conn->output_broken ||
conn->close_indicated || conn->tunneling ||
http_client_connection_count_pending(conn) >=
conn->client->set.max_pipelined_requests)
@@ -209,6 +209,9 @@
{
unsigned int timeout, count;
+ i_assert(!conn->close_indicated);
+ i_assert(!conn->output_broken);
+
if (conn->connected &&
array_is_created(&conn->request_wait_list) &&
array_count(&conn->request_wait_list) == 0 &&
@@ -312,6 +315,8 @@
if (req == NULL)
return 0;
+ i_assert(req->state == HTTP_REQUEST_STATE_QUEUED);
+
if (conn->to_idle != NULL)
timeout_remove(&conn->to_idle);
@@ -328,7 +333,6 @@
if (conn->peer->no_payload_sync)
req->payload_sync = FALSE;
- i_assert(req->state == HTTP_REQUEST_STATE_QUEUED);
array_append(&conn->request_wait_list, &req, 1);
http_client_request_ref(req);
@@ -552,11 +556,12 @@
struct http_client_connection *conn =
(struct http_client_connection *)_conn;
struct http_response response;
- struct http_client_request *const *req_idx;
+ struct http_client_request *const *reqs;
struct http_client_request *req = NULL;
+ enum http_response_payload_type payload_type;
+ unsigned int count;
int finished = 0, ret;
const char *error;
- enum http_response_payload_type payload_type;
i_assert(conn->incoming_payload == NULL);
@@ -608,9 +613,9 @@
timeout_reset(conn->to_requests);
/* get first waiting request */
- if (array_count(&conn->request_wait_list) > 0) {
- req_idx = array_idx(&conn->request_wait_list, 0);
- req = req_idx[0];
+ reqs = array_get(&conn->request_wait_list, &count);
+ if (count > 0) {
+ req = reqs[0];
/* determine whether to expect a response payload */
payload_type = http_client_request_get_payload_type(req);
@@ -619,6 +624,14 @@
payload_type = HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED;
}
+ /* drop connection with broken output if last possible input was
+ received */
+ if (conn->output_broken && (count == 0 ||
+ (count == 1 && req->state == HTTP_REQUEST_STATE_ABORTED))) {
+ http_client_connection_server_close(&conn);
+ return;
+ }
+
// FIXME: handle somehow if server replies before request->input is at EOF
while ((ret=http_response_parse_next
(conn->http_parser, payload_type, &response, &error)) > 0) {
@@ -648,11 +661,21 @@
"Got 100-continue response after timeout");
continue;
}
+
conn->peer->no_payload_sync = FALSE;
conn->peer->seen_100_response = TRUE;
conn->payload_continue = TRUE;
+
http_client_connection_debug(conn,
"Got expected 100-continue response");
+
+ if (req->state == HTTP_REQUEST_STATE_ABORTED) {
+ http_client_connection_debug(conn,
+ "Request aborted before sending payload was complete.");
+ http_client_connection_close(&conn);
+ return;
+ }
+
if (http_client_request_send_more(req, &error) < 0) {
http_client_connection_abort_temp_error(&conn,
HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST,
@@ -660,11 +683,11 @@
}
return;
} else if (response.status / 100 == 1) {
- /* ignore them for now */
+ /* ignore other 1xx for now */
http_client_connection_debug(conn,
"Got unexpected %u response; ignoring", response.status);
continue;
- }
+ }
http_client_connection_debug(conn,
"Got %u response for request %s (took %u ms + %u ms in queue)",
@@ -736,9 +759,9 @@
}
/* get next waiting request */
- if (array_count(&conn->request_wait_list) > 0) {
- req_idx = array_idx(&conn->request_wait_list, 0);
- req = req_idx[0];
+ reqs = array_get(&conn->request_wait_list, &count);
+ if (count > 0) {
+ req = reqs[0];
/* determine whether to expect a response payload */
payload_type = http_client_request_get_payload_type(req);
@@ -749,6 +772,14 @@
req = NULL;
payload_type = HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED;
}
+
+ /* drop connection with broken output if last possible input was
+ received */
+ if (conn->output_broken && (count == 0 ||
+ (count == 1 && req->state == HTTP_REQUEST_STATE_ABORTED))) {
+ http_client_connection_server_close(&conn);
+ return;
+ }
}
if (ret <= 0 &&
@@ -783,8 +814,9 @@
int http_client_connection_output(struct http_client_connection *conn)
{
- struct http_client_request *const *req_idx, *req;
+ struct http_client_request *const *reqs;
struct ostream *output = conn->conn.output;
+ unsigned int count;
const char *error;
int ret;
@@ -802,14 +834,27 @@
return ret;
}
+ i_assert(!conn->output_broken);
+
if (conn->ssl_iostream != NULL &&
!ssl_iostream_is_handshaked(conn->ssl_iostream))
return 1;
- if (array_count(&conn->request_wait_list) > 0 && conn->output_locked) {
- req_idx = array_idx(&conn->request_wait_list,
- array_count(&conn->request_wait_list)-1);
- req = req_idx[0];
+ reqs = array_get(&conn->request_wait_list, &count);
+ if (count > 0 && conn->output_locked) {
+ struct http_client_request *req = reqs[count-1];
+
+ if (req->state == HTTP_REQUEST_STATE_ABORTED) {
+ http_client_connection_debug(conn,
+ "Request aborted before sending payload was complete.");
+ if (count == 1) {
+ http_client_connection_close(&conn);
+ } else {
+ o_stream_unset_flush_callback(output);
+ conn->output_broken = TRUE;
+ }
+ return 1;
+ }
if (!req->payload_sync || conn->payload_continue) {
if (http_client_request_send_more(req, &error) < 0) {
diff -r 84b5e075c62c -r cffa8349f167 src/lib-http/http-client-private.h
--- a/src/lib-http/http-client-private.h Sat Oct 25 01:38:42 2014 +0300
+++ b/src/lib-http/http-client-private.h Sat Oct 25 01:38:42 2014 +0300
@@ -147,6 +147,7 @@
unsigned int closing:1;
unsigned int close_indicated:1;
unsigned int output_locked:1; /* output is locked; no pipelining */
+ unsigned int output_broken:1; /* output is broken; no more requests */
unsigned int payload_continue:1; /* received 100-continue for current
request */
unsigned int in_req_callback:1; /* performin request callback (busy) */
More information about the dovecot-cvs
mailing list