GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/serializer.cpp
Date: 2024-09-18 08:42:23
Exec Total Coverage
Lines: 336 367 91.6%
Functions: 26 28 92.9%
Branches: 180 220 81.8%

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