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
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 { Response0.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
let write_bigstring_chunk t chunk =
write_chunk_length t (Bigstring.length chunk);
write_bigstring t chunk
let schedule_bigstring_chunk t chunk =
write_chunk_length t (Bigstring.length chunk);
schedule_bigstring t chunk
module Writer = struct
type t =
{ buffer : Bigstring.t
; encoder : Faraday.t
; mutable drained_bytes : int
}
let create ?(buffer_size=0x800) () =
let buffer = Bigstring.create buffer_size in
let encoder = Faraday.of_bigstring buffer in
{ buffer
; encoder
; drained_bytes = 0
}
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
let flush t f =
flush t.encoder f
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
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 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