github yhirose/cpp-httplib v0.61.0

4 hours ago

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 a dNSName or 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 * and prefix* forms. The OpenSSL backend uses X509_check_host() and was not affected.
  • Reject an ambiguous or invalid Host in a request (#2623). A request with more than one Host field line, or with a Host value holding a byte that cannot appear in uri-host [ ":" port ], is now answered with 400 and the connection is closed (RFC 9112 §3.2). A handler sees only the first Host line, 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 a Host line 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 with Content-Length was already unlimited.
  • Wake a blocked WebSocket read() when the pong timeout fires. When max_missed_pongs was exceeded, the heartbeat thread closed the connection, but a read() waiting in another thread stayed blocked until its read timeout: forever by default on a client, 300 seconds on a server. The pending read() 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 id that cannot be sent as Last-Event-ID. An id with a NUL, a control character or surrounding whitespace made every reconnect fail with Error::InvalidHeaders before reaching the server, and the id could never be replaced. Such an id is now ignored and the previous one stays in effect.
  • Ignore quoted-strings when parsing an Accept header. A parameter value such as profile="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 Range unit case-insensitively. A request with Range: Bytes=1-3 was answered with 416 (RFC 9110 §14.1).
  • Send proxy Basic authentication when one credential is empty. Proxy-Authorization was 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, as Authorization has 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() and MultipartFormData::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. The Content-Length of 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_handler timing, and the TLS backend requirements of Digest authentication and the WebSocket TLS setters). List the Error values 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

Don't miss a new cpp-httplib release

NewReleases is sending notifications on new releases.