Hi

I experienced a problem in conjunction with HTTP Post requests and keep-alive connections when the request body is being sent using the CURLOPT_READFUNCTION callback. The behaviour was that the keep-alive connection was droped by libcurl after a POST request that was answered by a 4xx error response from the server. The curl debug message read "HTTP error before end of send, stop sending" which suggests, that the reply from the server was sent before curl was aware the "request sending" was finished. This is indeed the case: Curl detects that all request data has been sent when the READFUNCTION returns '0', but this happens only after curl tries to read the response from the server, which is already available, since from the servers perspective the request is complete at this point.

Now this only happens if the Request is being sent with a content-length header, meaning not a chunked. Since the length of the request body is known, it could be set with CURLOPT_INFILESIZE, in which case curl knows when the the "request sending" is finished and there is no need to call the READFUNCTION again. While this works as expected. Strangly this does not work when CURLOPT_POSTFIELDSIZE is used instead.


So I'd propose 2 patches:
1) also respect CURLOPT_POSTFIELDSIZE as an information for the size of the request body, and therefore improve the detection when "request sending" is finished. 2) While uploading, call the READFUNCTION twice before trying to receive the response. So it's possible to signal the end of the request from inside the READFUNCTION (this might be a bit hacky and someone comes up with a better idea)


cheers,

Frank Meier
diff --git a/lib/transfer.c b/lib/transfer.c
index 42d38b5..96c2701 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -223,6 +223,11 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
 
     nread+=(int)strlen(endofline_native); /* for the added end of line */
   }
+  else if ( nread == 0 )
+  {
+    /* fread_func signaled transfer is finished -> mark as done */
+    data->req.upload_done = TRUE;
+  }
 #ifdef CURL_DOES_CONVERSIONS
   else if((data->set.prefer_ascii) && (!sending_http_headers)) {
     CURLcode result;
@@ -1074,6 +1079,14 @@ CURLcode Curl_readwrite(struct connectdata *conn,
     result = readwrite_upload(data, conn, k, &didwhat);
     if(result)
       return result;
+
+    /* If we are still sending call readwrite_upload() again to check if we got EOF */
+    if ( k->keepon & KEEP_SEND )
+    {
+      result = readwrite_upload(data, conn, k, &didwhat);
+      if(result)
+        return result;
+    }
   }
 
   k->now = Curl_tvnow();
diff --git a/lib/multi.c b/lib/multi.c
index fcef2e1..e6e72f9 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -403,6 +403,10 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
   data->state.conn_cache = &multi->conn_cache;
 
   data->state.infilesize = data->set.filesize;
+  if (data->state.infilesize == -1)
+  {
+    data->state.infilesize = data->set.postfieldsize;
+  }
 
   /* This adds the new entry at the 'end' of the doubly-linked circular
      list of SessionHandle structs to try and maintain a FIFO queue so
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to