0 | module TyTTP.Adapter.Node.HTTPS
2 | import public Data.Buffer
3 | import Data.Buffer.Ext
6 | import public Node.Error
8 | import public Node.HTTPS
10 | import public TyTTP.Adapter.Node.Error
14 | %hide Node.HTTP.Server.Server
15 | %hide Node.Net.Server.Server
18 | RawHttpRequest : Type
19 | RawHttpRequest = HttpRequest String StringHeaders $
Publisher IO Error Buffer
22 | RawHttpResponse : Type
23 | RawHttpResponse = Response Status StringHeaders $
Publisher IO Error Buffer
26 | record Options e where
27 | constructor MkOptions
28 | netServerOptions : Net.CreateServer.Options
29 | tlsServerOptions : TLS.CreateServer.Options
30 | tlsContextOptions : TLS.CreateSecureContext.Options
31 | serverOptions : HTTPS.CreateServer.Options
32 | listenOptions : Listen.Options
33 | errorHandler : e -> RawHttpResponse
36 | defaultOptions : Error e => HTTPS.Options e
37 | defaultOptions = MkOptions
38 | { netServerOptions = Net.CreateServer.defaultOptions
39 | , tlsServerOptions = TLS.CreateServer.defaultOptions
40 | , tlsContextOptions = TLS.CreateSecureContext.defaultOptions
41 | , serverOptions = HTTPS.CreateServer.defaultOptions
44 | , host := Just "localhost"
45 | } Listen.defaultOptions
46 | , errorHandler = \e => MkResponse
47 | { status = INTERNAL_SERVER_ERROR
49 | [ ("Content-Type", "text/plain")
50 | , ("Content-Length", show $
length $
TyTTP.Core.Error.message e)
52 | , body = singleton $
fromString $
TyTTP.Core.Error.message e
56 | toNodeResponse : RawHttpResponse -> ServerResponse -> IO ()
57 | toNodeResponse res nodeRes = do
58 | let status = res.status.code
59 | headers <- mapHeaders res.headers
61 | nodeRes.writeHead status headers
62 | res.body.subscribe $
MkSubscriber
63 | { onNext = \a => nodeRes.write a Nothing }
64 | { onFailed = \e => pure () }
65 | { onSucceded = \_ => nodeRes.end Nothing {d = Buffer} }
67 | mapHeaders : StringHeaders -> IO Headers
70 | foldlM (\hs, (k,v) => hs.setHeader k v) newHeaders h
72 | fromPromiseToNodeResponse : Error e
73 | => (e -> RawHttpResponse)
74 | -> Promise e IO (Context Method String Version StringHeaders Status StringHeaders b $
Publisher IO Error Buffer)
77 | fromPromiseToNodeResponse errorHandler (MkPromise cont) nodeRes =
78 | let callbacks = MkCallbacks
79 | { onSucceded = \a => toNodeResponse a.response nodeRes }
80 | { onFailed = \e => toNodeResponse (errorHandler e) nodeRes }
84 | fromNodeRequest : IncomingMessage -> RawHttpRequest
85 | fromNodeRequest nodeReq =
86 | let method = parseMethod nodeReq.method
88 | headers = nodeReq.headers.asList
89 | version = parseVersion nodeReq.httpVersion
90 | in mkRequest method path version headers $
MkPublisher $
\s => do
91 | nodeReq.onData s.onNext
92 | nodeReq.onError s.onFailed
93 | nodeReq.onEnd $
s.onSucceded ()
101 | Context Method String Version StringHeaders Status StringHeaders (Publisher IO Error Buffer) ()
102 | -> Promise e IO $
Context Method String Version StringHeaders Status StringHeaders b (Publisher IO Error Buffer)
105 | listen https options handler = do
106 | server <- https.createServer $
MkOptions
107 | { server = options.serverOptions
108 | , context = options.tlsContextOptions
109 | , tls = options.tlsServerOptions
110 | , net = options.netServerOptions
113 | server.onRequest $
\req => \res => do
114 | let handlerReq = fromNodeRequest req
115 | initialRes = MkResponse OK [] () {h = StringHeaders}
116 | result = handler $
MkContext handlerReq initialRes
118 | fromPromiseToNodeResponse options.errorHandler result res
120 | server.listen options.listenOptions