cURL / Mailing Lists / curl-library / Single Mail


[PATCH 3/7] pipelining: Keep bundle when closing broken pipe.

From: Carlo Wood <>
Date: Thu, 6 Nov 2014 03:03:17 +0100

If a request on a pipe times out, it breaks that pipe: the
connection needs to be closed. However, when doing http pipelining
we really don't want to delete the bundle and forget that this
server can do pipelining because that results in a separate connection
for every handle in the pipeline that didn't timeout yet, plus one
for every handle that is added until we receive new headers from the
server again, potentially a lot.

The user application could battle this a little bit by holding back
on adding new requests when it sees a timeout, until it saw a reply
again from the server - but that is an extra burden on the user
application that is unnecessary. Besides, that doesn't guarantee that
multiple connections won't formed due to requests already in the
pipe that didn't timeout yet (i.e. because they were added later than
the one that did).

Although theoretically this is still a leak of the bundle (though note
that before this series of commits it was ALREADY leaking), in practice
a new request WILL*) be added and the bundle will be reused without any
trace of a leak.
*) After all, we're talking about a pipelining server here :p.

 lib/multi.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
diff --git a/lib/multi.c b/lib/multi.c
index add396d..fde54fa 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -1646,15 +1646,31 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       if(data->easy_conn) {
         CURLcode res;
+        struct connectbundle *bundle;
+        bool keep_bundle;
         /* Remove ourselves from the receive pipeline, if we are there. */
         Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
         /* Check if we can move pending requests to send pipe */
+        /* If we're doing pipelining and this connection timed out then we do
+           not want Curl_done -> Curl_disconnect -> Curl_conncache_remove_conn
+           to remove the bundle: we need to remember that this server is
+           capable of pipelining. */
+        bundle = data->easy_conn->bundle;
+        keep_bundle = (bundle->server_supports_pipelining &&
+                       data->result == CURLE_OPERATION_TIMEDOUT);
+        if(keep_bundle)
+          ++bundle->num_connections;
         /* post-transfer command */
         res = Curl_done(&data->easy_conn, data->result, FALSE);
+        /* Restore num_connections to its original value. */
+        if(keep_bundle)
+          --bundle->num_connections;
         /* allow a previously set error code take precedence */
           data->result = res;
List admin:
Received on 2014-11-06