http.bend fails
raw source on the hub · import 0x5ddb90739641adb64ef94dd80c43f8d4/http.bend as Http
HTTP/1.1 client for http and https, with DNS and TLS.
5 imports
import Base import ./about.bend as About import ./wire.bend as Wire import ./dns/dns.bend as Dns import ./url/url.bend as Url
Types
type Req source · line 15 · raw
Data
Req@method:String -> @path:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> Req
type Res source · line 18 · raw
Data
Res@status:U32 -> @headers:Map<&2, List<&2, String>> -> @body:String -> Res
type Err source · line 23 · raw
Data
Why fetch failed. Wire errors keep the errno and the text the effect already had. ponytail: 60 and 110 are ETIMEDOUT on macOS and Linux. Windows is out of scope.
ErrUrlErr
ErrDnsErr
ErrConnect@code:U32 -> @why:String -> Err
ErrTls@code:U32 -> @why:String -> Err
ErrRead@code:U32 -> @why:String -> Err
ErrWrite@code:U32 -> @why:String -> Err
ErrTimeoutErr
ErrRedirectErr
ErrBadErr
type Fields source · line 47 · raw
Data
FieldsBadFields
FieldsOk@m:Map<&2, List<&2, String>> -> Fields
type HexSize source · line 281 · raw
Data
HexSize@n:U32 -> @rest:String -> HexSize
type Step source · line 284 · raw
Data
StepFailStep
StepDone@body:String -> Step
StepNext@rest:String -> @acc:String -> Step
type Took source · line 386 · raw
Data
Took@racc:String -> @rest:String -> Took
type Frame source · line 571 · raw
Data
Bad: never a message. More: a valid prefix; read on. Done: a whole response.
FrameBadFrame
FrameMoreFrame
FrameDone@res:Res -> Frame
type Need source · line 688 · raw
Data
When can a response be whole? fetch uses this to skip re-framing a growing buffer after every read. Head: the header block is not in yet. Len: the message is total bytes long. Chunk: it ends with CRLF CRLF. Close: only at close. Now: frame it at once (no body, or already malformed).
NeedHeadNeed
NeedLen@total:Nat -> Need
NeedChunkNeed
NeedCloseNeed
NeedNowNeed
type Hop source · line 853 · raw
Data
One request to make: headers are already lowercased (see req.put).
Hop@method:String -> @url:0x5ddb90739641adb64ef94dd80c43f8d4/url/url.Abs -> @headers:Map<&2, List<&2, String>> -> @body:String -> Hop
type Rd source · line 943 · raw
Data
Read state: bytes so far reversed (appends are cheap), their count, the framing hint, the last verdict, and a wire error if the read itself failed.
Rd@rbuf:String -> @n:Nat -> @need:Need -> @f:Frame -> @err:Maybe<&2, Err> -> Rd
type Next source · line 1102 · raw
Data
NDone@res:Result<&2, &2, Err, Res> -> Next
NStopNext
NGo@left:Nat -> @hop:Hop -> Next
Definitions
def err.late source · line 34 · raw
@+code:U32 -> Bool
def err.pick source · line 37 · raw
@e:Err -> @late:Bool -> Err
def err.or_late source · line 44 · raw
@code:U32 -> @e:Err -> Err
def empty source · line 53 · raw
Map<&2, List<&2, String>>
One list per field name, in arrival order. header() is the first value. Set-Cookie is never joined. Encode writes one line per value.
def fields.of source · line 56 · raw
@r:Pair(Map<&2, List<&2, String>>, List<&2, String>) -> List<&2, String>
def fields source · line 60 · raw
@+h:Map<&2, List<&2, String>> -> @k:String -> List<&2, String>
def header.first source · line 63 · raw
@xs:List<&2, String> -> String
def header source · line 70 · raw
@+h:Map<&2, List<&2, String>> -> @k:String -> String
def field.last source · line 73 · raw
@xs:List<&2, String> -> String
def header.last source · line 83 · raw
@+h:Map<&2, List<&2, String>> -> @k:String -> String
Transfer-Encoding is a list; chunked, when present, is the last coding.
def snoc source · line 86 · raw
@xs:List<&2, String> -> @v:String -> List<&2, String>
def set source · line 93 · raw
@m:Map<&2, List<&2, String>> -> @k:String -> @v:String -> Map<&2, List<&2, String>>
def add source · line 96 · raw
@+m:Map<&2, List<&2, String>> -> @+k:String -> @v:String -> Map<&2, List<&2, String>>
def sanitize.cons source · line 99 · raw
@ch:Char -> @rest:String -> @drop:Bool -> String
def sanitize source · line 106 · raw
@s:String -> String
def drop_cr.if source · line 113 · raw
@+s:String -> @cr:Bool -> String
def drop_cr source · line 120 · raw
@+s:String -> String
def take_sp.go source · line 123 · raw
@s:String -> @+acc:String -> Pair(String, String)
def take_sp source · line 130 · raw
@s:String -> Pair(String, String)
def start_line.ver source · line 133 · raw
@m:String -> @pv:Pair(String, String) -> Pair(String, Pair(String, String))
def start_line.rest source · line 137 · raw
@mr:Pair(String, String) -> Pair(String, Pair(String, String))
def start_line source · line 141 · raw
@s:String -> Pair(String, Pair(String, String))
def split_at_blank.go source · line 144 · raw
@s:String -> @e:Bool -> @w:U32 -> @acc:String -> Pair(String, String)
def split_at_blank source · line 156 · raw
@s:String -> Pair(String, String)
def split_colon.go source · line 159 · raw
@s:String -> @+acc:String -> Pair(String, String)
def split_colon source · line 166 · raw
@s:String -> Pair(String, String)
def has_header.of source · line 169 · raw
@r:Pair(Map<&2, List<&2, String>>, Bool) -> Bool
def has_header source · line 173 · raw
@+h:Map<&2, List<&2, String>> -> @k:String -> Bool
def folded source · line 176 · raw
@+line:String -> Bool
def tracked source · line 179 · raw
@+k:String -> Bool
def fields_put.dup source · line 182 · raw
@m:Map<&2, List<&2, String>> -> @k:String -> @v:String -> @bad:Bool -> Fields
def fields_put.key source · line 189 · raw
@+m:Map<&2, List<&2, String>> -> @+k:String -> @v:String -> Fields
def fields_put.kv source · line 192 · raw
@m:Map<&2, List<&2, String>> -> @kv:Pair(String, String) -> Fields
def fields_put.fold source · line 196 · raw
@m:Map<&2, List<&2, String>> -> @line:String -> @fold:Bool -> Fields
def fields_put.empty source · line 203 · raw
@m:Map<&2, List<&2, String>> -> @+line:String -> @e:Bool -> Fields
def fields_put.ok source · line 210 · raw
@m:Map<&2, List<&2, String>> -> @+line:String -> Fields
def fields_put source · line 213 · raw
@acc:Fields -> @line:String -> Fields
def parse.headers.done source · line 220 · raw
@acc:Fields -> Maybe<&2, Map<&2, List<&2, String>>>
def parse.headers source · line 227 · raw
@xs:List<&2, String> -> @acc:Fields -> Maybe<&2, Map<&2, List<&2, String>>>
def parse_u32.digit source · line 234 · raw
@+c:U32 -> Bool
def parse_u32.add source · line 237 · raw
@acc:U32 -> @c:U32 -> U32
def parse_u32.done source · line 240 · raw
@acc:U32 -> @bad:Bool -> Maybe<&2, U32>
def parse_u32.go source · line 247 · raw
@s:String -> @acc:U32 -> @bad:Bool -> Maybe<&2, U32>
def parse_u32 source · line 254 · raw
@s:String -> Maybe<&2, U32>
def parse.take.if source · line 263 · raw
@+rest:String -> @+k:Nat -> @short:Bool -> Maybe<&2, String>
def parse.take.have source · line 271 · 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 274 · raw
@rest:String -> @n:Maybe<&2, U32> -> Maybe<&2, String>
def is_hex source · line 289 · raw
@+c:U32 -> Bool
def hexv source · line 292 · raw
@+c:U32 -> U32
def chunk.lf1 source · line 295 · raw
@r:String -> @n:U32 -> @lf:Bool -> Maybe<&2, HexSize>
def chunk.lf source · line 302 · raw
@t:String -> @n:U32 -> Maybe<&2, HexSize>
def chunk.ext.go source · line 313 · raw
@t:String -> @+c:U32 -> @+n:U32 -> @stop:Bool -> Maybe<&2, HexSize>
def chunk.ext source · line 325 · raw
@s:String -> @n:U32 -> Maybe<&2, HexSize>
RFC 9112 §7.1.1: recipients ignore unknown chunk extensions; a bare LF is not CRLF.
def chunk.size.end source · line 332 · raw
@+c:U32 -> @+t:String -> @+n:U32 -> @seen:Bool -> Maybe<&2, HexSize>
def chunk.digit source · line 340 · raw
@+c:U32 -> @+acc:U32 -> Bool
A size that would overflow 32 bits ends the digits, and size.end then refuses it.
def chunk.size.go source · line 343 · raw
@t:String -> @+c:U32 -> @+acc:U32 -> @seen:Bool -> @digit:Bool -> Maybe<&2, HexSize>
def chunk.size source · line 355 · raw
@s:String -> Maybe<&2, HexSize>
def chunk.trailer.ok source · line 364 · raw
@racc:String -> @ok:Bool -> Step
def chunk.trailer.end source · line 371 · raw
@hb:Pair(String, String) -> @racc:String -> Step
def chunk.trailer.if source · line 375 · raw
@rest:String -> @racc:String -> @blank:Bool -> Step
def chunk.trailer source · line 383 · raw
@+rest:String -> @racc:String -> Step
ponytail: trailer fields are dropped unparsed (§7.1.2 allows discarding)
def take.exact source · line 390 · raw
@s:String -> @k:Nat -> @racc:String -> Maybe<&2, Took>
Moves exactly k chars onto racc; None if s runs out first. O(k), no length scan.
def chunk.crlf.if source · line 405 · raw
@racc:String -> @+after:String -> @ok:Bool -> Step
def chunk.data source · line 412 · raw
@m:Maybe<&2, Took> -> Step
def chunk.step.n source · line 419 · raw
@+n:U32 -> @rest:String -> @racc:String -> @zero:Bool -> Step
def chunk.step.got source · line 426 · raw
@got:Maybe<&2, HexSize> -> @racc:String -> Step
def chunk.step source · line 433 · raw
@s:String -> @racc:String -> Step
def chunk.go source · line 436 · raw
@fuel:Nat -> @st:Step -> Maybe<&2, String>
def chunk.decode source · line 450 · 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 453 · raw
@+h:Map<&2, List<&2, String>> -> @rest:String -> @hascl:Bool -> Maybe<&2, String>
def parse.body.chunked.eq source · line 460 · raw
@rest:String -> @ok:Bool -> Maybe<&2, String>
def parse.body.chunked.val source · line 467 · raw
@te:String -> @rest:String -> Maybe<&2, String>
def parse.body.chunked source · line 470 · raw
@+h:Map<&2, List<&2, String>> -> @rest:String -> @hascl:Bool -> Maybe<&2, String>
def parse.body.te source · line 477 · raw
@+h:Map<&2, List<&2, String>> -> @rest:String -> @te:Bool -> Maybe<&2, String>
def parse.body source · line 484 · raw
@+h:Map<&2, List<&2, String>> -> @rest:String -> Maybe<&2, String>
def parse.finish source · line 487 · raw
@method:String -> @path:String -> @h:Map<&2, List<&2, String>> -> @body:Maybe<&2, String> -> Maybe<&2, Req>
def parse.host source · line 494 · raw
@method:String -> @path:String -> @+h:Map<&2, List<&2, String>> -> @rest:String -> @has:Bool -> Maybe<&2, Req>
def parse.fields source · line 501 · raw
@method:String -> @path:String -> @rest:String -> @fs:Maybe<&2, Map<&2, List<&2, String>>> -> Maybe<&2, Req>
def target_ok source · line 508 · raw
@+p:String -> Bool
def parse.target source · line 511 · raw
@method:String -> @+path:String -> @headers:List<&2, String> -> @rest:String -> @ok:Bool -> Maybe<&2, Req>
def parse.ver source · line 518 · raw
@method:String -> @+path:String -> @v:String -> @headers:List<&2, String> -> @rest:String -> @ok:Bool -> Maybe<&2, Req>
def parse.empty_method source · line 525 · raw
@method:String -> @path:String -> @+v:String -> @headers:List<&2, String> -> @rest:String -> @empty:Bool -> Maybe<&2, Req>
def parse.start3 source · line 532 · raw
@mpv:Pair(String, Pair(String, String)) -> @headers:List<&2, String> -> @rest:String -> Maybe<&2, Req>
def parse.lines source · line 536 · raw
@xs:List<&2, String> -> @rest:String -> Maybe<&2, Req>
def parse.head source · line 543 · raw
@head:String -> @rest:String -> Maybe<&2, Req>
def parse.of source · line 546 · raw
@hb:Pair(String, String) -> Maybe<&2, Req>
def parse source · line 550 · raw
@raw:String -> Maybe<&2, Req>
def parse.res.cl source · line 553 · raw
@+h:Map<&2, List<&2, String>> -> @rest:String -> @hascl:Bool -> Maybe<&2, String>
def parse.res.te source · line 560 · raw
@+h:Map<&2, List<&2, String>> -> @rest:String -> @te:Bool -> Maybe<&2, String>
def parse.res.body source · line 567 · raw
@+h:Map<&2, List<&2, String>> -> @rest:String -> Maybe<&2, String>
def frame.cut source · line 577 · raw
@closed:Bool -> Frame
RFC 9112 §8: a message cut short by close is incomplete, not valid.
def frame.wait source · line 584 · raw
@res:Res -> @wait:Bool -> Frame
def frame.done source · line 591 · raw
@status:U32 -> @h:Map<&2, List<&2, String>> -> @body:Maybe<&2, String> -> @+closed:Bool -> @open:Bool -> Frame
def frame.open source · line 599 · raw
@+h:Map<&2, List<&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 604 · 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 607 · raw
@status:U32 -> @+h:Map<&2, List<&2, String>> -> @rest:String -> @closed:Bool -> @nobody:Bool -> Frame
def parse.res.fields source · line 614 · raw
@+status:U32 -> @rest:String -> @fs:Maybe<&2, Map<&2, List<&2, String>>> -> @closed:Bool -> @head:Bool -> Frame
def parse.res.num source · line 621 · raw
@code:Maybe<&2, U32> -> @headers:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> Frame
def parse.res.ver source · line 628 · raw
@code:String -> @headers:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> @ok:Bool -> Frame
def parse.res.start3 source · line 635 · raw
@mpv:Pair(String, Pair(String, String)) -> @headers:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> Frame
def parse.res.lines source · line 639 · raw
@xs:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> Frame
def parse.res.blank source · line 646 · raw
@hd:String -> @rest:String -> @+closed:Bool -> @head:Bool -> @ok:Bool -> Frame
def parse.res.of source · line 653 · raw
@hb:Pair(String, String) -> @closed:Bool -> @head:Bool -> Frame
def frame source · line 658 · raw
@raw:String -> @closed:Bool -> @head:Bool -> Frame
frame(bytes so far, server closed?, request was HEAD?)
def frame.res source · line 661 · raw
@f:Frame -> Maybe<&2, Res>
def parse_res source · line 670 · raw
@raw:String -> Maybe<&2, Res>
def res_fields.res source · line 673 · raw
@res:Res -> @k:String -> List<&2, String>
def res_fields source · line 677 · raw
@m:Maybe<&2, Res> -> @k:String -> List<&2, String>
def need.cl source · line 695 · raw
@hlen:Nat -> @n:Maybe<&2, U32> -> Need
def need.framing source · line 702 · raw
@+h:Map<&2, List<&2, String>> -> @hlen:Nat -> @te:Bool -> @cl:Bool -> Need
def need.fields source · line 713 · raw
@hlen:Nat -> @nobody:Bool -> @fs:Maybe<&2, Map<&2, List<&2, String>>> -> Need
def need.num source · line 724 · raw
@code:Maybe<&2, U32> -> @headers:List<&2, String> -> @hlen:Nat -> @head:Bool -> Need
def need.start3 source · line 731 · raw
@mpv:Pair(String, Pair(String, String)) -> @headers:List<&2, String> -> @hlen:Nat -> @head:Bool -> Need
def need.lines source · line 735 · raw
@xs:List<&2, String> -> @hlen:Nat -> @head:Bool -> Need
def need.blank source · line 742 · raw
@+hd:String -> @head:Bool -> @ok:Bool -> Need
def need.of source · line 749 · raw
@hb:Pair(String, String) -> @head:Bool -> Need
def need source · line 754 · raw
@raw:String -> @head:Bool -> Need
A hint only: frame() stays the judge of every byte.
def res_body.res source · line 757 · raw
@res:Res -> String
def res_body source · line 761 · raw
@m:Maybe<&2, Res> -> String
def got_body.req source · line 768 · raw
@req:Req -> String
def got_body source · line 772 · raw
@m:Maybe<&2, Req> -> String
def body.of source · line 779 · raw
@hb:Pair(String, String) -> String
def body source · line 783 · raw
@s:String -> String
def headers_lines source · line 786 · raw
@+k:String -> @vs:List<&2, String> -> @acc:String -> String
def headers_block.go source · line 793 · raw
@xs:List<&2, Sigma<&2, &2, String, _ => List<&2, String>>> -> @acc:String -> String
def headers_block source · line 800 · raw
@h:Map<&2, List<&2, String>> -> String
def response source · line 803 · raw
@status:U32 -> @headers:Map<&2, List<&2, String>> -> @body:String -> String
def nat_u32 source · line 806 · raw
@n:Nat -> U32
def encode source · line 813 · raw
@r:Res -> String
def request source · line 817 · raw
@method:String -> @path:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> String
def req.reserved source · line 820 · raw
@+k:String -> Bool
def req.put.one source · line 823 · raw
@m:Map<&2, List<&2, String>> -> @+k:String -> @vs:List<&2, String> -> @skip:Bool -> Map<&2, List<&2, String>>
def req.put source · line 830 · raw
@xs:List<&2, Sigma<&2, &2, String, _ => List<&2, String>>> -> @m:Map<&2, List<&2, String>> -> Map<&2, List<&2, String>>
def req.cl source · line 839 · raw
@+m:Map<&2, List<&2, String>> -> @+method:String -> @+body:String -> Map<&2, List<&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 845 · raw
@+method:String -> @target:String -> @host:String -> @headers:Map<&2, List<&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 redirect.code source · line 856 · raw
@+s:U32 -> Bool
def redirect.origin source · line 859 · raw
@a:0x5ddb90739641adb64ef94dd80c43f8d4/url/url.Abs -> String
def redirect.del source · line 863 · raw
@ks:List<&2, String> -> @m:Map<&2, List<&2, String>> -> Map<&2, List<&2, String>>
def redirect.hdrs source · line 870 · raw
@+h:Map<&2, List<&2, String>> -> @drop:Bool -> @cross:Bool -> Map<&2, List<&2, String>>
def redirect.to source · line 877 · raw
@+status:U32 -> @+method:String -> @+from:0x5ddb90739641adb64ef94dd80c43f8d4/url/url.Abs -> @headers:Map<&2, List<&2, String>> -> @+body:String -> @next:Maybe<&2, 0x5ddb90739641adb64ef94dd80c43f8d4/url/url.Abs> -> Maybe<&2, Hop>
303 turns any method but HEAD into GET; 301 and 302 turn POST into GET; 307 and 308 keep method and body. A GET carries no body or body headers. Credentials do not follow a hop to another origin.
def redirect.hop source · line 885 · raw
@status:U32 -> @h:Hop -> @loc:String -> Maybe<&2, Hop>
def redirect.if source · line 889 · raw
@status:U32 -> @h:Hop -> @loc:String -> @ok:Bool -> Maybe<&2, Hop>
def redirect source · line 897 · raw
@+status:U32 -> @+headers:Map<&2, List<&2, String>> -> @h:Hop -> Maybe<&2, Hop>
The next request after a response, or None when it is not a redirect we follow.
def io.recv source · line 901 · raw
@tls:Bool -> @s:Socket -> @max:U32 -> @ms:U32 -> IO(Pair(Socket, Result<&1, &1, Pair(U32, String), String>))
Transport: plain TCP or TLS over the same socket.
def io.send source · line 908 · raw
@tls:Bool -> @s:Socket -> @data:String -> IO(Pair(Socket, Result<&1, &1, Pair(U32, String), Unit>))
def io.close source · line 915 · raw
@tls:Bool -> @s:Socket -> IO(Unit)
def fetch.close source · line 922 · raw
@tls:Bool -> @s:Socket -> @r:Result<&2, &2, Err, Res> -> IO(Result<&2, &2, Err, Res>)
def fetch.fail source · line 927 · raw
@e:Err -> IO(Result<&2, &2, Err, Res>)
def fetch.cap source · line 930 · raw
@f:Frame -> @over:Bool -> Frame
def fetch.max source · line 938 · raw
Nat
Untrusted servers must not grow the buffer without bound.
def fetch.need source · line 947 · raw
@hint:Need -> @+rbuf:String -> @head:Bool -> Need
The hint is worked out once, when the header block has arrived.
def fetch.gate source · line 962 · raw
@closed:Bool -> @need:Need -> @+n:Nat -> @+got:String -> Bool
Could the buffer hold a whole response now? A yes may be wrong (frame then says More); a no must never be.
def fetch.try source · line 979 · raw
@gate:Bool -> @rbuf:String -> @closed:Bool -> @head:Bool -> Frame
def fetch.step source · line 986 · raw
@+head:Bool -> @s:Socket -> @rd:Rd -> @+got:String -> @+closed:Bool -> Pair(Socket, Rd)
def fetch.wire source · line 993 · raw
@s:Socket -> @rd:Rd -> @+code:U32 -> @why:String -> Pair(Socket, Rd)
def fetch.next.go source · line 998 · raw
@+head:Bool -> @s:Socket -> @rd:Rd -> @r:Result<&1, &1, Pair(U32, String), String> -> Pair(Socket, Rd)
def fetch.next source · line 1005 · raw
@head:Bool -> @rd:Rd -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), String>) -> Pair(Socket, Rd)
def fetch.bad source · line 1009 · raw
@tls:Bool -> @s:Socket -> @e:Maybe<&2, Err> -> IO(Result<&2, &2, Err, Res>)
def fetch.sent source · line 1031 · raw
@head:Bool -> @tls:Bool -> @ms:U32 -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), Unit>) -> IO(Result<&2, &2, Err, Res>)
def fetch.send source · line 1039 · raw
@head:Bool -> @+tls:Bool -> @ms:U32 -> @s:Socket -> @wire:String -> IO(Result<&2, &2, Err, Res>)
def fetch.shook source · line 1045 · raw
@head:Bool -> @ms:U32 -> @wire:String -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), Unit>) -> IO(Result<&2, &2, Err, Res>)
A failed handshake is an error, never plaintext.
def fetch.secure source · line 1053 · raw
@head:Bool -> @+ms:U32 -> @sni:String -> @wire:String -> @c:Socket -> @tls:Bool -> IO(Result<&2, &2, Err, Res>)
def fetch.conn source · line 1062 · raw
@head:Bool -> @ms:U32 -> @sni:String -> @wire:String -> @tls:Bool -> @r:Result<&1, &1, Pair(U32, String), Socket> -> IO(Result<&2, &2, Err, Res>)
def fetch.ip source · line 1070 · raw
@+method:String -> @ip:String -> @port:U32 -> @sni:String -> @hf:String -> @target:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> @tls:Bool -> @+ms:U32 -> IO(Result<&2, &2, Err, Res>)
One request on one connection to an IPv4 address. Bodies are byte strings.
def fetch.addr source · line 1075 · raw
@method:String -> @port:U32 -> @sni:String -> @hf:String -> @target:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> @tls:Bool -> @ms:U32 -> @ip:Maybe<&2, String> -> IO(Result<&2, &2, Err, Res>)
def fetch.dns source · line 1082 · raw
@method:String -> @+host:String -> @port:U32 -> @hf:String -> @target:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> @tls:Bool -> @ms:U32 -> IO(Result<&2, &2, Err, Res>)
def fetch.scheme source · line 1087 · raw
@method:String -> @host:String -> @port:U32 -> @hf:String -> @target:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> @ms:U32 -> @+scheme:String -> @known:Bool -> IO(Result<&2, &2, Err, Res>)
def fetch.abs source · line 1094 · raw
@method:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> @ms:U32 -> @hf:String -> @a:0x5ddb90739641adb64ef94dd80c43f8d4/url/url.Abs -> IO(Result<&2, &2, Err, Res>)
def fetch.one source · line 1098 · raw
@h:Hop -> @ms:U32 -> IO(Result<&2, &2, Err, Res>)
def fetch.hop source · line 1108 · raw
@left:Nat -> @h:Hop -> Next
left: redirects still allowed after the request we just finished.
def fetch.decide.r source · line 1115 · raw
@left:Nat -> @+r:Res -> @next:Maybe<&2, Hop> -> Next
def fetch.decide.res source · line 1122 · raw
@left:Nat -> @h:Hop -> @+r:Res -> Next
def fetch.decide source · line 1126 · raw
@left:Nat -> @h:Hop -> @m:Result<&2, &2, Err, Res> -> Next
def fetch.start source · line 1146 · raw
@method:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> @u:Maybe<&2, 0x5ddb90739641adb64ef94dd80c43f8d4/url/url.Abs> -> Next
def fetch.with source · line 1157 · raw
@method:String -> @url:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> @ms:U32 -> IO(Result<&2, &2, Err, Res>)
fetch("GET", "https://example.com/x?y=1", headers, body) follows redirects. Fail is a bad URL, a failed lookup, connect, handshake, send, read, a malformed response, more than 20 redirects, or a step past ms. Body and response body are bytes.
def fetch source · line 1161 · raw
@method:String -> @url:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> IO(Result<&2, &2, Err, Res>)
fetch.with and a 30 s step timeout.
def get source · line 1164 · raw
@url:String -> IO(Result<&2, &2, Err, Res>)
def sent_fin source · line 1167 · raw
@m:Pair(Socket, Result<&1, &1, Pair(U32, String), Unit>) -> IO(Unit)
def reply_send source · line 1171 · raw
@s:Socket -> @res:Res -> IO(Unit)
Templates
template reply_handle source · line 1176 · raw
@-h:(@_:Req -> IO(Res)) -> @s:Socket -> @req:Req -> IO(Unit)
template reply_parsed source · line 1181 · raw
@-h:(@_:Req -> IO(Res)) -> @s:Socket -> @m:Maybe<&2, Req> -> IO(Unit)
template reply_ok source · line 1188 · raw
@-h:(@_:Req -> IO(Res)) -> @s:Socket -> @raw:String -> IO(Unit)
template reply source · line 1191 · raw
@-h:(@_:Req -> IO(Res)) -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), String>) -> IO(Unit)
template talk source · line 1199 · raw
@-h:(@_:Req -> IO(Res)) -> @s:Socket -> IO(Unit)
template conn source · line 1204 · raw
@-h:(@_:Req -> IO(Res)) -> @m:Pair(Listener, Result<&1, &1, Pair(U32, String), Socket>) -> IO(Listener)
template serve source · line 1218 · raw
@-h:(@_:Req -> IO(Res)) -> @+port:U32 -> IO(Unit)
Unsafe
unsafe fetch.read source · line 1018 · raw
@+head:Bool -> @+tls:Bool -> @+ms:U32 -> @st:Pair(Socket, Rd) -> IO(Result<&2, &2, Err, Res>)
Reads until frame says Done or Bad; an empty recv means the server closed.
unsafe fetch.hops source · line 1135 · raw
@+ms:U32 -> @st:Next -> IO(Result<&2, &2, Err, Res>)
NGo.left is how many redirects may follow this request. 20 is WHATWG's limit.
unsafe loop source · line 1212 · raw
@-h:(@_:Req -> IO(Res)) -> @l:Listener -> IO(Unit)