Skip to content

Send origin Host header for plain-HTTP proxied requests#491

Merged
ericmj merged 2 commits into
elixir-mint:mainfrom
Leonard013:fix/446-proxy-host-header
Jul 18, 2026
Merged

Send origin Host header for plain-HTTP proxied requests#491
ericmj merged 2 commits into
elixir-mint:mainfrom
Leonard013:fix/446-proxy-host-header

Conversation

@Leonard013

Copy link
Copy Markdown
Contributor

Fix Host header for plain-HTTP proxied requests

Fixes #446.

Problem

When connecting to an origin server through a plain-HTTP proxy —
Mint.HTTP.connect(:http, "example.com", 80, proxy: {:http, "127.0.0.1", 9055, []})
Mint sends the proxy's address as the Host header instead of the origin's:

GET http://example.com/ HTTP/1.1
host: 127.0.0.1:9055        <-- wrong: this is the proxy, not the origin
user-agent: mint/1.9.3

hackney and HTTPoison send Host: example.com for the identical proxied
request. Per RFC 7230 §5.4 the Host header must identify the origin server,
so Mint's behavior breaks virtual-hosted origins, proxy logging, and any server
behind the proxy that routes on Host.

Root cause

Mint.UnsafeProxy (the plain-HTTP, non-tunnel proxy) holds an Mint.HTTP1
connection whose socket points at the proxy. In Mint.UnsafeProxy.request/5
the request path is correctly rewritten to the absolute origin URI, but no
Host header is set, so it falls through to Mint.HTTP1, whose
add_default_headers/2 fills in Host from its connection — i.e. the proxy's
host and port (lib/mint/http1.ex:1170, default_host_header/1 at
lib/mint/http1.ex:1174). UnsafeProxy is the only layer that knows the
origin, so the origin Host has to be set there.

Fix

lib/mint/unsafe_proxy.exrequest/5 now sets the Host header to the
origin server (host, plus port when it is not the scheme default) before
delegating to Mint.HTTP1. Because Mint.HTTP1 uses put_new for its default
Host, the origin value is left untouched. A caller-supplied Host header
(matched case-insensitively) is still respected, matching the direct-connection
behavior.

Tests

New test/mint/unsafe_proxy_host_header_test.exs. It uses a local one-shot TCP
server as the "proxy" and inspects the raw request bytes, so it needs no live
proxy or internet connection and runs in the default suite (it is a separate
module so it isn't excluded by unsafe_proxy_test.exs's :proxy moduletag).
Covers: origin Host for a default port, origin host:port for a non-default
port, and that a caller-supplied Host is not overridden.

Verification

Before (on main):

GET http://example.com/ HTTP/1.1
host: localhost:60234
user-agent: mint/1.9.3

After:

GET http://example.com/ HTTP/1.1
user-agent: mint/1.9.3
host: example.com

Commands:

$ mix test test/mint/unsafe_proxy_host_header_test.exs
...
3 passed

# whole offline suite unaffected
$ mix test --exclude requires_internet_connection
304 passed, 51 excluded

$ mix format --check-formatted   # clean
$ mix compile --warnings-as-errors   # clean
$ mix dialyzer   # done (passed successfully)

The new tests fail before the fix (host: localhost:<port> / host: example.com:8080) and pass after.

Compatibility

No public API change. Only the Host header for plain-HTTP proxied requests is
affected, bringing it in line with RFC 7230 §5.4 and with hackney/HTTPoison.
Callers that explicitly pass their own Host header are unaffected. Tunnel
(CONNECT) proxying and direct connections are untouched.


AI-authored and AI-reviewed; not yet human-reviewed.

When connecting to an origin through a plain-HTTP (non-tunnel) proxy,
Mint.UnsafeProxy rewrote the request target to the absolute origin URI
but left the Host header unset, so Mint.HTTP1 defaulted it to the proxy's
own host:port. Per RFC 7230 section 5.4 the Host header must identify the
origin server; hackney and HTTPoison already do this.

Set the Host header to the origin (dropping the port when it is the
scheme default) in Mint.UnsafeProxy.request/5 before delegating to
Mint.HTTP1, whose put_new leaves it intact. A caller-supplied Host header
is still respected.

Fixes elixir-mint#446.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NX8ygWTRa86kE8k8Yn9bpu
Comment thread lib/mint/unsafe_proxy.ex Outdated
@ericmj
ericmj merged commit 57b1295 into elixir-mint:main Jul 18, 2026
3 checks passed
@ericmj

ericmj commented Jul 18, 2026

Copy link
Copy Markdown
Member

Thank you!

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.

HTTP_PROXY doesn't set host for a connection, using proxy as host

2 participants