Repository navigation
What's Changed
Security-relevant fixes
- Match a certificate wildcard only in the leftmost label (#2619). With the Mbed TLS and wolfSSL backends, hostname verification treated a
*in any label of adNSNameor CN as a wildcard, so a certificate matched hosts it does not cover. A wildcard is now honored in the leftmost label only (RFC 6125 §6.4.3), in both its*andprefix*forms. The OpenSSL backend usesX509_check_host()and was not affected. - Reject an ambiguous or invalid
Hostin a request (#2623). A request with more than oneHostfield line, or with aHostvalue holding a byte that cannot appear inuri-host [ ":" port ], is now answered with 400 and the connection is closed (RFC 9112 §3.2). A handler sees only the firstHostline, so such a request could reach it with an authority that differs from the one an intermediary acted on. Only the byte set is checked, not the full grammar. An empty value stays valid, and a request without aHostline is still accepted.
Bug fixes
- Treat a payload max length of 0 as unlimited on every read path.
set_payload_max_length(0)is documented to disable the limit, but the readers for a chunked body and for a body delimited by the connection closing did not check for 0. A server configured that way answered a chunked request with 413, and a client failed to read a chunked or unframed response. A body withContent-Lengthwas already unlimited. - Wake a blocked WebSocket
read()when the pong timeout fires. Whenmax_missed_pongswas exceeded, the heartbeat thread closed the connection, but aread()waiting in another thread stayed blocked until its read timeout: forever by default on a client, 300 seconds on a server. The pendingread()now returns right away, so a plain read loop notices the unresponsive peer. - SSE client parsing fixes:
- Ignore a leading UTF-8 BOM. It was kept as part of the first field name, so the first event was silently dropped.
- Treat a bare CR as a line ending. Lines were split on LF only, so a stream that uses CR alone never produced an event. A CRLF split across two chunks is handled as one line ending. A long line is also no longer rescanned for every received chunk.
- Ignore an
idthat cannot be sent asLast-Event-ID. Anidwith a NUL, a control character or surrounding whitespace made every reconnect fail withError::InvalidHeadersbefore reaching the server, and theidcould never be replaced. Such anidis now ignored and the previous one stays in effect.
- Ignore quoted-strings when parsing an
Acceptheader. A parameter value such asprofile="a,b"was cut at the comma or semicolon inside the quotes, and the request was answered with 400 (RFC 9110 §5.6.6). - Compare the
Rangeunit case-insensitively. A request withRange: Bytes=1-3was answered with 416 (RFC 9110 §14.1). - Send proxy Basic authentication when one credential is empty.
Proxy-Authorizationwas added only when both the proxy username and the proxy password were set, and a cross-host redirect carried the proxy credentials over only when the username was set. Both now apply when either one is set, asAuthorizationhas done since #958. A client that has both a proxy Basic credential with one empty field and a proxy bearer token now sends Basic rather than Bearer. - Stop at the last match when getting a value by index.
get_header_value(),get_header_value_u64(),get_param_value(),get_file_value(),get_trailer_value()andMultipartFormData::get_field()did not bound the index by the number of values for the key. A very large index could return a value that belongs to another key, or loop for a long time. An out-of-range index now returns the default value.
Docker server
- Log the response length for static files. The access log took the size from
res.body, which stays empty for a file sent by a content provider, so every static file was logged as 0 bytes. TheContent-Lengthof the response is now used, and 0 for HEAD.
Documentation
- README, README-stream, README-websocket: fix samples that did not compile or did not do what they showed, and correct statements that no longer matched the code (among them the
ssl_error()return type, exception handling,post_routing_handlertiming, and the TLS backend requirements of Digest authentication and the WebSocket TLS setters). List theErrorvalues and compressible MIME types that were missing. - Docs site: the same corrections across the tour, the cookbook and the LLM app tutorial, in English and Japanese. The client keep-alive page is rewritten around
set_keep_alive(true), since keep-alive is off by default.
Full Changelog: v0.60.1...v0.61.0