Skip to content

Releases: benoitc/hackney

4.7.4

Choose a tag to compare

@benoitc benoitc released this 12 Aug 05:54
9928f3c

Fixed

  • A connection attempt that outlives its timeout no longer terminates the pool,
    and with it every caller of that pool. The dial is made with the request's
    connect_timeout, and a call that times out, like a connection process that
    dies while dialing, comes back as a checkout error (#927, #928, thanks
    @aboroska).
  • Handing a pooled connection to a new owner, and the prewarm dial, are guarded
    like the other calls the pool makes into a connection process. A connection
    that is gone or wedged is dropped instead of taking the pool down (#929).
  • Stopping a connection from inside the pool is bounded to 100ms, after which
    the connection is killed. A connection wedged in a transport call, which a
    failed dial makes likely, used to hold every caller of the pool for as long
    as the transport took to return (#929).
  • The health probes the pool runs on a connection (is_ready, checkin_info,
    set_owner, get_state) take an explicit timeout, and the pool passes
    250ms. h2_conn_usable/1 used the 5s default, so one wedged HTTP/2
    connection stalled the pool for 5 seconds on every checkout for that host
    (#929).

Added

  • Fault injection test harness for the pool: a transport which can be told to
    misbehave, a sentinel which makes a dead pool visible, fault and chaos
    suites, and a structural test which fails if the pool calls a connection
    process outside a try. DEVELOPMENT.md explains how to use it (#929).

Changed

  • Update dependencies to their latest releases: h2 0.12.0 and webtransport
    0.4.5 (#930).

4.7.3

Choose a tag to compare

@benoitc benoitc released this 11 Aug 07:38
6d6254b

hackney 4.7.3 is a bugfix and hardening release for the Erlang HTTP client. It clears a few ways a pooled connection could stall or leak, hardens CRLF handling on the proxy and streaming request paths, restores curl-style Content-Length: 0 on empty POST/PUT/PATCH bodies (so servers such as AWS that require the header are happy again), and refreshes every dependency to its latest release.

Upgrading from 4.7.2 needs no code changes.

Fixed

  • Reusing a pooled HTTP/2 or HTTP/3 connection no longer crashes the caller of
    hackney:connect/4 when the pooled connection terminates during the checkout
    liveness probe. The get_state probe is guarded so a terminating connection
    falls through to a fresh one (#914).
  • hackney_url:normalize/2 now rejects a host that reaches an IP literal only
    after IDNA folds the Unicode full-stop variants (U+3002/U+FF0E/U+FF61) to
    ASCII dots (for example 127。0。0。1 becoming 127.0.0.1), closing a bypass
    of the percent-encoded-IP check.
  • The CONNECT proxy handshake rejects CR/LF/NUL in the target host instead of
    concatenating it into the request line and Host header.
  • The pooled HTTPS upgrade bounds the TLS handshake with connect_timeout
    (ssl:connect/3), so a server that stalls the handshake no longer pins the
    connection process and its pool slot (#916).
  • The streaming request path sanitizes header values (CR/LF) like the buffered
    path, and the request method is validated (CR/LF/NUL) at every entry point,
    not just the request target.
  • A response body cut short by the peer closing mid-transfer no longer leaks
    the connection process. read_full_body/2 hands back socket = undefined,
    so the connection went straight to closed and never reached the reuse
    check added for #902. An unpooled connection arms no grace timer there and,
    when started under hackney_conn_sup, has the supervisor as its owner, so
    the owner-DOWN clause never fired either: the process parked forever holding
    every refc binary it had read. Callers could not clean up, since a
    synchronous request returns the body directly and the truncated read still
    reports {ok, Body} (#918). The same applies to a failed body read and to
    bodyless (204/304) responses.
  • hackney_conn:get_location/1 and set_location/2 no longer exit with
    noproc when the connection has already stopped, which would otherwise
    propagate out of hackney:request/5 on the redirect path.

Changed

  • Like curl, an empty body on a body-bearing method (POST/PUT/PATCH) now sends
    Content-Length: 0; bodyless methods (GET/HEAD/DELETE) are unchanged (#917).
  • Update dependencies to their latest releases: quic 1.8.0, webtransport
    0.4.4, mimerl 1.5.0, and cowboy 2.18.0 for the test suite.

4.7.2

Choose a tag to compare

@benoitc benoitc released this 17 Jul 09:38

Bump quic to 1.7.1. A clean QUIC connection close (idle pooled HTTP/3 connections, orderly shutdown) no longer emits ERROR and CRASH reports from quic_h3_connection nor propagates an abnormal exit to the connection owner. This also removes the intermittent eunit group cancellation in the h3/wt test suites.

See NEWS.md for details. PR #913.

4.7.1

Choose a tag to compare

@benoitc benoitc released this 17 Jul 00:00

Chunked decoding no longer fails with {error, invalid_chunk_size} when the CRLF terminating a chunk-size line is split across two socket reads (buffer ending on a lone \r). The parser now waits for the \n (#901).

A malformed chunk-size line or chunk terminator now fails cleanly with {error, invalid_chunk_size} or {error, poorly_formatted_chunked_size} instead of crashing the parser with a case_clause error.

See NEWS.md for details. PR #912.

4.7.0

Choose a tag to compare

@benoitc benoitc released this 16 Jul 22:46

HTTP/2 request bodies larger than the peer's flow control window no longer fail with {error, send_buffer_full}. Body sends block until the server opens the window, bounded by the new send_timeout option (default 30000 ms, infinity allowed, nonblock restores the old fail-fast behavior). If the window never opens the request fails with {error, timeout} and the abandoned stream is reset so its buffered body does not linger on a shared connection. Applies to whole-body and streamed HTTP/2 request bodies; HTTP/1.1 and HTTP/3 are unchanged.

HTTP/2 async requests now deliver their response messages: the stream entry stored an internal reference where the delivery code expected the stream_to pid, so every async HTTP/2 response was silently dropped.

HTTP/2 {async, once} now honors stream_next/1 with the same contract as HTTP/1.1: status and headers eagerly, then one message per pull. once streams use h2 manual flow control, so a slow consumer keeps the peer's window closed and in-flight data stays bounded to one window.

Connections created with hackney:connect/4 and {pool, false} honor a {send_timeout, T} connect option; pooled connections keep the default and take the per-request option instead.

See NEWS.md for details. PR #911.

4.6.1

Choose a tag to compare

@benoitc benoitc released this 15 Jul 18:06
fc8bd38

Changed

  • Bump h2 to 0.11.0. It adds h2:peername/1, which returns the peer's {IpAddress, Port} for a live connection. Additive only; no behavior change for hackney.

4.6.0

Choose a tag to compare

@benoitc benoitc released this 15 Jul 07:34

Added

  • set_owner/2 now works while a response body is streaming, in both the synchronous and the async path. It used to return {error, invalid_state} once the body had started. This lets a short lived worker run a request and hand the still streaming response to a longer lived process before it exits, without stopping the connection.
  • connect/4 accepts a binary host, restoring the 1.x behavior. A binary is converted to a string, so callers passing a binary host no longer fail.

Fixed

  • A non-reusable connection (flagged no_reuse for proxy tunnels, SSL upgrades or a disabled pool, or answered with Connection: close) is now closed and its process stopped when a synchronous request completes, instead of parking in connected forever. With a long lived owner nothing stopped it, so one hackney_conn process leaked per request until the node ran out of memory (#902). The sync and async reuse decision now share the same check, which also stops a no_reuse pooled connection on the async path.

hackney 4.5.2

Choose a tag to compare

@benoitc benoitc released this 05 Jul 23:50

Dependency bump release. No API changes.

Changed

  • Bump h2 to 0.10.4. It fixes a regression from 0.10.3 where a blocking send whose data had fully drained received {error, stream_closed} when the stream closed on its END_STREAM chunk. A waiting sender is now settled as ok once the send buffer has drained, and only gets the close-reason error when data is still outstanding.
  • Bump quic to 1.7.0. Relevant to hackney's HTTP/3 client: the connection flow-control window now slides forward with received bytes instead of stalling after 8 MiB, so large HTTP/3 downloads keep flowing; the idle timer restarts on received activity per RFC 9000 §10.1; an invalid peer SETTINGS frame now closes the connection cleanly instead of crashing; and a client recognizes a server stateless reset (RFC 9000 §10.3) and closes promptly instead of waiting for the idle timeout.
  • Bump webtransport to 0.4.3, which aligns its transitive h2 (0.10.4) and quic (1.7.0) dependencies with hackney's own, so the wt_* API runs on the same HTTP/2 and HTTP/3 stack versions.

4.5.1

Choose a tag to compare

@benoitc benoitc released this 04 Jul 13:13
86993e0

Changed

  • Bump h2 to 0.10.3. It fixes an HTTP/2 upload hang: a sender blocked on
    flow control is now released with {error, stream_reset} or
    {error, stream_closed} when the peer cancels the stream, instead of
    hanging for the connection's lifetime. This affects hackney's streamed
    request bodies over HTTP/2 when the server resets the stream
    mid-backpressure.

4.5.0

Choose a tag to compare

@benoitc benoitc released this 04 Jul 09:45
50b2691

Added

  • HTTP QUERY method (RFC 10008) as a first-class method: hackney:query/1..4
    helpers and hackney:request(query, ...). QUERY is safe and idempotent and
    carries a request body like POST. It works over HTTP/1.1, HTTP/2, and
    HTTP/3 with every request body mode (binary, streamed, async, connection
    API).