Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
3 | // Copyright (c) 2024 Christian Mazakas | ||
4 | // Copyright (c) 2024 Mohammad Nejati | ||
5 | // | ||
6 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
7 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
8 | // | ||
9 | // Official repository: https://github.com/cppalliance/http_proto | ||
10 | // | ||
11 | |||
12 | #include <boost/http_proto/detail/except.hpp> | ||
13 | #include <boost/http_proto/message_view_base.hpp> | ||
14 | #include <boost/http_proto/serializer.hpp> | ||
15 | #include <boost/http_proto/service/zlib_service.hpp> | ||
16 | |||
17 | #include "detail/filter.hpp" | ||
18 | |||
19 | #include <boost/buffers/algorithm.hpp> | ||
20 | #include <boost/buffers/buffer_copy.hpp> | ||
21 | #include <boost/buffers/buffer_size.hpp> | ||
22 | #include <boost/core/ignore_unused.hpp> | ||
23 | |||
24 | #include <stddef.h> | ||
25 | |||
26 | namespace boost { | ||
27 | namespace http_proto { | ||
28 | |||
29 | namespace { | ||
30 | class deflator_filter | ||
31 | : public http_proto::detail::filter | ||
32 | { | ||
33 | zlib::stream& deflator_; | ||
34 | |||
35 | public: | ||
36 | 48 | deflator_filter( | |
37 | context& ctx, | ||
38 | http_proto::detail::workspace& ws, | ||
39 | bool use_gzip) | ||
40 | 192 | : deflator_{ ctx.get_service<zlib::service>() | |
41 |
2/2✓ Branch 2 taken 24 times.
✓ Branch 3 taken 24 times.
|
48 | .make_deflator(ws, -1, use_gzip ? 31 : 15, 8) } |
42 | { | ||
43 | 48 | } | |
44 | |||
45 | virtual filter::results | ||
46 | 23756 | on_process( | |
47 | buffers::mutable_buffer out, | ||
48 | buffers::const_buffer in, | ||
49 | bool more) override | ||
50 | { | ||
51 | 23756 | auto flush = | |
52 |
2/2✓ Branch 0 taken 23644 times.
✓ Branch 1 taken 112 times.
|
23756 | more ? zlib::flush::none : zlib::flush::finish; |
53 | 23756 | filter::results results; | |
54 | |||
55 | for(;;) | ||
56 | { | ||
57 | 36232 | auto params = zlib::params{in.data(), in.size(), | |
58 | 36232 | out.data(), out.size() }; | |
59 | 36232 | results.ec = deflator_.write(params, flush); | |
60 | |||
61 | 36232 | results.in_bytes += in.size() - params.avail_in; | |
62 | 36232 | results.out_bytes += out.size() - params.avail_out; | |
63 | |||
64 |
2/2✓ Branch 1 taken 12316 times.
✓ Branch 2 taken 23916 times.
|
36232 | if(results.ec.failed()) |
65 | 23756 | return results; | |
66 | |||
67 |
2/2✓ Branch 2 taken 96 times.
✓ Branch 3 taken 23820 times.
|
23916 | if(results.ec == zlib::error::stream_end) |
68 | { | ||
69 | 96 | results.finished = true; | |
70 | 96 | return results; | |
71 | } | ||
72 | |||
73 | 23820 | in = buffers::suffix(in, params.avail_in); | |
74 | 23820 | out = buffers::suffix(out, params.avail_out); | |
75 | |||
76 |
2/2✓ Branch 1 taken 22448 times.
✓ Branch 2 taken 1372 times.
|
23820 | if(in.size() == 0) |
77 | { | ||
78 | // TODO: is this necessary? | ||
79 |
2/2✓ Branch 0 taken 11104 times.
✓ Branch 1 taken 11344 times.
|
22448 | if(results.out_bytes == 0) |
80 | { | ||
81 | 11104 | flush = zlib::flush::sync; | |
82 | 11104 | continue; | |
83 | } | ||
84 | 11344 | return results; | |
85 | } | ||
86 | 12476 | } | |
87 | } | ||
88 | }; | ||
89 | } // namespace | ||
90 | |||
91 | void | ||
92 | ✗ | consume_buffers( | |
93 | buffers::const_buffer*& p, | ||
94 | std::size_t& n, | ||
95 | std::size_t bytes) | ||
96 | { | ||
97 | ✗ | while(n > 0) | |
98 | { | ||
99 | ✗ | if(bytes < p->size()) | |
100 | { | ||
101 | ✗ | *p += bytes; | |
102 | ✗ | return; | |
103 | } | ||
104 | ✗ | bytes -= p->size(); | |
105 | ✗ | ++p; | |
106 | ✗ | --n; | |
107 | } | ||
108 | |||
109 | // Precondition violation | ||
110 | ✗ | if(bytes > 0) | |
111 | ✗ | detail::throw_invalid_argument(); | |
112 | } | ||
113 | |||
114 | template<class MutableBuffers> | ||
115 | void | ||
116 | 6312 | write_chunk_header( | |
117 | MutableBuffers const& dest0, | ||
118 | std::size_t size) noexcept | ||
119 | { | ||
120 | static constexpr char hexdig[] = | ||
121 | "0123456789ABCDEF"; | ||
122 | char buf[18]; | ||
123 | 6312 | auto p = buf + 16; | |
124 |
2/2✓ Branch 0 taken 100992 times.
✓ Branch 1 taken 6312 times.
|
107304 | for(std::size_t i = 16; i--;) |
125 | { | ||
126 | 100992 | *--p = hexdig[size & 0xf]; | |
127 | 100992 | size >>= 4; | |
128 | } | ||
129 | 6312 | buf[16] = '\r'; | |
130 | 6312 | buf[17] = '\n'; | |
131 | 6312 | auto n = buffers::buffer_copy( | |
132 | dest0, | ||
133 | 12624 | buffers::const_buffer( | |
134 | buf, sizeof(buf))); | ||
135 | ignore_unused(n); | ||
136 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6312 times.
|
6312 | BOOST_ASSERT(n == 18); |
137 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6312 times.
|
6312 | BOOST_ASSERT( |
138 | buffers::buffer_size(dest0) == n); | ||
139 | 6312 | } | |
140 | |||
141 | template<class DynamicBuffer> | ||
142 | void | ||
143 | write_chunk_close(DynamicBuffer& db) | ||
144 | { | ||
145 | db.commit( | ||
146 | buffers::buffer_copy( | ||
147 | db.prepare(2), | ||
148 | buffers::const_buffer("\r\n", 2))); | ||
149 | } | ||
150 | |||
151 | template<class DynamicBuffer> | ||
152 | void | ||
153 | write_last_chunk(DynamicBuffer& db) | ||
154 | { | ||
155 | db.commit( | ||
156 | buffers::buffer_copy( | ||
157 | db.prepare(5), | ||
158 | buffers::const_buffer("0\r\n\r\n", 5))); | ||
159 | } | ||
160 | |||
161 | //------------------------------------------------ | ||
162 | |||
163 | 43 | serializer:: | |
164 | ~serializer() | ||
165 | { | ||
166 | 43 | } | |
167 | |||
168 | ✗ | serializer:: | |
169 | serializer( | ||
170 | serializer&&) noexcept = default; | ||
171 | |||
172 | 9 | serializer:: | |
173 | serializer( | ||
174 | 9 | context& ctx) | |
175 | 9 | : serializer(ctx, 65536) | |
176 | { | ||
177 | 9 | } | |
178 | |||
179 | 43 | serializer:: | |
180 | serializer( | ||
181 | context& ctx, | ||
182 | 43 | std::size_t buffer_size) | |
183 | 43 | : ws_(buffer_size) | |
184 | 43 | , ctx_(ctx) | |
185 | { | ||
186 | 43 | } | |
187 | |||
188 | void | ||
189 | 56 | serializer:: | |
190 | reset() noexcept | ||
191 | { | ||
192 | 56 | chunk_header_ = {}; | |
193 | 56 | chunk_close_ = {}; | |
194 | 56 | last_chunk_ = {}; | |
195 | 56 | filter_ = nullptr; | |
196 | 56 | more_ = false; | |
197 | 56 | is_done_ = false; | |
198 | 56 | is_chunked_ = false; | |
199 | 56 | is_expect_continue_ = false; | |
200 | 56 | is_compressed_ = false; | |
201 | 56 | filter_done_ = false; | |
202 | 56 | in_ = nullptr; | |
203 | 56 | out_ = nullptr; | |
204 | 56 | ws_.clear(); | |
205 | 56 | } | |
206 | |||
207 | //------------------------------------------------ | ||
208 | |||
209 | auto | ||
210 | 12604 | serializer:: | |
211 | prepare() -> | ||
212 | system::result< | ||
213 | const_buffers_type> | ||
214 | { | ||
215 | // Precondition violation | ||
216 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12603 times.
|
12604 | if( is_done_ ) |
217 | 1 | detail::throw_logic_error(); | |
218 | |||
219 | // Expect: 100-continue | ||
220 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12599 times.
|
12603 | if( is_expect_continue_ ) |
221 | { | ||
222 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if( !is_header_done_ ) |
223 | 2 | return const_buffers_type(hp_, 1); | |
224 | 2 | is_expect_continue_ = false; | |
225 | 2 | BOOST_HTTP_PROTO_RETURN_EC( | |
226 | error::expect_100_continue); | ||
227 | } | ||
228 | |||
229 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12596 times.
|
12599 | if( st_ == style::empty ) |
230 | 9 | return const_buffers_type( | |
231 | 6 | prepped_.data(), prepped_.size()); | |
232 | |||
233 |
4/4✓ Branch 0 taken 1575 times.
✓ Branch 1 taken 11021 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1572 times.
|
12596 | if( st_ == style::buffers && !filter_ ) |
234 | 9 | return const_buffers_type( | |
235 | 6 | prepped_.data(), prepped_.size()); | |
236 | |||
237 | // callers must consume() everything before invoking | ||
238 | // prepare() again | ||
239 |
4/6✓ Branch 0 taken 59 times.
✓ Branch 1 taken 12534 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 59 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12593 times.
|
12652 | if( !is_header_done_ && |
240 | 59 | buffers::buffer_size(prepped_) != prepped_[0].size() ) | |
241 | ✗ | detail::throw_logic_error(); | |
242 | |||
243 |
4/6✓ Branch 0 taken 12534 times.
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12534 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12593 times.
|
25127 | if( is_header_done_ && |
244 | 12534 | buffers::buffer_size(prepped_) > 0 ) | |
245 | ✗ | detail::throw_logic_error(); | |
246 | |||
247 | 12593 | auto& input = *in_; | |
248 | 12593 | auto& output = *out_; | |
249 |
3/4✓ Branch 0 taken 5490 times.
✓ Branch 1 taken 7103 times.
✓ Branch 2 taken 5490 times.
✗ Branch 3 not taken.
|
12593 | if( st_ == style::source && more_ ) |
250 | { | ||
251 |
1/2✓ Branch 1 taken 5490 times.
✗ Branch 2 not taken.
|
5490 | auto results = src_->read( |
252 |
1/2✓ Branch 2 taken 5490 times.
✗ Branch 3 not taken.
|
5490 | input.prepare(input.capacity())); |
253 | 5490 | more_ = !results.finished; | |
254 | 5490 | input.commit(results.bytes); | |
255 | } | ||
256 | |||
257 | 30717 | if( st_ == style::stream && | |
258 |
8/8✓ Branch 0 taken 5531 times.
✓ Branch 1 taken 7062 times.
✓ Branch 2 taken 5510 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 5509 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 12592 times.
|
18103 | more_ && |
259 | 5510 | in_->size() == 0 ) | |
260 | 1 | BOOST_HTTP_PROTO_RETURN_EC(error::need_data); | |
261 | |||
262 | bool has_avail_out = | ||
263 |
6/6✓ Branch 0 taken 44 times.
✓ Branch 1 taken 12548 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 33 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 6 times.
|
25145 | ((!filter_ && (more_ || input.size() > 0)) || |
264 |
3/4✓ Branch 0 taken 12548 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 12548 times.
✗ Branch 3 not taken.
|
12553 | (filter_ && !filter_done_)); |
265 | |||
266 | 25312 | auto get_input = [&]() -> buffers::const_buffer | |
267 | { | ||
268 |
2/2✓ Branch 0 taken 3360 times.
✓ Branch 1 taken 21952 times.
|
25312 | if( st_ == style::buffers ) |
269 | { | ||
270 |
2/2✓ Branch 1 taken 64 times.
✓ Branch 2 taken 3296 times.
|
3360 | if( buffers::buffer_size(buf_) == 0 ) |
271 | 64 | return {}; | |
272 | |||
273 | 3296 | auto buf = *(buf_.data()); | |
274 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3296 times.
|
3296 | BOOST_ASSERT(buf.size() > 0); |
275 | 3296 | return buf; | |
276 | } | ||
277 | else | ||
278 | { | ||
279 |
2/2✓ Branch 1 taken 10992 times.
✓ Branch 2 taken 10960 times.
|
21952 | if( input.size() == 0 ) |
280 | 10992 | return {}; | |
281 | |||
282 | 10960 | auto cbs = input.data(); | |
283 | 10960 | auto buf = *cbs.begin(); | |
284 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10960 times.
|
10960 | if( buf.size() == 0 ) |
285 | { | ||
286 | ✗ | auto p = cbs.begin(); | |
287 | ✗ | ++p; | |
288 | ✗ | buf = *p; | |
289 | } | ||
290 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10960 times.
|
10960 | if( buf.size() == 0 ) |
291 | ✗ | detail::throw_logic_error(); | |
292 | 10960 | return buf; | |
293 | } | ||
294 | 12592 | }; | |
295 | |||
296 | 25312 | auto get_output = [&]() -> buffers::mutable_buffer | |
297 | { | ||
298 |
1/2✓ Branch 2 taken 25312 times.
✗ Branch 3 not taken.
|
25312 | auto mbs = output.prepare(output.capacity()); |
299 | 25312 | auto buf = *mbs.begin(); | |
300 |
2/2✓ Branch 1 taken 1556 times.
✓ Branch 2 taken 23756 times.
|
25312 | if( buf.size() == 0 ) |
301 | { | ||
302 | 1556 | auto p = mbs.begin(); | |
303 | 1556 | ++p; | |
304 | 1556 | buf = *p; | |
305 | } | ||
306 | 25312 | return buf; | |
307 | 12592 | }; | |
308 | |||
309 | 23756 | auto consume = [&](std::size_t n) | |
310 | { | ||
311 |
2/2✓ Branch 0 taken 1804 times.
✓ Branch 1 taken 21952 times.
|
23756 | if( st_ == style::buffers ) |
312 | { | ||
313 | 1804 | buf_.consume(n); | |
314 |
2/2✓ Branch 1 taken 64 times.
✓ Branch 2 taken 1740 times.
|
1804 | if( buffers::buffer_size(buf_) == 0 ) |
315 | 64 | more_ = false; | |
316 | } | ||
317 | else | ||
318 | 21952 | input.consume(n); | |
319 | 36348 | }; | |
320 | |||
321 | 12592 | std::size_t num_written = 0; | |
322 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 12548 times.
|
12592 | if( !filter_ ) |
323 | 44 | num_written += input.size(); | |
324 | else | ||
325 | { | ||
326 | for(;;) | ||
327 | { | ||
328 |
1/2✓ Branch 1 taken 25312 times.
✗ Branch 2 not taken.
|
25312 | auto in = get_input(); |
329 |
1/2✓ Branch 1 taken 25312 times.
✗ Branch 2 not taken.
|
25312 | auto out = get_output(); |
330 |
2/2✓ Branch 1 taken 1556 times.
✓ Branch 2 taken 23756 times.
|
25312 | if( out.size() == 0 ) |
331 | { | ||
332 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1556 times.
|
1556 | if( output.size() == 0 ) |
333 | ✗ | detail::throw_logic_error(); | |
334 | 12548 | break; | |
335 | } | ||
336 | |||
337 | 23756 | auto rs = filter_->process( | |
338 |
1/2✓ Branch 1 taken 23756 times.
✗ Branch 2 not taken.
|
23756 | out, in, more_); |
339 | |||
340 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 23660 times.
|
23756 | if( rs.finished ) |
341 | 96 | filter_done_ = true; | |
342 | |||
343 |
1/2✓ Branch 1 taken 23756 times.
✗ Branch 2 not taken.
|
23756 | consume(rs.in_bytes); |
344 | |||
345 |
2/2✓ Branch 0 taken 10992 times.
✓ Branch 1 taken 12764 times.
|
23756 | if( rs.out_bytes == 0 ) |
346 | 10992 | break; | |
347 | |||
348 | 12764 | num_written += rs.out_bytes; | |
349 | 12764 | output.commit(rs.out_bytes); | |
350 | 12764 | } | |
351 | } | ||
352 | |||
353 | // end: | ||
354 | 12592 | std::size_t n = 0; | |
355 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 12534 times.
|
12592 | if( !is_header_done_ ) |
356 | { | ||
357 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
|
58 | BOOST_ASSERT(hp_ == &prepped_[0]); |
358 | 58 | ++n; | |
359 | } | ||
360 | else | ||
361 | 12534 | prepped_.reset(prepped_.capacity()); | |
362 | |||
363 |
2/2✓ Branch 0 taken 6278 times.
✓ Branch 1 taken 6314 times.
|
12592 | if( !is_chunked_ ) |
364 | { | ||
365 |
2/2✓ Branch 3 taken 12556 times.
✓ Branch 4 taken 6278 times.
|
18834 | for(buffers::const_buffer const& b : output.data()) |
366 | 12556 | prepped_[n++] = b; | |
367 | } | ||
368 | else | ||
369 | { | ||
370 |
2/2✓ Branch 0 taken 6311 times.
✓ Branch 1 taken 3 times.
|
6314 | if( has_avail_out ) |
371 | { | ||
372 | 6311 | write_chunk_header( | |
373 | 6311 | chunk_header_, num_written); | |
374 | 6311 | prepped_[n++] = chunk_header_; | |
375 | |||
376 |
2/2✓ Branch 3 taken 12622 times.
✓ Branch 4 taken 6311 times.
|
18933 | for(buffers::const_buffer const& b : output.data()) |
377 | 12622 | prepped_[n++] = b; | |
378 | |||
379 | 6311 | prepped_[n++] = chunk_close_; | |
380 | } | ||
381 | |||
382 |
4/4✓ Branch 0 taken 6292 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 6268 times.
✓ Branch 3 taken 24 times.
|
6314 | if( (filter_ && filter_done_) || |
383 |
4/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 6268 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 17 times.
|
6290 | (!filter_ && !more_) ) |
384 | 29 | prepped_[n++] = last_chunk_; | |
385 | } | ||
386 | |||
387 | auto cbs = const_buffers_type( | ||
388 | 12592 | prepped_.data(), prepped_.size()); | |
389 | |||
390 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 12592 times.
|
12592 | BOOST_ASSERT(buffers::buffer_size(cbs) > 0); |
391 | 12592 | return cbs; | |
392 | } | ||
393 | |||
394 | void | ||
395 | 14345 | serializer:: | |
396 | consume( | ||
397 | std::size_t n) | ||
398 | { | ||
399 | // Precondition violation | ||
400 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14344 times.
|
14345 | if( is_done_ ) |
401 | 1 | detail::throw_logic_error(); | |
402 | |||
403 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 14341 times.
|
14344 | if( is_expect_continue_ ) |
404 | { | ||
405 | // Cannot consume more than | ||
406 | // the header on 100-continue | ||
407 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
|
3 | if( n > hp_->size() ) |
408 | 1 | detail::throw_invalid_argument(); | |
409 | } | ||
410 | |||
411 |
2/2✓ Branch 0 taken 76 times.
✓ Branch 1 taken 14267 times.
|
14343 | if( !is_header_done_ ) |
412 | { | ||
413 | // consume header | ||
414 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 65 times.
|
76 | if( n < hp_->size() ) |
415 | { | ||
416 | 11 | prepped_.consume(n); | |
417 | 11 | return; | |
418 | } | ||
419 | 65 | n -= hp_->size(); | |
420 | 65 | prepped_.consume(hp_->size()); | |
421 | 65 | is_header_done_ = true; | |
422 | } | ||
423 | |||
424 | 14332 | prepped_.consume(n); | |
425 | 14332 | auto is_empty = (buffers::buffer_size(prepped_) == 0); | |
426 | |||
427 |
6/6✓ Branch 0 taken 1580 times.
✓ Branch 1 taken 12752 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1572 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 5 times.
|
14332 | if( st_ == style::buffers && !filter_ && is_empty ) |
428 | 3 | more_ = false; | |
429 | |||
430 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 14327 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
|
14332 | if( st_ == style::empty && |
431 | 4 | is_empty && | |
432 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | !is_expect_continue_ ) |
433 | 3 | more_ = false; | |
434 | |||
435 |
2/2✓ Branch 0 taken 12600 times.
✓ Branch 1 taken 1732 times.
|
14332 | if( is_empty ) |
436 | { | ||
437 |
6/6✓ Branch 0 taken 12593 times.
✓ Branch 1 taken 7 times.
✓ Branch 3 taken 12587 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 12587 times.
✓ Branch 6 taken 13 times.
|
12600 | if( out_ && out_->size() ) |
438 | { | ||
439 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12587 times.
|
12587 | BOOST_ASSERT(st_ != style::empty); |
440 | 12587 | out_->consume(out_->size()); | |
441 | } | ||
442 |
2/2✓ Branch 0 taken 12548 times.
✓ Branch 1 taken 52 times.
|
12600 | is_done_ = filter_ ? filter_done_ : !more_; |
443 | } | ||
444 | } | ||
445 | |||
446 | void | ||
447 | 24 | serializer:: | |
448 | use_deflate_encoding() | ||
449 | { | ||
450 | // can only apply one encoding | ||
451 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if(filter_) |
452 | ✗ | detail::throw_logic_error(); | |
453 | |||
454 | 24 | is_compressed_ = true; | |
455 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | filter_ = &ws_.emplace<deflator_filter>(ctx_, ws_, false); |
456 | 24 | } | |
457 | |||
458 | void | ||
459 | 24 | serializer:: | |
460 | use_gzip_encoding() | ||
461 | { | ||
462 | // can only apply one encoding | ||
463 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if( filter_ ) |
464 | ✗ | detail::throw_logic_error(); | |
465 | |||
466 | 24 | is_compressed_ = true; | |
467 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | filter_ = &ws_.emplace<deflator_filter>(ctx_, ws_, true); |
468 | 24 | } | |
469 | |||
470 | //------------------------------------------------ | ||
471 | |||
472 | void | ||
473 | 7 | serializer:: | |
474 | copy( | ||
475 | buffers::const_buffer* dest, | ||
476 | buffers::const_buffer const* src, | ||
477 | std::size_t n) noexcept | ||
478 | { | ||
479 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
|
14 | while(n--) |
480 | 7 | *dest++ = *src++; | |
481 | 7 | } | |
482 | |||
483 | void | ||
484 | 73 | serializer:: | |
485 | start_init( | ||
486 | message_view_base const& m) | ||
487 | { | ||
488 | // VFALCO what do we do with | ||
489 | // metadata error code failures? | ||
490 | // m.ph_->md.maybe_throw(); | ||
491 | |||
492 | 73 | auto const& md = m.metadata(); | |
493 | |||
494 | 73 | is_done_ = false; | |
495 | 73 | is_header_done_ = false; | |
496 | 73 | is_expect_continue_ = md.expect.is_100_continue; | |
497 | |||
498 | // Transfer-Encoding | ||
499 | { | ||
500 | 73 | auto const& te = md.transfer_encoding; | |
501 | 73 | is_chunked_ = te.is_chunked; | |
502 | } | ||
503 | |||
504 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 42 times.
|
73 | if( is_chunked_) |
505 | { | ||
506 | 31 | auto* p = ws_.reserve_front(chunked_overhead_); | |
507 | 31 | chunk_header_ = | |
508 | 31 | buffers::mutable_buffer(p, chunk_header_len_); | |
509 | 31 | chunk_close_ = | |
510 | 62 | buffers::mutable_buffer( | |
511 | 31 | p + chunk_header_len_, crlf_len_); | |
512 | 31 | last_chunk_ = | |
513 | 62 | buffers::mutable_buffer( | |
514 | 31 | p + chunk_header_len_ + crlf_len_, | |
515 | last_chunk_len_); | ||
516 | |||
517 | 31 | buffers::buffer_copy( | |
518 | 31 | chunk_close_, buffers::const_buffer("\r\n", 2)); | |
519 | 31 | buffers::buffer_copy( | |
520 | 31 | last_chunk_, | |
521 | 62 | buffers::const_buffer("0\r\n\r\n", 5)); | |
522 | } | ||
523 | 73 | } | |
524 | |||
525 | void | ||
526 | 4 | serializer:: | |
527 | start_empty( | ||
528 | message_view_base const& m) | ||
529 | { | ||
530 | 4 | start_init(m); | |
531 | |||
532 | 4 | st_ = style::empty; | |
533 | 4 | more_ = true; | |
534 | |||
535 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if(! is_chunked_) |
536 | { | ||
537 | 3 | prepped_ = make_array( | |
538 | 1); // header | ||
539 | } | ||
540 | else | ||
541 | { | ||
542 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | prepped_ = make_array( |
543 | 1 + // header | ||
544 | 1); // final chunk | ||
545 | |||
546 | // Buffer is too small | ||
547 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(ws_.size() < 5) |
548 | ✗ | detail::throw_length_error(); | |
549 | |||
550 | buffers::mutable_buffer dest( | ||
551 | 1 | ws_.data(), 5); | |
552 | 1 | buffers::buffer_copy( | |
553 | dest, | ||
554 | 1 | buffers::const_buffer( | |
555 | "0\r\n\r\n", 5)); | ||
556 | 1 | prepped_[1] = dest; | |
557 | } | ||
558 | |||
559 | 4 | hp_ = &prepped_[0]; | |
560 | 4 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
561 | 4 | } | |
562 | |||
563 | void | ||
564 | 23 | serializer:: | |
565 | start_buffers( | ||
566 | message_view_base const& m) | ||
567 | { | ||
568 | 23 | st_ = style::buffers; | |
569 | 23 | tmp1_ = {}; | |
570 | |||
571 |
4/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1 times.
|
23 | if( !filter_ && !is_chunked_ ) |
572 | { | ||
573 | 6 | prepped_ = make_array( | |
574 | 1 + // header | ||
575 | 6 | buf_.size()); // user input | |
576 | |||
577 | 6 | hp_ = &prepped_[0]; | |
578 | 6 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
579 | |||
580 | 6 | copy(&prepped_[1], buf_.data(), buf_.size()); | |
581 | |||
582 | 6 | more_ = (buffers::buffer_size(buf_) > 0); | |
583 | 6 | return; | |
584 | } | ||
585 | |||
586 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
17 | if( !filter_ && is_chunked_ ) |
587 | { | ||
588 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if( buffers::buffer_size(buf_) == 0 ) |
589 | { | ||
590 | ✗ | prepped_ = make_array( | |
591 | 1 + // header | ||
592 | 1); // last chunk | ||
593 | |||
594 | ✗ | hp_ = &prepped_[0]; | |
595 | ✗ | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
596 | ✗ | prepped_[1] = last_chunk_; | |
597 | ✗ | more_ = false; | |
598 | ✗ | return; | |
599 | } | ||
600 | |||
601 | 2 | write_chunk_header( | |
602 | 1 | chunk_header_, buffers::buffer_size(buf_)); | |
603 | |||
604 | 1 | prepped_ = make_array( | |
605 | 1 + // header | ||
606 | 1 + // chunk header | ||
607 | 1 | buf_.size() + // user input | |
608 | 1 + // chunk close | ||
609 | 1); // last chunk | ||
610 | |||
611 | 1 | hp_ = &prepped_[0]; | |
612 | 1 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
613 | 1 | prepped_[1] = chunk_header_; | |
614 | 1 | copy(&prepped_[2], buf_.data(), buf_.size()); | |
615 | |||
616 | 1 | prepped_[prepped_.size() - 2] = chunk_close_; | |
617 | 1 | prepped_[prepped_.size() - 1] = last_chunk_; | |
618 | 1 | more_ = true; | |
619 | 1 | return; | |
620 | } | ||
621 | |||
622 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | if( is_chunked_ ) |
623 | { | ||
624 | 8 | prepped_ = make_array( | |
625 | 1 + // header | ||
626 | 1 + // chunk header | ||
627 | 2 + // tmp | ||
628 | 1 + // chunk close | ||
629 | 1); // last chunk | ||
630 | } | ||
631 | else | ||
632 | 8 | prepped_ = make_array( | |
633 | 1 + // header | ||
634 | 2); // tmp | ||
635 | |||
636 | 16 | hp_ = &prepped_[0]; | |
637 | 16 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
638 | 16 | tmp0_ = { ws_.data(), ws_.size() }; | |
639 | 16 | out_ = &tmp0_; | |
640 | 16 | in_ = out_; | |
641 | 16 | more_ = true; | |
642 | } | ||
643 | |||
644 | void | ||
645 | 24 | serializer:: | |
646 | start_source( | ||
647 | message_view_base const& m, | ||
648 | source* src) | ||
649 | { | ||
650 | 24 | st_ = style::source; | |
651 | 24 | src_ = src; | |
652 | |||
653 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 14 times.
|
24 | if( is_chunked_ ) |
654 | { | ||
655 | 10 | prepped_ = make_array( | |
656 | 1 + // header | ||
657 | 1 + // chunk header | ||
658 | 2 + // tmp | ||
659 | 1 + // chunk close | ||
660 | 1); // last chunk | ||
661 | } | ||
662 | else | ||
663 | 14 | prepped_ = make_array( | |
664 | 1 + // header | ||
665 | 2); // tmp | ||
666 | |||
667 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 16 times.
|
24 | if( !filter_ ) |
668 | { | ||
669 | 8 | tmp0_ = { ws_.data(), ws_.size() }; | |
670 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
|
8 | if( tmp0_.capacity() < 1 ) |
671 | ✗ | detail::throw_length_error(); | |
672 | |||
673 | 8 | in_ = &tmp0_; | |
674 | 8 | out_ = &tmp0_; | |
675 | } | ||
676 | else | ||
677 | { | ||
678 | 16 | auto n = ws_.size() / 2; | |
679 | 16 | auto* p = ws_.reserve_front(n); | |
680 | 16 | tmp1_ = buffers::circular_buffer(p, n); | |
681 | |||
682 | 16 | tmp0_ = { ws_.data(), ws_.size() }; | |
683 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | if( tmp0_.capacity() < 1 ) |
684 | ✗ | detail::throw_length_error(); | |
685 | |||
686 | 16 | in_ = &tmp1_; | |
687 | 16 | out_ = &tmp0_; | |
688 | } | ||
689 | |||
690 | 24 | hp_ = &prepped_[0]; | |
691 | 24 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
692 | 24 | more_ = true; | |
693 | 24 | } | |
694 | |||
695 | auto | ||
696 | 22 | serializer:: | |
697 | start_stream( | ||
698 | message_view_base const& m) -> | ||
699 | stream | ||
700 | { | ||
701 | 22 | start_init(m); | |
702 | |||
703 | 22 | st_ = style::stream; | |
704 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
|
22 | if( is_chunked_ ) |
705 | { | ||
706 | 11 | prepped_ = make_array( | |
707 | 1 + // header | ||
708 | 1 + // chunk header | ||
709 | 2 + // tmp | ||
710 | 1 + // chunk close | ||
711 | 1); // last chunk | ||
712 | } | ||
713 | else | ||
714 | 11 | prepped_ = make_array( | |
715 | 1 + // header | ||
716 | 2); // tmp | ||
717 | |||
718 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
|
22 | if( !filter_ ) |
719 | { | ||
720 | 6 | tmp0_ = { ws_.data(), ws_.size() }; | |
721 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
6 | if( tmp0_.capacity() < 1 ) |
722 | ✗ | detail::throw_length_error(); | |
723 | |||
724 | 6 | in_ = &tmp0_; | |
725 | 6 | out_ = &tmp0_; | |
726 | } | ||
727 | else | ||
728 | { | ||
729 | 16 | auto n = ws_.size() / 2; | |
730 | 16 | auto* p = ws_.reserve_front(n); | |
731 | 16 | tmp1_ = buffers::circular_buffer(p, n); | |
732 | |||
733 | 16 | tmp0_ = { ws_.data(), ws_.size() }; | |
734 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | if( tmp0_.capacity() < 1 ) |
735 | ✗ | detail::throw_length_error(); | |
736 | |||
737 | 16 | in_ = &tmp1_; | |
738 | 16 | out_ = &tmp0_; | |
739 | } | ||
740 | |||
741 | 22 | hp_ = &prepped_[0]; | |
742 | 22 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
743 | 22 | more_ = true; | |
744 | 22 | return stream{*this}; | |
745 | } | ||
746 | |||
747 | //------------------------------------------------ | ||
748 | |||
749 | std::size_t | ||
750 | 139 | serializer:: | |
751 | stream:: | ||
752 | capacity() const noexcept | ||
753 | { | ||
754 | 139 | return sr_->in_->capacity(); | |
755 | } | ||
756 | |||
757 | std::size_t | ||
758 | 72 | serializer:: | |
759 | stream:: | ||
760 | size() const noexcept | ||
761 | { | ||
762 | 72 | return sr_->in_->size(); | |
763 | } | ||
764 | |||
765 | bool | ||
766 | 63 | serializer:: | |
767 | stream:: | ||
768 | is_full() const noexcept | ||
769 | { | ||
770 | 63 | return capacity() == 0; | |
771 | } | ||
772 | |||
773 | auto | ||
774 | 5512 | serializer:: | |
775 | stream:: | ||
776 | prepare() const -> | ||
777 | buffers_type | ||
778 | { | ||
779 | 5512 | return sr_->in_->prepare(sr_->in_->capacity()); | |
780 | } | ||
781 | |||
782 | void | ||
783 | 5512 | serializer:: | |
784 | stream:: | ||
785 | commit(std::size_t n) const | ||
786 | { | ||
787 | // the stream must make a non-zero amount of bytes | ||
788 | // available to the serializer | ||
789 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5511 times.
|
5512 | if( n == 0 ) |
790 | 1 | detail::throw_logic_error(); | |
791 | |||
792 | 5511 | sr_->in_->commit(n); | |
793 | 5511 | } | |
794 | |||
795 | void | ||
796 | 25 | serializer:: | |
797 | stream:: | ||
798 | close() const | ||
799 | { | ||
800 | // Precondition violation | ||
801 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 21 times.
|
25 | if(! sr_->more_ ) |
802 | 4 | detail::throw_logic_error(); | |
803 | 21 | sr_->more_ = false; | |
804 | 21 | } | |
805 | |||
806 | //------------------------------------------------ | ||
807 | |||
808 | } // http_proto | ||
809 | } // boost | ||
810 |