src/server.bend
emerging-ezhttp@0.21.0.0 · 551 lines · 64 definitions
1
2
3
4
5
6
7
8
9
10import Base
11import bend-kit-wire@0.4.6.1/wire.bend as W
12import bend-kit-bytes@0.3.2.0/bytes.bend as Bytes
13import emerging-ezhttp@0.21.0.0/src/http.bend as Http
14import emerging-ezhttp@0.21.0.0/src/cors.bend as Cors
15import emerging-ezhttp@0.21.0.0/src/step.bend as Step
16import emerging-ezhttp@0.21.0.0/src/wirespec.bend as Spec
17
18
19
20type Req is Type:
21 Req{method: String, target: String, headers: List<&2, Http.Header>,
22 body: String, bytes: Bytes.Bytes}
23
24
25
26
27type Answer is Type:
28 TextReply{status: U32, headers: List<&2, Http.Header>, body: String}
29 OctetsReply{status: U32, headers: List<&2, Http.Header>, bytes: Bytes.Bytes}
30 StreamReply{status: U32, headers: List<&2, Http.Header>,
31 chunks: Chan(Bytes.Bytes)}
32
33
34def server.max() -> U32:
35 65536
36
37
38def server.reads() -> Nat:
39 65536n
40
41
42def server.wait() -> U32:
43 3600000
44
45
46def server.idles() -> Nat:
47 1000000n
48
49
50def server.pause() -> U32:
51 100
52
53
54def server.listen(host: String, port: U32) -> IO(Listener):
55 IO.try(Listener, TCP.listen(host, port))
56
57
58def server.accept.un(r: Listener & Result<&1, &1, U32 & String, Socket>)
59 -> IO(Listener & Step.Accept<Socket>):
60 (lst, res) = r
61 IO.pure(Listener & Step.Accept<Socket>, (lst, Step.step.accepted(Socket, res)))
62
63def server.accept(listener: Listener) -> IO(Listener & Step.Accept<Socket>):
64 IO.bind(Listener & Result<&1, &1, U32 & String, Socket>,
65 Listener & Step.Accept<Socket>,
66 W.accept.deadline(listener, server.wait()), server.accept.un)
67
68
69def server.lose(sock: Socket, line: String) -> IO(Unit):
70 IO.bind(Unit, Unit, IO.print_err(line), _u => Socket.close(sock))
71
72
73
74
75
76def server.read.done(sock: Socket, ps: List<&2, String>)
77 -> IO(Socket & Step.Got<Http.Request>):
78 IO.pure(Socket & Step.Got<Http.Request>,
79 (sock, Step.Kept{Http.ask(Spec.wire.join(ps))}))
80
81
82def server.read.needs(m: Maybe<&2, Nat>, ps: List<&2, String>)
83 -> Maybe<&2, Nat>:
84 match m:
85 case None{}:
86 Step.step.need(Spec.wire.join(ps))
87 case Some{n}:
88 Some{n}
89
90
91def server.read.whole(m: Maybe<&2, Nat>, +have: Nat) -> Bool:
92 match m:
93 case None{}:
94 False{}
95 case Some{n}:
96 Bool.not(Nat.is_lt(have, n))
97
98
99def server.read.more(sock: Socket, +ps: List<&2, String>, +have: Nat,
100 +need: Maybe<&2, Nat>, whole: Bool,
101 rest: Socket -> List<&2, String> -> Nat -> Maybe<&2, Nat>
102 -> IO(Socket & Step.Got<Http.Request>))
103 -> IO(Socket & Step.Got<Http.Request>):
104 match whole:
105 case True{}:
106 server.read.done(sock, ps)
107 case False{}:
108 rest(sock)(ps)(have)(need)
109
110
111def server.read.add(sock: Socket, +ps: List<&2, String>, +have: Nat,
112 need: Maybe<&2, Nat>,
113 rest: Socket -> List<&2, String> -> Nat -> Maybe<&2, Nat>
114 -> IO(Socket & Step.Got<Http.Request>))
115 -> IO(Socket & Step.Got<Http.Request>):
116 +need2 = server.read.needs(need, ps)
117 server.read.more(sock, ps, have, need2, server.read.whole(need2, have), rest)
118
119
120def server.read.text(sock: Socket, +ps: List<&2, String>, +have: Nat,
121 need: Maybe<&2, Nat>, +text: String, closed: Bool,
122 rest: Socket -> List<&2, String> -> Nat -> Maybe<&2, Nat>
123 -> IO(Socket & Step.Got<Http.Request>))
124 -> IO(Socket & Step.Got<Http.Request>):
125 match closed:
126 case True{}:
127 server.read.done(sock, ps)
128 case False{}:
129 server.read.add(sock, text <> ps, Nat.add(have, String.length(text)),
130 need, rest)
131
132
133
134def server.read.got(+ps: List<&2, String>, +have: Nat, need: Maybe<&2, Nat>,
135 r: Socket & Result<&1, &1, U32 & String, String>,
136 rest: Socket -> List<&2, String> -> Nat -> Maybe<&2, Nat>
137 -> IO(Socket & Step.Got<Http.Request>))
138 -> IO(Socket & Step.Got<Http.Request>):
139 (sock, res) = r
140 match res:
141 case Fail{(code, why)}:
142 IO.pure(Socket & Step.Got<Http.Request>,
143 (sock, Step.Lost{Step.step.line("read", why)}))
144 case Done{+text}:
145 server.read.text(sock, ps, have, need, text, String.is_empty(text), rest)
146
147
148
149def server.read.go(fuel: Nat, sock: Socket, +ps: List<&2, String>, +have: Nat,
150 +need: Maybe<&2, Nat>) -> IO(Socket & Step.Got<Http.Request>):
151 match fuel:
152 case 0n:
153 server.read.done(sock, ps)
154 case 1n+f:
155 IO.bind(Socket & Result<&1, &1, U32 & String, String>,
156 Socket & Step.Got<Http.Request>,
157 W.recv(sock, server.max(), 0),
158 r => server.read.got(ps, have, need, r,
159 s => p => h => m => server.read.go(f, s, p, h, m)))
160
161
162def server.read(sock: Socket) -> IO(Socket & Step.Got<Http.Request>):
163 server.read.go(server.reads(), sock, [], 0n, None{})
164
165
166
167
168def server.sent.un(r: Socket & Result<&1, &1, U32 & String, Unit>)
169 -> IO(Socket & Step.Got<Unit>):
170 (sock, res) = r
171 IO.pure(Socket & Step.Got<Unit>, (sock, Step.step.got(Unit, "write", res)))
172
173
174def server.send(sock: Socket, b: Bytes.Bytes) -> IO(Socket & Step.Got<Unit>):
175 Bytes.Bytes{+len, buf} = b
176 IO.bind(Socket & Result<&1, &1, U32 & String, Unit>, Socket & Step.Got<Unit>,
177 W.send.words(sock, len, buf), server.sent.un)
178
179
180def server.send.text(sock: Socket, text: String) -> IO(Socket & Step.Got<Unit>):
181 server.send(sock, Bytes.from_string(Spec.wire.payload(text)))
182
183
184def server.close(r: Socket & Step.Got<Unit>) -> IO(Unit):
185 (sock, got) = r
186 match got:
187 case Step.Lost{line}:
188 server.lose(sock, line)
189 case Step.Kept{_u}:
190 Socket.close(sock)
191
192
193def server.then(r: Socket & Step.Got<Unit>, more: Socket -> IO(Unit))
194 -> IO(Unit):
195 (sock, got) = r
196 match got:
197 case Step.Lost{line}:
198 server.lose(sock, line)
199 case Step.Kept{_u}:
200 more(sock)
201
202
203def server.answer(sock: Socket, method: String, reply: Http.Reply) -> IO(Unit):
204 IO.bind(Socket & Step.Got<Unit>, Unit,
205 server.send.text(sock, Http.respond.of(Http.reply.for(method, reply))),
206 server.close)
207
208
209
210def server.octets.go(sock: Socket, +status: U32, headers: List<&2, Http.Header>,
211 r: Bytes.Bytes & U32, bare: Bool) -> IO(Unit):
212 (b, +n) = r
213 match bare:
214 case True{}:
215 IO.bind(Socket & Step.Got<Unit>, Unit,
216 server.send.text(sock, Http.respond.head(status, headers, 0n)),
217 server.close)
218 case False{}:
219 IO.bind(Socket & Step.Got<Unit>, Unit,
220 server.send(sock, Bytes.append(Bytes.from_string(
221 Http.respond.head(status, headers, U32.to_nat(n))), b)),
222 server.close)
223
224
225def server.chunks() -> Nat:
226 U32.to_nat(4294967295)
227
228
229def server.chunk.put(sock: Socket, c: Http.Chunk, b: Bytes.Bytes,
230 more: Socket -> IO(Unit)) -> IO(Unit):
231 match c:
232 case Http.NoChunk{}:
233 more(sock)
234 case Http.Chunk{line}:
235 IO.bind(Socket & Step.Got<Unit>, Unit,
236 server.send(sock, Bytes.append(Bytes.append(Bytes.from_string(line), b),
237 Bytes.from_string("\r\n"))),
238 r => server.then(r, more))
239
240
241def server.chunk.sized(sock: Socket, r: Bytes.Bytes & U32,
242 more: Socket -> IO(Unit)) -> IO(Unit):
243 (b, +n) = r
244 server.chunk.put(sock, Http.chunk.frame(n), b, more)
245
246
247def server.chunk.got(sock: Socket, m: Maybe<&1, Bytes.Bytes>,
248 more: Socket -> IO(Unit)) -> IO(Unit):
249 match m:
250 case None{}:
251 IO.bind(Socket & Step.Got<Unit>, Unit,
252 server.send.text(sock, Http.chunk.end()), server.close)
253 case Some{b}:
254 server.chunk.sized(sock, Bytes.length(b), more)
255
256
257def server.stream.go(fuel: Nat, sock: Socket, +ch: Chan(Bytes.Bytes))
258 -> IO(Unit):
259 match fuel:
260 case 0n:
261 IO.bind(Socket & Step.Got<Unit>, Unit,
262 server.send.text(sock, Http.chunk.end()), server.close)
263 case 1n+f:
264 IO.bind(Maybe<&1, Bytes.Bytes>, Unit, Chan.recv(Bytes.Bytes, ch),
265 m => server.chunk.got(sock, m, s => server.stream.go(f, s, ch)))
266
267
268def server.stream.body(sock: Socket, +ch: Chan(Bytes.Bytes), bare: Bool)
269 -> IO(Unit):
270 match bare:
271 case True{}:
272 IO.bind(Unit, Unit, Chan.close(Bytes.Bytes, ch), _u => Socket.close(sock))
273 case False{}:
274 server.stream.go(server.chunks(), sock, ch)
275
276
277def server.reply(sock: Socket, +method: String, a: Answer) -> IO(Unit):
278 match a:
279 case TextReply{status, headers, body}:
280 server.answer(sock, method, Http.Reply{status, headers, body})
281 case OctetsReply{+status, headers, bytes}:
282 server.octets.go(sock, status, headers, Bytes.length(bytes),
283 Step.step.bare(method, status))
284 case StreamReply{+status, +headers, +chunks}:
285 IO.bind(Socket & Step.Got<Unit>, Unit,
286 server.send.text(sock, Http.respond.stream(status, headers)),
287 r => server.then(r,
288 s => server.stream.body(s, chunks, Step.step.bare(method, status))))
289
290
291
292
293def server.req(req: Http.Request, +octets: String) -> Req:
294 match req:
295 case Http.Bad{why}:
296 Req{"", "", [], why, Bytes.from_string(octets)}
297 case Http.Request{method, target, headers, body}:
298 Req{method, target, headers, body, Bytes.from_string(octets)}
299
300
301def server.step(~C: Data, ~handle: C -> Req -> IO(Answer), +ctx: C,
302 sock: Socket, +method: String, +octets: String, step: Step.Step) -> IO(Unit):
303 match step:
304 case Step.Answer{reply}:
305 server.answer(sock, method, reply)
306 case Step.Call{req}:
307 IO.bind(Answer, Unit, handle(ctx)(server.req(req, octets)),
308 a => server.reply(sock, method, a))
309
310
311def server.conn.got(~C: Data, ~handle: C -> Req -> IO(Answer), +ctx: C,
312 r: Socket & Step.Got<Http.Request>) -> IO(Unit):
313 (sock, got) = r
314 match got:
315 case Step.Lost{line}:
316 server.lose(sock, line)
317 case Step.Kept{+raw}:
318 +req = Step.step.text(raw)
319 server.step(~C, handle, ctx, sock, Http.method.of(req),
320 Step.step.octets(raw), Step.step.of(req))
321
322
323def server.conn(~C: Data, ~handle: C -> Req -> IO(Answer), +ctx: C,
324 sock: Socket) -> IO(Unit):
325 IO.bind(Socket & Step.Got<Http.Request>, Unit, server.read(sock),
326 r => server.conn.got(~C, handle, ctx, r))
327
328
329
330
331def server.slot.give(+slots: Chan(Unit), limited: Bool) -> IO(Unit):
332 match limited:
333 case True{}:
334 IO.bind(Maybe<&1, Unit>, Unit, Chan.recv(Unit, slots),
335 _m => IO.pure(Unit, Unit{}))
336 case False{}:
337 IO.pure(Unit, Unit{})
338
339
340def server.slot.take(+slots: Chan(Unit), limited: Bool) -> IO(Unit):
341 match limited:
342 case True{}:
343 IO.bind(Result<&1, &1, Unit, Unit>, Unit, Chan.send(Unit, slots, Unit{}),
344 _r => IO.pure(Unit, Unit{}))
345 case False{}:
346 IO.pure(Unit, Unit{})
347
348
349def server.done(+done: Chan(Unit), tracked: Bool) -> IO(Unit):
350 match tracked:
351 case True{}:
352 IO.bind(Result<&1, &1, Unit, Unit>, Unit, Chan.send(Unit, done, Unit{}),
353 _r => IO.pure(Unit, Unit{}))
354 case False{}:
355 IO.pure(Unit, Unit{})
356
357
358def server.fork.body(~C: Data, ~handle: C -> Req -> IO(Answer), +ctx: C,
359 sock: Socket, +slots: Chan(Unit), +limited: Bool, +done: Chan(Unit),
360 +tracked: Bool) -> IO(Unit):
361 IO.bind(Unit, Unit, server.conn(~C, handle, ctx, sock),
362 _u => IO.bind(Unit, Unit, server.slot.give(slots, limited),
363 _v => server.done(done, tracked)))
364
365
366def server.fork(~C: Data, ~handle: C -> Req -> IO(Answer), +ctx: C,
367 sock: Socket, +slots: Chan(Unit), +limited: Bool, +done: Chan(Unit),
368 +tracked: Bool) -> IO(Unit):
369 IO.bind(Unit, Unit, server.slot.take(slots, limited),
370 _u => IO.spawn(Unit,
371 server.fork.body(~C, handle, ctx, sock, slots, limited, done, tracked)))
372
373
374def server.join(n: Nat, +done: Chan(Unit)) -> IO(Unit):
375 match n:
376 case 0n:
377 IO.pure(Unit, Unit{})
378 case 1n+p:
379 IO.bind(Maybe<&1, Unit>, Unit, Chan.recv(Unit, done),
380 _m => server.join(p, done))
381
382
383
384
385def server.loop.got(~C: Data, ~handle: C -> Req -> IO(Answer), +ctx: C,
386 +slots: Chan(Unit), +limited: Bool, +done: Chan(Unit), +tracked: Bool,
387 r: Listener & Step.Accept<Socket>, took: Listener -> IO(Unit),
388 idle: Listener -> IO(Unit), missed: Listener -> IO(Unit)) -> IO(Unit):
389 (lst, got) = r
390 match got:
391 case Step.Took{sock}:
392 IO.bind(Unit, Unit,
393 server.fork(~C, handle, ctx, sock, slots, limited, done, tracked),
394 _u => took(lst))
395 case Step.Idle{}:
396 idle(lst)
397 case Step.Missed{line}:
398 IO.bind(Unit, Unit, IO.print_err(line), _u =>
399 IO.bind(Unit, Unit, IO.sleep(server.pause()), _v => missed(lst)))
400
401
402
403def server.loop.go(~C: Data, ~handle: C -> Req -> IO(Answer), +ctx: C,
404 fuel: Nat, idles: Nat, +forks: Nat, +slots: Chan(Unit), +limited: Bool,
405 +done: Chan(Unit), listener: Listener) -> IO(Unit):
406 match fuel idles:
407 case 0n _:
408 IO.bind(Unit, Unit, Listener.close(listener), _u => server.join(forks, done))
409 case 1n+_f 0n:
410 IO.bind(Unit, Unit, Listener.close(listener), _u => server.join(forks, done))
411 case 1n+f0 1n+i:
412 +f = f0
413 IO.bind(Listener & Step.Accept<Socket>, Unit, server.accept(listener),
414 r => server.loop.got(~C, handle, ctx, slots, limited, done, True{}, r,
415 l => server.loop.go(~C, handle, ctx, f, server.idles(), 1n+forks, slots,
416 limited, done, l),
417 l => server.loop.go(~C, handle, ctx, 1n+f, i, forks, slots, limited,
418 done, l),
419 l => server.loop.go(~C, handle, ctx, f, server.idles(), forks, slots,
420 limited, done, l)))
421
422
423def server.slots(+max: U32) -> IO(Chan(Unit)):
424 Chan.new(Unit, Bool.pick(U32, U32.is_eq(max, 0), 1, max))
425
426
427
428
429def server.serve_io_with(~C: Data, ~handle: C -> Req -> IO(Answer), +ctx: C,
430 host: String, port: U32, limit: U32, +max: U32) -> IO(Unit):
431 do IO<Unit>:
432 lst : Listener <- server.listen(host, port)
433 +slots : Chan(Unit) <- server.slots(max)
434 +done : Chan(Unit) <- Chan.new(Unit, 1024)
435 server.loop.go(~C, handle, ctx, U32.to_nat(limit), server.idles(), 0n, slots,
436 Bool.not(U32.is_eq(max, 0)), done, lst)
437
438
439def server.lift.with(~C: Data, ~handle: C -> Req -> Answer, +ctx: C, req: Req)
440 -> IO(Answer):
441 IO.pure(Answer, handle(ctx)(req))
442
443
444def server.serve_with(~C: Data, ~handle: C -> Req -> Answer, +ctx: C,
445 host: String, port: U32, limit: U32, max: U32) -> IO(Unit):
446 server.serve_io_with(~C, ~(c => r => server.lift.with(~C, handle, c, r)), ctx,
447 host, port, limit, max)
448
449
450@unsafe def server.forever.go(~C: Data, ~handle: C -> Req -> IO(Answer),
451 +ctx: C, +slots: Chan(Unit), +limited: Bool, +done: Chan(Unit),
452 listener: Listener) -> IO(Unit):
453 IO.bind(Listener & Step.Accept<Socket>, Unit, server.accept(listener),
454 r => server.loop.got(~C, handle, ctx, slots, limited, done, False{}, r,
455 l => server.forever.go(~C, handle, ctx, slots, limited, done, l),
456 l => server.forever.go(~C, handle, ctx, slots, limited, done, l),
457 l => server.forever.go(~C, handle, ctx, slots, limited, done, l)))
458
459
460
461@unsafe def server.serve_forever_with(~C: Data,
462 ~handle: C -> Req -> IO(Answer), +ctx: C, host: String, port: U32, +max: U32)
463 -> IO(Unit):
464 do IO<Unit>:
465 lst : Listener <- server.listen(host, port)
466 +slots : Chan(Unit) <- server.slots(max)
467 +done : Chan(Unit) <- Chan.new(Unit, 1)
468 server.forever.go(~C, handle, ctx, slots, Bool.not(U32.is_eq(max, 0)), done,
469 lst)
470
471
472
473
474def server.plain(r: Req) -> Http.Request:
475 Req{method, target, headers, body, bytes} = r
476 Http.Request{method, target, headers, body}
477
478
479def server.text(reply: Http.Reply) -> IO(Answer):
480 match reply:
481 case Http.Torn{why}:
482 IO.pure(Answer, TextReply{500, [], why})
483 case Http.Reply{status, headers, body}:
484 IO.pure(Answer, TextReply{status, headers, body})
485
486
487def server.wrap.io(~handle: Http.Request -> IO(Http.Reply), r: Req)
488 -> IO(Answer):
489 IO.bind(Http.Reply, Answer, handle(server.plain(r)), server.text)
490
491
492def server.serve_io(~handle: Http.Request -> IO(Http.Reply), host: String,
493 port: U32, limit: U32) -> IO(Unit):
494 server.serve_io_with(~Unit, ~(_u => r => server.wrap.io(handle, r)), Unit{},
495 host, port, limit, 0)
496
497
498def server.lift(~handle: Http.Request -> Http.Reply, req: Http.Request)
499 -> IO(Http.Reply):
500 IO.pure(Http.Reply, handle(req))
501
502
503def server.serve(~handle: Http.Request -> Http.Reply, host: String, port: U32,
504 limit: U32) -> IO(Unit):
505 server.serve_io(~(req => server.lift(handle, req)), host, port, limit)
506
507
508def server.once(~handle: Http.Request -> Http.Reply, host: String, port: U32)
509 -> IO(Unit):
510 server.serve(handle, host, port, 1)
511
512
513@unsafe def server.serve_forever(~handle: Http.Request -> IO(Http.Reply),
514 host: String, port: U32) -> IO(Unit):
515 server.serve_forever_with(~Unit, ~(_u => r => server.wrap.io(handle, r)), Unit{},
516 host, port, 0)
517
518
519
520
521def server.dispatch(~handle: Http.Request -> Http.Reply, req: Http.Request)
522 -> Http.Reply:
523 match req:
524 case Http.Bad{why}:
525 Http.Reply{400, [], why}
526 case Http.Request{method, target, headers, body}:
527 handle(Http.Request{method, target, headers, body})
528
529
530def server.reply.built(~handle: Http.Request -> Http.Reply, method: String,
531 req: Http.Request) -> Http.Reply:
532 Http.reply.for(method, server.dispatch(handle, req))
533
534
535def server.reply.text(~handle: Http.Request -> Http.Reply, req: Http.Request)
536 -> Http.Reply:
537 match req:
538 case Http.Bad{why}:
539 server.dispatch(handle, Http.Bad{why})
540 case Http.Request{+method, target, headers, body}:
541 server.reply.built(handle, method,
542 Http.Request{method, target, headers, body})
543
544
545def server.cors_reply(
546 ~handle: Http.Request -> Http.Reply,
547 cfg: Cors.Cfg,
548 +req: Http.Request
549) -> Http.Reply:
550 Cors.cors.on(cfg, req, server.reply.text(handle, req))
551