src/net.bend
bend-kube-runtime@0.2.0.0 · 157 lines · 20 definitions
1import Base
2import bend-kube-runtime@0.2.0.0/src/proxy.bend as P
3
4
5
6
7
8
9
10
11
12type Tls is Type:
13 Tls{sock: Socket}
14
15type Bytes is Data:
16 Bytes{list: List<&2, U32>}
17
18def Res(-A: Type) -> Type:
19 Result<&1, &1, U32 & String, A>
20
21
22
23
24
25
26
27def Tls.dial(host: String, port: U32, ms: U32) -> IO(Res(Socket)):
28 import "./effs/tls.c"
29 import "./effs/tls.js"
30
31
32
33
34
35
36def Tls.secure(sock: Socket, host: String, ca: String, cert: String, key: String, ms: U32) ->
37 IO(Res(Socket)):
38 import "./effs/tls.c"
39 import "./effs/tls.js"
40
41
42def Tls.send(sock: Socket, text: String, ms: U32) -> IO(Socket & Res(Unit)):
43 import "./effs/tls.c"
44 import "./effs/tls.js"
45
46
47def Tls.send_bytes(sock: Socket, bytes: List<&2, U32>, ms: U32) -> IO(Socket & Res(Unit)):
48 import "./effs/tls.c"
49 import "./effs/tls.js"
50
51
52
53def Tls.recv(sock: Socket, max: U32, ms: U32) -> IO(Socket & Res(List<&2, U32>)):
54 import "./effs/tls.c"
55 import "./effs/tls.js"
56
57def Tls.close(sock: Socket) -> IO(Unit):
58 import "./effs/tls.c"
59 import "./effs/tls.js"
60
61
62
63
64def Tls.fail(s: Socket, e: U32 & String) -> IO(Res(Socket)):
65 IO.bind(Unit, Res(Socket), Tls.close(s), u => IO.pure(Res(Socket), Fail{e}))
66
67
68type TunEv is Type:
69 TGot{sock: Socket, r: Res(List<&2, U32>), st: P.Tunnel}
70 TStep{sock: Socket, st: P.Tunnel}
71
72def TunEv.got(p: Socket & Res(List<&2, U32>), st: P.Tunnel) -> TunEv:
73 match p:
74 case (s, r):
75 TGot{s, r, st}
76
77
78
79def Tls.tunnel(fuel: Nat, ev: TunEv, +host: String, ca: String, cert: String, key: String,
80 +ms: U32) -> IO(Res(Socket)):
81 match fuel ev:
82 case 0n TGot{s, r, st}:
83 Tls.fail(s, (0, "proxy: answer too long"))
84 case 0n TStep{s, st}:
85 Tls.fail(s, (0, "proxy: answer too long"))
86 case 1n+f TGot{s, Done{bs}, st}:
87 Tls.tunnel(f, TStep{s, P.Tunnel.feed(st, bs)}, host, ca, cert, key, ms)
88 case 1n+f TGot{s, Fail{(c, m)}, st}:
89 Tls.fail(s, (c, "proxy: " ++ m))
90 case 1n+f TStep{s, P.TMore{h}}:
91 IO.bind(Socket & Res(List<&2, U32>), Res(Socket), Tls.recv(s, 4096, ms),
92 p => Tls.tunnel(f, TunEv.got(p, P.TMore{h}), host, ca, cert, key, ms))
93 case 1n+f TStep{s, P.TOpen{}}:
94 Tls.secure(s, host, ca, cert, key, ms)
95 case 1n+f TStep{s, P.TFail{why}}:
96 Tls.fail(s, (0, why))
97
98def Tls.open.sent(p: Socket & Res(Unit), +host: String, ca: String, cert: String, key: String,
99 +ms: U32) -> IO(Res(Socket)):
100 match p:
101 case (s, Done{u}):
102 Tls.tunnel(4294967295n, TStep{s, P.Tunnel.init()}, host, ca, cert, key, ms)
103 case (s, Fail{(c, m)}):
104 Tls.fail(s, (c, "proxy: " ++ m))
105
106def Tls.open.proxied(d: Res(Socket), req: String, +host: String, ca: String, cert: String,
107 key: String, +ms: U32) -> IO(Res(Socket)):
108 match d:
109 case Done{s}:
110 IO.bind(Socket & Res(Unit), Res(Socket), Tls.send(s, req, ms),
111 p => Tls.open.sent(p, host, ca, cert, key, ms))
112 case Fail{(c, m)}:
113 IO.pure(Res(Socket), Fail{(c, "proxy: " ++ m)})
114
115def Tls.open.direct(d: Res(Socket), +host: String, ca: String, cert: String, key: String,
116 +ms: U32) -> IO(Res(Socket)):
117 match d:
118 case Done{s}:
119 Tls.secure(s, host, ca, cert, key, ms)
120 case Fail{e}:
121 IO.pure(Res(Socket), Fail{e})
122
123def Tls.open.route(r: P.Route, +host: String, +port: U32, ca: String, cert: String,
124 key: String, +ms: U32) -> IO(Res(Socket)):
125 match r:
126 case P.Direct{}:
127 IO.bind(Res(Socket), Res(Socket), Tls.dial(host, port, ms),
128 d => Tls.open.direct(d, host, ca, cert, key, ms))
129 case P.Via{P.Proxy{ph, pp, auth}}:
130 IO.bind(Res(Socket), Res(Socket), Tls.dial(ph, pp, ms),
131 d => Tls.open.proxied(d, P.Proxy.connect(host, port, auth), host, ca, cert, key, ms))
132 case P.NoRoute{why}:
133 IO.pure(Res(Socket), Fail{(22, why)})
134
135def Tls.env.or(r: Res(String), alt: Res(String)) -> String:
136 match r alt:
137 case Done{SCon{c, t}} a:
138 SCon{c, t}
139 case _ Done{v}:
140 v
141 case _ _:
142 ""
143
144
145
146def Tls.env(name: String, alt: String) -> IO(String):
147 IO.bind(Res(String), String, IO.get_env(name),
148 r => IO.bind(Res(String), String, IO.get_env(alt), a => IO.pure(String, Tls.env.or(r, a))))
149
150
151
152
153def Tls.open(+host: String, +port: U32, ca: String, cert: String, key: String, +ms: U32) ->
154 IO(Res(Socket)):
155 IO.bind(String, Res(Socket), Tls.env("HTTPS_PROXY", "https_proxy"),
156 url => IO.bind(String, Res(Socket), Tls.env("NO_PROXY", "no_proxy"),
157 no => Tls.open.route(P.Proxy.route(url, no, host, port), host, port, ca, cert, key, ms)))