http_gun/config
Configures a client: destinations, protocol, TLS trust, timeouts, size limits, redaction and observations.
Start from default() and change only what you need:
let settings =
config.default()
|> config.allow_loopback
|> config.with_protocol(config.PreferHttp2)
|> config.with_request_timeout(config.After(duration.seconds(10)))
let assert Ok(client) = http_gun.start(settings)
Every timeout is a gleam/time/duration.Duration; a timeout that may be
lifted takes a Timeout, where Infinity must be chosen explicitly.
HTTP Gun keeps whole milliseconds, rounding a sub-millisecond remainder
away from zero.
A Config is opaque, so a new option never breaks your code. validate
checks it without starting processes; http_gun.start validates it too
and returns the same ConfigError. A configured client identity contains
private key material; never log arbitrary configuration values.
Defaults
| Setting | Default | Setter |
|---|---|---|
| destinations | public addresses only | allow_loopback, with_destination |
| destination on every view | not required | require_view_destination |
| protocol | HTTP/1.1 | with_protocol |
| TLS client identity | none | with_client_identity |
| TLS trust | system CA store, peer and host name verified | with_trust |
| connect, including DNS and TLS | duration.seconds(5) | with_connect_timeout |
| waiting for a pooled connection | duration.seconds(5) | with_pool_timeout |
| request, admission to last byte | After(duration.seconds(30)) | with_request_timeout |
| idle read, no bytes while reading | After(duration.seconds(30)) | with_idle_timeout |
| idle pooled connection | duration.seconds(60) | with_connection_idle_timeout |
draining on stop | duration.seconds(5) | with_shutdown_timeout |
| connections / per origin | 16 / 4 | with_max_connections, with_max_connections_per_origin |
| HTTP/2 streams per connection | 100 | with_max_streams_per_connection |
| open response bodies | 128 | with_max_open_bodies |
| queued requests | 128 | with_max_queued_requests |
| request body | 1 MiB | with_max_request_body_bytes |
| header bytes / count | 16 KiB / 100 | with_max_header_bytes, with_max_header_count |
| buffered response bytes | 128 KiB | with_max_buffered_bytes |
collected response body (send) | 8 MiB | with_max_response_body_bytes |
bytes retained by one batch | 64 MiB | with_max_batch_bytes |
| redaction | credential headers | with_redaction |
| observations | sinal.emit, which follows the application’s routes | with_observations, without_observations |
| client label in events | none | with_label |
Types
Client settings. Build with default() and the with_* functions.
pub type Config =
@internal Settings
Why a configuration is invalid.
pub type ConfigError {
OutOfRange(setting: Setting, value: Int)
TimeoutOutOfRange(setting: Setting, value: duration.Duration)
EmptyTrustAnchors
InvalidTrustAnchor
InvalidAllowedHost(entry: String)
}
Constructors
-
OutOfRange(setting: Setting, value: Int)A capacity is out of range: it must be positive; queued requests, request body and response body limits may also be zero.
-
TimeoutOutOfRange(setting: Setting, value: duration.Duration)A timeout is out of range, in HTTP Gun’s whole-millisecond precision: it must be positive; the shutdown timeout may also be zero.
-
EmptyTrustAnchorsAnchors([])trusts nothing. -
InvalidTrustAnchorA trust anchor is empty or not whole bytes.
-
InvalidAllowedHost(entry: String)A
destination.only_hostsentry is malformed.
The protocol a response used. Scripted and cassette responses report
Offline.
pub type Negotiated {
H1
H2
Offline
}
Constructors
-
H1 -
H2 -
Offline
Which HTTP versions a client negotiates.
pub type Protocol {
Http1
PreferHttp2
RequireHttp2
}
Constructors
-
Http1HTTP/1.1 only.
-
PreferHttp2HTTP/2 over TLS when the server offers it through ALPN, else HTTP/1.1. Plain-text connections use HTTP/1.1.
-
RequireHttp2HTTP/2 only; a server that negotiates HTTP/1.1 fails the connection.
Resolves a host name for a new connection, replacing DNS, for example in tests. It receives the host and the time left in the connect timeout, runs in an isolated worker, and returns the complete A/AAAA answer. Every address is checked against the destination policy; an exception or an empty answer fails closed.
pub type Resolver =
fn(String, duration.Duration) -> Result(
List(destination.Address),
Nil,
)
A setting, as ConfigError names it.
pub type Setting {
ConnectTimeout
PoolTimeout
RequestTimeout
IdleTimeout
ConnectionIdleTimeout
ShutdownTimeout
MaxConnections
MaxConnectionsPerOrigin
MaxStreamsPerConnection
MaxOpenBodies
MaxQueuedRequests
MaxRequestBodyBytes
MaxHeaderBytes
MaxHeaderCount
MaxBufferedBytes
MaxResponseBodyBytes
MaxBatchBytes
}
Constructors
-
ConnectTimeout -
PoolTimeout -
RequestTimeout -
IdleTimeout -
ConnectionIdleTimeout -
ShutdownTimeout -
MaxConnections -
MaxConnectionsPerOrigin -
MaxStreamsPerConnection -
MaxOpenBodies -
MaxQueuedRequests -
MaxRequestBodyBytes -
MaxHeaderBytes -
MaxHeaderCount -
MaxBufferedBytes -
MaxResponseBodyBytes -
MaxBatchBytes
A time bound that may be lifted. Infinity lifts it and must be chosen
explicitly.
pub type Timeout {
After(duration.Duration)
Infinity
}
Constructors
-
After(duration.Duration) -
Infinity
Which certificate authorities verify a TLS server. Every choice verifies the peer and its host name.
pub type Trust {
SystemTrust
CustomCa(path: String)
Anchors(certificates: List(BitArray))
}
Constructors
-
SystemTrust -
CustomCa(path: String)A PEM file of CA certificates, replacing system trust.
-
Anchors(certificates: List(BitArray))DER-encoded CA certificates, replacing system trust without file IO.
Values
pub fn allow_loopback(config: Config) -> Config
Also admit loopback destinations (127.0.0.0/8 and ::1), for a local server in tests or development. Every other destination setting is kept.
pub fn default() -> Config
Public destinations only, HTTP/1.1, verified TLS with system trust, and the bounds in the module’s defaults table. Starts nothing.
pub fn describe_error(error: ConfigError) -> String
Describe a configuration error for logs.
pub fn require_view_destination(config: Config) -> Config
Refuse every request whose client view has not chosen a destination with
http_gun.with_destination, failing it with ViewDestinationRequired and
NotSent before it is validated, resolved or matched. The client’s own
policy then only bounds what views may narrow to: a view still narrows
and never widens it.
A view chooses a destination when one of its policies sets
destination.only_hosts or refuses an address class this client admits.
A plaintext rule never counts: a library that only tightens
destination.with_plaintext on a caller’s view leaves the requirement in
force.
A multi-tenant client must admit the union of its tenants’ destinations, for example public addresses and loopback. Without this setting, a call that skips the tenant’s view reaches that union; with it, the call fails closed. The check applies to live, recording and playback clients alike, so a cassette test catches a call that skips the view.
let assert Ok(client) =
config.default()
|> config.allow_loopback
|> config.require_view_destination
|> http_gun.start
let public = client |> http_gun.with_destination(destination.default())
pub fn validate(config: Config) -> Result(Config, ConfigError)
Check every setting without starting processes.
pub fn with_client_identity(
config: Config,
identity: client_identity.Identity,
) -> Config
Present this immutable identity when a TLS server requests client authentication. Trust and hostname verification remain independent. Every connection in this client uses the same snapshot, including reconnects. Views cannot replace it. Rotate by starting a new client and draining/stopping the old client; in-flight old-client exchanges retain their old identity. The setter is pure. Plaintext connections send no identity material.
pub fn with_connect_timeout(
config: Config,
timeout: duration.Duration,
) -> Config
Bound resolving, connecting and the TLS handshake of each new connection, together. Default 5 s.
pub fn with_connection_idle_timeout(
config: Config,
timeout: duration.Duration,
) -> Config
Close a pooled connection that has carried no request for this long. Default 60 s.
pub fn with_destination(
config: Config,
policy: destination.Policy,
) -> Config
Replace the destination policy.
pub fn with_idle_timeout(
config: Config,
timeout: Timeout,
) -> Config
Fail a response when no bytes arrive for this long while its owner waits
for the head or reads the body. A reader that pauses is not idle. Also
bounds a stalled socket write. Default 30 s; http_gun.with_idle_timeout
replaces it for one client view.
pub fn with_label(config: Config, label: String) -> Config
Name this client in every lifecycle event, as the metadata’s client
field, so a handler that sees every client’s events can tell them apart.
Unlabelled clients report None. The label is any text; it is not a
credential and is not stored in cassettes.
A library that starts its own private client should label it with the
library’s name, for example "hellhound".
pub fn with_max_batch_bytes(config: Config, bytes: Int) -> Config
Body bytes that one batch call retains across its results. Once
reached, the response being collected fails and requests not yet sent
fail with LimitExceeded(BatchBytes, ..). Default 64 MiB.
pub fn with_max_buffered_bytes(
config: Config,
bytes: Int,
) -> Config
Response bytes buffered between the network and a slow reader, which also bounds one chunk. Default 128 KiB.
pub fn with_max_connections(config: Config, count: Int) -> Config
Connections across all origins. Default 16.
pub fn with_max_connections_per_origin(
config: Config,
count: Int,
) -> Config
Connections to one scheme, host and port. Default 4.
pub fn with_max_header_bytes(
config: Config,
bytes: Int,
) -> Config
Header bytes (names plus values) of a request, a response head or its trailers. Default 16 KiB.
pub fn with_max_header_count(
config: Config,
count: Int,
) -> Config
Headers in a request, a response head or its trailers. Default 100.
pub fn with_max_open_bodies(config: Config, count: Int) -> Config
Response bodies open at once; further requests queue. Default 128.
pub fn with_max_queued_requests(
config: Config,
count: Int,
) -> Config
Requests waiting for capacity; beyond this a request fails with
AdmissionFull. Default 128.
pub fn with_max_request_body_bytes(
config: Config,
bytes: Int,
) -> Config
Request body bytes. Default 1 MiB.
pub fn with_max_response_body_bytes(
config: Config,
bytes: Int,
) -> Config
Body bytes that send and batch collect per response; a larger body
fails with LimitExceeded(ResponseBodyBytes, ..) and the response status.
http_gun.with_body_limit replaces it per view. Streaming reads are not
bounded by it. Default 8 MiB.
pub fn with_max_streams_per_connection(
config: Config,
count: Int,
) -> Config
Concurrent HTTP/2 streams per connection, below the server’s own limit. Default 100.
pub fn with_observations(
config: Config,
target: forwarder.Forwarder,
) -> Config
Hand lifecycle events to this forwarder instead of emitting them with
sinal.emit. By default HTTP Gun calls sinal.emit, so the events follow
the application’s forwarder.route for ["http_gun"]; without a route,
handlers run in HTTP Gun’s pool and body processes.
pub fn with_pool_timeout(
config: Config,
timeout: duration.Duration,
) -> Config
Bound the wait for a connection or stream from the pool, including an HTTP/1.1 readiness check. A request that triggers a new connection is bounded by the connect timeout instead. Default 5 s.
pub fn with_redaction(
config: Config,
redaction: redaction.Redaction,
) -> Config
Choose what cassettes never store. See http_gun/redaction.
pub fn with_request_timeout(
config: Config,
timeout: Timeout,
) -> Config
Bound each request from admission to the last body byte. Default 30 s.
http_gun.with_timeout and http_gun.with_deadline replace it for one
client view, shorter or longer. Infinity lifts it; the connect, pool
and idle timeouts still apply.
pub fn with_resolver(
config: Config,
resolver: fn(String, duration.Duration) -> Result(
List(destination.Address),
Nil,
),
) -> Config
Resolve host names with resolver instead of DNS.
pub fn with_shutdown_timeout(
config: Config,
timeout: duration.Duration,
) -> Config
How long http_gun.stop lets open responses finish before cancelling
them. Zero cancels at once. Default 5 s.
pub fn without_observations(config: Config) -> Config
Emit no lifecycle events from this client. A later with_observations
turns them back on.
A library that owns a private client may choose this so that its HTTP
stays out of the application’s handlers. Prefer with_label: a labelled
client lets the application decide whether to watch or skip it.