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

Authorization.pudu

Pudu40 lines2.0 KB

GitHub ↗
1/** @Handlers.Authorization.Module — credentials added to requests, and refreshed when refused */2module PuduLangHttpClient.Handlers.Authorization34import Std.Concurrent.Cancel as Cancel5import Std.Http as Http6import PuduLangHttpClient.Domain.Headers as Headers7import PuduLangHttpClient.Handler as Handler8import PuduLangHttpClient as HttpClient9import PuduLangHttpClient.Request as Request10import PuduLangHttpClient.Response as Response1112/** @Handlers.Authorization.Tokens — a bearer token, fetched again when `refresh` is true */13export type Tokens = fn(Bool) -> HttpClient.Outcome[Str]1415/// The status a server refuses missing or stale credentials with.16const UNAUTHORIZED: Int = 4011718/// A handler authorizing every request without an `authorization` header with a user name and19/// password, sent in the clear and so only over https.20export fn basic(user: Str, password: Str) -> Handler.Handler { fixed(Http.basicAuth(user, password)) }2122/// A handler authorizing every request without an `authorization` header with a bearer token from23/// `tokens`; when the server answers `401`, the token is fetched again and the request sent once24/// more. A failure to fetch a token is the request's failure.25export fn bearer(tokens: Tokens) -> Handler.Handler {26  fn(request: Request.Request, token: Cancel.Token, next: Handler.Send) -> HttpClient.Outcome[Response.Response] {27    if Headers.has(&request.headers, "authorization") { return next(request, token) }28    let first = next(request.setHeader("authorization", Http.bearerAuth(tokens(false) ?)), token) ?29    if first.status.code != UNAUTHORIZED { return Ok(first) }30    next(request.setHeader("authorization", Http.bearerAuth(tokens(true) ?)), token)31  }32}3334/// A handler adding a fixed `authorization` value to every request without one.35fn fixed(value: Str) -> Handler.Handler {36  fn(request: Request.Request, token: Cancel.Token, next: Handler.Send) -> HttpClient.Outcome[Response.Response] {37    if Headers.has(&request.headers, "authorization") { next(request, token) } else { next(request.setHeader("authorization", value), token) }38  }39}40