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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
open Faraday
let write_space t = write_char t ' '
let write_crlf t = write_string t "\r\n"
let write_version t version =
write_string t (Version.to_string version)
let write_method t meth =
write_string t (Method.to_string meth)
let write_status t status =
write_string t (Status.to_string status)
let t =
List.iter (fun (name, value) ->
write_string t name;
write_string t ": ";
write_string t value;
write_crlf t)
(Headers.to_list headers);
write_crlf t
let write_request t { Request.meth; target; version; } =
write_method t meth ; write_space t;
write_string t target ; write_space t;
write_version t version; write_crlf t;
write_headers t headers
let write_response t { Response.version; status; reason; } =
write_version t version; write_space t;
write_status t status ; write_space t;
write_string t reason ; write_crlf t;
write_headers t headers
let write_chunk_length t len =
write_string t (Printf.sprintf "%x" len);
write_crlf t
let write_string_chunk t chunk =
write_chunk_length t (String.length chunk);
write_string t chunk;
write_crlf t
let write_bigstring_chunk t chunk =
write_chunk_length t (Bigstringaf.length chunk);
write_bigstring t chunk;
write_crlf t
let schedule_bigstring_chunk t chunk =
write_chunk_length t (Bigstringaf.length chunk);
schedule_bigstring t chunk;
write_crlf t
module Writer = struct
type t =
{ buffer : Bigstringaf.t
; encoder : Faraday.t
; mutable drained_bytes : int
; mutable wakeup : Optional_thunk.t
}
let create ?(buffer_size=0x800) () =
let buffer = Bigstringaf.create buffer_size in
let encoder = Faraday.of_bigstring buffer in
{ buffer
; encoder
; drained_bytes = 0
; wakeup = Optional_thunk.none
}
let faraday t = t.encoder
let write_request t request =
write_request t.encoder request
let write_response t response =
write_response t.encoder response
let write_string t ?off ?len string =
write_string t.encoder ?off ?len string
let write_bytes t ?off ?len bytes =
write_bytes t.encoder ?off ?len bytes
let write_bigstring t ?off ?len bigstring =
write_bigstring t.encoder ?off ?len bigstring
let schedule_bigstring t ?off ?len bigstring =
schedule_bigstring t.encoder ?off ?len bigstring
let schedule_fixed t iovecs =
List.iter (fun { IOVec.buffer; off; len } ->
schedule_bigstring t ~off ~len buffer)
iovecs
let schedule_chunk t iovecs =
let length = IOVec.lengthv iovecs in
write_chunk_length t.encoder length;
schedule_fixed t iovecs;
write_crlf t.encoder
let on_wakeup t k =
if Faraday.is_closed t.encoder
then failwith "on_wakeup on closed writer"
else if Optional_thunk.is_some t.wakeup
then failwith "on_wakeup: only one callback can be registered at a time"
else t.wakeup <- Optional_thunk.some k
;;
let wakeup t =
let f = t.wakeup in
t.wakeup <- Optional_thunk.none;
Optional_thunk.call_if_some f
;;
let flush t f =
flush t.encoder f
let unyield t =
flush t (fun () -> ())
let yield t =
Faraday.yield t.encoder
let close t =
Faraday.close t.encoder
let close_and_drain t =
Faraday.close t.encoder;
let drained = Faraday.drain t.encoder in
t.drained_bytes <- t.drained_bytes + drained;
wakeup t
let is_closed t =
Faraday.is_closed t.encoder
let drained_bytes t =
t.drained_bytes
let report_result t result =
match result with
| `Closed -> close_and_drain t
| `Ok len -> shift t.encoder len
let next t =
match Faraday.operation t.encoder with
| `Close -> `Close (drained_bytes t)
| `Yield -> `Yield
| `Writev iovecs -> `Write iovecs
end