livery_s3_uri (livery_s3 v0.1.0)
View SourceURL building and RFC 3986 encoding for S3 requests.
S3 SigV4 is unforgiving about encoding: the canonical request must use the same
percent-encoding and query ordering as the bytes actually put on the wire. This
module is the single source of truth for both. Operations build the absolute
request URL here; the signer (livery_s3_sigv4) reads the path and query back
out of that URL with url_parts/1, so the signed and sent forms cannot drift.
Two encoders are exposed: encode/1 (encode every reserved byte, used for
buckets and query components) and encode_path/1 (the same but keeping / so
object keys with slashes map to literal path separators).
Summary
Functions
Build the canonical query string from key/value pairs: each component is
percent-encoded, then the pairs are sorted by encoded key (ties by value) and
joined with &. This is both what we sign and what we put in the URL.
Percent-encode every byte outside the RFC 3986 unreserved set.
Like encode/1 but keep / (for object keys used as path segments).
Parse an endpoint URL into scheme/host/port. Accepts https://host,
http://host:port, bare host[:port] (defaults to https), and bracketed IPv6
literals. A trailing path is ignored.
Build the absolute request URL and the matching host header value.
Split an absolute URL into authority, path, and (already canonical) query. The path and query are returned verbatim so the signer reuses the exact bytes that were placed in the URL.
Types
-type config() :: #s3_config{scheme :: binary(), host :: binary(), port :: undefined | inet:port_number(), region :: binary(), credentials :: livery_s3_credentials:handle(), addressing :: path | virtual}.
Functions
-spec canonical_query(query_params()) -> binary().
Build the canonical query string from key/value pairs: each component is
percent-encoded, then the pairs are sorted by encoded key (ties by value) and
joined with &. This is both what we sign and what we put in the URL.
Percent-encode every byte outside the RFC 3986 unreserved set.
Like encode/1 but keep / (for object keys used as path segments).
-spec parse_endpoint(binary()) -> #{scheme := binary(), host := binary(), port := undefined | inet:port_number()}.
Parse an endpoint URL into scheme/host/port. Accepts https://host,
http://host:port, bare host[:port] (defaults to https), and bracketed IPv6
literals. A trailing path is ignored.
-spec request_target(config(), undefined | binary(), undefined | binary(), query_params()) -> {binary(), binary()}.
Build the absolute request URL and the matching host header value.
Bucket and Key may be undefined (service- and bucket-level requests). The
returned authority is the exact host[:port] we will sign, computed from the
addressing style: path-style keeps the endpoint host and puts the bucket in the
path; virtual-hosted prefixes the bucket onto the host.
Split an absolute URL into authority, path, and (already canonical) query. The path and query are returned verbatim so the signer reuses the exact bytes that were placed in the URL.