Skip to content

HTTP/2 infinite retries on REFUSED_STREAM #5794

@Cherish98

Description

@Cherish98

I did this

I set up a (misbehaving) HTTP/2 server that always returns REFUSED_STREAM. Then, I ran curl to make a request. curl retried infinitely.

The HTTP/2 server was set up with haproxy, which always returns REFUSED_STREAM (edit: that is the intended behaviour, when the upstream server closes the TCP connection without sending any data; previously I thought that was a bug on their end). The minimum haproxy configuration file that can reproduce the bug (reproducible on haproxy 2.0.17, 2.1.7, and 2.2.2, but not < 1.9):

defaults
    timeout connect 5s
    timeout client 1m
    timeout server 1m

listen bad
    mode tcp
    bind *:1234

listen https
    mode http
    bind *:443 ssl crt /tmp/test.pem alpn h2
    server bad 127.0.0.1:1234

The curl command line is simply curl -vk https://127.0.0.1

I expected the following

curl should not retry at all, because I did not set the --retry option.

Or, it should retry a limited number of times, as intended in #5074. The fix in #5074 didn't work because on every retry, the old connection is freed and a new one is created, and thus conn->retrycount is always zero.

This bug is probably related to #5250.

curl/libcurl version

(git master)
curl 7.72.0-DEV (x86_64-pc-linux-gnu) libcurl/7.72.0-DEV OpenSSL/1.1.1g zlib/1.2.11 zstd/1.4.5 libidn2/2.3.0 libpsl/0.21.0 (+libidn2/2.2.0) nghttp2/1.41.0

operating system

Linux Arch 5.4.50-1-lts #1 SMP Wed, 01 Jul 2020 14:53:03 +0000 x86_64 GNU/Linux

curl -v output

* STATE: PROTOCONNECT => DO handle 0x55fe6520aa68; line 1900 (connection #62)
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55fe6520aa68)
> GET / HTTP/2
> Host: 127.0.0.1
> user-agent: curl/7.72.0-DEV
> accept: */*
>
* STATE: DO => DO_DONE handle 0x55fe6520aa68; line 1955 (connection #62)
* multi changed, check CONNECT_PEND queue!
* STATE: DO_DONE => PERFORM handle 0x55fe6520aa68; line 2076 (connection #62)
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
* multi changed, check CONNECT_PEND queue!
* Marked for [closure]: REFUSED_STREAM
* REFUSED_STREAM, retrying a fresh connect
* Connection died, retrying a fresh connect
* multi_done
* The cache now contains 0 members
* Closing connection 62
* TLSv1.3 (OUT), TLS alert, close notify (256):
* Issue another request to this URL: 'https://127.0.0.1/'
* STATE: PERFORM => CONNECT handle 0x55fe6520aa68; line 2243 (connection #-5000)
* Added connection 63. The cache now contains 1 members
* Hostname 127.0.0.1 was found in DNS cache
* family0 == v4, family1 == v6
*   Trying 127.0.0.1:443...
* STATE: CONNECT => WAITCONNECT handle 0x55fe6520aa68; line 1730 (connection #63)
* Connected to 127.0.0.1 (127.0.0.1) port 443 (#63)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions