summaryrefslogtreecommitdiff
path: root/lib/http/server.myr
diff options
context:
space:
mode:
Diffstat (limited to 'lib/http/server.myr')
-rw-r--r--lib/http/server.myr100
1 files changed, 100 insertions, 0 deletions
diff --git a/lib/http/server.myr b/lib/http/server.myr
new file mode 100644
index 0000000..0cfdcb0
--- /dev/null
+++ b/lib/http/server.myr
@@ -0,0 +1,100 @@
+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)
+ | `std.Err e: break
+ ;;
+ ;;
+ std.close(fd)
+ unref(srv)
+}
+
+const respond = {srv, s, resp
+ var sb
+
+ sb = std.mksb()
+ ioput(s, "HTTP/1.1 {} {}\r\n", resp.status, statusstr(resp.status))
+ ioput(s, "Content-Length: {}\r\n", resp.body.len)
+ ioput(s, "Encoding: {}\r\n", resp.enc)
+ 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)
+ ;;
+}