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