You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fixed
hackney:send_request/2 works on HTTP/2 and HTTP/3. Those protocols answer
a request with the body included, which the function did not handle, so it
failed with a case_clause. It returns the connection on every protocol
now, so the response is read with body/1 or pulled with stream_body/1.
Several callers reading responses on one HTTP/2 or HTTP/3 connection each
get their own. The read was resolved from the connection's last stream
rather than the caller's, so on HTTP/2 all but one caller got {error, no_stream}, and on HTTP/3 two callers could be handed each
other's body.
A caller reading an HTTP/3 response with body/1 or stream_body/1 is
answered when the server resets its stream, instead of waiting for its own
timeout. Needs quic 2.0.0, the first release to report a peer RESET_STREAM.
A pooled HTTP/2 connection no longer closes when the caller that opened it
exits. It stayed owned by that caller, so its exit failed every other
caller's request on the connection with {error, closed}. A shared
connection now has no owner: each stream is tied to its own caller and is
reset if that caller dies, and the connection closes itself once it has had
no open stream for the pool timeout (#937, thanks @smartinio).
Unregistering a pooled HTTP/2 connection no longer leaks its per-host slot.
The pool dropped its monitor on the connection, so the slot was never
released when the connection stopped.
A response that crosses a reset of its stream no longer closes the HTTP/2
connection. h2 dropped the header block of that response without decoding
it, so the next response on the connection failed with COMPRESSION_ERROR.
The response to an HTTP/3 streaming upload can be read. After start_response/1, body/1 returned {error, invalid_state} and stream_body/1 returned {error, no_stream}: the body went to the start_response/1 caller as a second reply and was lost. When the response
headers arrived before start_response/1 was called, it could wait forever.
HTTP/3 response headers carry one :status. quic_h3 passes the status
separately and keeps it in the header list, and hackney prepended its own,
so every response reached the low-level {h3, _, {stream_headers, ...}}
consumer with the pseudo-header twice, which RFC 9114 4.3.1 makes a
malformed response. Requests through hackney:request/5 were not affected:
pseudo-headers are filtered before the caller sees them.
An HTTP/3 connection that goes away reports why. quic_h3 sends the reason
with its close event, and the handler only matched the older shape without
one, so the message was dropped: the caller waited out its own timeout and
the connection process stayed alive. A handshake that fails on a bad
certificate or a TLS alert now comes back as that error instead of {error, timeout}.
hackney_h3:connect/3,4 and hackney_h3:request/5 honor a cacertfile
option. It was handed to quic, which only takes DER cacerts, so it was
ignored and verification failed as {error, timeout}. hackney:request/5
was not affected.
Connection-specific headers are dropped from HTTP/2 and HTTP/3 requests.
A caller's Connection: keep-alive, legal in HTTP/1.1 and banned by
RFC 9113 8.2.2 and RFC 9114 4.2, reached the header block and every request
failed before anything was written. hackney picks the protocol through ALPN,
so the caller cannot know which rules apply: Connection, Keep-Alive, Proxy-Connection, Transfer-Encoding and Upgrade are stripped alongside Host. TE is kept, being allowed with the value trailers
(#935, thanks @lennartschoch).
A pooled HTTP/1.1 connection handed to a requester no longer closes itself
under the request. Checkout left the keepalive timer running, armed before
the readiness probe, so a connection could pass the probe and then fire the
timer, and the request that followed came back as {error, invalid_state}.
The timer is disarmed on checkout and re-armed when the connection returns
to the pool (#934, thanks @lennartschoch).
A request that races a peer-initiated close now returns {error, closed}
instead of {error, invalid_state}. A connection that sees the peer close
stays alive briefly so late calls get an answer, and during that window every
call without a handler answered with the generic invalid_state. The same
race therefore had two answers: {error, closed} once the connection process
was gone, {error, invalid_state} while it lingered. Callers can now tell a
closed connection from a misuse of the API (#932, #933, thanks @kpy3).
Changed
Update h2 to 0.12.3. 0.12.3 sends the DATA already buffered on a stream
when a SETTINGS frame raises the initial window, so a request body queued
against a zero window no longer stalls until an unrelated WINDOW_UPDATE
arrives.
Update quic to 2.0.0 and webtransport to 0.4.7. quic 2.0.0 reports a
peer resetting a request stream, always sends a reason with its HTTP/3
close event, and fixes a handshake that could stall when resuming from a
cached session ticket.