silk.http.proxy.
Proxy settings for HTTP clients, and the choice of a route for each origin.
When to use#
Make a ProxyConfig with ProxyConfig.fromUri or ProxyConfig.make. Then call
selectRoute for each origin. silk.http.request and silk.http.exchange use the Route
to prepare and send the request.
Details#
selectRoute does not allocate or use the network. It returns:
Directfor an origin in theBypassPolicy.Tunnelfor an HTTPS origin. The client sendsCONNECTto the proxy, then does TLS with the origin through the tunnel.Forwardfor a plain HTTP origin. The client sends the request to the proxy with the full URI as target.
The configuration owns its Basic token. A route writes the Proxy-Authorization value only into
a buffer that you give. classifyConnect reads the response of the proxy to CONNECT.
Errors#
ProxyErrorwith aProxyAdmissionErrorif a setting is not valid. It holds no credentials.ProxyErrorwith the response head if the proxy rejectsCONNECT.
Gotchas#
Only plain http proxies are supported. An https proxy URI fails with
UnsupportedProxyTransport. This module reads no environment variables;
NativeHttp.fromEnvironment in silk.http.client_native reads HTTPS_PROXY and the others.
Examples#
Select routes#
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.core.effect { Effect }
import silk.http.origin { Origin, OriginError }
import silk.http.proxy {
BypassPolicy,
ProxyAuth,
ProxyAuthContextId,
ProxyConfig,
ProxyConfigId,
ProxyError,
Route,
RouteMode,
selectRoute
}
import silk.core.option { Option }
import silk.core.result { Result }
import silk.uri.uri { Uri }
import silk.uri.reference { ParseError }
fn origin(text: string<'static>) -> Origin {
let uri = match Uri.parse(text) {
Result<Uri, ParseError>.Success { value } => value
Result<Uri, ParseError>.Failure { error: _ } => {
Intrinsic.trap("unexpected failure")
return origin(text)
}
}
return match Origin.fromUri(&uri) {
Result<Origin, OriginError>.Success { value } => value
Result<Origin, OriginError>.Failure { error: _ } => {
Intrinsic.trap("unexpected failure")
return origin(text)
}
}
}
effect fn program() -> i32
! OutOfMemoryError
? &mut Allocator {
// The token is the Base64 of "user:pass".
let auth = match run ProxyAuth.preparedBasic(ProxyAuthContextId.make(1), b"dXNlcjpwYXNz") {
Result<ProxyAuth, ProxyError>.Success { value } => move value
Result<ProxyAuth, ProxyError>.Failure { error: _ } => {
return 1
}
}
let local = [origin("http://localhost:8080")]
let bypass = match run BypassPolicy.copy(&local) {
Result<BypassPolicy, ProxyError>.Success { value } => move value
Result<BypassPolicy, ProxyError>.Failure { error: _ } => {
return 1
}
}
let config = match ProxyConfig.fromUri(
ProxyConfigId.make(1),
"http://proxy.example:3128",
move auth,
move bypass,
4096,
) {
Result<ProxyConfig, ProxyError>.Success { value } => move value
Result<ProxyConfig, ProxyError>.Failure { error: _ } => {
return 1
}
}
// HTTPS goes through a CONNECT tunnel, plain HTTP is forwarded, and the bypass origin is direct.
let secure = selectRoute(&config, origin("https://example.com/"))
let plain = selectRoute(&config, origin("http://example.com/"))
let direct = selectRoute(&config, origin("http://localhost:8080/"))
if Route.mode(&secure) != RouteMode.Tunnel || Route.mode(&plain) != RouteMode.Forward
|| Route.mode(&direct) != RouteMode.Direct {
return 1
}
let mut header: [u8; 64] = [0; 64]
let length = match Route.writeProxyAuthorizationInto(&plain, &mut header) {
Option<usize>.Some { value } => value
Option<usize>.None => 0
}
// "Basic dXNlcjpwYXNz"
if length != 18 || header[0] != 66 {
return 1
}
return 0
}
effect fn failed<E>(error: E) -> i32 {
drop error
return 1
}
pub fn main() -> i32 {
let mut allocator = Allocator.systemAllocatorProvider()
return run Effect.catchAll(program(), failed) |> Effect.provideMut<Allocator>(&mut allocator)
}Import as ProxyConfig with import silk.http.proxy { ProxyConfig }.
Public declarations: 15.
ProxyComponent#
pub enum ProxyComponentThe setting that is not valid.
ProxyUri#
ProxyUriThe proxy URI.
ProxyEndpoint#
ProxyEndpointThe proxy host and port.
Authentication#
AuthenticationThe Basic token.
Bypass#
BypassThe bypass list.
Configuration#
ConfigurationThe configuration as a whole.
Route#
RouteA route that was used for the wrong operation, or for another origin.
Implementation Debug for ProxyComponent#
impl Debug for ProxyComponentOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as ProxyUri.
ProxyLimit#
pub enum ProxyLimitA limit of a proxy configuration.
AuthenticationBytes#
AuthenticationBytesThe maximum length of the Basic token.
BypassOrigins#
BypassOriginsThe maximum number of bypass origins, 64.
OwnedConfigurationBytes#
OwnedConfigurationBytesThe maxOwnedConfigBytes of the configuration.
Implementation Debug for ProxyLimit#
impl Debug for ProxyLimitOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as AuthenticationBytes.
ProxyReason#
pub union ProxyReasonThe rule that failed.
InvalidProxyUri#
InvalidProxyUriThe proxy URI is not valid, or has a part that is not allowed, such as a path or user information.
InvalidProxyPort#
InvalidProxyPortThe proxy port is 0.
InvalidAuthentication#
InvalidAuthenticationThe Basic token is empty, or is not canonical Base64.
SizeOverflow#
SizeOverflowA size does not fit in usize.
LimitExceeded#
LimitExceededA value exceeded a limit.
Field limit#
pub limit: ProxyLimitThe limit.
Field allowed#
pub allowed: usizeThe value of the limit.
Field attempted#
pub attempted: usizeThe value that was found.
UnsupportedProxyTransport#
UnsupportedProxyTransportThe proxy URI uses https, which is not supported.
InvalidRoute#
InvalidRouteThe route mode or its origin does not fit the operation.
Implementation Debug for ProxyReason#
impl Debug for ProxyReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as InvalidProxyUri.
ProxyAdmissionError#
pub struct ProxyAdmissionErrorThe error for a setting that is not valid. It holds no credentials.
Field component#
pub component: ProxyComponentThe setting.
Field reason#
pub reason: ProxyReasonThe rule that failed.
Implementation Debug for ProxyAdmissionError#
impl Debug for ProxyAdmissionErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the fields, as ProxyAdmissionError { component: ..., reason: ... }.
ProxyError#
pub union ProxyErrorThe error from proxy settings or from a CONNECT response. For a setting that is not valid, it
has a ProxyAdmissionError and holds no credentials. If the proxy rejects CONNECT, it has
the response head.
Admission#
AdmissionA setting or a route is not valid.
Field error#
pub error: ProxyAdmissionErrorThe error.
ProxyMetadataLimit#
ProxyMetadataLimitThe CONNECT response head is too large to copy.
ProxyAuthenticationRequired#
ProxyAuthenticationRequiredThe proxy answered 407. The copy keeps only the status, the reason, and the
Proxy-Authenticate fields.
Field response#
pub response: OwnedResponseHeadThe copy of the response head.
ProxyRejected#
ProxyRejectedThe proxy answered with another status that is not 2xx. The copy keeps all fields.
Field response#
pub response: OwnedResponseHeadThe copy of the response head.
InvalidConnectResponse#
InvalidConnectResponseclassifyConnect was called before a final response.
Implementation Debug for ProxyError#
impl Debug for ProxyErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as Admission { ... }.
ProxyConfigId#
pub struct ProxyConfigIdA number that you choose to identify a configuration, for example in a pool key. It is not secret.
ProxyAuthContextId#
pub struct ProxyAuthContextIdA number that you choose to identify a set of credentials, for example in a pool key. It is not secret.
ProxyAuth#
pub union ProxyAuthThe credentials for the proxy.
None#
NoneNo credentials.
Basic#
BasicA Basic token.
BypassPolicy#
pub struct BypassPolicyThe origins that do not use the proxy. An origin matches only with the same scheme, host, and port.
ProxyConfig#
pub struct ProxyConfigThe settings of a proxy: its host and port, its credentials, and the bypass list.
When to use#
Make one with ProxyConfig.fromUri or ProxyConfig.make. Then call selectRoute for
each origin.
Details#
The configuration owns its Basic token. A route writes the Proxy-Authorization value only into
a buffer that you give.
Gotchas#
Only plain http proxies are supported. An https proxy URI fails with
UnsupportedProxyTransport. This module reads no environment variables;
NativeHttp.fromEnvironment in silk.http.client_native reads HTTPS_PROXY and the others.
RouteMode#
pub enum RouteModeHow a request goes to an origin.
Direct#
DirectDirectly to the origin.
Forward#
ForwardTo the proxy, with the full URI as target.
Tunnel#
TunnelThrough a CONNECT tunnel at the proxy, then TLS with the origin.
Route#
pub union Route<'configuration>The route for one origin, from selectRoute.
Details#
Direct connects to the origin. Tunnel is for an HTTPS origin: the client sends CONNECT to
the proxy, then does TLS with the origin through the tunnel. Forward is for a plain HTTP
origin: the client sends the request to the proxy with the full URI as target.
Direct#
DirectGo directly to an origin in the bypass list.
Field origin#
pub origin: OriginThe origin.
Forward#
ForwardSend plain HTTP through the proxy.
Field origin#
pub origin: OriginThe plain HTTP origin.
Tunnel#
TunnelOpen a tunnel through the proxy for TLS with the origin.
Field origin#
pub origin: OriginThe HTTPS origin. TLS checks its certificate.
RouteKey#
pub struct RouteKeyA key that identifies a route, for example for a connection pool. It has no credentials.
Implementation Copy for ProxyReason#
impl Copy for ProxyReasonImplementation Copy for ProxyAdmissionError#
impl Copy for ProxyAdmissionErrorImplementation Copy for ProxyConfigId#
impl Copy for ProxyConfigIdImplementation Copy for ProxyAuthContextId#
impl Copy for ProxyAuthContextIdImplementation Copy for Route<'configuration>#
impl<'configuration> Copy for Route<'configuration>Implementation Copy for RouteKey#
impl Copy for RouteKeyImplementation ProxyError#
impl ProxyErrorAssociated function invalidRoute#
pub fn invalidRoute() -> ProxyErrorReturns the InvalidRoute error.
Implementation ProxyConfigId#
impl ProxyConfigIdAssociated function make#
pub fn make(value: u64) -> ProxyConfigIdReturns the identity for value.
Method equals#
pub fn equals(self: &Self, other: &Self) -> boolReturns true if the two identities have the same value.
Implementation ProxyAuthContextId#
impl ProxyAuthContextIdAssociated function make#
pub fn make(value: u64) -> ProxyAuthContextIdReturns the identity for value.
Method equals#
pub fn equals(self: &Self, other: &Self) -> boolReturns true if the two identities have the same value.
Implementation ProxyAuth#
impl ProxyAuthAssociated function none#
pub fn none(contextId: ProxyAuthContextId) -> ProxyAuthReturns credentials with no token.
Associated function preparedBasic#
pub effect fn preparedBasic(
contextId: ProxyAuthContextId,
token: &[u8],
) -> Result<ProxyAuth, ProxyError> ! OutOfMemoryError ? &mut AllocatorChecks and copies token, the Base64 of user:password. It must be canonical Base64, and at
most 4096 bytes.
Method contextId#
pub fn contextId(self: &Self) -> ProxyAuthContextIdReturns the identity of the credentials.
Method ownedBytes#
pub fn ownedBytes(self: &Self) -> usizeReturns the length of the token, or 0.
Implementation BypassPolicy#
impl BypassPolicyAssociated function copy#
pub effect fn copy(origins: &[Origin]) -> Result<BypassPolicy, ProxyError>
! OutOfMemoryError
? &mut AllocatorCopies up to 64 origins into a bypass list.
Method contains#
pub fn contains(self: &Self, origin: &Origin) -> boolReturns true if origin has the same scheme, host, and port as an origin in the list.
Method ownedBytes#
pub fn ownedBytes(self: &Self) -> usizeReturns the memory of the list, in bytes.
Implementation ProxyConfig#
impl ProxyConfigAssociated function make#
pub fn make(
id: ProxyConfigId,
proxyHost: Host,
proxyPort: Port,
authentication: ProxyAuth,
bypass: BypassPolicy,
maxOwnedConfigBytes: usize,
) -> Result<ProxyConfig, ProxyError>Returns a configuration for a proxy at proxyHost and proxyPort. The port cannot be 0.
maxOwnedConfigBytes limits the memory of the host, the token, and the bypass list.
Associated function fromUri#
pub fn fromUri<'text>(
id: ProxyConfigId,
text: string<'text>,
authentication: ProxyAuth,
bypass: BypassPolicy,
maxOwnedConfigBytes: usize,
) -> Result<ProxyConfig, ProxyError>Returns a configuration for the proxy in text, such as http://proxy:3128. The URI can have
only the http scheme, a host, and a port.
Method id#
pub fn id(self: &Self) -> ProxyConfigIdReturns the identity of the configuration.
Method authContextId#
pub fn authContextId(self: &Self) -> ProxyAuthContextIdReturns the identity of the credentials.
Method proxyHost#
pub fn proxyHost(self: &Self) -> HostReturns the proxy host.
Method proxyPort#
pub fn proxyPort(self: &Self) -> PortReturns the proxy port.
Method ownedBytes#
pub fn ownedBytes(self: &Self) -> usizeReturns the memory of the configuration, in bytes.
selectRoute#
pub fn selectRoute<'configuration>(
configuration: &'configuration ProxyConfig,
origin: Origin,
) -> Route<'configuration>Returns the route for origin: Direct for a bypass origin, Tunnel for HTTPS, and Forward
for plain HTTP. It does not allocate or use the network.
classifyConnect#
pub effect fn classifyConnect(
head: &ResponseHead,
) -> () ! ProxyError | OutOfMemoryError ? &mut AllocatorReads the final response of the proxy to CONNECT.
Details#
A 2xx status succeeds. A 407 fails with ProxyAuthenticationRequired, and other statuses with
ProxyRejected, with a copy of the head. If the head is too large to copy, it fails with
ProxyMetadataLimit. Call it only after a final response head.
Implementation Route<'configuration>#
impl<'configuration> Route<'configuration>Method mode#
pub fn mode(self: &Self) -> RouteModeReturns the mode of the route.
Method originalOrigin#
pub fn originalOrigin(self: &Self) -> OriginReturns the origin that the route is for.
Method proxyHost#
pub fn proxyHost(self: &Self) -> HostReturns the proxy host.
Method proxyPort#
pub fn proxyPort(self: &Self) -> PortReturns the proxy port.
Method physicalPeer#
pub fn physicalPeer(self: &Self) -> Result<Origin, OriginError>Returns the proxy as a plain HTTP origin, the server to connect to.
Method proxyAuthorizationLength#
pub fn proxyAuthorizationLength(self: &Self) -> usizeReturns the length of the Proxy-Authorization value, or 0 if there are no credentials.
Method writeProxyAuthorizationInto#
pub fn writeProxyAuthorizationInto(self: &Self, output: &mut [u8]) -> Option<usize>Writes the Proxy-Authorization value, such as Basic dXNlcjpwYXNz, to the start of
output, and returns its length. Returns None and writes nothing if output is too small.
Method configId#
pub fn configId(self: &Self) -> ProxyConfigIdReturns the identity of the configuration.
Method authContextId#
pub fn authContextId(self: &Self) -> ProxyAuthContextIdReturns the identity of the credentials.
Method key#
pub fn key(self: &Self) -> RouteKeyReturns the key of the route. It does not read the credentials.
Method recompute#
pub fn recompute(self: &Self, origin: Origin) -> Route<'configuration>Returns the route for another origin, with the same configuration, for example after a redirect.
Implementation RouteKey#
impl RouteKeyMethod originalOrigin#
pub fn originalOrigin(self: &Self) -> OriginReturns the origin of the route.
Method mode#
pub fn mode(self: &Self) -> RouteModeReturns the mode of the route.
Method equals#
pub fn equals(self: &Self, other: &Self) -> boolReturns true if the mode, the origin, the proxy, and the two identities are equal.
Category: HTTP.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.