Skip to content

fix: pool http+unix connections over the unix socket - #997

Open
ashtonian wants to merge 1 commit into
benoitc:masterfrom
ashtonian:fix/pooled-unix-socket
Open

ashtonian wants to merge 1 commit into
benoitc:masterfrom
ashtonian:fix/pooled-unix-socket

Conversation

@ashtonian

@ashtonian ashtonian commented Nov 4, 2026 •

Copy link
Copy Markdown

What

Pooled http+unix:// requests now work. Before this change, every pooled request over a unix domain socket failed with {error, nxdomain}. Only {pool, false} worked.

Why

connect_pool_new/6 checks out every non-SSL request as hackney_tcp, so the pool dials the socket path as a TCP host name. Only HTTPS needs a TCP checkout, because the pool stores plain connections and upgrades them in place. Other transports are now checked out as themselves.

Two related places also assumed TCP:

  • connection_key/4 lowercases the host, and the pool dials the host stored in the key, so /run/App.sock was dialled as /run/app.sock. Unix socket paths now keep their case.
  • Closing a connection at checkin prewarms the host over TCP. Prewarm now dials the transport the closed connection used.

How to test

rebar3 eunit --module=hackney_pool_unix_socket_tests runs cowboy on a unix socket with a mixed-case path. It checks that pooled requests reuse one connection, and that closing an overflow connection prewarms over the socket. Reverting any one of the three changes makes at least one of the tests fail.

rebar3 xref, rebar3 eunit (1232 tests) and rebar3 dialyzer pass on OTP 27.3.

The tests send Host: localhost. The default Host for an http+unix URL is the percent-encoded socket path (#383), which released cowlib versions reject with a 400. Cowlib master accepts it since ninenines/cowlib@774a7bf (ninenines/cowlib#53), but that isn't in a release yet.

A pooled http+unix request failed with {error, nxdomain}:
connect_pool_new/6 checked every non-SSL request out of the pool as
hackney_tcp, so the pool dialled the socket path as a TCP host name.
Only HTTPS needs a TCP checkout, because the pool stores plain
connections and upgrades them in place. Other transports are now
checked out as themselves.

Two more places assumed every plain connection is TCP:

- connection_key/4 lowercased the host, and the pool dials the host
  stored in the key, so a socket path with upper-case letters was not
  found. Unix socket paths now keep their case.
- Closing a connection at checkin prewarmed the host over TCP. Prewarm
  now dials the transport the closed connection used.
@ashtonian
ashtonian marked this pull request as ready for review November 4, 2026 06:12
Sign up for free to 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.

1 participant