ref: 22d71e9e0471402b4d9e918f4f10683137ee9121
dir: /lib/http/verbs.myr/
use std use bio use "types" use "session" use "parse" pkg http = const get : (s : session#, path : byte[:] -> std.result(resp#, err)) const head : (s : session#, path : byte[:] -> std.result(resp#, err)) const put : (s : session#, path : byte[:], data : byte[:] -> std.result(resp#, err)) const post : (s : session#, path : byte[:], data : byte[:] -> std.result(resp#, err)) const delete : (s : session#, path : byte[:] -> std.result(resp#, err)) const options : (s : session#, path : byte[:] -> std.result(resp#, err)) const trace : (s : session#, path : byte[:] -> std.result(resp#, err)) const freeresp : (r : resp# -> void) ;; const get = {s, path match request(s, `Get, path, [][:], `std.None) | `std.Ok _: /* nothing */ | `std.Fail e: -> `std.Fail e ;; -> response(s, true) } const head = {s, path match request(s, `Head, path, [][:], `std.None) | `std.Ok _: /* nothing */ | `std.Fail e: -> `std.Fail e ;; -> response(s, false) } const put = {s, path, data match request(s, `Put, path, [][:], `std.Some data) | `std.Ok _: /* nothing */ | `std.Fail e: -> `std.Fail e ;; -> response(s, true) } const post = {s, path, data match request(s, `Post, path, [][:], `std.Some data) | `std.Ok _: /* nothing */ | `std.Fail e: -> `std.Fail e ;; -> response(s, true) } const delete = {s, path match request(s, `Delete, path, [][:], `std.None) | `std.Ok _: /* nothing */ | `std.Fail e: -> `std.Fail e ;; -> response(s, true) } const options = {s, path match request(s, `Options, path, [][:], `std.None) | `std.Ok _: /* nothing */ | `std.Fail e: -> `std.Fail e ;; -> response(s, true) } const trace = {s, path match request(s, `Options, path, [][:], `std.None) | `std.Ok _: /* nothing */ | `std.Fail e: -> `std.Fail e ;; -> response(s, true) } const response = {s, body var resp resp = std.mk([ .hdrs = [][:], .len = 0, .err = `std.None, .reason = "", .status = 0, .enc = `Length, ]) if parseresp(s, resp) if !body -> `std.Ok resp else match readbody(s, resp) | `std.Ok buf: resp.body = buf | `std.Fail e: -> `std.Fail e ;; ;; else match resp.err | `std.Some e: -> `std.Fail e | `std.None: -> `std.Fail `Ewat ;; ;; -> `std.Ok resp } const request = {s, method, path, hdrs : (byte[:], byte[:])[:], data /* status */ ioput(s, "{} {} HTTP/1.1\r\n", method, path) /* headers */ ioput(s, "Host: {}\r\n", s.host) ioput(s, "User-Agent: {}\r\n", s.ua) match data | `std.Some d: ioput(s, "Content-Length: {}\r\n", d.len) | `std.None: /* nothing to do */ ;; for (k, v) in hdrs ioput(s, "{}: {}\r\n", k, v) ;; ioput(s, "\r\n") /* body */ match data | `std.None: /* nothing to do */ | `std.Some d: ioput(s, d) ioput(s, "\r\n") ;; ioflush(s) if s.err -> `std.Fail `Econn else -> `std.Ok void ;; } const readbody = {s, r -> std.result(byte[:], err) match r.enc | `Length: -> readlenbody(s, r) | `Chunked: -> readchunkedbody(s, r) | badenc: std.fatal("unsupported encoding {}\n", badenc) ;; } const readlenbody = {s, r var buf buf = "" if r.len == 0 -> `std.Ok buf ;; buf = std.slalloc(r.len) match bio.read(s.f, buf) | `bio.Err e: goto shortread | `bio.Eof: goto shortread | `bio.Ok rd: if rd.len != r.len goto shortread ;; ;; -> `std.Ok buf :shortread std.slfree(buf) -> `std.Fail `Eshort } const __init__ = { var m m = `Get std.fmtinstall(std.typeof(m), fmtmethod, [][:]) } const readchunkedbody = {s, r var buf, len buf = "" len = 0 while true match parsechunksz(s) | `std.Fail e: std.slfree(buf) -> `std.Fail e | `std.Ok 0: break | `std.Ok sz: std.slgrow(&buf, buf.len + sz) match bio.read(s.f, buf[len:len + sz]) | `bio.Eof: std.slfree(buf) -> `std.Fail `Eshort | `bio.Err e: std.slfree(buf) -> `std.Fail `Econn | `bio.Ok str: if str.len != sz std.slfree(buf) -> `std.Fail `Eshort ;; len += sz match checkendln(s) | `std.Ok _: /* nothing */ | `std.Fail e: std.slfree(buf) -> `std.Fail e ;; ;; ;; ;; -> `std.Ok buf } const checkendln = {s var r match bio.readln(s.f) | `bio.Err e: r = `std.Fail `Econn | `bio.Eof: r = `std.Fail `Econn | `bio.Ok crlf: if std.strstrip(crlf).len == 0 r = `std.Ok void else r = `std.Fail `Eproto ;; std.slfree(crlf) ;; -> r } const fmtmethod = {sb, ap, opt var r r = std.vanext(ap) match r | `Get: std.sbputs(sb, "GET") | `Head: std.sbputs(sb, "HEAD") | `Put: std.sbputs(sb, "PUT") | `Post: std.sbputs(sb, "POST") | `Delete: std.sbputs(sb, "DELETE") | `Trace: std.sbputs(sb, "TRACE") | `Options: std.sbputs(sb, "OPTIONS") ;; } const freeresp = {r for (k, v) in r.hdrs std.slfree(k) std.slfree(v) ;; std.slfree(r.reason) std.free(r) }