src/step.bend
emerging-ezhttp@0.21.0.0 · 126 lines · 15 definitions
1
2
3
4import Base
5import emerging-ezhttp@0.21.0.0/src/http.bend as Http
6import emerging-ezhttp@0.21.0.0/src/qs.bend as Qs
7
8
9type Step is Data:
10 Answer{reply: Http.Reply}
11 Call{req: Http.Request}
12
13
14
15type Got<-A: Type> is Type:
16 Kept{value: A}
17 Lost{line: String}
18
19
20
21
22def step.text(req: Http.Request) -> Http.Request:
23 match req:
24 case Http.Bad{why}:
25 Http.Bad{why}
26 case Http.Request{method, target, headers, body}:
27 Http.Request{Qs.octets.text(method), Qs.octets.text(target),
28 Qs.octets.headers(headers), Qs.octets.text(body)}
29
30
31
32def step.of(req: Http.Request) -> Step:
33 match req:
34 case Http.Bad{why}:
35 Answer{Http.Reply{400, [], why}}
36 case Http.Request{method, target, headers, body}:
37 Call{Http.Request{method, target, headers, body}}
38
39
40def step.line(phase: String, why: String) -> String:
41 "ezhttp: " ++ phase ++ ": " ++ why
42
43
44def step.got(
45 -A: Type,
46 phase: String,
47 res: Result<&1, &1, U32 & String, A>
48) -> Got<A>:
49 match res:
50 case Fail{(code, why)}:
51 Lost{step.line(phase, why)}
52 case Done{value}:
53 Kept{value}
54
55
56def step.sent(res: Result<&1, &1, (U32 & String) & List<&2, U32>, Unit>)
57 -> Got<Unit>:
58 match res:
59 case Fail{((code, why), left)}:
60 Lost{step.line("write", why)}
61 case Done{value}:
62 Kept{value}
63
64
65
66
67
68def step.bare(+method: String, +status: U32) -> Bool:
69 Bool.or(String.eq(method, "HEAD"), Http.status.nocontent(status))
70
71
72def step.octets(req: Http.Request) -> String:
73 match req:
74 case Http.Bad{why}:
75 ""
76 case Http.Request{method, target, headers, body}:
77 body
78
79
80
81type Accept<-A: Type> is Type:
82 Took{value: A}
83 Idle{}
84 Missed{line: String}
85
86
87def step.missed(-A: Type, +why: String, late: Bool) -> Accept<A>:
88 match late:
89 case True{}:
90 Idle{}
91 case False{}:
92 Missed{step.line("accept", why)}
93
94
95def step.accepted(-A: Type, res: Result<&1, &1, U32 & String, A>)
96 -> Accept<A>:
97 match res:
98 case Fail{(+code, why)}:
99 step.missed(A, why, U32.is_eq(code, 110))
100 case Done{value}:
101 Took{value}
102
103
104
105
106def step.clen(m: Maybe<&2, Nat>) -> Nat:
107 match m:
108 case None{}:
109 0n
110 case Some{n}:
111 n
112
113
114
115def step.need.of(c: Http.Cut) -> Maybe<&2, Nat>:
116 match c:
117 case Http.NoCut{}:
118 None{}
119 case Http.Cut{+before, after}:
120 Some{Nat.add(Nat.add(String.length(before), 4n),
121 step.clen(Http.digits.read(Http.first(
122 Http.head.values(String.lines(before), "content-length")))))}
123
124
125def step.need(+text: String) -> Maybe<&2, Nat>:
126 step.need.of(Http.divide(text, "\r\n\r\n"))