github yhirose/cpp-httplib v0.49.0

4 hours ago

What's Changed

Security fixes

  • Escape ", CR, and LF in multipart field names and filenames when serializing multipart/form-data bodies. Previously these values were concatenated into the Content-Disposition quoted-string unescaped, so a " silently terminated the quoted-string early, and embedded CR/LF allowed injecting arbitrary part headers or forging part boundaries when a filename comes from external input. Escaping follows the WHATWG HTML standard ("%22, CR → %0D, LF → %0A), matching what browsers send; behavior only changes for inputs that previously produced malformed HTTP
  • Close the same header-injection vector for part content types: CR/LF in MultipartFormData::content_type are now escaped (%0D/%0A) before being written into the part's Content-Type header. " is left intact since it is legal in Content-Type values (e.g. quoted charset parameters)

New features

  • Add public MultipartFormDataWriter for multipart body serialization outside Client::Post/Put/Patch (e.g. to feed a custom content provider or compose with other body sources), which previously required calling unstable detail:: functions directly. Supports whole-body serialization with known content length and per-part framing (item_begin/item_end/finish) for streaming. Also exposes is_valid_multipart_boundary() so callers using an explicit boundary can validate it without exceptions
  • Make the ThreadPool idle timeout for dynamic threads configurable at runtime via a new fourth constructor parameter: ThreadPool(base_threads, max_threads, max_queued_requests, idle_timeout_sec) (Fix #2481)

Bug fixes

  • Classify ASCII bytes without consulting the global C locale. std::isalnum/std::isdigit read the locale, so a byte like 0xC5 could classify as alphanumeric once an embedder called setlocale() (observed on macOS). New detail::is_ascii_digit/is_ascii_alpha/is_ascii_alnum helpers are now used at every classification site — multipart boundary validation, token checks, URI encoding, range header parsing, and IPv4 host detection — and the <cctype> include is dropped (Fix #2482, Fix #2483)
  • Omit the default port from the WebSocket handshake Host header, per RFC 6455 Section 4.1 (include the port only when it is not 80 for ws / 443 for wss). Some CDNs alter routing when the Host header carries an explicit default port. IPv6 literal hosts are now bracketed correctly as well (Fix #2480)
  • Send the query string verbatim when path encoding is disabled. set_path_encode(false) only suppressed encoding of the path; the query was still decoded and re-encoded, which is lossy for pre-encoded payloads (%2C,, %20+, etc.) and could corrupt binary query data on strict RFC 3986 servers (#2479)
  • Use an unsigned accumulator in base64_encode to avoid implementation-defined behavior with high-bit input bytes (#2477)

Build

  • meson: fix build failure on glibc >= 2.34, where getaddrinfo_a is built into libc and no standalone libanl exists (also fixes architectures like loongarch64/riscv64 that never shipped one) (#2484)

Full Changelog: v0.48.0...v0.49.0

Don't miss a new cpp-httplib release

NewReleases is sending notifications on new releases.