http.bend fails
raw source on the hub · import 0x977945edff4d58fb1fd04f769d651271/http.bend as Http
4 imports
import Base import ./wire.bend as Wire import ./dns/dns.bend as Dns import ./url/url.bend as Url
Types
type Req source · line 13 · raw
Data
Req@method:String -> @path:String -> @headers:Map<&2, String> -> @body:String -> Req
type Res source · line 16 · raw
Data
Res@status:U32 -> @headers:Map<&2, String> -> @body:String -> Res
type Fields source · line 19 · raw
Data
FieldsBadFields
FieldsOk@m:Map<&2, String> -> Fields
type HexSize source · line 215 · raw
Data
HexSize@n:U32 -> @rest:String -> HexSize
type Step source · line 218 · raw
Data
StepFailStep
StepDone@body:String -> Step
StepNext@rest:String -> @acc:String -> Step
type Frame source · line 463 · raw
Data
Bad: never a message. More: a valid prefix; read on. Done: a whole response.
FrameBadFrame
FrameMoreFrame
FrameDone@res:Res -> Frame
Definitions
def empty source · line 23 · raw
Map<&2, String>
def sanitize.cons source · line 26 · raw
@ch:Char -> @rest:String -> @drop:Bool -> String
def sanitize source · line 33 · raw
@s:String -> String
def drop_cr.if source · line 40 · raw
@+s:String -> @cr:Bool -> String
def drop_cr source · line 47 · raw
@+s:String -> String
def take_sp.go source · line 50 · raw
@s:String -> @+acc:String -> Pair(String, String)
def take_sp source · line 57 · raw
@s:String -> Pair(String, String)
def start_line.ver source · line 60 · raw
@m:String -> @pv:Pair(String, String) -> Pair(String, Pair(String, String))
def start_line.rest source · line 64 · raw
@mr:Pair(String, String) -> Pair(String, Pair(String, String))
def start_line source · line 68 · raw
@s:String -> Pair(String, Pair(String, String))
def split_at_blank.go source · line 71 · raw
@s:String -> @e:Bool -> @w:U32 -> @acc:String -> Pair(String, String)
def split_at_blank source · line 83 · raw
@s:String -> Pair(String, String)
def split_colon.go source · line 86 · raw
@s:String -> @+acc:String -> Pair(String, String)
def split_colon source · line 93 · raw
@s:String -> Pair(String, String)
def has_header.of source · line 96 · raw
@r:Pair(Map<&2, String>, Bool) -> Bool
def has_header source · line 100 · raw
@+h:Map<&2, String> -> @k:String -> Bool
def header.of source · line 103 · raw
@r:Pair(Map<&2, String>, String) -> String
def header source · line 107 · raw
@+h:Map<&2, String> -> @k:String -> String
def folded source · line 110 · raw
@+line:String -> Bool
def tracked source · line 113 · raw
@+k:String -> Bool
def fields_put.dup source · line 116 · raw
@m:Map<&2, String> -> @k:String -> @v:String -> @bad:Bool -> Fields
def fields_put.key source · line 123 · raw
@+m:Map<&2, String> -> @+k:String -> @v:String -> Fields
def fields_put.kv source · line 126 · raw
@m:Map<&2, String> -> @kv:Pair(String, String) -> Fields
def fields_put.fold source · line 130 · raw
@m:Map<&2, String> -> @line:String -> @fold:Bool -> Fields
def fields_put.empty source · line 137 · raw
@m:Map<&2, String> -> @+line:String -> @e:Bool -> Fields
def fields_put.ok source · line 144 · raw
@m:Map<&2, String> -> @+line:String -> Fields
def fields_put source · line 147 · raw
@acc:Fields -> @line:String -> Fields
def parse.headers.done source · line 154 · raw
@acc:Fields -> Maybe<&2, Map<&2, String>>
def parse.headers source · line 161 · raw
@xs:List<&2, String> -> @acc:Fields -> Maybe<&2, Map<&2, String>>
def parse_u32.digit source · line 168 · raw
@+c:U32 -> Bool
def parse_u32.add source · line 171 · raw
@acc:U32 -> @c:U32 -> U32
def parse_u32.done source · line 174 · raw
@acc:U32 -> @bad:Bool -> Maybe<&2, U32>
def parse_u32.go source · line 181 · raw
@s:String -> @acc:U32 -> @bad:Bool -> Maybe<&2, U32>
def parse_u32 source · line 188 · raw
@s:String -> Maybe<&2, U32>
def parse.take.if source · line 197 · raw
@+rest:String -> @+k:Nat -> @short:Bool -> Maybe<&2, String>
def parse.take.have source · line 205 · raw
@+rest:String -> @+k:Nat -> Maybe<&2, String>
RFC 9112 §8: fewer bytes than Content-Length is an incomplete message.
def parse.take source · line 208 · raw
@rest:String -> @n:Maybe<&2, U32> -> Maybe<&2, String>
def is_hex source · line 223 · raw
@+c:U32 -> Bool
def hexv source · line 226 · raw
@+c:U32 -> U32
def chunk.lf1 source · line 229 · raw
@r:String -> @n:U32 -> @lf:Bool -> Maybe<&2, HexSize>
def chunk.lf source · line 236 · raw
@t:String -> @n:U32 -> Maybe<&2, HexSize>
def chunk.ext source · line 244 · raw
@s:String -> @+n:U32 -> Maybe<&2, HexSize>
RFC 9112 §7.1.1: recipients ignore unknown chunk extensions.
def chunk.size.end source · line 251 · raw
@+c:U32 -> @+t:String -> @+n:U32 -> @seen:Bool -> Maybe<&2, HexSize>
def chunk.size.go source · line 258 · raw
@s:String -> @+acc:U32 -> @+seen:Bool -> Maybe<&2, HexSize>
def chunk.size source · line 265 · raw
@s:String -> Maybe<&2, HexSize>
def chunk.trailer.ok source · line 268 · raw
@acc:String -> @ok:Bool -> Step
def chunk.trailer.end source · line 275 · raw
@hb:Pair(String, String) -> @acc:String -> Step
def chunk.trailer.if source · line 279 · raw
@rest:String -> @acc:String -> @blank:Bool -> Step
def chunk.trailer source · line 287 · raw
@+rest:String -> @acc:String -> Step
ponytail: trailer fields are dropped unparsed (§7.1.2 allows discarding)
def chunk.crlf.if source · line 290 · raw
@data:String -> @+after:String -> @acc:String -> @ok:Bool -> Step
def chunk.crlf source · line 297 · raw
@data:String -> @+after:String -> @acc:String -> Step
def chunk.data.if source · line 300 · raw
@+rest:String -> @+k:Nat -> @acc:String -> @short:Bool -> Step
def chunk.data source · line 307 · raw
@+rest:String -> @+k:Nat -> @acc:String -> Step
def chunk.step.n source · line 310 · raw
@+n:U32 -> @rest:String -> @acc:String -> @zero:Bool -> Step
def chunk.step.got source · line 317 · raw
@got:Maybe<&2, HexSize> -> @acc:String -> Step
def chunk.step source · line 324 · raw
@s:String -> @acc:String -> Step
def chunk.go source · line 328 · raw
@fuel:Nat -> @st:Step -> Maybe<&2, String>
ponytail: acc ++ per chunk is O(body * chunks); a chunk list if bodies get big
def chunk.decode source · line 342 · raw
@+s:String -> Maybe<&2, String>
Every chunk eats at least 3 bytes, so length(s) steps always suffice.
def parse.body.cl source · line 345 · raw
@+h:Map<&2, String> -> @rest:String -> @hascl:Bool -> Maybe<&2, String>
def parse.body.chunked.eq source · line 352 · raw
@rest:String -> @ok:Bool -> Maybe<&2, String>
def parse.body.chunked.val source · line 359 · raw
@te:String -> @rest:String -> Maybe<&2, String>
def parse.body.chunked source · line 362 · raw
@+h:Map<&2, String> -> @rest:String -> @hascl:Bool -> Maybe<&2, String>
def parse.body.te source · line 369 · raw
@+h:Map<&2, String> -> @rest:String -> @te:Bool -> Maybe<&2, String>
def parse.body source · line 376 · raw
@+h:Map<&2, String> -> @rest:String -> Maybe<&2, String>
def parse.finish source · line 379 · raw
@method:String -> @path:String -> @h:Map<&2, String> -> @body:Maybe<&2, String> -> Maybe<&2, Req>
def parse.host source · line 386 · raw
@method:String -> @path:String -> @+h:Map<&2, String> -> @rest:String -> @has:Bool -> Maybe<&2, Req>
def parse.fields source · line 393 · raw
@method:String -> @path:String -> @rest:String -> @fs:Maybe<&2, Map<&2, String>> -> Maybe<&2, Req>
def target_ok source · line 400 · raw
@+p:String -> Bool
def parse.target source · line 403 · raw
@method:String -> @+path:String -> @headers:List<&2, String> -> @rest:String -> @ok:Bool -> Maybe<&2, Req>
def parse.ver source · line 410 · raw
@method:String -> @+path:String -> @v:String -> @headers:List<&2, String> -> @rest:String -> @ok:Bool -> Maybe<&2, Req>
def parse.empty_method source · line 417 · raw
@method:String -> @path:String -> @+v:String -> @headers:List<&2, String> -> @rest:String -> @empty:Bool -> Maybe<&2, Req>
def parse.start3 source · line 424 · raw
@mpv:Pair(String, Pair(String, String)) -> @headers:List<&2, String> -> @rest:String -> Maybe<&2, Req>
def parse.lines source · line 428 · raw
@xs:List<&2, String> -> @rest:String -> Maybe<&2, Req>
def parse.head source · line 435 · raw
@head:String -> @rest:String -> Maybe<&2, Req>
def parse.of source · line 438 · raw
@hb:Pair(String, String) -> Maybe<&2, Req>
def parse source · line 442 · raw
@raw:String -> Maybe<&2, Req>
def parse.res.cl source · line 445 · raw
@+h:Map<&2, String> -> @rest:String -> @hascl:Bool -> Maybe<&2, String>
def parse.res.te source · line 452 · raw
@+h:Map<&2, String> -> @rest:String -> @te:Bool -> Maybe<&2, String>
def parse.res.body source · line 459 · raw
@+h:Map<&2, String> -> @rest:String -> Maybe<&2, String>
def frame.cut source · line 469 · raw
@closed:Bool -> Frame
RFC 9112 §8: a message cut short by close is incomplete, not valid.
def frame.wait source · line 476 · raw
@res:Res -> @wait:Bool -> Frame
def frame.done source · line 483 · raw
@status:U32 -> @h:Map<&2, String> -> @body:Maybe<&2, String> -> @+closed:Bool -> @open:Bool -> Frame
def frame.open source · line 491 · raw
@+h:Map<&2, String> -> Bool
RFC 9112 §6.3 (8): no TE and no CL ⇒ the body runs until the server closes.
def frame.nobody source · line 496 · raw
@+status:U32 -> @head:Bool -> Bool
RFC 9112 §6.3 (1): HEAD, 1xx, 204 and 304 responses end at the blank line. ponytail: 1xx is returned as final; skip interim responses if a server sends 103
def frame.status source · line 499 · raw
@status:U32 -> @+h:Map<&2, String> -> @rest:String -> @closed:Bool -> @nobody:Bool -> Frame
def parse.res.fields source · line 506 · raw
@+status:U32 -> @rest:String -> @fs:Maybe<&2, Map<&2, String>> -> @closed:Bool -> @head:Bool -> Frame
def parse.res.num source · line 513 · raw
@code:Maybe<&2, U32> -> @headers:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> Frame
def parse.res.ver source · line 520 · raw
@code:String -> @headers:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> @ok:Bool -> Frame
def parse.res.start3 source · line 527 · raw
@mpv:Pair(String, Pair(String, String)) -> @headers:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> Frame
def parse.res.lines source · line 531 · raw
@xs:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> Frame
def parse.res.blank source · line 538 · raw
@hd:String -> @rest:String -> @+closed:Bool -> @head:Bool -> @ok:Bool -> Frame
def parse.res.of source · line 545 · raw
@hb:Pair(String, String) -> @closed:Bool -> @head:Bool -> Frame
def frame source · line 550 · raw
@raw:String -> @closed:Bool -> @head:Bool -> Frame
frame(bytes so far, server closed?, request was HEAD?)
def frame.res source · line 553 · raw
@f:Frame -> Maybe<&2, Res>
def parse_res source · line 562 · raw
@raw:String -> Maybe<&2, Res>
def res_body.res source · line 565 · raw
@res:Res -> String
def res_body source · line 569 · raw
@m:Maybe<&2, Res> -> String
def got_body.req source · line 576 · raw
@req:Req -> String
def got_body source · line 580 · raw
@m:Maybe<&2, Req> -> String
def body.of source · line 587 · raw
@hb:Pair(String, String) -> String
def body source · line 591 · raw
@s:String -> String
def headers_block.go source · line 594 · raw
@xs:List<&2, Sigma<&2, &2, String, _ => String>> -> @acc:String -> String
def headers_block source · line 601 · raw
@h:Map<&2, String> -> String
def response source · line 604 · raw
@status:U32 -> @headers:Map<&2, String> -> @body:String -> String
def nat_u32 source · line 607 · raw
@n:Nat -> U32
def encode source · line 614 · raw
@r:Res -> String
def request source · line 618 · raw
@method:String -> @path:String -> @headers:Map<&2, String> -> @body:String -> String
def req.reserved source · line 621 · raw
@+k:String -> Bool
def req.put.one source · line 624 · raw
@m:Map<&2, String> -> @+k:String -> @v:String -> @skip:Bool -> Map<&2, String>
def req.put source · line 631 · raw
@xs:List<&2, Sigma<&2, &2, String, _ => String>> -> @m:Map<&2, String> -> Map<&2, String>
def req.cl source · line 640 · raw
@+m:Map<&2, String> -> @+method:String -> @+body:String -> Map<&2, String>
RFC 9110 §8.6: no Content-Length on a bodiless request whose method gives a body no meaning.
def encode_req source · line 646 · raw
@+method:String -> @target:String -> @host:String -> @headers:Map<&2, String> -> @+body:String -> String
Caller headers are lowercased so they cannot duplicate ours; host, connection, content-length and transfer-encoding are always ours (no smuggling through them).
def fetch.close source · line 650 · raw
@s:Socket -> @r:Maybe<&2, Res> -> IO(Maybe<&2, Res>)
def fetch.none source · line 655 · raw
IO(Maybe<&2, Res>)
def fetch.cap source · line 658 · raw
@f:Frame -> @over:Bool -> Frame
def fetch.max source · line 666 · raw
Nat
Untrusted servers must not grow the buffer without bound.
def fetch.next.buf source · line 669 · raw
@s:Socket -> @+buf:String -> @closed:Bool -> @head:Bool -> Pair(Socket, Pair(String, Frame))
def fetch.next.r source · line 672 · raw
@head:Bool -> @s:Socket -> @buf:String -> @r:Result<&1, &1, Pair(U32, String), String> -> Pair(Socket, Pair(String, Frame))
def fetch.next source · line 679 · raw
@head:Bool -> @buf:String -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), String>) -> Pair(Socket, Pair(String, Frame))
def fetch.sent source · line 697 · raw
@head:Bool -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), Unit>) -> IO(Maybe<&2, Res>)
def fetch.conn source · line 705 · raw
@head:Bool -> @wire:String -> @r:Result<&1, &1, Pair(U32, String), Socket> -> IO(Maybe<&2, Res>)
def fetch.ip source · line 715 · raw
@+method:String -> @ip:String -> @port:U32 -> @host:String -> @target:String -> @headers:Map<&2, String> -> @body:String -> IO(Maybe<&2, Res>)
One request on one connection to an IPv4 address. Bodies are byte strings.
def fetch.addr source · line 720 · raw
@method:String -> @port:U32 -> @hf:String -> @target:String -> @headers:Map<&2, String> -> @body:String -> @ip:Maybe<&2, String> -> IO(Maybe<&2, Res>)
def fetch.http source · line 728 · raw
@method:String -> @host:String -> @port:U32 -> @hf:String -> @target:String -> @headers:Map<&2, String> -> @body:String -> @http:Bool -> IO(Maybe<&2, Res>)
ponytail: http only; https lands with TLS
def fetch.abs source · line 737 · raw
@method:String -> @headers:Map<&2, String> -> @body:String -> @hf:String -> @a:0x977945edff4d58fb1fd04f769d651271/url/url.Abs -> IO(Maybe<&2, Res>)
def fetch.url source · line 741 · raw
@method:String -> @headers:Map<&2, String> -> @body:String -> @u:Maybe<&2, 0x977945edff4d58fb1fd04f769d651271/url/url.Abs> -> IO(Maybe<&2, Res>)
def fetch source · line 750 · raw
@method:String -> @url:String -> @headers:Map<&2, String> -> @body:String -> IO(Maybe<&2, Res>)
fetch("GET", "http://example.com/x?y=1", headers, body): None on a bad URL, a failed lookup or connect, or a malformed response. Body and response body are bytes.
def get source · line 753 · raw
@url:String -> IO(String)
def sent_fin source · line 758 · raw
@m:Pair(Socket, Result<&1, &1, Pair(U32, String), Unit>) -> IO(Unit)
def reply_send source · line 762 · raw
@s:Socket -> @res:Res -> IO(Unit)
Templates
template reply_handle source · line 767 · raw
@-h:(@_:Req -> IO(Res)) -> @s:Socket -> @req:Req -> IO(Unit)
template reply_parsed source · line 772 · raw
@-h:(@_:Req -> IO(Res)) -> @s:Socket -> @m:Maybe<&2, Req> -> IO(Unit)
template reply_ok source · line 779 · raw
@-h:(@_:Req -> IO(Res)) -> @s:Socket -> @raw:String -> IO(Unit)
template reply source · line 782 · raw
@-h:(@_:Req -> IO(Res)) -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), String>) -> IO(Unit)
template talk source · line 790 · raw
@-h:(@_:Req -> IO(Res)) -> @s:Socket -> IO(Unit)
template conn source · line 795 · raw
@-h:(@_:Req -> IO(Res)) -> @m:Pair(Listener, Result<&1, &1, Pair(U32, String), Socket>) -> IO(Listener)
template serve source · line 809 · raw
@-h:(@_:Req -> IO(Res)) -> @+port:U32 -> IO(Unit)
Unsafe
unsafe fetch.read source · line 685 · raw
@+head:Bool -> @st:Pair(Socket, Pair(String, Frame)) -> IO(Maybe<&2, Res>)
Reads until frame says Done or Bad; an empty recv means the server closed.
unsafe loop source · line 803 · raw
@-h:(@_:Req -> IO(Res)) -> @l:Listener -> IO(Unit)