Skip to content
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

Proxy-level timeout as FIN is not handled as error #5992

Closed
TvdW opened this issue Sep 21, 2020 · 4 comments
Closed

Proxy-level timeout as FIN is not handled as error #5992

TvdW opened this issue Sep 21, 2020 · 4 comments
Assignees

Comments

@TvdW
Copy link

TvdW commented Sep 21, 2020

Some proxy in my environment appears to have a 30 second timeout, and will send a FIN back when this happens. When curl sees this, it does not recognize that this is an error (it is indeed not a RST), and it proceeds normally. In libcurl, CURLINFO_RESPONSE_CODE is reported as 0.

To reproduce, find a proxy that has this behavior (I'm told it's Squid, not sure how to configure it this way, but any CONNECT-based proxy that sends a FIN while in the middle of processing a request should do), then run this test command (thanks to a stranger on the internet for hosting this):

https_proxy=<something> curl --insecure -v https://slowwly.robertomurray.co.uk/delay/45000/url/https://curl.haxx.se/

It produces output along the lines of:

$ [curl command]
[snip]
> CONNECT slowwly.robertomurray.co.uk:443 HTTP/1.1
> Host: slowwly.robertomurray.co.uk:443
> User-Agent: curl/7.73.0-DEV
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 Connection established
<
* Proxy replied 200 to CONNECT request
[snip]
> GET /delay/45000/url/https://curl.haxx.se/ HTTP/1.1
> Host: slowwly.robertomurray.co.uk
> User-Agent: curl/7.73.0-DEV
> Accept: */*
>
* Connection #0 to host [proxy] left intact

$ echo $?
0

I expected the following

The server did not send a response, and thus an error condition should be marked.

By comparison, wget does consider this an error condition and will retry:

$ wget -v -O - --no-check-certificate https://slowwly.robertomurray.co.uk/delay/45000/url/https://curl.haxx.se/
--2020-09-21 18:08:12--  https://slowwly.robertomurray.co.uk/delay/45000/url/https://curl.haxx.se/
Resolving [proxy] ([proxy])... [ip]
Connecting to [proxy] ([proxy])|[ip]|:3128... connected.
WARNING: no certificate subject alternative name matches
        requested host name ‘slowwly.robertomurray.co.uk’.
Proxy request sent, awaiting response... No data received.
Retrying.

--2020-09-21 18:08:43--  (try: 2)  https://slowwly.robertomurray.co.uk/delay/45000/url/https://curl.haxx.se/
Connecting to [proxy] ([proxy])|[ip]|:3128... connected.
[snip]

curl/libcurl version

Fresh build (autoreconf -fi, ./configure, make -j4) from the master branch. But, also reproducible on the CentOS 7 curl 7.29.0 build with its bazillion backports.

$ src/curl -V
curl 7.73.0-DEV (x86_64-unknown-linux-gnu) libcurl/7.73.0-DEV OpenSSL/1.0.2k-fips zlib/1.2.7
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher http https imap imaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS HTTPS-proxy IPv6 Largefile libz NTLM NTLM_WB SSL UnixSockets
Linux [hostname] 3.10.0-862.14.4.el7.x86_64 #1 SMP Wed Sep 26 15:12:11 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
@TvdW
Copy link
Author

TvdW commented Sep 21, 2020

strace, the relevant bit:

poll([{fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 1, 0) = 0 (Timeout)
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fefccdfd5e0}, NULL, 8) = 0
poll([{fd=5, events=POLLIN}, {fd=3, events=POLLIN}], 2, 1000) = 1 ([{fd=5, revents=POLLIN}])
rt_sigaction(SIGPIPE, NULL, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fefccdfd5e0}, 8) = 0
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fefccdfd5e0}, NULL, 8) = 0
poll([{fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 1, 0) = 1 ([{fd=5, revents=POLLIN|POLLRDNORM}])
read(5, "", 5)                          = 0
write(2, "*", 1*)                        = 1
write(2, " ", 1 )                        = 1
write(2, "Connection #0 to host [proxy]"..., 43) = 43

@bagder
Copy link
Member

bagder commented Sep 21, 2020

In this case, you haven't gotten anything back from the remote server? Ie the request is sent off but nothing has seen in the form of a response status line or headers?

@TvdW
Copy link
Author

TvdW commented Sep 21, 2020

Correct, the socket is closed before any data is received. The request bytes were written, and thirty seconds later (the timeout) the connection is closed with a FIN

@bagder
Copy link
Member

bagder commented Sep 21, 2020

I can reproduce it and I might have a fix pending...

@bagder bagder self-assigned this Sep 21, 2020
bagder added a commit that referenced this issue Sep 22, 2020
... as that counter is subsequently used to detect if nothing was
returned from the peer. This made curl return CURLE_OK when it should
have returned CURLE_GOT_NOTHING.

Fixes #5992
Reported-by: Tom van der Woerdt
@bagder bagder closed this as completed in e580308 Sep 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

2 participants