Improve upload_finished detection for HTTP requests.
We detect the end of an upload when libcurl informs us
that it is no longer interested in knowing if a socket
is writable (which it tells us cause we're doing the call
to select(), by means of a call to MultiHandle::socket_callback).
However, this does not *always* work.
The debug output might look like this:
[...initialization and first part of a TLS handshake...]
0x7f759f0ad700 CURL : select(55, {17, 39, 46, 47, 48, 49, 50, 51, 52, 54}, NULL, NULL, timeout = 1 ms) = 7
0x7f759f0ad700 CURLTR : curl_multi_socket_action((CURLM*)0x7f758c002920, 46, CURL_CSELECT_IN, <unfinished> <--- Calling curl_multi_socket_action (socket 46 is readable)
0x7f759f0ad700 CURLIO 0x13fce7b0 * SSLv3, TLS change cipher, Client hello (1):
0x7f759f0ad700 CURLIO 0x13fce7b0 S> 1 bytes
0x7f759f0ad700 CURLIO 0x13fce7b0 * SSLv3, TLS handshake, Finished (20):
0x7f759f0ad700 CURLIO 0x13fce7b0 S> 16 bytes
0x7f759f0ad700 CURLIO 0x13fce7b0 * SSL connection using AES256-SHA
0x7f759f0ad700 CURLIO 0x13fce7b0 * Server certificate:
0x7f759f0ad700 CURLIO 0x13fce7b0 * subject: C=US; ST=California; L=San Francisco; O=Linden Lab, Inc.; CN=*.agni.lindenlab.com; emailAddress=root@lindenlab.com
0x7f759f0ad700 CURLIO 0x13fce7b0 * start date: 2012-09-20 22:55:47 GMT
0x7f759f0ad700 CURLIO 0x13fce7b0 * expire date: 2015-09-20 22:55:47 GMT
0x7f759f0ad700 CURLIO 0x13fce7b0 * issuer: C=US; ST=California; L=San Francisco; O=Linden Lab, Inc.; OU=Linden Lab Certificate Authority; CN=Linden Lab Certificate Authority; emailAddress=ca@lindenlab.com
0x7f759f0ad700 CURLIO 0x13fce7b0 * SSL certificate verify ok.
0x7f759f0ad700 CURLIO 0x13fce7b0 * STATE: PROTOCONNECT => DO handle 0x7f758d62d810; (connection #2)
0x7f759f0ad700 CURLIO 0x13fce7b0 H< POST /cap/d67d4540-4504-b3d1-1d26-112010e88bd8 HTTP/1.1\r\nHost: sim10480.agni.lindenlab.com:12043\r\nAccept: */*\r\nAccept-Encoding: deflate, gzip\r\nContent-Type: application/llsd+xml\r\nX-SecondLife-UDP-Listen-Port: 32837\r\nConnection: keep-alive\r\nKeep-alive: 300\r\nContent-Length: 333\r\n\r\n
0x7f759f0ad700 CURLIO 0x13fce7b0 * STATE: DO => DO_DONE handle 0x7f758d62d810; (connection #2)
0x7f759f0ad700 CURL : Entering BufferedCurlEasyRequest::curlProgressCallback(0x13fce7b0, 0, 0, 333, 0) <=== THIS IS NEW: total to upload: 333 bytes, total uploaded: 0 bytes.
0x7f759f0ad700 CURLIO 0x13fce7b0 * STATE: DO_DONE => WAITPERFORM handle 0x7f758d62d810; (connection #2)
0x7f759f0ad700 CURL : Entering BufferedCurlEasyRequest::curlProgressCallback(0x13fce7b0, 0, 0, 333, 0)
0x7f759f0ad700 CURLIO 0x13fce7b0 * STATE: WAITPERFORM => PERFORM handle 0x7f758d62d810; (connection #2)
0x7f759f0ad700 CURL : Entering BufferedCurlEasyRequest::curlProgressCallback(0x13fce7b0, 0, 0, 333, 0)
0x7f759f0ad700 CURL : Entering BufferedCurlEasyRequest::curlProgressCallback(0x13fce7b0, 0, 0, 333, 0)
0x7f759f0ad700 CURL : Entering BufferedCurlEasyRequest::curlProgressCallback(0x13fce7b0, 0, 0, 333, 0)
0x7f759f0ad700 CURLTR : curl_easy_getinfo((CURL*)0x13fcf320, CURLINFO_PRIVATE, 0x7f759f0abdb0) = CURLE_OK
0x7f759f0ad700 CURL : Entering MultiHandle::socket_callback((CURL*)0x13fcf320, 46, CURL_POLL_INOUT, 0x7f758c001508, 0x7f758c2ce4e0) [CURLINFO_PRIVATE = 0x13fce7b0]
0x7f759f0ad700 CURL : CurlSocketInfo::set_action(CURL_POLL_IN --> CURL_POLL_INOUT) [0x13fce7b0] <=== WATING FOR WRITING BUT ALREADY WAITING FOR INPUT!
0x7f759f0ad700 CURL 0x13fce7b0 reset_lowspeed: mLowSpeedClock = 138530973390; mStalled = -1
0x7f759f0ad700 CURLTR : <continued> {11}) = 0 <--- Returning from curl_multi_socket_action
0x7f759f0ad700 CURL : select(58, {17, 39, 46, 47, 48, 49, 50, 51, 52, 54}, {36, 46, 57}, NULL, timeout = 756 ms) = 5
0x7f759f0ad700 CURLTR : curl_multi_socket_action((CURLM*)0x7f758c002920, 46, CURL_CSELECT_OUT, <unfinished> <=== SOCKET AVAILABLE FOR WRITING
0x7f759f0ad700 CURLIO 0x13fce7b0 * additional stuff not fine transfer.c:1037: 0 0
0x7f759f0ad700 CURLIO 0x13fce7b0 D< 333 bytes: "<llsd><map><key>folders</key><array><map><key>fetch_folders</key>...etc" <=== WRITING *ALL* DATA
0x7f759f0ad700 CURL : Entering BufferedCurlEasyRequest::curlProgressCallback(0x13fce7b0, 0, 0, 333, 333) <=== THIS IS NEW, DETECT END OF UPLOAD
0x7f759f0ad700 CURL 0x13fce7b0 upload_finished: mStalled set to Time_10ms (138530973390) + 6000 (60 seconds)
0x7f759f0ad700 CURL : Entering BufferedCurlEasyRequest::curlProgressCallback(0x13fce7b0, 0, 0, 333, 333)
0x7f759f0ad700 CURL : select(58, {17, 39, 46, 47, 50, 52, 54}, {36, 46, 57}, NULL, timeout = 0 ms) = 8
0x7f759f0ad700 CURLTR : curl_multi_socket_action((CURLM*)0x7f758c002920, 46, CURL_CSELECT_IN|CURL_CSELECT_OUT, <unfinished>
0x7f759f0ad700 CURLIO 0x13fce7b0 * HTTP 1.1 or later with persistent connection, pipelining supported
0x7f759f0ad700 CURLIO 0x13fce7b0 H> HTTP/1.1 200 OK\r\n
...and the server already replies without a call to MultiHandle::socket_callback between
writing and reading, because the socket was still (already) waiting for input anyway
(since it was waiting for the SSL/TLS handshake before in this case, but
it also happens when the data has to be written in more than one writes).
Using the progress callback however, we are able to detect the end of the upload right
after writing, anyway.