- Igor Novoseltsev filed bug #2351645
authorDaniel Stenberg <daniel@haxx.se>
Wed, 3 Dec 2008 15:20:27 +0000 (15:20 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 3 Dec 2008 15:20:27 +0000 (15:20 +0000)
  (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.

CHANGES
RELEASE-NOTES
lib/multi.c
lib/url.c
lib/url.h

diff --git a/CHANGES b/CHANGES
index 67dd1d7..c052fc8 100644 (file)
--- 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)
index 41408de..c417765 100644 (file)
@@ -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)
index b82be62..ccccf7e 100644 (file)
@@ -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) {
+
+      /* 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) {
 
-      /* Curl_done() clears the conn->data field to lose the association
-         between the easy handle and the connection
+        /* Curl_done() clears the conn->data field to lose the association
+           between the easy handle and the connection
 
-         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);
+           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;
+        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
index 6bb3e3e..9037bf9 100644 (file)
--- 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 &&
index 229f408..8ca70a8 100644 (file)
--- 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);