GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/serializer.cpp
Date: 2024-07-12 15:42:46
Exec Total Coverage
Lines: 319 350 91.1%
Functions: 24 26 92.3%
Branches: 166 206 80.6%

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