GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/impl/serializer.ipp
Date: 2023-02-10 23:49:12
Exec Total Coverage
Lines: 167 245 68.2%
Functions: 12 20 60.0%
Branches: 75 153 49.0%

Line Branch Exec Source
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/CPPAlliance/http_proto
8 //
9
10 #ifndef BOOST_HTTP_PROTO_IMPL_SERIALIZER_IPP
11 #define BOOST_HTTP_PROTO_IMPL_SERIALIZER_IPP
12
13 #include <boost/http_proto/serializer.hpp>
14 #include <boost/http_proto/detail/codec.hpp>
15 #include <boost/http_proto/detail/except.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 namespace boost {
22 namespace http_proto {
23
24 //------------------------------------------------
25
26 void
27 consume_buffers(
28 buffers::const_buffer*& p,
29 std::size_t& n,
30 std::size_t bytes)
31 {
32 while(n > 0)
33 {
34 if(bytes < p->size())
35 {
36 *p += bytes;
37 return;
38 }
39 bytes -= p->size();
40 ++p;
41 --n;
42 }
43
44 // Precondition violation
45 if(bytes > 0)
46 detail::throw_invalid_argument();
47 }
48
49 template<class MutableBuffers>
50 void
51 6 write_chunk_header(
52 MutableBuffers const& dest0,
53 std::size_t size) noexcept
54 {
55 static constexpr char hexdig[] =
56 "0123456789ABCDEF";
57 char buf[18];
58 6 auto p = buf + 16;
59
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 3 times.
102 for(std::size_t i = 16; i--;)
60 {
61 96 *--p = hexdig[size & 0xf];
62 96 size >>= 4;
63 }
64 6 buf[16] = '\r';
65 6 buf[17] = '\n';
66 6 auto n = buffers::buffer_copy(
67 dest0,
68 buffers::const_buffer(
69 buf, sizeof(buf)));
70 ignore_unused(n);
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 BOOST_ASSERT(n == 18);
72
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
6 BOOST_ASSERT(
73 buffers::buffer_size(dest0) == n);
74 6 }
75
76 //------------------------------------------------
77
78 11 serializer::
79
6/8
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 11 times.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 33 times.
✓ Branch 8 taken 11 times.
77 ~serializer()
80 {
81 11 }
82
83 10 serializer::
84 10 serializer()
85 10 : serializer(65536)
86 {
87 10 }
88
89 serializer::
90 serializer(
91 serializer&&) noexcept = default;
92
93 11 serializer::
94 serializer(
95 11 std::size_t buffer_size)
96 11 : ws_(buffer_size)
97 {
98 11 }
99
100 void
101 serializer::
102 reset() noexcept
103 {
104 }
105
106 //------------------------------------------------
107
108 auto
109 14 serializer::
110 prepare() ->
111 result<const_buffers_type>
112 {
113 // Precondition violation
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if(is_done_)
115 detail::throw_logic_error();
116
117 // Expect: 100-continue
118
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10 times.
14 if(is_expect_continue_)
119 {
120
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if(out_.data() == hp_)
121 2 return const_buffers_type(hp_, 1);
122 2 is_expect_continue_ = false;
123 2 BOOST_HTTP_PROTO_RETURN_EC(
124 error::expect_100_continue);
125 }
126
127
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7 times.
10 if(st_ == style::empty)
128 {
129 9 return const_buffers_type(
130 3 out_.data(),
131 3 out_.size());
132 }
133
134
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if(st_ == style::buffers)
135 {
136 9 return const_buffers_type(
137 3 out_.data(),
138 3 out_.size());
139 }
140
141
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if(st_ == style::source)
142 {
143
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if(! is_chunked_)
144 {
145 3 auto rv = src_->read(
146 tmp0_.prepare(
147 3 tmp0_.capacity() -
148
2/4
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
3 tmp0_.size()));
149
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 tmp0_.commit(rv.bytes);
150
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if(rv.ec.failed())
151 return rv.ec;
152 3 more_ = ! rv.finished;
153 }
154 else
155 {
156 1 if((tmp0_.capacity() -
157
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tmp0_.size()) >
158 chunked_overhead_)
159 {
160
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 auto dest = tmp0_.prepare(18);
161 1 write_chunk_header(dest, 0);
162
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tmp0_.commit(18);
163 1 auto rv = src_->read(
164 tmp0_.prepare(
165 1 tmp0_.capacity() -
166 2 - // CRLF
167 1 5 - // final chunk
168
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 tmp0_.size()));
169
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tmp0_.commit(rv.bytes);
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(rv.bytes == 0)
171 tmp0_.uncommit(18); // undo
172
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if(rv.ec.failed())
173 return rv.ec;
174
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(rv.bytes > 0)
175 {
176 // rewrite with correct size
177 1 write_chunk_header(
178 dest, rv.bytes);
179 // terminate chunk
180
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 tmp0_.commit(
181 buffers::buffer_copy(
182
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tmp0_.prepare(2),
183 2 buffers::const_buffer(
184 "\r\n", 2)));
185 }
186
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(rv.finished)
187 {
188
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 tmp0_.commit(
189 buffers::buffer_copy(
190
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tmp0_.prepare(5),
191 2 buffers::const_buffer(
192 "0\r\n\r\n", 5)));
193 }
194 1 more_ = ! rv.finished;
195 }
196 }
197
198 4 std::size_t n = 0;
199
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
4 if(out_.data() == hp_)
200 3 ++n;
201
2/2
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 4 times.
12 for(buffers::const_buffer const& b : tmp0_.data())
202 8 out_[n++] = b;
203
204 12 return const_buffers_type(
205 4 out_.data(),
206 4 out_.size());
207 }
208
209 if(st_ == style::stream)
210 {
211 std::size_t n = 0;
212 if(out_.data() == hp_)
213 ++n;
214 if(tmp0_.size() == 0 && more_)
215 {
216 BOOST_HTTP_PROTO_RETURN_EC(
217 error::need_data);
218 }
219 for(buffers::const_buffer const& b : tmp0_.data())
220 out_[n++] = b;
221
222 return const_buffers_type(
223 out_.data(),
224 out_.size());
225 }
226
227 // should never get here
228 detail::throw_logic_error();
229 }
230
231 void
232 12 serializer::
233 consume(
234 std::size_t n)
235 {
236 // Precondition violation
237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(is_done_)
238 detail::throw_logic_error();
239
240
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
12 if(is_expect_continue_)
241 {
242 // Cannot consume more than
243 // the header on 100-continue
244
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if(n > hp_->size())
245 detail::throw_invalid_argument();
246
247 2 out_.consume(n);
248 2 return;
249 }
250
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
10 else if(out_.data() == hp_)
251 {
252 // consume header
253
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if(n < hp_->size())
254 {
255 out_.consume(n);
256 return;
257 }
258 8 n -= hp_->size();
259 8 out_.consume(hp_->size());
260 }
261
262
3/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
10 switch(st_)
263 {
264 3 default:
265 case style::empty:
266 3 out_.consume(n);
267
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if(out_.empty())
268 3 is_done_ = true;
269 3 return;
270
271 3 case style::buffers:
272 3 out_.consume(n);
273
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 if(out_.empty())
274 3 is_done_ = true;
275 3 return;
276
277 4 case style::source:
278 case style::stream:
279 4 tmp0_.consume(n);
280
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
8 if( tmp0_.size() == 0 &&
281
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 ! more_)
282 4 is_done_ = true;
283 4 return;
284 }
285 }
286
287 //------------------------------------------------
288
289 void
290 14 serializer::
291 copy(
292 buffers::const_buffer* dest,
293 buffers::const_buffer const* src,
294 std::size_t n) noexcept
295 {
296
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 while(n--)
297 7 *dest++ = *src++;
298 7 }
299
300 void
301 17 serializer::
302 start_init(
303 message_view_base const& m)
304 {
305 17 ws_.clear();
306
307 // VFALCO what do we do with
308 // metadata error code failures?
309 // m.ph_->md.maybe_throw();
310
311 17 is_done_ = false;
312
313 17 is_expect_continue_ =
314 17 m.ph_->md.expect.is_100_continue;
315
316 // Transfer-Encoding
317 {
318 17 auto const& te =
319 17 m.ph_->md.transfer_encoding;
320 17 is_chunked_ = te.is_chunked;
321 17 cod_ = nullptr;
322 }
323 17 }
324
325 void
326 4 serializer::
327 start_empty(
328 message_view_base const& m)
329 {
330 4 start_init(m);
331
332 4 st_ = style::empty;
333
334
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if(! is_chunked_)
335 {
336 out_ = make_array(
337 3 1); // header
338 }
339 else
340 {
341 out_ = make_array(
342 1 + // header
343
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 1); // final chunk
344
345 // Buffer is too small
346
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if(ws_.size() < 5)
347 detail::throw_length_error();
348
349 buffers::mutable_buffer dest(
350 1 ws_.data(), 5);
351 1 buffers::buffer_copy(
352 dest,
353 1 buffers::const_buffer(
354 "0\r\n\r\n", 5));
355 1 out_[1] = dest;
356 }
357
358 4 hp_ = &out_[0];
359 4 *hp_ = { m.ph_->cbuf, m.ph_->size };
360 4 }
361
362 void
363 7 serializer::
364 start_buffers(
365 message_view_base const& m)
366 {
367 7 st_ = style::buffers;
368
369
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 if(! is_chunked_)
370 {
371
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(! cod_)
372 {
373 out_ = make_array(
374 1 + // header
375 6 buf_.size()); // body
376 12 copy(&out_[1],
377 6 buf_.data(), buf_.size());
378 }
379 else
380 {
381 out_ = make_array(
382 1 + // header
383 2); // tmp1
384 }
385 }
386 else
387 {
388
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(! cod_)
389 {
390 out_ = make_array(
391 1 + // header
392 1 + // chunk size
393 1 buf_.size() + // body
394
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 1); // final chunk
395 2 copy(&out_[2],
396 1 buf_.data(), buf_.size());
397
398 // Buffer is too small
399
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if(ws_.size() < 18 + 7)
400 detail::throw_length_error();
401 1 buffers::mutable_buffer s1(ws_.data(), 18);
402 1 buffers::mutable_buffer s2(ws_.data(), 18 + 7);
403 1 s2 += 18; // VFALCO HACK
404 1 write_chunk_header(
405 s1,
406 1 buffers::buffer_size(buf_));
407 1 buffers::buffer_copy(s2, buffers::const_buffer(
408 "\r\n"
409 "0\r\n"
410 "\r\n", 7));
411 1 out_[1] = s1;
412 1 out_[out_.size() - 1] = s2;
413 }
414 else
415 {
416 out_ = make_array(
417 1 + // header
418 2); // tmp1
419 }
420 }
421
422 7 hp_ = &out_[0];
423 7 *hp_ = { m.ph_->cbuf, m.ph_->size };
424 7 }
425
426 void
427 6 serializer::
428 start_source(
429 message_view_base const& m,
430 buffers::source* src)
431 {
432 6 st_ = style::source;
433 6 src_ = src;
434 out_ = make_array(
435 1 + // header
436 6 2); // tmp
437
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(! cod_)
438 {
439 buffers::buffered_base::allocator a(
440 6 ws_.data(), ws_.size()/2, false);
441
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 src->init(a);
442
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 ws_.reserve(a.size_used());
443
444 6 tmp0_ = { ws_.data(), ws_.size() };
445
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if(tmp0_.capacity() <
446 18 + // chunk size
447 1 + // body (1 byte)
448 2 + // CRLF
449 5) // final chunk
450 detail::throw_length_error();
451 }
452 else
453 {
454 buffers::buffered_base::allocator a(
455 ws_.data(), ws_.size()/3, false);
456 src->init(a);
457 ws_.reserve(a.size_used());
458
459 auto const n = ws_.size() / 2;
460
461 tmp0_ = { ws_.data(), ws_.size() / 2 };
462 ws_.reserve(n);
463
464 // Buffer is too small
465 if(ws_.size() < 1)
466 detail::throw_length_error();
467
468 tmp1_ = { ws_.data(), ws_.size() };
469 }
470
471 6 hp_ = &out_[0];
472 6 *hp_ = { m.ph_->cbuf, m.ph_->size };
473 6 }
474
475 auto
476 serializer::
477 start_stream(
478 message_view_base const& m) ->
479 stream
480 {
481 start_init(m);
482
483 st_ = style::stream;
484 out_ = make_array(
485 1 + // header
486 2); // tmp
487 if(! cod_)
488 {
489 tmp0_ = { ws_.data(), ws_.size() };
490 if(tmp0_.capacity() <
491 18 + // chunk size
492 1 + // body (1 byte)
493 2 + // CRLF
494 5) // final chunk
495 detail::throw_length_error();
496 }
497 else
498 {
499 auto const n = ws_.size() / 2;
500 tmp0_ = { ws_.data(), n };
501 ws_.reserve(n);
502
503 // Buffer is too small
504 if(ws_.size() < 1)
505 detail::throw_length_error();
506
507 tmp1_ = { ws_.data(), ws_.size() };
508 }
509
510 hp_ = &out_[0];
511 *hp_ = { m.ph_->cbuf, m.ph_->size };
512
513 more_ = true;
514
515 return stream{*this};
516 }
517
518 //------------------------------------------------
519
520 std::size_t
521 serializer::
522 stream::
523 capacity() const
524 {
525 auto const n =
526 chunked_overhead_ +
527 2 + // CRLF
528 5; // final chunk
529 return sr_->tmp0_.capacity() - n; // VFALCO ?
530 }
531
532 std::size_t
533 serializer::
534 stream::
535 size() const
536 {
537 return sr_->tmp0_.size();
538 }
539
540 auto
541 serializer::
542 stream::
543 prepare(
544 std::size_t n) const ->
545 buffers_type
546 {
547 return sr_->tmp0_.prepare(n);
548 }
549
550 void
551 serializer::
552 stream::
553 commit(std::size_t n) const
554 {
555 sr_->tmp0_.commit(n);
556 }
557
558 void
559 serializer::
560 stream::
561 close() const
562 {
563 // Precondition violation
564 if(! sr_->more_)
565 detail::throw_logic_error();
566 sr_->more_ = false;
567 }
568
569 //------------------------------------------------
570
571 } // http_proto
572 } // boost
573
574 #endif
575