summaryrefslogtreecommitdiff
path: root/lib/http/server.myr
blob: 34c0eef61faf34d004b3641bb8d64ebd33d4723d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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
	;;
}