~/bend-docscommunity

http.bend fails

raw source on the hub · import 0x173c3ffc0efe5dd0532b157e241ba1a7/http.bend as Http

HTTP/1.1 client for http and https, with DNS and TLS.

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 14 · raw

Data

type Res source · line 17 · raw

Data

type Err source · line 22 · 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.

type Fields source · line 46 · raw

Data

type HexSize source · line 280 · raw

Data

type Step source · line 283 · raw

Data

type Took source · line 385 · raw

Data

type Frame source · line 570 · raw

Data

Bad: never a message. More: a valid prefix; read on. Done: a whole response.

type Need source · line 687 · 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).

type Hop source · line 852 · raw

Data

One request to make: headers are already lowercased (see req.put).

type Rd source · line 942 · 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.

type Next source · line 1101 · raw

Data

Definitions

def err.late source · line 33 · raw

@+code:U32 -> Bool

def err.pick source · line 36 · raw

@e:Err -> @late:Bool -> Err

def err.or_late source · line 43 · raw

@code:U32 -> @e:Err -> Err

def empty source · line 52 · 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 55 · raw

@r:Pair(Map<&2, List<&2, String>>, List<&2, String>) -> List<&2, String>

def fields source · line 59 · raw

@+h:Map<&2, List<&2, String>> -> @k:String -> List<&2, String>

def header.first source · line 62 · raw

@xs:List<&2, String> -> String

def field.last source · line 72 · raw

@xs:List<&2, String> -> String

def header.last source · line 82 · 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 85 · raw

@xs:List<&2, String> -> @v:String -> List<&2, String>

def set source · line 92 · raw

@m:Map<&2, List<&2, String>> -> @k:String -> @v:String -> Map<&2, List<&2, String>>

def add source · line 95 · raw

@+m:Map<&2, List<&2, String>> -> @+k:String -> @v:String -> Map<&2, List<&2, String>>

def sanitize.cons source · line 98 · raw

@ch:Char -> @rest:String -> @drop:Bool -> String

def sanitize source · line 105 · raw

@s:String -> String

def drop_cr.if source · line 112 · raw

@+s:String -> @cr:Bool -> String

def drop_cr source · line 119 · raw

@+s:String -> String

def take_sp.go source · line 122 · raw

@s:String -> @+acc:String -> Pair(String, String)

def take_sp source · line 129 · raw

@s:String -> Pair(String, String)

def start_line.ver source · line 132 · raw

@m:String -> @pv:Pair(String, String) -> Pair(String, Pair(String, String))

def start_line.rest source · line 136 · raw

@mr:Pair(String, String) -> Pair(String, Pair(String, String))

def start_line source · line 140 · raw

@s:String -> Pair(String, Pair(String, String))

def split_at_blank.go source · line 143 · raw

@s:String -> @e:Bool -> @w:U32 -> @acc:String -> Pair(String, String)

def split_at_blank source · line 155 · raw

@s:String -> Pair(String, String)

def split_colon.go source · line 158 · raw

@s:String -> @+acc:String -> Pair(String, String)

def split_colon source · line 165 · raw

@s:String -> Pair(String, String)

def has_header.of source · line 168 · raw

@r:Pair(Map<&2, List<&2, String>>, Bool) -> Bool

def has_header source · line 172 · raw

@+h:Map<&2, List<&2, String>> -> @k:String -> Bool

def folded source · line 175 · raw

@+line:String -> Bool

def tracked source · line 178 · raw

@+k:String -> Bool

def fields_put.dup source · line 181 · raw

@m:Map<&2, List<&2, String>> -> @k:String -> @v:String -> @bad:Bool -> Fields

def fields_put.key source · line 188 · raw

@+m:Map<&2, List<&2, String>> -> @+k:String -> @v:String -> Fields

def fields_put.kv source · line 191 · raw

@m:Map<&2, List<&2, String>> -> @kv:Pair(String, String) -> Fields

def fields_put.fold source · line 195 · raw

@m:Map<&2, List<&2, String>> -> @line:String -> @fold:Bool -> Fields

def fields_put.empty source · line 202 · raw

@m:Map<&2, List<&2, String>> -> @+line:String -> @e:Bool -> Fields

def fields_put.ok source · line 209 · raw

@m:Map<&2, List<&2, String>> -> @+line:String -> Fields

def fields_put source · line 212 · raw

@acc:Fields -> @line:String -> Fields

def parse.headers.done source · line 219 · raw

@acc:Fields -> Maybe<&2, Map<&2, List<&2, String>>>

def parse.headers source · line 226 · raw

@xs:List<&2, String> -> @acc:Fields -> Maybe<&2, Map<&2, List<&2, String>>>

def parse_u32.digit source · line 233 · raw

@+c:U32 -> Bool

def parse_u32.add source · line 236 · raw

@acc:U32 -> @c:U32 -> U32

def parse_u32.done source · line 239 · raw

@acc:U32 -> @bad:Bool -> Maybe<&2, U32>

def parse_u32.go source · line 246 · raw

@s:String -> @acc:U32 -> @bad:Bool -> Maybe<&2, U32>

def parse_u32 source · line 253 · raw

@s:String -> Maybe<&2, U32>

def parse.take.if source · line 262 · raw

@+rest:String -> @+k:Nat -> @short:Bool -> Maybe<&2, String>

def parse.take.have source · line 270 · 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 273 · raw

@rest:String -> @n:Maybe<&2, U32> -> Maybe<&2, String>

def is_hex source · line 288 · raw

@+c:U32 -> Bool

def hexv source · line 291 · raw

@+c:U32 -> U32

def chunk.lf1 source · line 294 · raw

@r:String -> @n:U32 -> @lf:Bool -> Maybe<&2, HexSize>

def chunk.lf source · line 301 · raw

@t:String -> @n:U32 -> Maybe<&2, HexSize>

def chunk.ext.go source · line 312 · raw

@t:String -> @+c:U32 -> @+n:U32 -> @stop:Bool -> Maybe<&2, HexSize>

def chunk.ext source · line 324 · 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 331 · raw

@+c:U32 -> @+t:String -> @+n:U32 -> @seen:Bool -> Maybe<&2, HexSize>

def chunk.digit source · line 339 · 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 342 · raw

@t:String -> @+c:U32 -> @+acc:U32 -> @seen:Bool -> @digit:Bool -> Maybe<&2, HexSize>

def chunk.size source · line 354 · raw

@s:String -> Maybe<&2, HexSize>

def chunk.trailer.ok source · line 363 · raw

@racc:String -> @ok:Bool -> Step

def chunk.trailer.end source · line 370 · raw

@hb:Pair(String, String) -> @racc:String -> Step

def chunk.trailer.if source · line 374 · raw

@rest:String -> @racc:String -> @blank:Bool -> Step

def chunk.trailer source · line 382 · raw

@+rest:String -> @racc:String -> Step

ponytail: trailer fields are dropped unparsed (§7.1.2 allows discarding)

def take.exact source · line 389 · 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 404 · raw

@racc:String -> @+after:String -> @ok:Bool -> Step

def chunk.data source · line 411 · raw

@m:Maybe<&2, Took> -> Step

def chunk.step.n source · line 418 · raw

@+n:U32 -> @rest:String -> @racc:String -> @zero:Bool -> Step

def chunk.step.got source · line 425 · raw

@got:Maybe<&2, HexSize> -> @racc:String -> Step

def chunk.step source · line 432 · raw

@s:String -> @racc:String -> Step

def chunk.go source · line 435 · raw

@fuel:Nat -> @st:Step -> Maybe<&2, String>

def chunk.decode source · line 449 · 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 452 · raw

@+h:Map<&2, List<&2, String>> -> @rest:String -> @hascl:Bool -> Maybe<&2, String>

def parse.body.chunked.eq source · line 459 · raw

@rest:String -> @ok:Bool -> Maybe<&2, String>

def parse.body.chunked.val source · line 466 · raw

@te:String -> @rest:String -> Maybe<&2, String>

def parse.body.chunked source · line 469 · raw

@+h:Map<&2, List<&2, String>> -> @rest:String -> @hascl:Bool -> Maybe<&2, String>

def parse.body.te source · line 476 · raw

@+h:Map<&2, List<&2, String>> -> @rest:String -> @te:Bool -> Maybe<&2, String>

def parse.body source · line 483 · raw

@+h:Map<&2, List<&2, String>> -> @rest:String -> Maybe<&2, String>

def parse.finish source · line 486 · raw

@method:String -> @path:String -> @h:Map<&2, List<&2, String>> -> @body:Maybe<&2, String> -> Maybe<&2, Req>

def parse.host source · line 493 · raw

@method:String -> @path:String -> @+h:Map<&2, List<&2, String>> -> @rest:String -> @has:Bool -> Maybe<&2, Req>

def parse.fields source · line 500 · raw

@method:String -> @path:String -> @rest:String -> @fs:Maybe<&2, Map<&2, List<&2, String>>> -> Maybe<&2, Req>

def target_ok source · line 507 · raw

@+p:String -> Bool

def parse.target source · line 510 · raw

@method:String -> @+path:String -> @headers:List<&2, String> -> @rest:String -> @ok:Bool -> Maybe<&2, Req>

def parse.ver source · line 517 · raw

@method:String -> @+path:String -> @v:String -> @headers:List<&2, String> -> @rest:String -> @ok:Bool -> Maybe<&2, Req>

def parse.empty_method source · line 524 · raw

@method:String -> @path:String -> @+v:String -> @headers:List<&2, String> -> @rest:String -> @empty:Bool -> Maybe<&2, Req>

def parse.start3 source · line 531 · raw

@mpv:Pair(String, Pair(String, String)) -> @headers:List<&2, String> -> @rest:String -> Maybe<&2, Req>

def parse.lines source · line 535 · raw

@xs:List<&2, String> -> @rest:String -> Maybe<&2, Req>

def parse.head source · line 542 · raw

@head:String -> @rest:String -> Maybe<&2, Req>

def parse.of source · line 545 · raw

@hb:Pair(String, String) -> Maybe<&2, Req>

def parse source · line 549 · raw

@raw:String -> Maybe<&2, Req>

def parse.res.cl source · line 552 · raw

@+h:Map<&2, List<&2, String>> -> @rest:String -> @hascl:Bool -> Maybe<&2, String>

def parse.res.te source · line 559 · raw

@+h:Map<&2, List<&2, String>> -> @rest:String -> @te:Bool -> Maybe<&2, String>

def parse.res.body source · line 566 · raw

@+h:Map<&2, List<&2, String>> -> @rest:String -> Maybe<&2, String>

def frame.cut source · line 576 · raw

@closed:Bool -> Frame

RFC 9112 §8: a message cut short by close is incomplete, not valid.

def frame.wait source · line 583 · raw

@res:Res -> @wait:Bool -> Frame

def frame.done source · line 590 · raw

@status:U32 -> @h:Map<&2, List<&2, String>> -> @body:Maybe<&2, String> -> @+closed:Bool -> @open:Bool -> Frame

def frame.open source · line 598 · 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 603 · 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 606 · raw

@status:U32 -> @+h:Map<&2, List<&2, String>> -> @rest:String -> @closed:Bool -> @nobody:Bool -> Frame

def parse.res.fields source · line 613 · raw

@+status:U32 -> @rest:String -> @fs:Maybe<&2, Map<&2, List<&2, String>>> -> @closed:Bool -> @head:Bool -> Frame

def parse.res.num source · line 620 · raw

@code:Maybe<&2, U32> -> @headers:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> Frame

def parse.res.ver source · line 627 · raw

@code:String -> @headers:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> @ok:Bool -> Frame

def parse.res.start3 source · line 634 · raw

@mpv:Pair(String, Pair(String, String)) -> @headers:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> Frame

def parse.res.lines source · line 638 · raw

@xs:List<&2, String> -> @rest:String -> @closed:Bool -> @head:Bool -> Frame

def parse.res.blank source · line 645 · raw

@hd:String -> @rest:String -> @+closed:Bool -> @head:Bool -> @ok:Bool -> Frame

def parse.res.of source · line 652 · raw

@hb:Pair(String, String) -> @closed:Bool -> @head:Bool -> Frame

def frame source · line 657 · raw

@raw:String -> @closed:Bool -> @head:Bool -> Frame

frame(bytes so far, server closed?, request was HEAD?)

def frame.res source · line 660 · raw

@f:Frame -> Maybe<&2, Res>

def parse_res source · line 669 · raw

@raw:String -> Maybe<&2, Res>

def res_fields.res source · line 672 · raw

@res:Res -> @k:String -> List<&2, String>

def res_fields source · line 676 · raw

@m:Maybe<&2, Res> -> @k:String -> List<&2, String>

def need.cl source · line 694 · raw

@hlen:Nat -> @n:Maybe<&2, U32> -> Need

def need.framing source · line 701 · raw

@+h:Map<&2, List<&2, String>> -> @hlen:Nat -> @te:Bool -> @cl:Bool -> Need

def need.fields source · line 712 · raw

@hlen:Nat -> @nobody:Bool -> @fs:Maybe<&2, Map<&2, List<&2, String>>> -> Need

def need.num source · line 723 · raw

@code:Maybe<&2, U32> -> @headers:List<&2, String> -> @hlen:Nat -> @head:Bool -> Need

def need.start3 source · line 730 · raw

@mpv:Pair(String, Pair(String, String)) -> @headers:List<&2, String> -> @hlen:Nat -> @head:Bool -> Need

def need.lines source · line 734 · raw

@xs:List<&2, String> -> @hlen:Nat -> @head:Bool -> Need

def need.blank source · line 741 · raw

@+hd:String -> @head:Bool -> @ok:Bool -> Need

def need.of source · line 748 · raw

@hb:Pair(String, String) -> @head:Bool -> Need

def need source · line 753 · raw

@raw:String -> @head:Bool -> Need

A hint only: frame() stays the judge of every byte.

def res_body.res source · line 756 · raw

@res:Res -> String

def res_body source · line 760 · raw

@m:Maybe<&2, Res> -> String

def got_body.req source · line 767 · raw

@req:Req -> String

def got_body source · line 771 · raw

@m:Maybe<&2, Req> -> String

def body.of source · line 778 · raw

@hb:Pair(String, String) -> String

def body source · line 782 · raw

@s:String -> String

def headers_lines source · line 785 · raw

@+k:String -> @vs:List<&2, String> -> @acc:String -> String

def headers_block.go source · line 792 · raw

@xs:List<&2, Sigma<&2, &2, String, _ => List<&2, String>>> -> @acc:String -> String

def headers_block source · line 799 · raw

@h:Map<&2, List<&2, String>> -> String

def response source · line 802 · raw

@status:U32 -> @headers:Map<&2, List<&2, String>> -> @body:String -> String

def nat_u32 source · line 805 · raw

@n:Nat -> U32

def encode source · line 812 · raw

@r:Res -> String

def request source · line 816 · raw

@method:String -> @path:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> String

def req.reserved source · line 819 · raw

@+k:String -> Bool

def req.put.one source · line 822 · 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 829 · 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 838 · 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 844 · 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 855 · raw

@+s:U32 -> Bool

def redirect.origin source · line 858 · raw

@a:0x173c3ffc0efe5dd0532b157e241ba1a7/url/url.Abs -> String

def redirect.del source · line 862 · raw

@ks:List<&2, String> -> @m:Map<&2, List<&2, String>> -> Map<&2, List<&2, String>>

def redirect.hdrs source · line 869 · raw

@+h:Map<&2, List<&2, String>> -> @drop:Bool -> @cross:Bool -> Map<&2, List<&2, String>>

def redirect.to source · line 876 · raw

@+status:U32 -> @+method:String -> @+from:0x173c3ffc0efe5dd0532b157e241ba1a7/url/url.Abs -> @headers:Map<&2, List<&2, String>> -> @+body:String -> @next:Maybe<&2, 0x173c3ffc0efe5dd0532b157e241ba1a7/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 884 · raw

@status:U32 -> @h:Hop -> @loc:String -> Maybe<&2, Hop>

def redirect.if source · line 888 · raw

@status:U32 -> @h:Hop -> @loc:String -> @ok:Bool -> Maybe<&2, Hop>

def redirect source · line 896 · 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 900 · 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 907 · raw

@tls:Bool -> @s:Socket -> @data:String -> IO(Pair(Socket, Result<&1, &1, Pair(U32, String), Unit>))

def io.close source · line 914 · raw

@tls:Bool -> @s:Socket -> IO(Unit)

def fetch.close source · line 921 · raw

@tls:Bool -> @s:Socket -> @r:Result<&2, &2, Err, Res> -> IO(Result<&2, &2, Err, Res>)

def fetch.fail source · line 926 · raw

@e:Err -> IO(Result<&2, &2, Err, Res>)

def fetch.cap source · line 929 · raw

@f:Frame -> @over:Bool -> Frame

def fetch.max source · line 937 · raw

Nat

Untrusted servers must not grow the buffer without bound.

def fetch.need source · line 946 · 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 961 · 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 978 · raw

@gate:Bool -> @rbuf:String -> @closed:Bool -> @head:Bool -> Frame

def fetch.step source · line 985 · raw

@+head:Bool -> @s:Socket -> @rd:Rd -> @+got:String -> @+closed:Bool -> Pair(Socket, Rd)

def fetch.wire source · line 992 · raw

@s:Socket -> @rd:Rd -> @+code:U32 -> @why:String -> Pair(Socket, Rd)

def fetch.next.go source · line 997 · raw

@+head:Bool -> @s:Socket -> @rd:Rd -> @r:Result<&1, &1, Pair(U32, String), String> -> Pair(Socket, Rd)

def fetch.next source · line 1004 · raw

@head:Bool -> @rd:Rd -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), String>) -> Pair(Socket, Rd)

def fetch.bad source · line 1008 · raw

@tls:Bool -> @s:Socket -> @e:Maybe<&2, Err> -> IO(Result<&2, &2, Err, Res>)

def fetch.sent source · line 1030 · 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 1038 · raw

@head:Bool -> @+tls:Bool -> @ms:U32 -> @s:Socket -> @wire:String -> IO(Result<&2, &2, Err, Res>)

def fetch.shook source · line 1044 · 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 1052 · raw

@head:Bool -> @+ms:U32 -> @sni:String -> @wire:String -> @c:Socket -> @tls:Bool -> IO(Result<&2, &2, Err, Res>)

def fetch.conn source · line 1061 · 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 1069 · 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 1074 · 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 1081 · 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 1086 · 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 1093 · raw

@method:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> @ms:U32 -> @hf:String -> @a:0x173c3ffc0efe5dd0532b157e241ba1a7/url/url.Abs -> IO(Result<&2, &2, Err, Res>)

def fetch.one source · line 1097 · raw

@h:Hop -> @ms:U32 -> IO(Result<&2, &2, Err, Res>)

def fetch.hop source · line 1107 · raw

@left:Nat -> @h:Hop -> Next

left: redirects still allowed after the request we just finished.

def fetch.decide.r source · line 1114 · raw

@left:Nat -> @+r:Res -> @next:Maybe<&2, Hop> -> Next

def fetch.decide.res source · line 1121 · raw

@left:Nat -> @h:Hop -> @+r:Res -> Next

def fetch.decide source · line 1125 · raw

@left:Nat -> @h:Hop -> @m:Result<&2, &2, Err, Res> -> Next

def fetch.start source · line 1145 · raw

@method:String -> @headers:Map<&2, List<&2, String>> -> @body:String -> @u:Maybe<&2, 0x173c3ffc0efe5dd0532b157e241ba1a7/url/url.Abs> -> Next

def fetch.with source · line 1156 · 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 1160 · 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 1163 · raw

@url:String -> IO(Result<&2, &2, Err, Res>)

def sent_fin source · line 1166 · raw

@m:Pair(Socket, Result<&1, &1, Pair(U32, String), Unit>) -> IO(Unit)

def reply_send source · line 1170 · raw

@s:Socket -> @res:Res -> IO(Unit)

Templates

template reply_handle source · line 1175 · raw

@-h:(@_:Req -> IO(Res)) -> @s:Socket -> @req:Req -> IO(Unit)

template reply_parsed source · line 1180 · raw

@-h:(@_:Req -> IO(Res)) -> @s:Socket -> @m:Maybe<&2, Req> -> IO(Unit)

template reply_ok source · line 1187 · raw

@-h:(@_:Req -> IO(Res)) -> @s:Socket -> @raw:String -> IO(Unit)

template reply source · line 1190 · raw

@-h:(@_:Req -> IO(Res)) -> @m:Pair(Socket, Result<&1, &1, Pair(U32, String), String>) -> IO(Unit)

template talk source · line 1198 · raw

@-h:(@_:Req -> IO(Res)) -> @s:Socket -> IO(Unit)

template conn source · line 1203 · raw

@-h:(@_:Req -> IO(Res)) -> @m:Pair(Listener, Result<&1, &1, Pair(U32, String), Socket>) -> IO(Listener)

template serve source · line 1217 · raw

@-h:(@_:Req -> IO(Res)) -> @+port:U32 -> IO(Unit)

Unsafe

unsafe fetch.read source · line 1017 · 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 1134 · 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 1211 · raw

@-h:(@_:Req -> IO(Res)) -> @l:Listener -> IO(Unit)