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
|
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)
;;
}
|