Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-httpclient

Named HTTP clients for Pudu: a client factory, delegating handlers, pooled keep-alive connections, handler lifetimes, logging, and resilience

0.1.1Apache-2.01

InstallClose

Proxy.pudu

Pudu62 lines2.8 KB

GitHub ↗
1/** @HttpClient.Proxy.Module — a forward proxy requests are sent through */2module PuduLangHttpClient.Proxy34import Std.Http as Http5import PuduLangHttpClient.Domain.Uri as Uri67/** @HttpClient.Proxy.Proxy — the proxy's address, its credentials, and the hosts reached directly */8export type Proxy = { address: Str, credentials: Option[(Str, Str)], bypass: Array[Str], bypassOnLocal: Bool }910/// The hosts that name the machine itself.11const LOCAL_HOSTS: Set[Str] = #{"localhost", "127.0.0.1", "::1"}1213/// A proxy at an `http` address, without credentials, reaching every host through it.14export fn at(address: Str) -> Proxy { Proxy{address: address, credentials: None, bypass: [], bypassOnLocal: false} }1516/// Every reason the proxy cannot be used.17export fn validate(proxy: &Proxy) -> Array[Str] {18  match Uri.endpointOf(proxy.address) {19    case Some(endpoint) => if endpoint.secure { ["proxy address must be an http address: " + proxy.address] } else { [] }20    case None => ["proxy address must be an absolute http address: " + proxy.address]21  }22}2324/// Whether a request to `host` goes directly rather than through the proxy: the host is listed,25/// matches a listed `*.suffix`, or is local while local hosts bypass.26export fn bypasses(proxy: &Proxy, host: Str) -> Bool {27  let lower = host.toLower()28  if proxy.bypassOnLocal && (lower in LOCAL_HOSTS || lower.startsWith("127.") || !lower.contains(".")) { return true }29  for entry in proxy.bypass {30    let wanted = entry.toLower()31    if wanted == lower || (wanted.startsWith("*.") && lower.endsWith(wanted.drop(1))) { return true }32  }33  false34}3536/// The `proxy-authorization` value the credentials make, when there are credentials.37export fn authorization(proxy: &Proxy) -> Option[Str] {38  let (user, password) = proxy.credentials ?39  Some(Http.basicAuth(user, password))40}4142/** @HttpClient.Proxy.Configuring — a proxy changed one decision at a time */43export trait Configuring {44  /// The proxy authenticating with a user name and password.45  fn withCredentials(self: &Self, user: Str, password: Str) -> Self46  /// The proxy reached around for the listed hosts; `*.example.com` covers every name under it.47  fn bypassing(self: &Self, hosts: &Array[Str]) -> Self48  /// The proxy reached around for the machine itself and for names without a dot.49  fn bypassingLocal(self: &Self) -> Self50}5152impl Configuring for Proxy {53  /// The proxy authenticating with a user name and password.54  fn withCredentials(self: &Self, user: Str, password: Str) -> Self { Proxy{..*self, credentials: Some((user, password))} }5556  /// The proxy reached around for the listed hosts; `*.example.com` covers every name under it.57  fn bypassing(self: &Self, hosts: &Array[Str]) -> Self { Proxy{..*self, bypass: self.bypass.concat(*hosts)} }5859  /// The proxy reached around for the machine itself and for names without a dot.60  fn bypassingLocal(self: &Self) -> Self { Proxy{..*self, bypassOnLocal: true} }61}62