diff --git a/CHANGES b/CHANGES index 67dd1d73a..c052fc8bf 100644 --- a/CHANGES +++ b/CHANGES @@ -6,7 +6,12 @@ Changelog -Daniel Fandrich (3 Dec 2008) +Daniel Stenberg (3 Dec 2008) +- Igor Novoseltsev filed bug #2351645 + (http://curl.haxx.se/bug/view.cgi?id=2351645) that identified a problem with + the multi interface that occured if you removed an easy handle while in + progress and the handle was used in a HTTP pipeline. + - Pawel Kierski pointed out a mistake in the cookie code that could lead to a bad fclose() after a fatal error had occured. (http://curl.haxx.se/bug/view.cgi?id=2382219) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 41408de0c..c41776500 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -23,6 +23,7 @@ This release includes the following bugfixes: o removed the default use of "Pragma: no-cache" o fix SCP/SFTP busyloop by using a new libssh2 0.19 function o bad fclose() after a fatal error in cookie code + o curl_multi_remove_handle() when the handle was in use in a HTTP pipeline This release includes the following known bugs: @@ -32,6 +33,6 @@ This release would not have looked like this without help, code, reports and advice from friends like these: Yang Tse, Daniel Fandrich, Jim Meyering, Christian Krause, Andreas Wurf, - Markus Koetter, Josef Wolf, Vlad Grachov, Pawel Kierski + Markus Koetter, Josef Wolf, Vlad Grachov, Pawel Kierski, Igor Novoseltsev Thanks! (and sorry if I forgot to mention someone) diff --git a/lib/multi.c b/lib/multi.c index b82be6245..ccccf7e8f 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -620,22 +620,27 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, easy->easy_handle->dns.hostcachetype = HCACHE_NONE; } - /* we must call Curl_done() here (if we still "own it") so that we don't - leave a half-baked one around */ - if(easy->easy_conn && - (easy->easy_conn->data == easy->easy_handle)) { + if(easy->easy_conn) { - /* Curl_done() clears the conn->data field to lose the association - between the easy handle and the connection + /* we must call Curl_done() here (if we still "own it") so that we don't + leave a half-baked one around */ + if (easy->easy_conn->data == easy->easy_handle) { - Note that this ignores the return code simply because there's nothing - really useful to do with it anyway! */ - (void)Curl_done(&easy->easy_conn, easy->result, premature); + /* Curl_done() clears the conn->data field to lose the association + between the easy handle and the connection - if(easy->easy_conn) - /* the connection is still alive, set back the association to enable - the check below to trigger TRUE */ - easy->easy_conn->data = easy->easy_handle; + Note that this ignores the return code simply because there's + nothing really useful to do with it anyway! */ + (void)Curl_done(&easy->easy_conn, easy->result, premature); + + if(easy->easy_conn) + /* the connection is still alive, set back the association to enable + the check below to trigger TRUE */ + easy->easy_conn->data = easy->easy_handle; + } + else + /* Clear connection pipelines, if Curl_done above was not called */ + Curl_getoff_all_pipelines(easy->easy_handle, easy->easy_conn); } /* If this easy_handle was the last one in charge for one or more diff --git a/lib/url.c b/lib/url.c index 6bb3e3ee7..9037bf920 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2359,6 +2359,20 @@ int Curl_removeHandleFromPipeline(struct SessionHandle *handle, return 0; } +/* remove the specified connection from all (possible) pipelines and related + queues */ +void Curl_getoff_all_pipelines(struct SessionHandle *data, + struct connectdata *conn) +{ + if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && + conn->readchannel_inuse) + conn->readchannel_inuse = FALSE; + if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && + conn->writechannel_inuse) + conn->writechannel_inuse = FALSE; + Curl_removeHandleFromPipeline(data, conn->pend_pipe); +} + #if 0 /* this code is saved here as it is useful for debugging purposes */ static void Curl_printPipeline(struct curl_llist *pipeline) { @@ -4548,13 +4562,7 @@ CURLcode Curl_done(struct connectdata **connp, Curl_expire(data, 0); /* stop timer */ - if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && - conn->readchannel_inuse) - conn->readchannel_inuse = FALSE; - if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && - conn->writechannel_inuse) - conn->writechannel_inuse = FALSE; - Curl_removeHandleFromPipeline(data, conn->pend_pipe); + Curl_getoff_all_pipelines(data, conn); if(conn->bits.done || (conn->send_pipe->size + conn->recv_pipe->size != 0 && diff --git a/lib/url.h b/lib/url.h index 229f40866..8ca70a850 100644 --- a/lib/url.h +++ b/lib/url.h @@ -69,6 +69,10 @@ CURLcode Curl_addHandleToPipeline(struct SessionHandle *handle, struct curl_llist *pipeline); int Curl_removeHandleFromPipeline(struct SessionHandle *handle, struct curl_llist *pipeline); +/* remove the specified connection from all (possible) pipelines and related + queues */ +void Curl_getoff_all_pipelines(struct SessionHandle *data, + struct connectdata *conn); void Curl_close_connections(struct SessionHandle *data);