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/detail/header.hpp> | ||
14 | #include <boost/http_proto/message_view_base.hpp> | ||
15 | #include <boost/http_proto/serializer.hpp> | ||
16 | |||
17 | #include "src/detail/array_of_const_buffers.hpp" | ||
18 | #include "src/detail/brotli_filter_base.hpp" | ||
19 | #include "src/detail/buffer_utils.hpp" | ||
20 | #include "src/detail/zlib_filter_base.hpp" | ||
21 | |||
22 | #include <boost/buffers/circular_buffer.hpp> | ||
23 | #include <boost/buffers/copy.hpp> | ||
24 | #include <boost/core/bit.hpp> | ||
25 | #include <boost/core/ignore_unused.hpp> | ||
26 | #include <boost/rts/brotli/encode.hpp> | ||
27 | #include <boost/rts/context.hpp> | ||
28 | #include <boost/rts/zlib/compression_method.hpp> | ||
29 | #include <boost/rts/zlib/compression_strategy.hpp> | ||
30 | #include <boost/rts/zlib/deflate.hpp> | ||
31 | #include <boost/rts/zlib/error.hpp> | ||
32 | #include <boost/rts/zlib/flush.hpp> | ||
33 | |||
34 | #include <stddef.h> | ||
35 | |||
36 | namespace boost { | ||
37 | namespace http_proto { | ||
38 | |||
39 | namespace { | ||
40 | |||
41 | const | ||
42 | buffers::const_buffer | ||
43 | crlf_and_final_chunk = {"\r\n0\r\n\r\n", 7}; | ||
44 | |||
45 | const | ||
46 | buffers::const_buffer | ||
47 | crlf = {"\r\n", 2}; | ||
48 | |||
49 | const | ||
50 | buffers::const_buffer | ||
51 | final_chunk = {"0\r\n\r\n", 5}; | ||
52 | |||
53 | constexpr | ||
54 | std::uint8_t | ||
55 | 76 | chunk_header_len( | |
56 | std::size_t max_chunk_size) noexcept | ||
57 | { | ||
58 | return | ||
59 | static_cast<uint8_t>( | ||
60 | 76 | (core::bit_width(max_chunk_size) + 3) / 4 + | |
61 | 76 | 2); // crlf | |
62 | }; | ||
63 | |||
64 | void | ||
65 | 1146 | write_chunk_header( | |
66 | const buffers::mutable_buffer_pair& mbs, | ||
67 | std::size_t size) noexcept | ||
68 | { | ||
69 | static constexpr char hexdig[] = | ||
70 | "0123456789ABCDEF"; | ||
71 | char buf[18]; | ||
72 | 1146 | auto p = buf + 16; | |
73 | 1146 | auto const n = buffers::size(mbs); | |
74 |
2/2✓ Branch 0 taken 4583 times.
✓ Branch 1 taken 1146 times.
|
5729 | for(std::size_t i = n - 2; i--;) |
75 | { | ||
76 | 4583 | *--p = hexdig[size & 0xf]; | |
77 | 4583 | size >>= 4; | |
78 | } | ||
79 | 1146 | buf[16] = '\r'; | |
80 | 1146 | buf[17] = '\n'; | |
81 | 1146 | auto copied = buffers::copy( | |
82 | mbs, | ||
83 | 2292 | buffers::const_buffer(p, n)); | |
84 | ignore_unused(copied); | ||
85 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1146 times.
|
1146 | BOOST_ASSERT(copied == n); |
86 | 1146 | } | |
87 | |||
88 | //------------------------------------------------ | ||
89 | |||
90 | class zlib_filter | ||
91 | : public detail::zlib_filter_base | ||
92 | { | ||
93 | rts::zlib::deflate_service& svc_; | ||
94 | |||
95 | public: | ||
96 | 52 | zlib_filter( | |
97 | const rts::context& ctx, | ||
98 | http_proto::detail::workspace& ws, | ||
99 | int comp_level, | ||
100 | int window_bits, | ||
101 | int mem_level) | ||
102 | 52 | : zlib_filter_base(ws) | |
103 | 52 | , svc_(ctx.get_service<rts::zlib::deflate_service>()) | |
104 | { | ||
105 | 104 | system::error_code ec = static_cast<rts::zlib::error>(svc_.init2( | |
106 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
52 | strm_, |
107 | comp_level, | ||
108 | rts::zlib::deflated, | ||
109 | window_bits, | ||
110 | mem_level, | ||
111 | 52 | rts::zlib::default_strategy)); | |
112 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 52 times.
|
52 | if(ec != rts::zlib::error::ok) |
113 | ✗ | detail::throw_system_error(ec); | |
114 | 52 | } | |
115 | |||
116 | private: | ||
117 | virtual | ||
118 | std::size_t | ||
119 | 86 | min_out_buffer() const noexcept override | |
120 | { | ||
121 | // Prevents deflate from producing | ||
122 | // zero output due to small buffer | ||
123 | 86 | return 8; | |
124 | } | ||
125 | |||
126 | virtual | ||
127 | results | ||
128 | 4914 | do_process( | |
129 | buffers::mutable_buffer out, | ||
130 | buffers::const_buffer in, | ||
131 | bool more) noexcept override | ||
132 | { | ||
133 | 4914 | strm_.next_out = static_cast<unsigned char*>(out.data()); | |
134 | 4914 | strm_.avail_out = saturate_cast(out.size()); | |
135 | 4914 | strm_.next_in = static_cast<unsigned char*>(const_cast<void *>(in.data())); | |
136 | 4914 | strm_.avail_in = saturate_cast(in.size()); | |
137 | |||
138 | auto rs = static_cast<rts::zlib::error>( | ||
139 |
2/2✓ Branch 0 taken 4828 times.
✓ Branch 1 taken 86 times.
|
4914 | svc_.deflate( |
140 | 4914 | strm_, | |
141 | more ? rts::zlib::no_flush : rts::zlib::finish)); | ||
142 | |||
143 | 4914 | results rv; | |
144 | 4914 | rv.out_bytes = saturate_cast(out.size()) - strm_.avail_out; | |
145 | 4914 | rv.in_bytes = saturate_cast(in.size()) - strm_.avail_in; | |
146 | 4914 | rv.finished = (rs == rts::zlib::error::stream_end); | |
147 | |||
148 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 4914 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
4914 | if(rs < rts::zlib::error::ok && rs != rts::zlib::error::buf_err) |
149 | ✗ | rv.ec = rs; | |
150 | |||
151 | 4914 | return rv; | |
152 | } | ||
153 | }; | ||
154 | |||
155 | class brotli_filter | ||
156 | : public detail::brotli_filter_base | ||
157 | { | ||
158 | rts::brotli::encode_service& svc_; | ||
159 | rts::brotli::encoder_state* state_; | ||
160 | |||
161 | public: | ||
162 | ✗ | brotli_filter( | |
163 | const rts::context& ctx, | ||
164 | http_proto::detail::workspace&, | ||
165 | std::uint32_t comp_quality, | ||
166 | std::uint32_t comp_window) | ||
167 | ✗ | : svc_(ctx.get_service<rts::brotli::encode_service>()) | |
168 | { | ||
169 | // TODO: use custom allocator | ||
170 | ✗ | state_ = svc_.create_instance(nullptr, nullptr, nullptr); | |
171 | ✗ | if(!state_) | |
172 | ✗ | detail::throw_bad_alloc(); | |
173 | using encoder_parameter = rts::brotli::encoder_parameter; | ||
174 | ✗ | svc_.set_parameter(state_, encoder_parameter::quality, comp_quality); | |
175 | ✗ | svc_.set_parameter(state_, encoder_parameter::lgwin, comp_window); | |
176 | ✗ | } | |
177 | |||
178 | ✗ | ~brotli_filter() | |
179 | ✗ | { | |
180 | ✗ | svc_.destroy_instance(state_); | |
181 | ✗ | } | |
182 | |||
183 | private: | ||
184 | virtual | ||
185 | results | ||
186 | ✗ | do_process( | |
187 | buffers::mutable_buffer out, | ||
188 | buffers::const_buffer in, | ||
189 | bool more) noexcept override | ||
190 | { | ||
191 | ✗ | auto* next_in = reinterpret_cast<const std::uint8_t*>(in.data()); | |
192 | ✗ | auto available_in = in.size(); | |
193 | ✗ | auto* next_out = reinterpret_cast<std::uint8_t*>(out.data()); | |
194 | ✗ | auto available_out = out.size(); | |
195 | |||
196 | using encoder_operation = | ||
197 | rts::brotli::encoder_operation; | ||
198 | |||
199 | ✗ | bool rs = svc_.compress_stream( | |
200 | state_, | ||
201 | more ? encoder_operation::process : encoder_operation::finish, | ||
202 | &available_in, | ||
203 | &next_in, | ||
204 | &available_out, | ||
205 | &next_out, | ||
206 | nullptr); | ||
207 | |||
208 | ✗ | results rv; | |
209 | ✗ | rv.in_bytes = in.size() - available_in; | |
210 | ✗ | rv.out_bytes = out.size() - available_out; | |
211 | ✗ | rv.finished = svc_.is_finished(state_); | |
212 | |||
213 | // TODO: use proper error code | ||
214 | ✗ | if(rs == false) | |
215 | ✗ | rv.ec = error::bad_payload; | |
216 | |||
217 | ✗ | return rv; | |
218 | } | ||
219 | }; | ||
220 | |||
221 | template<class UInt> | ||
222 | std::size_t | ||
223 | 8 | clamp( | |
224 | UInt x, | ||
225 | std::size_t limit = (std::numeric_limits< | ||
226 | std::size_t>::max)()) noexcept | ||
227 | { | ||
228 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | if(x >= limit) |
229 | 2 | return limit; | |
230 | 6 | return static_cast<std::size_t>(x); | |
231 | } | ||
232 | |||
233 | class serializer_service | ||
234 | : public rts::service | ||
235 | { | ||
236 | public: | ||
237 | serializer::config cfg; | ||
238 | std::size_t space_needed = 0; | ||
239 | |||
240 | 24 | serializer_service( | |
241 | const rts::context&, | ||
242 | serializer::config const& cfg_) | ||
243 | 24 | : cfg(cfg_) | |
244 | { | ||
245 | 24 | space_needed += cfg.payload_buffer; | |
246 | 24 | space_needed += cfg.max_type_erase; | |
247 | |||
248 |
3/4✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
|
24 | if(cfg.apply_deflate_encoder || cfg.apply_gzip_encoder) |
249 | { | ||
250 | // TODO: Account for the number of allocations and | ||
251 | // their overhead in the workspace. | ||
252 | |||
253 | // https://www.zlib.net/zlib_tech.html | ||
254 | 1 | space_needed += | |
255 | 1 | (1 << (cfg.zlib_window_bits + 2)) + | |
256 | 1 | (1 << (cfg.zlib_mem_level + 9)) + | |
257 | 1 | (6 * 1024) + | |
258 | #ifdef __s390x__ | ||
259 | 5768 + | ||
260 | #endif | ||
261 | 1 | detail::workspace::space_needed<zlib_filter>(); | |
262 | } | ||
263 | 24 | } | |
264 | }; | ||
265 | |||
266 | } // namespace | ||
267 | |||
268 | //------------------------------------------------ | ||
269 | |||
270 | void | ||
271 | 24 | install_serializer_service( | |
272 | rts::context& ctx, | ||
273 | serializer::config const& cfg) | ||
274 | { | ||
275 | 24 | ctx.make_service<serializer_service>(cfg); | |
276 | 24 | } | |
277 | |||
278 | //------------------------------------------------ | ||
279 | |||
280 | class serializer::impl | ||
281 | { | ||
282 | friend stream; | ||
283 | |||
284 | enum class state | ||
285 | { | ||
286 | reset, | ||
287 | start, | ||
288 | header, | ||
289 | body | ||
290 | }; | ||
291 | |||
292 | enum class style | ||
293 | { | ||
294 | empty, | ||
295 | buffers, | ||
296 | source, | ||
297 | stream | ||
298 | }; | ||
299 | |||
300 | const rts::context& ctx_; | ||
301 | serializer_service& svc_; | ||
302 | detail::workspace ws_; | ||
303 | |||
304 | detail::filter* filter_ = nullptr; | ||
305 | cbs_gen* cbs_gen_ = nullptr; | ||
306 | source* source_ = nullptr; | ||
307 | |||
308 | buffers::circular_buffer out_; | ||
309 | buffers::circular_buffer in_; | ||
310 | detail::array_of_const_buffers prepped_; | ||
311 | buffers::const_buffer tmp_; | ||
312 | |||
313 | state state_ = state::start; | ||
314 | style style_ = style::empty; | ||
315 | uint8_t chunk_header_len_ = 0; | ||
316 | bool more_input_ = false; | ||
317 | bool is_chunked_ = false; | ||
318 | bool needs_exp100_continue_ = false; | ||
319 | bool filter_done_ = false; | ||
320 | |||
321 | public: | ||
322 | 24 | impl(const rts::context& ctx) | |
323 | 24 | : ctx_(ctx) | |
324 | 24 | , svc_(ctx_.get_service<serializer_service>()) | |
325 | 24 | , ws_(svc_.space_needed) | |
326 | { | ||
327 | 24 | } | |
328 | |||
329 | void | ||
330 | 82 | reset() noexcept | |
331 | { | ||
332 | 82 | ws_.clear(); | |
333 | 82 | state_ = state::start; | |
334 | 82 | } | |
335 | |||
336 | auto | ||
337 | 2426 | prepare() -> | |
338 | system::result<const_buffers_type> | ||
339 | { | ||
340 | // Precondition violation | ||
341 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2424 times.
|
2426 | if(state_ < state::header) |
342 | 2 | detail::throw_logic_error(); | |
343 | |||
344 | // Expect: 100-continue | ||
345 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2420 times.
|
2424 | if(needs_exp100_continue_) |
346 | { | ||
347 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if(!is_header_done()) |
348 | 4 | return const_buffers_type( | |
349 | prepped_.begin(), | ||
350 | 2 | 1); // limit to header | |
351 | |||
352 | 2 | needs_exp100_continue_ = false; | |
353 | |||
354 | 2 | BOOST_HTTP_PROTO_RETURN_EC( | |
355 | error::expect_100_continue); | ||
356 | } | ||
357 | |||
358 |
2/2✓ Branch 0 taken 62 times.
✓ Branch 1 taken 2358 times.
|
2420 | if(!filter_) |
359 | { | ||
360 |
4/5✓ Branch 0 taken 6 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
62 | switch(style_) |
361 | { | ||
362 | 6 | case style::empty: | |
363 | 6 | break; | |
364 | |||
365 | 20 | case style::buffers: | |
366 | { | ||
367 | // add more buffers if prepped_ is half empty. | ||
368 |
6/6✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 16 times.
|
30 | if(more_input_ && |
369 | 10 | prepped_.capacity() >= prepped_.size()) | |
370 | { | ||
371 | 4 | prepped_.slide_to_front(); | |
372 |
2/2✓ Branch 1 taken 48 times.
✓ Branch 2 taken 2 times.
|
50 | while(prepped_.capacity() != 0) |
373 | { | ||
374 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | auto buf = cbs_gen_->next(); |
375 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 46 times.
|
48 | if(buf.size() == 0) |
376 | 2 | break; | |
377 | 46 | prepped_.append(buf); | |
378 | } | ||
379 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if(cbs_gen_->is_empty()) |
380 | { | ||
381 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if(is_chunked_) |
382 | { | ||
383 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if(prepped_.capacity() != 0) |
384 | { | ||
385 | 1 | prepped_.append( | |
386 | crlf_and_final_chunk); | ||
387 | 1 | more_input_ = false; | |
388 | } | ||
389 | } | ||
390 | else | ||
391 | { | ||
392 | 1 | more_input_ = false; | |
393 | } | ||
394 | } | ||
395 | } | ||
396 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | return detail::make_span(prepped_); |
397 | } | ||
398 | |||
399 | 23 | case style::source: | |
400 | { | ||
401 |
5/6✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 16 times.
✓ Branch 6 taken 7 times.
|
23 | if(out_capacity() == 0 || !more_input_) |
402 | 22 | break; | |
403 | |||
404 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | const auto rs = source_->read( |
405 | 7 | out_prepare()); | |
406 | |||
407 | 7 | out_commit(rs.bytes); | |
408 | |||
409 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
|
7 | if(rs.ec.failed()) |
410 | { | ||
411 | 1 | ws_.clear(); | |
412 | 1 | state_ = state::reset; | |
413 | 1 | return rs.ec; | |
414 | } | ||
415 | |||
416 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if(rs.finished) |
417 | { | ||
418 | 6 | more_input_ = false; | |
419 | 6 | out_finish(); | |
420 | } | ||
421 | |||
422 | 6 | break; | |
423 | } | ||
424 | |||
425 | 13 | case style::stream: | |
426 |
8/8✓ Branch 1 taken 7 times.
✓ Branch 2 taken 6 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 10 times.
|
13 | if(out_.size() == 0 && is_header_done() && more_input_) |
427 | 3 | BOOST_HTTP_PROTO_RETURN_EC( | |
428 | error::need_data); | ||
429 | 10 | break; | |
430 | } | ||
431 | } | ||
432 | else // filter | ||
433 | { | ||
434 |
4/5✓ Branch 0 taken 4 times.
✓ Branch 1 taken 376 times.
✓ Branch 2 taken 734 times.
✓ Branch 3 taken 1244 times.
✗ Branch 4 not taken.
|
2358 | switch(style_) |
435 | { | ||
436 | 4 | case style::empty: | |
437 | { | ||
438 |
3/6✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
|
4 | if(out_capacity() == 0 || filter_done_) |
439 | 4 | break; | |
440 | |||
441 |
3/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
12 | const auto rs = filter_->process( |
442 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | detail::make_span(out_prepare()), |
443 | {}, // empty input | ||
444 | false); | ||
445 | |||
446 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if(rs.ec.failed()) |
447 | { | ||
448 | ✗ | ws_.clear(); | |
449 | ✗ | state_ = state::reset; | |
450 | ✗ | return rs.ec; | |
451 | } | ||
452 | |||
453 | 4 | out_commit(rs.out_bytes); | |
454 | |||
455 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if(rs.finished) |
456 | { | ||
457 | 4 | filter_done_ = true; | |
458 | 4 | out_finish(); | |
459 | } | ||
460 | |||
461 | 4 | break; | |
462 | } | ||
463 | |||
464 | 376 | case style::buffers: | |
465 | { | ||
466 |
6/6✓ Branch 1 taken 2212 times.
✓ Branch 2 taken 360 times.
✓ Branch 3 taken 2196 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 2196 times.
✓ Branch 6 taken 376 times.
|
2572 | while(out_capacity() != 0 && !filter_done_) |
467 | { | ||
468 |
6/6✓ Branch 0 taken 2188 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 2008 times.
✓ Branch 4 taken 180 times.
✓ Branch 5 taken 2008 times.
✓ Branch 6 taken 188 times.
|
2196 | if(more_input_ && tmp_.size() == 0) |
469 | { | ||
470 |
1/2✓ Branch 1 taken 2008 times.
✗ Branch 2 not taken.
|
2008 | tmp_ = cbs_gen_->next(); |
471 |
2/2✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1992 times.
|
2008 | if(tmp_.size() == 0) // cbs_gen_ is empty |
472 | 16 | more_input_ = false; | |
473 | } | ||
474 | |||
475 |
1/2✓ Branch 3 taken 2196 times.
✗ Branch 4 not taken.
|
4392 | const auto rs = filter_->process( |
476 |
1/2✓ Branch 2 taken 2196 times.
✗ Branch 3 not taken.
|
2196 | detail::make_span(out_prepare()), |
477 | 2196 | { tmp_, {} }, | |
478 | 2196 | more_input_); | |
479 | |||
480 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2196 times.
|
2196 | if(rs.ec.failed()) |
481 | { | ||
482 | ✗ | ws_.clear(); | |
483 | ✗ | state_ = state::reset; | |
484 | ✗ | return rs.ec; | |
485 | } | ||
486 | |||
487 | 2196 | buffers::trim_front(tmp_, rs.in_bytes); | |
488 | 2196 | out_commit(rs.out_bytes); | |
489 | |||
490 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2196 times.
|
2196 | if(rs.out_short) |
491 | ✗ | break; | |
492 | |||
493 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2180 times.
|
2196 | if(rs.finished) |
494 | { | ||
495 | 16 | filter_done_ = true; | |
496 | 16 | out_finish(); | |
497 | } | ||
498 | } | ||
499 | 376 | break; | |
500 | } | ||
501 | |||
502 | 734 | case style::source: | |
503 | { | ||
504 |
6/6✓ Branch 1 taken 1462 times.
✓ Branch 2 taken 718 times.
✓ Branch 3 taken 1446 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 1446 times.
✓ Branch 6 taken 734 times.
|
2180 | while(out_capacity() != 0 && !filter_done_) |
505 | { | ||
506 |
6/6✓ Branch 0 taken 1432 times.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 984 times.
✓ Branch 4 taken 448 times.
✓ Branch 5 taken 984 times.
✓ Branch 6 taken 462 times.
|
1446 | if(more_input_ && in_.capacity() != 0) |
507 | { | ||
508 |
1/2✓ Branch 1 taken 984 times.
✗ Branch 2 not taken.
|
984 | const auto rs = source_->read( |
509 |
1/2✓ Branch 2 taken 984 times.
✗ Branch 3 not taken.
|
984 | in_.prepare(in_.capacity())); |
510 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 984 times.
|
984 | if(rs.ec.failed()) |
511 | { | ||
512 | ✗ | ws_.clear(); | |
513 | ✗ | state_ = state::reset; | |
514 | ✗ | return rs.ec; | |
515 | } | ||
516 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 968 times.
|
984 | if(rs.finished) |
517 | 16 | more_input_ = false; | |
518 | 984 | in_.commit(rs.bytes); | |
519 | } | ||
520 | |||
521 |
1/2✓ Branch 2 taken 1446 times.
✗ Branch 3 not taken.
|
1446 | const auto rs = filter_->process( |
522 |
1/2✓ Branch 2 taken 1446 times.
✗ Branch 3 not taken.
|
1446 | detail::make_span(out_prepare()), |
523 | in_.data(), | ||
524 | 1446 | more_input_); | |
525 | |||
526 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1446 times.
|
1446 | if(rs.ec.failed()) |
527 | { | ||
528 | ✗ | ws_.clear(); | |
529 | ✗ | state_ = state::reset; | |
530 | ✗ | return rs.ec; | |
531 | } | ||
532 | |||
533 | 1446 | in_.consume(rs.in_bytes); | |
534 | 1446 | out_commit(rs.out_bytes); | |
535 | |||
536 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1446 times.
|
1446 | if(rs.out_short) |
537 | ✗ | break; | |
538 | |||
539 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1430 times.
|
1446 | if(rs.finished) |
540 | { | ||
541 | 16 | filter_done_ = true; | |
542 | 16 | out_finish(); | |
543 | } | ||
544 | } | ||
545 | 734 | break; | |
546 | } | ||
547 | |||
548 | 1244 | case style::stream: | |
549 | { | ||
550 |
3/6✓ Branch 1 taken 1244 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1244 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1244 times.
|
1244 | if(out_capacity() == 0 || filter_done_) |
551 | 804 | break; | |
552 | |||
553 |
1/2✓ Branch 2 taken 1244 times.
✗ Branch 3 not taken.
|
1244 | const auto rs = filter_->process( |
554 |
1/2✓ Branch 2 taken 1244 times.
✗ Branch 3 not taken.
|
1244 | detail::make_span(out_prepare()), |
555 | in_.data(), | ||
556 | 1244 | more_input_); | |
557 | |||
558 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1244 times.
|
1244 | if(rs.ec.failed()) |
559 | { | ||
560 | ✗ | ws_.clear(); | |
561 | ✗ | state_ = state::reset; | |
562 | 440 | return rs.ec; | |
563 | } | ||
564 | |||
565 | 1244 | in_.consume(rs.in_bytes); | |
566 | 1244 | out_commit(rs.out_bytes); | |
567 | |||
568 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1228 times.
|
1244 | if(rs.finished) |
569 | { | ||
570 | 16 | filter_done_ = true; | |
571 | 16 | out_finish(); | |
572 | } | ||
573 | |||
574 |
6/8✓ Branch 1 taken 440 times.
✓ Branch 2 taken 804 times.
✓ Branch 4 taken 440 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 440 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 440 times.
✓ Branch 9 taken 804 times.
|
1244 | if(out_.size() == 0 && is_header_done() && more_input_) |
575 | 440 | BOOST_HTTP_PROTO_RETURN_EC( | |
576 | error::need_data); | ||
577 | 804 | break; | |
578 | } | ||
579 | } | ||
580 | } | ||
581 | |||
582 | 1956 | prepped_.reset(!is_header_done()); | |
583 |
2/2✓ Branch 3 taken 3912 times.
✓ Branch 4 taken 1956 times.
|
5868 | for(auto const& cb : out_.data()) |
584 | { | ||
585 |
2/2✓ Branch 1 taken 1948 times.
✓ Branch 2 taken 1964 times.
|
3912 | if(cb.size() != 0) |
586 | 1948 | prepped_.append(cb); | |
587 | } | ||
588 |
1/2✓ Branch 1 taken 1956 times.
✗ Branch 2 not taken.
|
1956 | return detail::make_span(prepped_); |
589 | } | ||
590 | |||
591 | void | ||
592 | 3717 | consume( | |
593 | std::size_t n) | ||
594 | { | ||
595 | // Precondition violation | ||
596 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3716 times.
|
3717 | if(state_ < state::header) |
597 | 1 | detail::throw_logic_error(); | |
598 | |||
599 |
2/2✓ Branch 1 taken 85 times.
✓ Branch 2 taken 3631 times.
|
3716 | if(!is_header_done()) |
600 | { | ||
601 | const auto header_remain = | ||
602 | 85 | prepped_[0].size(); | |
603 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 73 times.
|
85 | if(n < header_remain) |
604 | { | ||
605 | 12 | prepped_.consume(n); | |
606 | 12 | return; | |
607 | } | ||
608 | 73 | n -= header_remain; | |
609 | 73 | prepped_.consume(header_remain); | |
610 | 73 | state_ = state::body; | |
611 | } | ||
612 | |||
613 | 3704 | prepped_.consume(n); | |
614 | |||
615 | // no-op when out_ is not in use | ||
616 | 3704 | out_.consume(n); | |
617 | |||
618 |
2/2✓ Branch 1 taken 1759 times.
✓ Branch 2 taken 1945 times.
|
3704 | if(!prepped_.empty()) |
619 | 1759 | return; | |
620 | |||
621 |
2/2✓ Branch 0 taken 1837 times.
✓ Branch 1 taken 108 times.
|
1945 | if(more_input_) |
622 | 1837 | return; | |
623 | |||
624 |
4/4✓ Branch 0 taken 86 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 52 times.
|
108 | if(filter_ && !filter_done_) |
625 | 34 | return; | |
626 | |||
627 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 73 times.
|
74 | if(needs_exp100_continue_) |
628 | 1 | return; | |
629 | |||
630 | // ready for next message | ||
631 | 73 | reset(); | |
632 | } | ||
633 | |||
634 | void | ||
635 | 84 | start_init( | |
636 | message_view_base const& m) | ||
637 | { | ||
638 | // Precondition violation | ||
639 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 83 times.
|
84 | if(state_ != state::start) |
640 | 1 | detail::throw_logic_error(); | |
641 | |||
642 | // TODO: To uphold the strong exception guarantee, | ||
643 | // `state_` must be reset to `state::start` if an | ||
644 | // exception is thrown during the start operation. | ||
645 | 83 | state_ = state::header; | |
646 | |||
647 | // VFALCO what do we do with | ||
648 | // metadata error code failures? | ||
649 | // m.ph_->md.maybe_throw(); | ||
650 | |||
651 | 83 | auto const& md = m.metadata(); | |
652 | 83 | needs_exp100_continue_ = md.expect.is_100_continue; | |
653 | |||
654 | // Transfer-Encoding | ||
655 | 83 | is_chunked_ = md.transfer_encoding.is_chunked; | |
656 | |||
657 | // Content-Encoding | ||
658 |
3/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 31 times.
|
83 | switch (md.content_encoding.coding) |
659 | { | ||
660 | 26 | case content_coding::deflate: | |
661 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if(!svc_.cfg.apply_deflate_encoder) |
662 | ✗ | goto no_filter; | |
663 | 52 | filter_ = &ws_.emplace<zlib_filter>( | |
664 | ctx_, | ||
665 | 26 | ws_, | |
666 | 26 | svc_.cfg.zlib_comp_level, | |
667 | 26 | svc_.cfg.zlib_window_bits, | |
668 | 26 | svc_.cfg.zlib_mem_level); | |
669 | 26 | filter_done_ = false; | |
670 | 26 | break; | |
671 | |||
672 | 26 | case content_coding::gzip: | |
673 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if(!svc_.cfg.apply_gzip_encoder) |
674 | ✗ | goto no_filter; | |
675 | 52 | filter_ = &ws_.emplace<zlib_filter>( | |
676 | ctx_, | ||
677 | 26 | ws_, | |
678 | 26 | svc_.cfg.zlib_comp_level, | |
679 | 52 | svc_.cfg.zlib_window_bits + 16, | |
680 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | svc_.cfg.zlib_mem_level); |
681 | 26 | filter_done_ = false; | |
682 | 26 | break; | |
683 | |||
684 | ✗ | case content_coding::br: | |
685 | ✗ | if(!svc_.cfg.apply_brotli_encoder) | |
686 | ✗ | goto no_filter; | |
687 | ✗ | filter_ = &ws_.emplace<brotli_filter>( | |
688 | ctx_, | ||
689 | ✗ | ws_, | |
690 | ✗ | svc_.cfg.brotli_comp_quality, | |
691 | ✗ | svc_.cfg.brotli_comp_window); | |
692 | ✗ | filter_done_ = false; | |
693 | ✗ | break; | |
694 | |||
695 | ✗ | no_filter: | |
696 | 31 | default: | |
697 | 31 | filter_ = nullptr; | |
698 | 31 | break; | |
699 | } | ||
700 | 83 | } | |
701 | |||
702 | void | ||
703 | 12 | start_empty( | |
704 | message_view_base const& m) | ||
705 | { | ||
706 | 12 | start_init(m); | |
707 | 11 | style_ = style::empty; | |
708 | |||
709 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
11 | prepped_ = make_array( |
710 | 1 + // header | ||
711 | 2); // out buffer pairs | ||
712 | |||
713 | 11 | out_init(); | |
714 | |||
715 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
|
11 | if(!filter_) |
716 | 7 | out_finish(); | |
717 | |||
718 | 11 | prepped_.append({ m.ph_->cbuf, m.ph_->size }); | |
719 | 11 | more_input_ = false; | |
720 | 11 | } | |
721 | |||
722 | void | ||
723 | 24 | start_buffers( | |
724 | message_view_base const& m, | ||
725 | cbs_gen& cbs_gen) | ||
726 | { | ||
727 | // start_init() already called | ||
728 | 24 | style_ = style::buffers; | |
729 | 24 | cbs_gen_ = &cbs_gen; | |
730 | |||
731 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 16 times.
|
24 | if(!filter_) |
732 | { | ||
733 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | auto stats = cbs_gen_->stats(); |
734 | 8 | auto batch_size = clamp(stats.count, 16); | |
735 | |||
736 | ✗ | prepped_ = make_array( | |
737 | 1 + // header | ||
738 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | batch_size + // buffers |
739 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | (is_chunked_ ? 2 : 0)); // chunk header + final chunk |
740 | |||
741 | 8 | prepped_.append({ m.ph_->cbuf, m.ph_->size }); | |
742 | 8 | more_input_ = (batch_size != 0); | |
743 | |||
744 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | if(is_chunked_) |
745 | { | ||
746 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if(!more_input_) |
747 | { | ||
748 | 1 | prepped_.append(final_chunk); | |
749 | } | ||
750 | else | ||
751 | { | ||
752 | 1 | auto h_len = chunk_header_len(stats.size); | |
753 | buffers::mutable_buffer mb( | ||
754 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ws_.reserve_front(h_len), h_len); |
755 | 1 | write_chunk_header({ mb, {} }, stats.size); | |
756 | 1 | prepped_.append(mb); | |
757 | } | ||
758 | } | ||
759 | 8 | return; | |
760 | } | ||
761 | |||
762 | // filter | ||
763 | |||
764 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | prepped_ = make_array( |
765 | 1 + // header | ||
766 | 2); // out buffer pairs | ||
767 | |||
768 | 16 | out_init(); | |
769 | |||
770 | 16 | prepped_.append({ m.ph_->cbuf, m.ph_->size }); | |
771 | 16 | tmp_ = {}; | |
772 | 16 | more_input_ = true; | |
773 | } | ||
774 | |||
775 | void | ||
776 | 25 | start_source( | |
777 | message_view_base const& m, | ||
778 | source& source) | ||
779 | { | ||
780 | // start_init() already called | ||
781 | 25 | style_ = style::source; | |
782 | 25 | source_ = &source; | |
783 | |||
784 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | prepped_ = make_array( |
785 | 1 + // header | ||
786 | 2); // out buffer pairs | ||
787 | |||
788 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 9 times.
|
25 | if(filter_) |
789 | { | ||
790 | // TODO: smarter buffer distribution | ||
791 | 16 | auto const n = (ws_.size() - 1) / 2; | |
792 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | in_ = { ws_.reserve_front(n), n }; |
793 | } | ||
794 | |||
795 | 25 | out_init(); | |
796 | |||
797 | 25 | prepped_.append({ m.ph_->cbuf, m.ph_->size }); | |
798 | 25 | more_input_ = true; | |
799 | 25 | } | |
800 | |||
801 | stream | ||
802 | 23 | start_stream(message_view_base const& m) | |
803 | { | ||
804 | 23 | start_init(m); | |
805 | 23 | style_ = style::stream; | |
806 | |||
807 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | prepped_ = make_array( |
808 | 1 + // header | ||
809 | 2); // out buffer pairs | ||
810 | |||
811 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 7 times.
|
23 | if(filter_) |
812 | { | ||
813 | // TODO: smarter buffer distribution | ||
814 | 16 | auto const n = (ws_.size() - 1) / 2; | |
815 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | in_ = { ws_.reserve_front(n), n }; |
816 | } | ||
817 | |||
818 | 23 | out_init(); | |
819 | |||
820 | 23 | prepped_.append({ m.ph_->cbuf, m.ph_->size }); | |
821 | 23 | more_input_ = true; | |
822 | 23 | return stream{ this }; | |
823 | } | ||
824 | |||
825 | bool | ||
826 | 2479 | is_done() const noexcept | |
827 | { | ||
828 | 2479 | return state_ == state::start; | |
829 | } | ||
830 | |||
831 | detail::workspace& | ||
832 | 49 | ws() noexcept | |
833 | { | ||
834 | 49 | return ws_; | |
835 | } | ||
836 | |||
837 | private: | ||
838 | bool | ||
839 | 6123 | is_header_done() const noexcept | |
840 | { | ||
841 | 6123 | return state_ == state::body; | |
842 | } | ||
843 | |||
844 | detail::array_of_const_buffers | ||
845 | 83 | make_array(std::size_t n) | |
846 | { | ||
847 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
|
83 | BOOST_ASSERT(n <= std::uint16_t(-1)); |
848 | |||
849 | return { | ||
850 | 83 | ws_.push_array(n, | |
851 | ✗ | buffers::const_buffer{}), | |
852 |
1/2✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
|
83 | static_cast<std::uint16_t>(n) }; |
853 | } | ||
854 | |||
855 | void | ||
856 | 75 | out_init() | |
857 | { | ||
858 | // use all the remaining buffer | ||
859 | 75 | auto const n = ws_.size() - 1; | |
860 |
1/2✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
|
75 | out_ = { ws_.reserve_front(n), n }; |
861 | 75 | chunk_header_len_ = | |
862 | 75 | chunk_header_len(out_.capacity()); | |
863 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
|
75 | if(out_capacity() == 0) |
864 | ✗ | detail::throw_length_error(); | |
865 | 75 | } | |
866 | |||
867 | buffers::mutable_buffer_pair | ||
868 | 4903 | out_prepare() noexcept | |
869 | { | ||
870 | 4903 | auto mbp = out_.prepare(out_.capacity()); | |
871 |
2/2✓ Branch 0 taken 2451 times.
✓ Branch 1 taken 2452 times.
|
4903 | if(is_chunked_) |
872 | { | ||
873 | 2451 | buffers::trim_front( | |
874 | 2451 | mbp, chunk_header_len_); | |
875 | 2451 | buffers::trim_back( | |
876 | mbp, crlf_and_final_chunk.size()); | ||
877 | } | ||
878 | 4903 | return mbp; | |
879 | } | ||
880 | |||
881 | void | ||
882 | 4903 | out_commit( | |
883 | std::size_t n) noexcept | ||
884 | { | ||
885 |
2/2✓ Branch 0 taken 2451 times.
✓ Branch 1 taken 2452 times.
|
4903 | if(is_chunked_) |
886 | { | ||
887 |
2/2✓ Branch 0 taken 1306 times.
✓ Branch 1 taken 1145 times.
|
2451 | if(n == 0) |
888 | 1306 | return; | |
889 | |||
890 | 1145 | write_chunk_header(out_.prepare(chunk_header_len_), n); | |
891 | 1145 | out_.commit(chunk_header_len_); | |
892 | |||
893 | 1145 | out_.prepare(n); | |
894 | 1145 | out_.commit(n); | |
895 | |||
896 | 1145 | buffers::copy(out_.prepare(crlf.size()), crlf); | |
897 | 1145 | out_.commit(crlf.size()); | |
898 | } | ||
899 | else | ||
900 | { | ||
901 | 2452 | out_.commit(n); | |
902 | } | ||
903 | } | ||
904 | |||
905 | std::size_t | ||
906 | 6122 | out_capacity() const noexcept | |
907 | { | ||
908 |
2/2✓ Branch 0 taken 3058 times.
✓ Branch 1 taken 3064 times.
|
6122 | if(is_chunked_) |
909 | { | ||
910 | 3058 | auto const overhead = chunk_header_len_ + | |
911 | 3058 | crlf_and_final_chunk.size(); | |
912 |
2/2✓ Branch 1 taken 541 times.
✓ Branch 2 taken 2517 times.
|
3058 | if(out_.capacity() < overhead) |
913 | 541 | return 0; | |
914 | 2517 | return out_.capacity() - overhead; | |
915 | } | ||
916 | 3064 | return out_.capacity(); | |
917 | } | ||
918 | |||
919 | void | ||
920 | 72 | out_finish() noexcept | |
921 | { | ||
922 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 39 times.
|
72 | if(is_chunked_) |
923 | { | ||
924 | 33 | buffers::copy( | |
925 | 33 | out_.prepare(final_chunk.size()), final_chunk); | |
926 | 33 | out_.commit(final_chunk.size()); | |
927 | } | ||
928 | 72 | } | |
929 | }; | ||
930 | |||
931 | //------------------------------------------------ | ||
932 | |||
933 | 24 | serializer:: | |
934 | 24 | serializer(const rts::context& ctx) | |
935 |
1/4✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
24 | : impl_(new impl(ctx)) |
936 | { | ||
937 | // TODO: use a single allocation for | ||
938 | // impl and workspace buffer. | ||
939 | 24 | } | |
940 | |||
941 | 1 | serializer:: | |
942 | 1 | serializer(serializer&& other) noexcept | |
943 | 1 | : impl_(other.impl_) | |
944 | { | ||
945 | 1 | other.impl_ = nullptr; | |
946 | 1 | } | |
947 | |||
948 | 25 | serializer:: | |
949 | ~serializer() | ||
950 | { | ||
951 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 times.
|
25 | delete impl_; |
952 | 25 | } | |
953 | |||
954 | void | ||
955 | 9 | serializer:: | |
956 | reset() noexcept | ||
957 | { | ||
958 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | BOOST_ASSERT(impl_); |
959 | 9 | impl_->reset(); | |
960 | 9 | } | |
961 | |||
962 | void | ||
963 | 12 | serializer:: | |
964 | start(message_view_base const& m) | ||
965 | { | ||
966 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | BOOST_ASSERT(impl_); |
967 | 12 | impl_->start_empty(m); | |
968 | 11 | } | |
969 | |||
970 | auto | ||
971 | 23 | serializer:: | |
972 | start_stream( | ||
973 | message_view_base const& m) -> stream | ||
974 | { | ||
975 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | BOOST_ASSERT(impl_); |
976 | 23 | return impl_->start_stream(m); | |
977 | } | ||
978 | |||
979 | auto | ||
980 | 2426 | serializer:: | |
981 | prepare() -> | ||
982 | system::result<const_buffers_type> | ||
983 | { | ||
984 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2426 times.
|
2426 | BOOST_ASSERT(impl_); |
985 | 2426 | return impl_->prepare(); | |
986 | } | ||
987 | |||
988 | void | ||
989 | 3717 | serializer:: | |
990 | consume(std::size_t n) | ||
991 | { | ||
992 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3717 times.
|
3717 | BOOST_ASSERT(impl_); |
993 | 3717 | impl_->consume(n); | |
994 | 3716 | } | |
995 | |||
996 | bool | ||
997 | 2479 | serializer:: | |
998 | is_done() const noexcept | ||
999 | { | ||
1000 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2479 times.
|
2479 | BOOST_ASSERT(impl_); |
1001 | 2479 | return impl_->is_done(); | |
1002 | } | ||
1003 | |||
1004 | //------------------------------------------------ | ||
1005 | |||
1006 | detail::workspace& | ||
1007 | 49 | serializer:: | |
1008 | ws() | ||
1009 | { | ||
1010 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
|
49 | BOOST_ASSERT(impl_); |
1011 | 49 | return impl_->ws(); | |
1012 | } | ||
1013 | |||
1014 | void | ||
1015 | 49 | serializer:: | |
1016 | start_init(message_view_base const& m) | ||
1017 | { | ||
1018 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
|
49 | BOOST_ASSERT(impl_); |
1019 | 49 | impl_->start_init(m); | |
1020 | 49 | } | |
1021 | |||
1022 | void | ||
1023 | 24 | serializer:: | |
1024 | start_buffers( | ||
1025 | message_view_base const& m, | ||
1026 | cbs_gen& cbs_gen) | ||
1027 | { | ||
1028 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | BOOST_ASSERT(impl_); |
1029 | 24 | impl_->start_buffers(m, cbs_gen); | |
1030 | 24 | } | |
1031 | |||
1032 | void | ||
1033 | 25 | serializer:: | |
1034 | start_source( | ||
1035 | message_view_base const& m, | ||
1036 | source& source) | ||
1037 | { | ||
1038 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
25 | BOOST_ASSERT(impl_); |
1039 | 25 | impl_->start_source(m, source); | |
1040 | 25 | } | |
1041 | |||
1042 | //------------------------------------------------ | ||
1043 | |||
1044 | std::size_t | ||
1045 | 1257 | serializer:: | |
1046 | stream:: | ||
1047 | capacity() const | ||
1048 | { | ||
1049 | // Precondition violation | ||
1050 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1256 times.
|
1257 | if(!is_open()) |
1051 | 1 | detail::throw_logic_error(); | |
1052 | |||
1053 |
2/2✓ Branch 0 taken 1232 times.
✓ Branch 1 taken 24 times.
|
1256 | if(impl_->filter_) |
1054 | 1232 | return impl_->in_.capacity(); | |
1055 | |||
1056 | 24 | return impl_->out_capacity(); | |
1057 | } | ||
1058 | |||
1059 | auto | ||
1060 | 1239 | serializer:: | |
1061 | stream:: | ||
1062 | prepare() -> | ||
1063 | mutable_buffers_type | ||
1064 | { | ||
1065 | // Precondition violation | ||
1066 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1238 times.
|
1239 | if(!is_open()) |
1067 | 1 | detail::throw_logic_error(); | |
1068 | |||
1069 |
2/2✓ Branch 0 taken 1232 times.
✓ Branch 1 taken 6 times.
|
1238 | if(impl_->filter_) |
1070 | 1232 | return impl_->in_.prepare( | |
1071 | 2464 | impl_->in_.capacity()); | |
1072 | |||
1073 | 6 | return impl_->out_prepare(); | |
1074 | } | ||
1075 | |||
1076 | void | ||
1077 | 1240 | serializer:: | |
1078 | stream:: | ||
1079 | commit(std::size_t n) | ||
1080 | { | ||
1081 | // Precondition violation | ||
1082 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1239 times.
|
1240 | if(!is_open()) |
1083 | 1 | detail::throw_logic_error(); | |
1084 | |||
1085 | // Precondition violation | ||
1086 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1238 times.
|
1239 | if(n > capacity()) |
1087 | 1 | detail::throw_invalid_argument(); | |
1088 | |||
1089 |
2/2✓ Branch 0 taken 1232 times.
✓ Branch 1 taken 6 times.
|
1238 | if(impl_->filter_) |
1090 | 1232 | return impl_->in_.commit(n); | |
1091 | |||
1092 | 6 | impl_->out_commit(n); | |
1093 | } | ||
1094 | |||
1095 | void | ||
1096 | 47 | serializer:: | |
1097 | stream:: | ||
1098 | close() noexcept | ||
1099 | { | ||
1100 |
2/2✓ Branch 1 taken 24 times.
✓ Branch 2 taken 23 times.
|
47 | if(!is_open()) |
1101 | 24 | return; // no-op; | |
1102 | |||
1103 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 16 times.
|
23 | if(!impl_->filter_) |
1104 | 7 | impl_->out_finish(); | |
1105 | |||
1106 | 23 | impl_->more_input_ = false; | |
1107 | 23 | impl_ = nullptr; | |
1108 | } | ||
1109 | |||
1110 | } // http_proto | ||
1111 | } // boost | ||
1112 |