main.bend source
main.bend on the hub · documented module
# ezhttp: HTTP/1.1 client and server for Bend 2, with auth, cookie and CORS helpers.## Shared message types, BYO JSON via encode/decode. TLS for the client stays# at the wire/runtime layer.import Baseimport ./src/url.bend as Urlimport ./src/http.bend as Httpimport ./src/body.bend as Bodyimport ./src/client.bend as Clientimport ./src/server.bend as Serverimport ./src/cookie.bend as Cookieimport ./src/cache.bend as Cacheimport ./src/cors.bend as Cors# URL parse re-exportdef parse_url(url: String) -> Url.Loc: Url.parse(url)# response parse re-exportdef parse_response(raw: String) -> Http.Reply: Http.parse(raw)# request parse re-export (server inbound)def parse_request(raw: String) -> Http.Request: Http.ask(raw)# format a response message (server outbound)def format_response(status: U32, headers: List<&2, Http.Header>, body: String) -> String: Http.respond(status, headers, body)# empty request bodydef empty_body() -> Body.Body: Body.body.empty()# UTF-8 text request bodydef text_body(s: String) -> Body.Body: Body.body.text(s)# octet-list request bodydef octets_body(bs: List<&2, U32>) -> Body.Body: Body.body.octets(bs)# BYO JSON (or any codec): encode a value with the caller's to_textdef encode(~A: Data, ~to_text: A -> String, value: A) -> Body.Body: Body.body.encode(A, to_text, value)# BYO JSON (or any codec): decode body text with the caller's from_textdef decode( ~A: Data, ~from_text: String -> Maybe<&2, A>, s: String) -> Maybe<&2, A>: Body.body.decode(A, from_text, s)# Bearer token header helperdef bearer(token: String) -> Http.Header: Client.client.bearer(token)# Basic credentials header (RFC 7617)def basic(user: String, password: String) -> Http.Header: Client.client.basic(user, password)# Set-Cookie header from a parsed cookie (RFC 6265)def set_cookie(c: Cookie.Cookie) -> Http.Header: Cookie.cookie.set(c)# parse one Set-Cookie field valuedef parse_cookie(line: String) -> Maybe<&2, Cookie.Cookie>: Cookie.cookie.parse(line)# Cookie request header for a list of cookiesdef cookie_header(cs: List<&2, Cookie.Cookie>) -> Http.Header: Cookie.cookie.request(cs)# parse a Cache-Control field value (RFC 9111)def cache_control(value: String) -> Cache.Cc: Cache.cache.parse(value)# freshness of a Cache-Control value at an age in secondsdef fresh(value: String, age: Nat) -> Bool: Cache.cache.fresh(Cache.cache.parse(value), age)# CORS preflight or simple headers on a handler replydef cors_reply(cfg: Cors.Cfg, req: Http.Request, reply: Http.Reply) -> Http.Reply: Cors.cors.on(cfg, req, reply)# GET with no extra headersdef http.get(url: String) -> IO(Client.Response): Client.client.get(url, [])# GET with headersdef http.get_with(url: String, headers: List<&2, Http.Header>) -> IO(Client.Response): Client.client.get(url, headers)# HEAD with no extra headersdef http.head(url: String) -> IO(Client.Response): Client.client.head(url, [])# HEAD with headersdef http.head_with(url: String, headers: List<&2, Http.Header>) -> IO(Client.Response): Client.client.head(url, headers)# POST with a body and no extra headersdef http.post(url: String, body: Body.Body) -> IO(Client.Response): Client.client.post(url, [], body)# POST with headers and a bodydef http.post_with( url: String, headers: List<&2, Http.Header>, body: Body.Body) -> IO(Client.Response): Client.client.post(url, headers, body)# PUT with a body and no extra headersdef http.put(url: String, body: Body.Body) -> IO(Client.Response): Client.client.put(url, [], body)# PUT with headers and a bodydef http.put_with(url: String, headers: List<&2, Http.Header>, body: Body.Body) -> IO(Client.Response): Client.client.put(url, headers, body)# DELETE with a body and no extra headersdef http.delete(url: String, body: Body.Body) -> IO(Client.Response): Client.client.delete(url, [], body)# DELETE with headers and a bodydef http.delete_with( url: String, headers: List<&2, Http.Header>, body: Body.Body) -> IO(Client.Response): Client.client.delete(url, headers, body)# OPTIONS with no extra headersdef http.options(url: String) -> IO(Client.Response): Client.client.options(url, [])# OPTIONS with headersdef http.options_with(url: String, headers: List<&2, Http.Header>) -> IO(Client.Response): Client.client.options(url, headers)# listen on host:port and serve up to `limit` connectionsdef http.serve( ~handle: Http.Request -> Http.Reply, host: String, port: U32, limit: U32) -> IO(Unit): Server.server.serve(handle, host, port, limit)# listen on host:port, serve one connection, then stopdef http.serve_once( ~handle: Http.Request -> Http.Reply, host: String, port: U32) -> IO(Unit): Server.server.once(handle, host, port)