GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/impl/serializer.ipp
Date: 2023-02-25 19:48:06
Exec Total Coverage
Lines: 162 221 73.3%
Functions: 12 20 60.0%
Branches: 60 113 53.1%

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/except.hpp>
15 #include <boost/buffers/buffer_copy.hpp>
16 #include <boost/buffers/buffer_size.hpp>
17 #include <boost/core/ignore_unused.hpp>
18 #include <stddef.h>
19
20 namespace boost {
21 namespace http_proto {
22
23 //------------------------------------------------
24
25 void
26 consume_buffers(
27 buffers::const_buffer*& p,
28 std::size_t& n,
29 std::size_t bytes)
30 {
31 while(n > 0)
32 {
33 if(bytes < p->size())
34 {
35 *p += bytes;
36 return;
37 }
38 bytes -= p->size();
39 ++p;
40 --n;
41 }
42
43 // Precondition violation
44 if(bytes > 0)
45 detail::throw_invalid_argument();
46 }
47
48 template<class MutableBuffers>
49 void
50 6 write_chunk_header(
51 MutableBuffers const& dest0,
52 std::size_t size) noexcept
53 {
54 static constexpr char hexdig[] =
55 "0123456789ABCDEF";
56 char buf[18];
57 6 auto p = buf + 16;
58
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 3 times.
102 for(std::size_t i = 16; i--;)
59 {
60 96 *--p = hexdig[size & 0xf];
61 96 size >>= 4;
62 }
63 6 buf[16] = '\r';
64 6 buf[17] = '\n';
65 6 auto n = buffers::buffer_copy(
66 dest0,
67 buffers::const_buffer(
68 buf, sizeof(buf)));
69 ignore_unused(n);
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 BOOST_ASSERT(n == 18);
71
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
6 BOOST_ASSERT(
72 buffers::buffer_size(dest0) == n);
73 6 }
74
75 //------------------------------------------------
76
77 12 serializer::
78 12 ~serializer()
79 {
80 12 }
81
82 10 serializer::
83 10 serializer()
84 10 : serializer(65536)
85 {
86 10 }
87
88 serializer::
89 serializer(
90 serializer&&) noexcept = default;
91
92 12 serializer::
93 serializer(
94 12 std::size_t buffer_size)
95 12 : ws_(buffer_size)
96 {
97 12 }
98
99 void
100 serializer::
101 reset() noexcept
102 {
103 }
104
105 //------------------------------------------------
106
107 auto
108 14 serializer::
109 prepare() ->
110 result<const_buffers_type>
111 {
112 // Precondition violation
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if(is_done_)
114 detail::throw_logic_error();
115
116 // Expect: 100-continue
117
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10 times.
14 if(is_expect_continue_)
118 {
119
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if(out_.data() == hp_)
120 2 return const_buffers_type(hp_, 1);
121 2 is_expect_continue_ = false;
122 2 BOOST_HTTP_PROTO_RETURN_EC(
123 error::expect_100_continue);
124 }
125
126
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7 times.
10 if(st_ == style::empty)
127 {
128 9 return const_buffers_type(
129 3 out_.data(),
130 3 out_.size());
131 }
132
133
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if(st_ == style::buffers)
134 {
135 9 return const_buffers_type(
136 3 out_.data(),
137 3 out_.size());
138 }
139
140
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if(st_ == style::source)
141 {
142
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if(! is_chunked_)
143 {
144 3 auto rv = src_->read(
145 tmp0_.prepare(
146 3 tmp0_.capacity() -
147
2/4
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
3 tmp0_.size()));
148 3 tmp0_.commit(rv.bytes);
149
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if(rv.ec.failed())
150 return rv.ec;
151 3 more_ = ! rv.finished;
152 }
153 else
154 {
155 1 if((tmp0_.capacity() -
156
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 tmp0_.size()) >
157 chunked_overhead_)
158 {
159
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 auto dest = tmp0_.prepare(18);
160 1 write_chunk_header(dest, 0);
161 1 tmp0_.commit(18);
162 1 auto rv = src_->read(
163 tmp0_.prepare(
164 1 tmp0_.capacity() -
165 2 - // CRLF
166 1 5 - // final chunk
167
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 tmp0_.size()));
168 1 tmp0_.commit(rv.bytes);
169 // VFALCO FIXME!
170 //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 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 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 }
322 17 }
323
324 void
325 4 serializer::
326 start_empty(
327 message_view_base const& m)
328 {
329 4 start_init(m);
330
331 4 st_ = style::empty;
332
333
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if(! is_chunked_)
334 {
335 out_ = make_array(
336 3 1); // header
337 }
338 else
339 {
340 out_ = make_array(
341 1 + // header
342
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 1); // final chunk
343
344 // Buffer is too small
345
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if(ws_.size() < 5)
346 detail::throw_length_error();
347
348 buffers::mutable_buffer dest(
349 1 ws_.data(), 5);
350 1 buffers::buffer_copy(
351 dest,
352 1 buffers::const_buffer(
353 "0\r\n\r\n", 5));
354 1 out_[1] = dest;
355 }
356
357 4 hp_ = &out_[0];
358 4 *hp_ = { m.ph_->cbuf, m.ph_->size };
359 4 }
360
361 void
362 7 serializer::
363 start_buffers(
364 message_view_base const& m)
365 {
366 7 st_ = style::buffers;
367
368
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 if(! is_chunked_)
369 {
370 //if(! cod_)
371 {
372 out_ = make_array(
373 1 + // header
374 6 buf_.size()); // body
375 12 copy(&out_[1],
376 6 buf_.data(), buf_.size());
377 }
378 #if 0
379 else
380 {
381 out_ = make_array(
382 1 + // header
383 2); // tmp1
384 }
385 #endif
386 }
387 else
388 {
389 //if(! cod_)
390 {
391 out_ = make_array(
392 1 + // header
393 1 + // chunk size
394 1 buf_.size() + // body
395
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 1); // final chunk
396 2 copy(&out_[2],
397 1 buf_.data(), buf_.size());
398
399 // Buffer is too small
400
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if(ws_.size() < 18 + 7)
401 detail::throw_length_error();
402 1 buffers::mutable_buffer s1(ws_.data(), 18);
403 1 buffers::mutable_buffer s2(ws_.data(), 18 + 7);
404 1 s2 += 18; // VFALCO HACK
405 1 write_chunk_header(
406 s1,
407 1 buffers::buffer_size(buf_));
408 1 buffers::buffer_copy(s2, buffers::const_buffer(
409 "\r\n"
410 "0\r\n"
411 "\r\n", 7));
412 1 out_[1] = s1;
413 1 out_[out_.size() - 1] = s2;
414 }
415 #if 0
416 else
417 {
418 out_ = make_array(
419 1 + // header
420 2); // tmp1
421 }
422 #endif
423 }
424
425 7 hp_ = &out_[0];
426 7 *hp_ = { m.ph_->cbuf, m.ph_->size };
427 7 }
428
429 void
430 6 serializer::
431 start_source(
432 message_view_base const& m,
433 buffers::source* src)
434 {
435 6 st_ = style::source;
436 6 src_ = src;
437 out_ = make_array(
438 1 + // header
439 6 2); // tmp
440 //if(! cod_)
441 {
442 buffers::buffered_base::allocator a(
443 6 ws_.data(), ws_.size()/2, false);
444
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 src->init(a);
445
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 ws_.reserve_front(a.size_used());
446
447 6 tmp0_ = { ws_.data(), ws_.size() };
448
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if(tmp0_.capacity() <
449 18 + // chunk size
450 1 + // body (1 byte)
451 2 + // CRLF
452 5) // final chunk
453 detail::throw_length_error();
454 }
455 #if 0
456 else
457 {
458 buffers::buffered_base::allocator a(
459 ws_.data(), ws_.size()/3, false);
460 src->init(a);
461 ws_.reserve(a.size_used());
462
463 auto const n = ws_.size() / 2;
464
465 tmp0_ = { ws_.data(), ws_.size() / 2 };
466 ws_.reserve(n);
467
468 // Buffer is too small
469 if(ws_.size() < 1)
470 detail::throw_length_error();
471
472 tmp1_ = { ws_.data(), ws_.size() };
473 }
474 #endif
475
476 6 hp_ = &out_[0];
477 6 *hp_ = { m.ph_->cbuf, m.ph_->size };
478 6 }
479
480 auto
481 serializer::
482 start_stream(
483 message_view_base const& m) ->
484 stream
485 {
486 start_init(m);
487
488 st_ = style::stream;
489 out_ = make_array(
490 1 + // header
491 2); // tmp
492 //if(! cod_)
493 {
494 tmp0_ = { ws_.data(), ws_.size() };
495 if(tmp0_.capacity() <
496 18 + // chunk size
497 1 + // body (1 byte)
498 2 + // CRLF
499 5) // final chunk
500 detail::throw_length_error();
501 }
502 #if 0
503 else
504 {
505 auto const n = ws_.size() / 2;
506 tmp0_ = { ws_.data(), n };
507 ws_.reserve(n);
508
509 // Buffer is too small
510 if(ws_.size() < 1)
511 detail::throw_length_error();
512
513 tmp1_ = { ws_.data(), ws_.size() };
514 }
515 #endif
516
517 hp_ = &out_[0];
518 *hp_ = { m.ph_->cbuf, m.ph_->size };
519
520 more_ = true;
521
522 return stream{*this};
523 }
524
525 //------------------------------------------------
526
527 std::size_t
528 serializer::
529 stream::
530 capacity() const
531 {
532 auto const n =
533 chunked_overhead_ +
534 2 + // CRLF
535 5; // final chunk
536 return sr_->tmp0_.capacity() - n; // VFALCO ?
537 }
538
539 std::size_t
540 serializer::
541 stream::
542 size() const
543 {
544 return sr_->tmp0_.size();
545 }
546
547 auto
548 serializer::
549 stream::
550 prepare(
551 std::size_t n) const ->
552 buffers_type
553 {
554 return sr_->tmp0_.prepare(n);
555 }
556
557 void
558 serializer::
559 stream::
560 commit(std::size_t n) const
561 {
562 sr_->tmp0_.commit(n);
563 }
564
565 void
566 serializer::
567 stream::
568 close() const
569 {
570 // Precondition violation
571 if(! sr_->more_)
572 detail::throw_logic_error();
573 sr_->more_ = false;
574 }
575
576 //------------------------------------------------
577
578 } // http_proto
579 } // boost
580
581 #endif
582