-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
schannel http2 unable to post large content #5177
Comments
If you redirect the output somewhere and get the progress meter displayed, can you see how far it gets before it stops? Have you figured out a specific size limit when the problem appears? Do you know if this happens to all/most HTTP/2 servers or just this/a few? |
|
particularly this time out happens https://github.com/curl/curl/blob/curl-7_69_1/lib/vtls/schannel.c#L1561 |
It seems winsock select() for write on non-block socket can return 0 and WSAGetLastError() == 0 ( just checked wsageetlasterror result then select returns 0). So i have made following changes and schannel starts to post large pieces properly: what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft);
if(what < 0) {
/* fatal error */
failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
*err = CURLE_SEND_ERROR;
written = -1;
break;
}
/* Non-Block socket may return 0 for select() write check
else if(0 == what) {
failf(conn->data, "schannel: timed out sending data "
"(bytes sent: %zd)", written);
*err = CURLE_OPERATION_TIMEDOUT;
written = -1;
break;
}
*/
/* socket is writable */
result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
len - written, &this_write);
if(result == CURLE_AGAIN)
continue;
else if(result != CURLE_OK) {
*err = result;
written = -1;
break;
} BTW gopther send buffer implementation also check only fatal error on select() for write: https://github.com/curl/curl/blob/curl-7_69_1/lib/gopher.c#L151 @bagder If you think it's appropriate change then i may create pull request. |
This should be correctly handled in our wrapper functions Curl_socket_check/Curl_select to make sure that our select calls stay cross-platform compatible (even though schannel of course is only available on Windows). I would like to take a look at this tomorrow.
Source: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select#remarks |
I find it highly unlikely that this is a select() issue. We use select with all TLS backends and all protocols so we would get this problem widely and frequently if it was. curl is used on Windows by many users very often after all. I rather suspect that this is a Schannel specific problem. Like perhaps it doesn't drain the TLS buffers correctly. |
This is what I was thinking too. But if it is a schannel specific problem, then it should happen regardless of HTTP/2. |
Some trace info:
curl -v --http2.0 -X POST -H "Expect:" -F "image=@large6MB.bin" "https://nghttp2.org/"
So as i mentioned earlier SOCKET_WRITABLE (while doing buffer send routing) was checked for zero only at schannel (gopher does only below zero check). And all Curl_socket_check(writefd) at connection routines treat 0 for nonblock as unfinished connection(non fatal state). May be select(writefd)==0 for nonblock sockets is a valid state? |
Perhaps, but HTTP/2 creates a pretty unique pattern of use with incoming/outgoing packages that is quite different than HTTP/1, so we've seen several issues in the past only trigger with HTTP/2. |
Quick question: @ajax16384 why are you talking about non-blocking sockets here? My understanding is that curl is using blocking socket operations with |
@mback2k singleipconnect marks socket with curlx_nonblock as nonblock ( https://github.com/curl/curl/blob/curl-7_69_1/lib/connect.c#L1205 ). That's why swrite-send can fail with WSAEWOULDBLOCK and return CURLE_AGAIN wrom Curl_write_*, so caller may wait and retry operation. |
Sorry, I am unable to dive deeper into this quickly at the moment, because I have never build curl with HTTP/2 support. Maybe @jay or @MarcelRaad can take a look at this and reproduce the issue? |
curl is using non-blocking sockets to never risk a blocking network call |
We don't have decryption for schannel so we can't see the HTTP/2 in wireshark. Schannel decryption involves getting the master key from somewhere in the OS memory. I've read it's possible but it looks time consuming. I don't have a debugging setup in Windows 10 to reproduce what was reported, maybe Marcel does. My guess is it's actually timing out. The reporter could print the timeout value passed to select before the call and GetTickCount() before and after to see if it's actually timing out. |
@jay you do not need to involve decryption analysis cause bug happens at encryption state:
as of possible timeout - i guess it's not in this case cause: a) -w "@curl-format.txt"
and fault request shows: b) SOCKET_WRITABLE checks socket with timeleft==0, (in both http1.1 and http2 variants). So nonblock socket immediatly return it's state. |
Ok. It seems to me technically it is timing out though. select is supposed to return the ready sockets even if 0 timeout (AFAIK). So there is no ready socket and it times out immediately. This is probably a race condition like #1410 which is why you don't see the server reply. We could probably improve on this in schannel. I'm playing around with making the schannel send not block on sending a full record. That requires that the function be called again with the same parameters but we have a similar situation with OpenSSL SSL_write so I'm thinking it should work.. |
Could this error be related? 8843678#comments I do not get the warning/error then I compile curl using autotools/mingw, but the CMake build on AppVeyor started to fail after that commit. |
I did this
curl builded with schannel only ssl backend + http2
trying to post large content through http2
small.bin - 4bytes
large.bin - 550400bytes
curl.exe -v --http2 -X POST -F "image=@small.bin" "https://nghttp2.org/"
curl.exe -v --http2 -X POST -F "image=@large.bin" "https://nghttp2.org/"
small one produces sane answer
large one unable to complete request
if i try curl compiled with openssl backend then large.bin produces right output
405 and nghttp2.org was taken as most simple example. Case can also be reproduced by unabling to POST valid large form through http2.
curl/libcurl version
curl 7.69.1 (x86_64-pc-win32) libcurl/7.69.1 Schannel zlib/1.2.8 libssh2/1.9.0 nghttp2/1.40.0
Release-Date: 2020-03-11
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS HTTP2 Kerberos Largefile NTLM SPNEGO SSL SSPI UnixSockets libz
operating system
Windows 10
The text was updated successfully, but these errors were encountered: