EndPointBlank. BaseUrl
(end_point_blank_elixir v0.6.0)
Copy Markdown
Resolves the base URL the caller used -- scheme, host and port -- from a
Plug.Conn.
This reads the request headers directly rather than trusting conn.scheme,
conn.host and conn.port. Plug has no notion of a trusted proxy at all
unless the host application installs Plug.RewriteOn itself, so those three
describe the internal hop and nothing else. More generally: Rack, Express, the
servlet spec and Plug each resolve "host" differently (Rack takes the last
X-Forwarded-Host hop, Express the first, WSGI and Plug neither), which is why
the same request produced five different answers across the five clients.
Forwarded headers are honored when trust_proxy_headers is on, which it is by
default, taking the LAST hop: host was already caller-controlled in every
client (conn.host comes from the Host header), and behind a proxy that
appends, the last value is the proxy's own observation rather than anything the
caller planted. A directly-exposed deployment can pass false and get scheme,
host and port from the conn and the Host header only.
The flag arrives as an argument rather than being read from
EndPointBlank.Config here, so that this module stays configuration-free and
both states are directly testable.
Summary
Functions
The hostname alone, for the authorize path.
Returns a map carrying only the fields that resolved to a usable value.
Functions
@spec hostname(Plug.Conn.t() | any()) :: String.t() | nil
The hostname alone, for the authorize path.
Deliberately not resolve/2's :host: reads the host header only, never
the forwarded chain, whatever trust_proxy_headers is set to. The value feeds
target_hostname and the access-token cache key, and the portal resolves an
application environment from it -- a value matching no registered row is a
hard 422 with no fallback, not a cache miss.
Composed from the same split_authority/1 and clean_host/1 pair resolve/2
uses, so lowercasing and shape and length validation are identical between the
two; only the authority's source differs, plus the IPv6 fix-up below.
@spec resolve(Plug.Conn.t() | any(), boolean()) :: map()
Returns a map carrying only the fields that resolved to a usable value.
A field that could not be resolved is absent, never nil: the receiver has to
be able to tell "this SDK did not report a port" from "the port is null".
With trust_proxy_headers false the three x-forwarded-* headers are not read
at all, so the request is never treated as proxied and conn.scheme and
conn.port stay evidence.