Skip to content

Improper parsing of alt-svc headers without parameters #5445

Description

@Lekensteyn

I did this

curl -v https://mew.org:443 -k --alt-svc alt.cache
cat alt.cache

This produces:

* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
...
< HTTP/1.1 200 OK
...
< Accept-Ranges: bytes
* Unknown alt-svc protocol "h3-28", skipping...
< Alt-Svc: h3-28=":4433",h3-27=":4433"
...
$ cat alt.cache
# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html
# This file was generated by libcurl! Edit at your own risk.
$

I expected the following

alt.cache should contain a h3-27 entry which should have enabled h3-27 support on the next attempt.

curl/libcurl version

curl 7.71.0-DEV (Linux) libcurl/7.71.0-DEV BoringSSL zlib/1.2.11 quiche/0.3.0
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 
Features: alt-svc AsynchDNS HTTP3 HTTPS-proxy IPv6 Largefile libz NTLM SSL UnixSockets

Pretty much current git master (commit d75e6ce) plus a fix for the ngtcp2 build (not relevant).

operating system

Arch Linux.

Further information

It appears there is a bug in what Curl_altsvc_parse expects and what the caller provides. The function expects to work on a single header line without CRLF, this is being verified by the unit tests (tests/unit/unit1654.c).

However, the actual HTTP code passes the header including the CRLF. This means that after parsing the last part of the alt-svc header (h3-27=":4433"), it returns early because there were no more options. It did not save the new alternative service entry though...

        /* Handle the optional 'ma' and 'persist' flags. Unknown flags
           are skipped. */
        for(;;) {
          while(*p && ISBLANK(*p) && *p != ';' && *p != ',')
            p++;
          if(!*p || *p == ',')    // <-- should have triggered, but it does not because p = "\r\n"
            break;
          p++; /* pass the semicolon */
          if(!*p)
            break;
          result = getalnum(&p, option, sizeof(option));

Metadata

Metadata

Assignees

Labels

HTTP/3h3 or quic related

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions