From e1d8d185fa74752ba6807e415a9c82ebfdb2082c Mon Sep 17 00:00:00 2001 From: Stephan Bosch Date: Mon, 8 Feb 2016 22:47:30 +0100 Subject: [PATCH] lib-http: client: Fixed pipelining bug: client sometimes sent new request while still waiting for 100-continue. --- src/lib-http/http-client-connection.c | 18 ++++++++++-------- src/lib-http/http-client-private.h | 3 +-- src/lib-http/http-client-request.c | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/lib-http/http-client-connection.c b/src/lib-http/http-client-connection.c index 0947a2a234..3931c5cd52 100644 --- a/src/lib-http/http-client-connection.c +++ b/src/lib-http/http-client-connection.c @@ -369,7 +369,7 @@ http_client_connection_continue_timeout(struct http_client_connection *conn) array_count(&conn->request_wait_list)-1); req = req_idx[0]; - conn->payload_continue = TRUE; + req->payload_sync_continue = TRUE; if (http_client_request_send_more(req, &error) < 0) { http_client_connection_abort_temp_error(&conn, HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST, @@ -401,7 +401,7 @@ int http_client_connection_next_request(struct http_client_connection *conn) timeout_remove(&conn->to_idle); req->conn = conn; - conn->payload_continue = FALSE; + req->payload_sync_continue = FALSE; if (conn->peer->no_payload_sync) req->payload_sync = FALSE; @@ -742,7 +742,7 @@ static void http_client_connection_input(struct connection *_conn) user agent MAY ignore unexpected 1xx responses. */ if (req->payload_sync && response.status == 100) { - if (conn->payload_continue) { + if (req->payload_sync_continue) { http_client_connection_debug(conn, "Got 100-continue response after timeout"); continue; @@ -750,7 +750,7 @@ static void http_client_connection_input(struct connection *_conn) conn->peer->no_payload_sync = FALSE; conn->peer->seen_100_response = TRUE; - conn->payload_continue = TRUE; + req->payload_sync_continue = TRUE; http_client_connection_debug(conn, "Got expected 100-continue response"); @@ -792,8 +792,10 @@ static void http_client_connection_input(struct connection *_conn) timeval_diff_msecs(&req->sent_time, &req->submit_time)); /* make sure connection output is unlocked if 100-continue failed */ - if (req->payload_sync && !conn->payload_continue) - conn->output_locked = FALSE; + if (req->payload_sync && !req->payload_sync_continue) { + http_client_connection_debug(conn, "Unlocked output"); + conn->output_locked = FALSE; + } /* remove request from queue */ array_delete(&conn->request_wait_list, 0, 1); @@ -822,7 +824,7 @@ static void http_client_connection_input(struct connection *_conn) blocks via http_client_request_send_payload() and we're not waiting for 100 continue */ if (!req->payload_wait || - (req->payload_sync && !conn->payload_continue)) { + (req->payload_sync && !req->payload_sync_continue)) { /* failed Expect: */ if (response.status == 417 && req->payload_sync) { /* drop Expect: continue */ @@ -971,7 +973,7 @@ int http_client_connection_output(struct http_client_connection *conn) return 1; } - if (!req->payload_sync || conn->payload_continue) { + if (!req->payload_sync || req->payload_sync_continue) { if (http_client_request_send_more(req, &error) < 0) { http_client_connection_abort_temp_error(&conn, HTTP_CLIENT_REQUEST_ERROR_CONNECTION_LOST, diff --git a/src/lib-http/http-client-private.h b/src/lib-http/http-client-private.h index 5fb3916343..67658153f6 100644 --- a/src/lib-http/http-client-private.h +++ b/src/lib-http/http-client-private.h @@ -115,6 +115,7 @@ struct http_client_request { unsigned int have_hdr_user_agent:1; unsigned int payload_sync:1; + unsigned int payload_sync_continue:1; unsigned int payload_chunked:1; unsigned int payload_wait:1; unsigned int urgent:1; @@ -160,8 +161,6 @@ struct http_client_connection { 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) */ }; diff --git a/src/lib-http/http-client-request.c b/src/lib-http/http-client-request.c index e8f3b64d3d..c1bc49e532 100644 --- a/src/lib-http/http-client-request.c +++ b/src/lib-http/http-client-request.c @@ -1239,7 +1239,7 @@ bool http_client_request_try_retry(struct http_client_request *req) 100 continue (there's no way to rewind the payload for a retry) */ if (req->payload_wait && - (!req->payload_sync || req->conn->payload_continue)) + (!req->payload_sync || req->payload_sync_continue)) return FALSE; /* limit the number of attempts for each request */ if (req->attempts+1 >= req->client->set.max_attempts)