Skip to content

Guard get_state liveness probe during pooled H2/H3 checkout (#914) - #915

Merged
benoitc merged 1 commit into
masterfrom
fix/914-guard-get_state-checkout
Aug 9, 2026
Merged

Guard get_state liveness probe during pooled H2/H3 checkout (#914)#915
benoitc merged 1 commit into
masterfrom
fix/914-guard-get_state-checkout

Conversation

@benoitc

Copy link
Copy Markdown
Owner

Fixes#914.

Reusing a pooled HTTP/2 or HTTP/3 connection probes it with hackney_conn:get_state/1, a bare gen_statem:call. If the pooled connection is terminating at that instant (idle teardown, GOAWAY, keepalive close) the call exits. The surrounding case only handled return values, so the exit propagated and crashed the caller of hackney:connect/4 ({noproc,{gen_statem,call,[Pid,get_state]}}) instead of falling through to a fresh connection.

The same file already guards the sibling probes for this exact race in maybe_register_h2 and maybe_upgrade_ssl; the two get_state checkout probes were missed.

Change

Wrap both checkout probes in try ... catch exit:_ -> {error, terminated} end (H2 site in connect_pool/4, H3 site in try_h3_connection/5). A terminating connection is treated as unusable and checkout falls through to the existing unregister + new-connection path. Only exit is caught; error/throw would be a genuine bug and still propagate.

Tests

New hackney_connect_race_tests with a hackney_race_pool handler that hands out an already-terminated pid on H2/H3 checkout. H2 asserts hackney:connect/4 returns {error, _}; H3 asserts the get_state probe exit does not escape. Reverting the guard makes both fail with the {noproc,...get_state...} exit. Full suite (1054 tests) passes.

Reusing a pooled HTTP/2 or HTTP/3 connection probes it with
hackney_conn:get_state/1, a bare gen_statem:call. If the connection is
terminating at that instant (idle teardown, GOAWAY, keepalive close) the
call exits, and the surrounding case only handled return values, so the
exit crashed the caller of hackney:connect/4 instead of falling through
to a fresh connection.
Wrap both checkout probes in try/catch exit, mirroring the existing race
handling in maybe_register_h2 and maybe_upgrade_ssl. A terminating
connection is now treated as unusable and the checkout opens a fresh one.
@benoitc
benoitc merged commit 3225e13 into masterAug 9, 2026
6 checks passed
@benoitcbenoitc mentioned this pull request Aug 11, 2026
benoitc added a commit that referenced this pull request Aug 11, 2026
Bundles the fixes merged since 4.7.2 (#914/#915, #918/#919, #920, #921,
#922, #924) and the curl-style Content-Length change (#917/#925). Bumps
dependencies to their latest releases: quic 1.8.0, webtransport 0.4.4,
mimerl 1.5.0, cowboy 2.18.0 (test).
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

connect_pool: unguarded hackney_conn:get_state/1 crashes checkout when a pooled HTTP/2/3 connection terminates mid-call

1 participant

@benoitc