bend-kit-multipart Releases (6): 0.3.0.0 0x39fdf1600978e53d86e47fb711ba28b3 indexed https://jend.leeeet.dev/files.txt?path=bend-kit-multipart@0.3.0.0 0.2.0.1 0xd042c3ff55d734ecab2d7e12722984a8 unindexed https://jend.leeeet.dev/files.txt?path=bend-kit-multipart@0.2.0.1 0.2.0.0 0xe74c8d946093ca2f300aef5ce96c1195 invalid https://jend.leeeet.dev/files.txt?path=bend-kit-multipart@0.2.0.0 expected a fresh constructor name (duplicate declaration: Text) At https://jend.leeeet.dev/read.txt?path=bend-kit-multipart@0.2.0.0/multipart.bend&start_line=324. Files that do not load: multipart.bend. 0.1.1.1 0xe7e5f3dfa42ee8efd8b402eac98183c5 invalid https://jend.leeeet.dev/files.txt?path=bend-kit-multipart@0.1.1.1 expected a fresh constructor name (duplicate declaration: Text) At https://jend.leeeet.dev/read.txt?path=bend-kit-multipart@0.1.1.1/multipart.bend&start_line=324. Files that do not load: multipart.bend. 0.1.1.0 0x4ac5209fa4a6e3fd4139a876056c7e73 invalid https://jend.leeeet.dev/files.txt?path=bend-kit-multipart@0.1.1.0 expected a fresh constructor name (duplicate declaration: Text) At https://jend.leeeet.dev/read.txt?path=bend-kit-multipart@0.1.1.0/multipart.bend&start_line=324. Files that do not load: multipart.bend. 0.1.0.0 0x5031ae624630f73426f2b6209dc55911 invalid https://jend.leeeet.dev/files.txt?path=bend-kit-multipart@0.1.0.0 expected a fresh constructor name (duplicate declaration: Text) At https://jend.leeeet.dev/read.txt?path=bend-kit-multipart@0.1.0.0/multipart.bend&start_line=324. Files that do not load: multipart.bend. Definitions (99): Multipart.Part (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=Part) # One form field. filename marks a file; ctype is its Content-Type (RFC 7578 §4.4 defaults to text/plain). type Part is Type: Part{name: String, filename: Maybe<&2, String>, ctype: Maybe<&2, String>, body: Bytes.Bytes} Multipart.Item (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=Item) # What the streaming decoder reports, in order: Head, then zero or more Body pieces, then Tail, per part. type Item is Type: Head{name: String, filename: Maybe<&2, String>, ctype: Maybe<&2, String>} Body{chunk: Bytes.Bytes} Tail{} Multipart.split1.cons (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=split1.cons) # The text before the first c, and the text after it. No c gives (s, ""). def split1.cons(+h: U32, r: String & String) -> String & String: Multipart.split1 (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=split1) def split1(s: String, +c: U32) -> String & String: Multipart.Cls (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=Cls) # Header parameters (RFC 2045 §5.1, RFC 7578 §4.2): key=token or key="quoted", split on ';'. # Keys are lowercased; a backslash escapes the next char inside quotes. An unterminated quote drops its parameter. type Cls is Data: CEq{} CSemi{} CQuote{} CSlash{} CSp{} COther{} Multipart.Pm (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=Pm) type Pm is Data: PKey{} PStart{} PQuo{} PEsc{} PTok{} PSkip{} Multipart.Param (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=Param) type Param is Data: Param{key: String, val: String} Multipart.PS (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=PS) # mode, the key and value so far (reversed), and the parameters found (latest first). type PS is Data: PS{mode: Pm, key: String, val: String, acc: List<&2, Param>} Multipart.cls (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=cls) def cls(+c: U32) -> Cls: Multipart.params.emit (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=params.emit) def params.emit(key: String, val: String, acc: List<&2, Param>) -> List<&2, Param>: Multipart.params.step (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=params.step) def params.step(st: PS, k: Cls, +c: U32) -> PS: Multipart.params.end (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=params.end) def params.end(st: PS) -> List<&2, Param>: Multipart.params.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=params.go) def params.go(s: String, st: PS) -> PS: Multipart.params (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=params) # The parameters of a header value's text after its first ';', in order. def params(s: String) -> List<&2, Param>: Multipart.lookup (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=lookup) # The first parameter named k (lowercase). def lookup(xs: List<&2, Param>, +k: String) -> Maybe<&2, String>: Multipart.esc.one (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=esc.one) # WHATWG form-data escapes for names and filenames. def esc.one(+c: U32) -> String: Multipart.esc (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=esc) def esc(s: String) -> String: Multipart.unesc.fix (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=unesc.fix) # acc is reversed, so "%22" shows as "22%". def unesc.fix(+a: String) -> String: Multipart.unesc.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=unesc.go) def unesc.go(s: String, acc: String) -> String: Multipart.unesc (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=unesc) # Undoes esc, as the Fetch spec's form-data parser does. A literal "%22" in a name reads back as '"'. def unesc(s: String) -> String: Multipart.unesc.m (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=unesc.m) def unesc.m(m: Maybe<&2, String>) -> Maybe<&2, String>: Multipart.bchar (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=bchar) # RFC 2046 §5.1.1 bchars: DIGIT ALPHA ' ( ) + _ , - . / : = ? and space. def bchar(+c: U32) -> Bool: Multipart.bchars (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=bchars) def bchars(s: String) -> Bool: Multipart.boundary.ok (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=boundary.ok) # 1 to 70 bchars, not ending in a space. def boundary.ok(+b: String) -> Bool: Multipart.boundary.words (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=boundary.words) def boundary.words(r: Result<&1, &1, U32 & String, U32 & Array>) -> Result<&1, &1, U32 & String, String>: Multipart.boundary.new (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=boundary.new) # "bend-kit-" and 128 bits from the OS secure random source, as hex: 41 bchars. def boundary.new() -> IO(Result<&1, &1, U32 & String, String>): Multipart.content_type (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=content_type) # The Content-Type header value for a body encoded with boundary b. def content_type(b: String) -> String: Multipart.boundary.get.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=boundary.get.of) def boundary.get.of(r: String & String) -> Maybe<&2, String>: Multipart.boundary.get (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=boundary.get) # The boundary parameter of a Content-Type value, such as a request's, or None. def boundary.get(ct: String) -> Maybe<&2, String>: Multipart.enc.fname (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=enc.fname) def enc.fname(m: Maybe<&2, String>) -> String: Multipart.enc.ctype (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=enc.ctype) def enc.ctype(m: Maybe<&2, String>) -> String: Multipart.enc.head (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=enc.head) def enc.head(+b: String, name: String, fname: Maybe<&2, String>, ct: Maybe<&2, String>) -> String: Multipart.enc.ctype.ok (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=enc.ctype.ok) # A Content-Type with CR or LF would inject header lines. def enc.ctype.ok(m: Maybe<&2, String>) -> Bool: Multipart.enc.found (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=enc.found) def enc.found(r: Bytes.Bytes & Maybe<&2, U32>, +head: String, xs: List<&1, Bytes.Bytes>) -> Result<&1, &1, String, List<&1, Bytes.Bytes>>: Multipart.enc.body (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=enc.body) def enc.body(ok: Bool, r: Bytes.Bytes & Maybe<&2, U32>, +head: String, xs: List<&1, Bytes.Bytes>) -> Result<&1, &1, String, List<&1, Bytes.Bytes>>: Multipart.enc.part (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=enc.part) # The pieces so far, latest first. A body cannot hold CRLF "--" boundary; bchars hold no CR, # so the delimiter cannot start inside the body and end in the one after it. def enc.part(acc: Result<&1, &1, String, List<&1, Bytes.Bytes>>, p: Part, +b: String, +delim: String) -> Result<&1, &1, String, List<&1, Bytes.Bytes>>: Multipart.enc.fin (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=enc.fin) def enc.fin(+b: String, acc: Result<&1, &1, String, List<&1, Bytes.Bytes>>) -> Result<&1, &1, String, Bytes.Bytes>: Multipart.enc.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=enc.go) def enc.go(parts: List<&1, Part>, +b: String, +delim: String, acc: Result<&1, &1, String, List<&1, Bytes.Bytes>>) -> Result<&1, &1, String, Bytes.Bytes>: Multipart.encode.if (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=encode.if) def encode.if(ok: Bool, +b: String, parts: List<&1, Part>) -> Result<&1, &1, String, Bytes.Bytes>: Multipart.encode (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=encode) # The body for parts under boundary b (RFC 7578 §4.1). Fails when b is not a valid boundary, # b's delimiter occurs in a body, or a Content-Type holds CR or LF. def encode(+b: String, parts: List<&1, Part>) -> Result<&1, &1, String, Bytes.Bytes>: Multipart.form.enc (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=form.enc) def form.enc(+b: String, r: Result<&1, &1, String, Bytes.Bytes>) -> Result<&1, &1, U32 & String, String & Bytes.Bytes>: Multipart.form.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=form.of) def form.of(r: Result<&1, &1, U32 & String, String>, parts: List<&1, Part>) -> Result<&1, &1, U32 & String, String & Bytes.Bytes>: Multipart.form (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=form) # The Content-Type value and body for parts, under a fresh random boundary. # Fails with the random source's error, or EINVAL (22) when encode fails. def form(parts: List<&1, Part>) -> IO(Result<&1, &1, U32 & String, String & Bytes.Bytes>): Multipart.Stage (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=Stage) # Pre: before the first delimiter. After: past a delimiter, before its line ends. # Heads: in a header block. Content: in a body. End: past the close delimiter. type Stage is Data: Pre{} After{} Heads{} Content{} End{} Multipart.Step (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=Step) type Step is Type: More{stage: Stage, buf: Bytes.Bytes, out: List<&1, Item>} Pause{stage: Stage, buf: Bytes.Bytes, out: List<&1, Item>} Bad{error: String} Multipart.Dec (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=Dec) # delim is CRLF "--" boundary and dlen its length; buf holds the bytes not yet decided. type Dec is Type: Dec{delim: String, dlen: U32, stage: Stage, buf: Bytes.Bytes} Multipart.MAX_HEAD (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=MAX_HEAD) # ponytail: a fixed cap on a header block or boundary line; make it a decoder field if a caller needs another. def MAX_HEAD() -> U32: Multipart.drop (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=drop) def drop(b: Bytes.Bytes, +n: U32) -> Bytes.Bytes: Multipart.keep.two (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=keep.two) def keep.two(+cut: U32, +k: U32, r: Bytes.Bytes & Bytes.Bytes) -> Bytes.Bytes & Bytes.Bytes: Multipart.keep.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=keep.of) def keep.of(+k: U32, r: Bytes.Bytes & U32) -> Bytes.Bytes & Bytes.Bytes: Multipart.keep (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=keep) # b as (all but its last k bytes, its last k bytes). def keep(b: Bytes.Bytes, +k: U32) -> Bytes.Bytes & Bytes.Bytes: Multipart.emit (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=emit) def emit(empty: Bool, b: Bytes.Bytes, out: List<&1, Item>) -> List<&1, Item>: Multipart.wait.if (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=wait.if) def wait.if(big: Bool, st: Stage, buf: Bytes.Bytes, out: List<&1, Item>) -> Step: Multipart.wait.big (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=wait.big) # Wait for more input, unless the undecided bytes already pass MAX_HEAD. def wait.big(st: Stage, r: Bytes.Bytes & U32, out: List<&1, Item>) -> Step: Multipart.suffix.dash (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=suffix.dash) # What follows a delimiter match (RFC 2046 §5.1.1): "--", or transport padding then CRLF, makes it a # delimiter (0). Anything else makes it data, as "--Bextra" is for boundary B (1). Too few bytes: 2. def suffix.dash(s: String) -> U32: Multipart.suffix.lf (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=suffix.lf) def suffix.lf(s: String) -> U32: Multipart.suffix (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=suffix) def suffix(s: String, +first: Bool) -> U32: Multipart.suffix.win (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=suffix.win) # ponytail: looks at 64 bytes past the match; padding longer than that counts as data. def suffix.win(+s: String) -> U32: Multipart.suffix.of (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=suffix.of) def suffix.of(r: Bytes.Bytes & Bytes.Bytes) -> Bytes.Bytes & U32: Multipart.suffix.at (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=suffix.at) # The buffer and the kind of the match at i. def suffix.at(buf: Bytes.Bytes, +i: U32, +dlen: U32) -> Bytes.Bytes & U32: Multipart.pre.if (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=pre.if) # Pre: the preamble is dropped. Keeping dlen - 1 bytes means a delimiter split across chunks is still found. # A 0/1/2 suffix kind as two flags, since only a parameter can be matched. def pre.if(delim: Bool, data: Bool, buf: Bytes.Bytes, +i: U32, +dlen: U32, out: List<&1, Item>) -> Step: Multipart.pre.kind (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=pre.kind) def pre.kind(r: Bytes.Bytes & U32, +i: U32, +dlen: U32, out: List<&1, Item>) -> Step: Multipart.pre.hit (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=pre.hit) def pre.hit(+dlen: U32, r: Bytes.Bytes & Maybe<&2, U32>, out: List<&1, Item>) -> Step: Multipart.after.line (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=after.line) # After: suffix already saw "--" or padding then CRLF, so both are in buf. "--" closes the body. # The CRLF stays in buf, so the header block is found as CRLF ... CRLF CRLF, empty or not. def after.line(r: Bytes.Bytes & Maybe<&2, U32>, out: List<&1, Item>) -> Step: Multipart.after.dash (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=after.dash) def after.dash(r: Bytes.Bytes & Bool, out: List<&1, Item>) -> Step: Multipart.meta.line (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=meta.line) # Header block to a Head (RFC 7578 §4.2, §4.4). Other headers are ignored (§4.8). def meta.line(r: String & String, st: Maybe<&2, String> & Maybe<&2, String>) -> Maybe<&2, String> & Maybe<&2, String>: Multipart.meta.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=meta.go) def meta.go(lines: List<&2, String>, st: Maybe<&2, String> & Maybe<&2, String>) -> Maybe<&2, String> & Maybe<&2, String>: Multipart.head.named (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=head.named) def head.named(n: Maybe<&2, String>, f: Maybe<&2, String>, ct: Maybe<&2, String>) -> Result<&1, &1, String, Item>: Multipart.head.form (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=head.form) def head.form(ok: Bool, +ps: List<&2, Param>, ct: Maybe<&2, String>) -> Result<&1, &1, String, Item>: Multipart.head.disp (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=head.disp) def head.disp(r: String & String, ct: Maybe<&2, String>) -> Result<&1, &1, String, Item>: Multipart.head.meta (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=head.meta) def head.meta(r: Maybe<&2, String> & Maybe<&2, String>) -> Result<&1, &1, String, Item>: Multipart.head.parse (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=head.parse) # Lines split on LF; trimming drops each CR. def head.parse(block: String) -> Result<&1, &1, String, Item>: Multipart.heads.item (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=heads.item) def heads.item(h: Result<&1, &1, String, Item>, rest: Bytes.Bytes, out: List<&1, Item>) -> Step: Multipart.heads.cut (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=heads.cut) def heads.cut(+j: U32, r: Bytes.Bytes & Bytes.Bytes, out: List<&1, Item>) -> Step: Multipart.heads.found (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=heads.found) # buf starts with the CRLF that ended the boundary line, so a match at 0 is an empty block. def heads.found(r: Bytes.Bytes & Maybe<&2, U32>, out: List<&1, Item>) -> Step: Multipart.text.flush.len (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=text.flush.len) # Content: bytes that cannot begin a delimiter go out as Body; the last dlen - 1 wait for the next chunk. def text.flush.len(r: Bytes.Bytes & U32, tail: Bytes.Bytes, out: List<&1, Item>) -> Step: Multipart.text.flush (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=text.flush) def text.flush(r: Bytes.Bytes & Bytes.Bytes, out: List<&1, Item>) -> Step: Multipart.text.cut (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=text.cut) def text.cut(+i: U32, +dlen: U32, r: Bytes.Bytes & Bytes.Bytes, out: List<&1, Item>) -> Step: Multipart.text.data (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=text.data) # A match that is data goes out through its first byte, and the search goes on after it. def text.data(+n: U32, r: Bytes.Bytes & Bytes.Bytes, out: List<&1, Item>) -> Step: Multipart.text.hold (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=text.hold) # A match whose suffix has not arrived: the bytes before it go out, and it waits. def text.hold(+i: U32, r: Bytes.Bytes & Bytes.Bytes, out: List<&1, Item>) -> Step: Multipart.text.if (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=text.if) def text.if(delim: Bool, data: Bool, buf: Bytes.Bytes, +i: U32, +dlen: U32, out: List<&1, Item>) -> Step: Multipart.text.kind (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=text.kind) def text.kind(r: Bytes.Bytes & U32, +i: U32, +dlen: U32, out: List<&1, Item>) -> Step: Multipart.text.hit (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=text.hit) def text.hit(+dlen: U32, r: Bytes.Bytes & Maybe<&2, U32>, out: List<&1, Item>) -> Step: Multipart.step (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=step) def step(st: Stage, +delim: String, +dlen: U32, buf: Bytes.Bytes, out: List<&1, Item>) -> Step: Multipart.go.stop (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=go.stop) def go.stop(+delim: String, +dlen: U32, s: Step) -> Result<&1, &1, String, Dec & List<&1, Item>>: Multipart.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=go) # Each More step consumes a byte, except the two after a delimiter, which itself consumes dlen >= 5, # so len + 8 steps suffice. Running out still returns a sound state: the next feed goes on from it. def go(fuel: Nat, +delim: String, +dlen: U32, s: Step) -> Result<&1, &1, String, Dec & List<&1, Item>>: Multipart.decoder (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=decoder) # A decoder for boundary b. It starts with a CRLF, so a delimiter at the very start is found like any other. def decoder(b: String) -> Dec: Multipart.feed.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=feed.go) def feed.go(+delim: String, +dlen: U32, st: Stage, r: Bytes.Bytes & U32) -> Result<&1, &1, String, Dec & List<&1, Item>>: Multipart.feed (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=feed) # The next chunk of a body, in any split. Answers the decoder and the items the chunk completes, # or the first error. A body piece is held back only while it could start a delimiter. def feed(d: Dec, chunk: Bytes.Bytes) -> Result<&1, &1, String, Dec & List<&1, Item>>: Multipart.finish (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=finish) # Done once the close delimiter has been read; the epilogue is ignored. def finish(d: Dec) -> Result<&1, &1, String, Unit>: Multipart.collect.add (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=collect.add) def collect.add(ps: List<&1, Part>, b: Bytes.Bytes) -> List<&1, Part>: Multipart.collect (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=collect) # Items folded into parts, latest first. def collect(items: List<&1, Item>, ps: List<&1, Part>) -> List<&1, Part>: Multipart.chunks.fed (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=chunks.fed) def chunks.fed(r: Result<&1, &1, String, Dec & List<&1, Item>>, ps: List<&1, Part>) -> Result<&1, &1, String, Dec & List<&1, Part>>: Multipart.chunks.step (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=chunks.step) def chunks.step(st: Result<&1, &1, String, Dec & List<&1, Part>>, c: Bytes.Bytes) -> Result<&1, &1, String, Dec & List<&1, Part>>: Multipart.chunks.fin (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=chunks.fin) def chunks.fin(r: Result<&1, &1, String, Unit>, ps: List<&1, Part>) -> Result<&1, &1, String, List<&1, Part>>: Multipart.chunks.end (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=chunks.end) def chunks.end(st: Result<&1, &1, String, Dec & List<&1, Part>>) -> Result<&1, &1, String, List<&1, Part>>: Multipart.chunks.go (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=chunks.go) def chunks.go(cs: List<&1, Bytes.Bytes>, st: Result<&1, &1, String, Dec & List<&1, Part>>) -> Result<&1, &1, String, List<&1, Part>>: Multipart.decode.chunks (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=decode.chunks) # The parts of a body that arrives as chunks, split anywhere. def decode.chunks(b: String, cs: List<&1, Bytes.Bytes>) -> Result<&1, &1, String, List<&1, Part>>: Multipart.decode (https://jend.leeeet.dev/definition.txt?path=bend-kit-multipart@0.3.0.0/multipart.bend&name=decode) # The parts of a whole body. def decode(b: String, body: Bytes.Bytes) -> Result<&1, &1, String, List<&1, Part>>: