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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
module Formats = Dream_pure.Formats
module Message = Dream_pure.Message
module Status = Dream_pure.Status
module Stream = Dream_pure.Stream
let client_field =
Message.new_field
~name:"dream.client"
~show_value:(fun client -> client)
()
let client request =
match Message.field request client_field with
| None -> "127.0.0.1:0"
| Some client -> client
let set_client request client =
Message.set_field request client_field client
let tls_field =
Message.new_field
~name:"dream.tls"
~show_value:string_of_bool
()
let tls request =
match Message.field request tls_field with
| Some true -> true
| _ -> false
let set_tls request tls =
Message.set_field request tls_field tls
let request ~client ~method_ ~target ~tls ~ server_stream =
let request =
Message.request ~method_ ~target ~headers Stream.null server_stream in
set_client request client;
set_tls request tls;
request
let request_with_body ?method_ ?target ? body =
Message.request ?method_ ?target ?headers Stream.null (Stream.string body)
let response_with_body ?status ?code ? body =
let response =
Message.response ?status ?code ?headers Stream.null Stream.null in
Message.set_body response body;
response
let respond ?status ?code ? body =
Lwt.return (response_with_body ?status ?code ?headers body)
let html ?status ?code ? body =
let response = response_with_body ?status ?code ?headers body in
Message.set_header response "Content-Type" Formats.text_html;
Lwt.return response
let json ?status ?code ? body =
let response = response_with_body ?status ?code ?headers body in
Message.set_header response "Content-Type" Formats.application_json;
Lwt.return response
let redirect ?status ?code ? _request location =
let status = (status :> Status.redirection option) in
let status =
match status, code with
| None, None -> Some (`See_Other)
| _ -> status
in
let response = response_with_body ?status ?code ?headers "" in
Message.set_header response "Location" location;
Lwt.return response
let stream ?status ?code ? ?(close = true) callback =
let reader, writer = Stream.pipe () in
let client_stream = Stream.stream reader Stream.no_writer
and server_stream = Stream.stream Stream.no_reader writer in
let response =
Message.response ?status ?code ?headers client_stream server_stream in
Lwt.async (fun () ->
if close then
match%lwt callback server_stream with
| () ->
Message.close server_stream
| exception exn ->
let%lwt () = Message.close server_stream in
raise exn
else
callback server_stream);
Lwt.return response
let empty ? status =
respond ?headers ~status ""
let not_found _ =
respond ~status:`Not_Found ""
let websocket ? ?(close = true) callback =
let response =
Message.response
~status:`Switching_Protocols ?headers Stream.empty Stream.null in
let websocket = Message.create_websocket response in
Lwt.async (fun () ->
if close then
match%lwt callback websocket with
| () ->
Message.close_websocket websocket
| exception exn ->
let%lwt () = Message.close_websocket websocket ~code:1005 in
raise exn
else
callback websocket);
Lwt.return response
let receive (_, server_stream) =
Message.receive server_stream
let receive_fragment (_, server_stream) =
Message.receive_fragment server_stream
let send ?text_or_binary ?end_of_message (_, server_stream) data =
Message.send ?text_or_binary ?end_of_message server_stream data