
Headers.pudu
Pudu100 lines3.6 KB
1/** @Domain.Headers.Module — header lists compared without regard to case */2module PuduLangHttpClient.Domain.Headers34import Std.Http.Safe as Safe5import Std.Result as Result678const CONTENT_HEADERS: Set[Str] = #{9 "allow",10 "content-disposition",11 "content-encoding",12 "content-language",13 "content-length",14 "content-location",15 "content-md5",16 "content-range",17 "content-type",18 "expires",19 "last-modified"20}212223export const REDACTED: Str = "*"242526export fn get(headers: &Array[(Str, Str)], name: Str) -> Option[Str] {27 let wanted = name.toLower()28 for pair in headers {29 if pair[0].toLower() == wanted { return Some(pair[1]) }30 }31 None32}333435export fn values(headers: &Array[(Str, Str)], name: Str) -> Array[Str] {36 let wanted = name.toLower()37 headers.filter(|pair: (Str, Str)| pair[0].toLower() == wanted).map(|pair: (Str, Str)| pair[1])38}394041export fn has(headers: &Array[(Str, Str)], name: Str) -> Bool {42 let wanted = name.toLower()43 for pair in headers {44 if pair[0].toLower() == wanted { return true }45 }46 false47}484950export fn add(headers: &Array[(Str, Str)], name: Str, value: Str) -> Array[(Str, Str)] { headers.push((name, value)) }515253export fn set(headers: &Array[(Str, Str)], name: Str, value: Str) -> Array[(Str, Str)] { remove(headers, name).push((name, value)) }545556export fn remove(headers: &Array[(Str, Str)], name: Str) -> Array[(Str, Str)] {57 let wanted = name.toLower()58 headers.filter(|pair: (Str, Str)| pair[0].toLower() != wanted)59}606162export fn removeAll(headers: &Array[(Str, Str)], names: &Set[Str]) -> Array[(Str, Str)] {63 headers.filter(|pair: (Str, Str)| !(pair[0].toLower() in *names))64}656667export fn merged(defaults: &Array[(Str, Str)], own: &Array[(Str, Str)]) -> Array[(Str, Str)] {68 defaults.filter(|pair: (Str, Str)| !has(own, pair[0])).concat(*own)69}707172export fn redacted(headers: &Array[(Str, Str)], redact: fn(Str) -> Bool) -> Array[(Str, Str)] {73 headers.map(|pair: (Str, Str)| if redact(pair[0].toLower()) { (pair[0], REDACTED) } else { pair })74}757677export fn isContentHeader(name: Str) -> Bool { name.toLower() in CONTENT_HEADERS }787980export fn splitContent(headers: &Array[(Str, Str)]) -> (Array[(Str, Str)], Array[(Str, Str)]) {81 (headers.filter(|pair: (Str, Str)| !isContentHeader(pair[0])), headers.filter(|pair: (Str, Str)| isContentHeader(pair[0])))82}838485export fn unwritable(headers: &Array[(Str, Str)]) -> Option[Str] {86 for pair in headers {87 if pair[0].isEmpty() || pair[0].contains(":") || Result.isErr(&Safe.headerWritable(pair[0], pair[1])) { return Some(pair[0]) }88 }89 None90}919293export fn lists(value: Str, token: Str) -> Bool {94 let wanted = token.toLower()95 for piece in value.split(",") {96 if piece.trim().toLower() == wanted { return true }97 }98 false99}100