shithub: mc

ref: f37c8970f11e21b0b6f29c4aac10f92101d0c906
dir: /lib/http/server.myr/

View raw version
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# -> void)
;;

const announce = {ds
	var afd

	match std.announce(ds)
	| `std.Ok f:	afd = f
	| `std.Err e:	-> `std.Err `Econn
	;;

	match std.listen(afd)
	| `std.Err e:	-> `std.Err `Econn
	| `std.Ok lfd:
		std.close(afd)
		-> `std.Ok std.mk([.lfd=lfd])
	;;
}

const serve = {srv
	while true
		match waitconn(srv)
		| `std.Ok fd:	
			thread.spawn({;communicate(srv, fd)})
		| `std.Err e:	/* eh? */
		;;
	;;
}

const communicate = {srv, fd
	var s

	s = mksrvsession(fd)
	while !srv.quit
		match parsereq(s)
		| `std.Ok req:
			dispatch(srv, s, req)
		| `std.Err e:
			break
		;;
	;;
	std.close(fd)
}

const dispatch = {srv, sess, req
	var resp : resp#

	resp = std.mk([
		.status=200,
		.hdrs = [][:],
		.len = 0,
		.err = `std.None,
		.reason = "",
		.body = "pong\n",
		.enc = `Length
	])
	respond(srv, sess, resp)
}

const respond = {srv, s, resp
	var sb

	sb = std.mksb()
	bio.put(s.f, "HTTP/1.1 {} {}\r\n", resp.status, statusstr(resp.status))
	bio.put(s.f, "Content-Length: {}\r\n", resp.body.len)
	bio.put(s.f, "Encoding: {}\r\n", resp.enc)
	for (k, v) in resp.hdrs
		bio.put(s.f, "{}: {}\r\n", k, v)
	;;
	bio.put(s.f, "\r\n")
	bio.write(s.f, resp.body)
	bio.flush(s.f)
}

const statusstr = {st
	match st
	| 200:	-> "OK"
	| 404:	-> "Not Found"
	| 503:	-> "Internal Error"
	| _:	-> "Bad State"
	;;
}

const shutdown = {srv
	std.close(srv.lfd)
}


const waitconn = {srv
	match std.accept(srv.lfd)
	| `std.Ok fd:	-> `std.Ok fd
	| `std.Err e:	-> `std.Err `Econn
	;;
}