GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/serializer.cpp
Date: 2024-09-20 16:11:52
Exec Total Coverage
Lines: 339 370 91.6%
Functions: 26 28 92.9%
Branches: 178 218 81.7%

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