ref: 0f3f41fae775b2647cd0cdaf0a9ef395c19b9878
dir: /lib/http/server.myr/
use bio
use std
use thread
use "types"
use "session"
use "parse"
pkg http =
const announce : (ds : byte[:] -> std.result(server#, err))
const shutdown : (srv : server# -> void)
const serve : (srv : server#, fn : (srv : server#, s : session#, req : req# -> void) -> void)
const respond : (srv : server#, sess : session#, resp : resp# -> void)
;;
const announce = {ds
match std.announce(ds)
| `std.Err e: -> `std.Err `Econn
| `std.Ok a:
-> `std.Ok std.mk([
.refs=1,
.ann=a,
.quit=false
])
;;
}
const serve = {srv, fn
while !srv.quit
match waitconn(srv)
| `std.Ok fd:
ref(srv)
thread.spawn({;communicate(srv, fd, fn)})
| `std.Err e: /* eh? */
;;
;;
unref(srv)
}
const communicate = {srv, fd, fn
var s
s = mksrvsession(fd)
while !srv.quit
match parsereq(s)
| `std.Ok req:
fn(srv, s, req)
freereq(req)
| `std.Err e:
break
;;
;;
freesession(s)
std.close(fd)
unref(srv)
}
const respond = {srv, s, resp
ioput(s, "HTTP/1.1 {} {}\r\n", resp.status, statusstr(resp.status))
if resp.enc != `Chunked
ioput(s, "Content-Length: {}\r\n", resp.body.len)
;;
match resp.enc
| `Length: /* noop */
| `Chunked: ioput(s, "Transfer-Encoding: chunked\r\n")
| `Compress: ioput(s, "Transfer-Encoding: compress\r\n")
| `Deflate: ioput(s, "Transfer-Encoding: deflate\r\n")
| `Gzip: ioput(s, "Transfer-Encoding: gzip\r\n")
;;
for (k, v) : resp.hdrs
ioput(s, "{}: {}\r\n", k, v)
;;
ioput(s, "\r\n")
iowrite(s, resp.body)
ioflush(s)
}
const statusstr = {st
match st
| 200: -> "OK"
| 404: -> "Not Found"
| 503: -> "Internal Error"
| _: -> "Bad State"
;;
}
const shutdown = {srv
std.aclose(srv.ann)
srv.quit = true
}
const waitconn = {srv
match std.accept(srv.ann)
| `std.Ok fd: -> `std.Ok fd
| `std.Err e: -> `std.Err `Econn
;;
}
const ref = {srv
thread.xadd(&srv.refs, 1)
}
const unref = {srv
thread.xadd(&srv.refs, -1)
if thread.xget(&srv.refs) == 0
std.free(srv)
;;
}