GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/parser.cpp
Date: 2024-07-08 21:32:35
Exec Total Coverage
Lines: 445 583 76.3%
Functions: 26 33 78.8%
Branches: 231 407 56.8%

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 #include <boost/http_proto/parser.hpp>
11 #include <boost/http_proto/context.hpp>
12 #include <boost/http_proto/error.hpp>
13 #include <boost/http_proto/service/zlib_service.hpp>
14 #include <boost/http_proto/detail/except.hpp>
15 #include <boost/buffers/buffer_copy.hpp>
16 #include <boost/url/grammar/ci_string.hpp>
17 #include <boost/assert.hpp>
18 #include <memory>
19
20 #include "zlib_service.hpp"
21
22 namespace boost {
23 namespace http_proto {
24
25 /*
26 Principles for fixed-size buffer design
27
28 axiom 1:
29 To read data you must have a buffer.
30
31 axiom 2:
32 The size of the HTTP header is not
33 known in advance.
34
35 conclusion 3:
36 A single I/O can produce a complete
37 HTTP header and additional payload
38 data.
39
40 conclusion 4:
41 A single I/O can produce multiple
42 complete HTTP headers, complete
43 payloads, and a partial header or
44 payload.
45
46 axiom 5:
47 A process is in one of two states:
48 1. at or below capacity
49 2. above capacity
50
51 axiom 6:
52 A program which can allocate an
53 unbounded number of resources can
54 go above capacity.
55
56 conclusion 7:
57 A program can guarantee never going
58 above capacity if all resources are
59 provisioned at program startup.
60
61 corollary 8:
62 `parser` and `serializer` should each
63 allocate a single buffer of calculated
64 size, and never resize it.
65
66 axiom #:
67 A parser and a serializer are always
68 used in pairs.
69
70 Buffer Usage
71
72 | | begin
73 | H | p | | f | read headers
74 | H | p | | T | f | set T body
75 | H | p | | C | T | f | make codec C
76 | H | p | b | C | T | f | decode p into b
77 | H | p | b | C | T | f | read/parse loop
78 | H | | T | f | destroy codec
79 | H | | T | f | finished
80
81 H headers
82 C codec
83 T body
84 f table
85 p partial payload
86 b body data
87
88 "payload" is the bytes coming in from
89 the stream.
90
91 "body" is the logical body, after transfer
92 encoding is removed. This can be the
93 same as the payload.
94
95 A "plain payload" is when the payload and
96 body are identical (no transfer encodings).
97
98 A "buffered payload" is any payload which is
99 not plain. A second buffer is required
100 for reading.
101
102 "overread" is additional data received past
103 the end of the headers when reading headers,
104 or additional data received past the end of
105 the message payload.
106 */
107 //-----------------------------------------------
108
109 class parser_service
110 : public service
111 {
112 public:
113 parser::config_base cfg;
114 std::size_t space_needed = 0;
115 std::size_t max_codec = 0;
116 zlib::detail::deflate_decoder_service const*
117 deflate_svc = nullptr;
118
119 parser_service(
120 context& ctx,
121 parser::config_base const& cfg_);
122
123 std::size_t
124 8934 max_overread() const noexcept
125 {
126 return
127 8934 cfg.headers.max_size +
128 8934 cfg.min_buffer;
129 }
130 };
131
132 32 parser_service::
133 parser_service(
134 context& ctx,
135 32 parser::config_base const& cfg_)
136 32 : cfg(cfg_)
137 {
138 /*
139 | fb | cb0 | cb1 | C | T | f |
140
141 fb flat_buffer headers.max_size
142 cb0 circular_buffer min_buffer
143 cb1 circular_buffer min_buffer
144 C codec max_codec
145 T body max_type_erase
146 f table max_table_space
147
148 */
149 // validate
150 //if(cfg.min_prepare > cfg.max_prepare)
151 //detail::throw_invalid_argument();
152
153
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 if( cfg.min_buffer < 1 ||
154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 cfg.min_buffer > cfg.body_limit)
155 detail::throw_invalid_argument();
156
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if(cfg.max_prepare < 1)
158 detail::throw_invalid_argument();
159
160 // VFALCO TODO OVERFLOW CHECING
161 {
162 //fb_.size() - h_.size +
163 //svc_.cfg.min_buffer +
164 //svc_.cfg.min_buffer +
165 //svc_.max_codec;
166 }
167
168 // VFALCO OVERFLOW CHECKING ON THIS
169 32 space_needed +=
170
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 cfg.headers.valid_space_needed();
171
172 // cb0_, cb1_
173 // VFALCO OVERFLOW CHECKING ON THIS
174 32 space_needed +=
175 32 cfg.min_buffer +
176 cfg.min_buffer;
177
178 // T
179 32 space_needed += cfg.max_type_erase;
180
181 // max_codec
182 {
183
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 31 times.
32 if(cfg.apply_deflate_decoder)
184 {
185 1 deflate_svc = &ctx.get_service<
186
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 zlib::detail::deflate_decoder_service>();
187 auto const n =
188 1 deflate_svc->space_needed();
189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if( max_codec < n)
190 max_codec = n;
191 }
192 }
193 32 space_needed += max_codec;
194
195 // round up to alignof(detail::header::entry)
196 32 auto const al = alignof(
197 detail::header::entry);
198 32 space_needed = al * ((
199 32 space_needed + al - 1) / al);
200 32 }
201
202 void
203 32 install_parser_service(
204 context& ctx,
205 parser::config_base const& cfg)
206 {
207 ctx.make_service<
208 32 parser_service>(cfg);
209 32 }
210
211 //------------------------------------------------
212 //
213 // Special Members
214 //
215 //------------------------------------------------
216
217 1044 parser::
218 parser(
219 context& ctx,
220 1044 detail::kind k)
221 1044 : ctx_(ctx)
222 1044 , svc_(ctx.get_service<
223 1044 parser_service>())
224 1044 , h_(detail::empty{k})
225 1044 , eb_(nullptr)
226 2088 , st_(state::reset)
227 {
228 1044 auto const n =
229 1044 svc_.space_needed;
230
1/2
✓ Branch 1 taken 1044 times.
✗ Branch 2 not taken.
1044 ws_.allocate(n);
231 1044 h_.cap = n;
232 1044 }
233
234 //------------------------------------------------
235
236 1044 parser::
237 ~parser()
238 {
239 1044 }
240
241 //------------------------------------------------
242 //
243 // Modifiers
244 //
245 //------------------------------------------------
246
247 // prepare for a new stream
248 void
249 1511 parser::
250 reset() noexcept
251 {
252 1511 ws_.clear();
253 1511 eb_ = nullptr;
254 1511 st_ = state::start;
255 1511 got_eof_ = false;
256 1511 }
257
258 void
259 1741 parser::
260 start_impl(
261 bool head_response)
262 {
263 1741 std::size_t leftover = 0;
264
5/5
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1496 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 240 times.
1741 switch(st_)
265 {
266 1 default:
267 case state::reset:
268 // reset must be called first
269 1 detail::throw_logic_error();
270
271 1496 case state::start:
272 // reset required on eof
273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1496 times.
1496 if(got_eof_)
274 detail::throw_logic_error();
275 1496 break;
276
277 3 case state::header:
278
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
3 if(fb_.size() == 0)
279 {
280 // start() called twice
281 2 detail::throw_logic_error();
282 }
283 BOOST_FALLTHROUGH;
284
285 case state::body:
286 case state::set_body:
287 // current message is incomplete
288 2 detail::throw_logic_error();
289
290 240 case state::complete:
291 {
292 // remove partial body.
293
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 if(body_buf_ == &cb0_)
294 240 cb0_.consume(static_cast<std::size_t>(body_avail_));
295
296
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 240 times.
240 if(cb0_.size() > 0)
297 {
298 // headers with no body
299 BOOST_ASSERT(h_.size > 0);
300 fb_.consume(h_.size);
301 leftover = fb_.size();
302 // move unused octets to front
303 buffers::buffer_copy(
304 buffers::mutable_buffer(
305 ws_.data(),
306 leftover),
307 fb_.data());
308 }
309 else
310 {
311 // leftover data after body
312 }
313 240 break;
314 }
315 }
316
317 1736 ws_.clear();
318
319 3472 fb_ = {
320 1736 ws_.data(),
321 1736 svc_.cfg.headers.max_size +
322 1736 svc_.cfg.min_buffer,
323 leftover };
324
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1736 times.
1736 BOOST_ASSERT(fb_.capacity() ==
325 svc_.max_overread());
326
327 3472 h_ = detail::header(
328 1736 detail::empty{h_.kind});
329 1736 h_.buf = reinterpret_cast<
330 1736 char*>(ws_.data());
331 1736 h_.cbuf = h_.buf;
332 1736 h_.cap = ws_.size();
333
334
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1736 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1736 BOOST_ASSERT(! head_response ||
335 h_.kind == detail::kind::response);
336 1736 head_response_ = head_response;
337
338 // begin with in_place mode
339 1736 how_ = how::in_place;
340 1736 st_ = state::header;
341 1736 nprepare_ = 0;
342 1736 }
343
344 auto
345 5549 parser::
346 prepare() ->
347 mutable_buffers_type
348 {
349 5549 nprepare_ = 0;
350
351
6/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5486 times.
✓ Branch 3 taken 31 times.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 3 times.
5549 switch(st_)
352 {
353 1 default:
354 case state::reset:
355 // reset must be called first
356 1 detail::throw_logic_error();
357
358 1 case state::start:
359 // start must be called first
360 1 detail::throw_logic_error();
361
362 5486 case state::header:
363 {
364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5486 times.
5486 BOOST_ASSERT(h_.size <
365 svc_.cfg.headers.max_size);
366 5486 auto n = fb_.capacity() - fb_.size();
367
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5486 times.
5486 BOOST_ASSERT(n <= svc_.max_overread());
368
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 5457 times.
5486 if( n > svc_.cfg.max_prepare)
369 29 n = svc_.cfg.max_prepare;
370 5486 mbp_[0] = fb_.prepare(n);
371 5486 nprepare_ = n;
372 5486 return mutable_buffers_type(
373 10972 &mbp_[0], 1);
374 }
375
376 31 case state::body:
377 {
378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
31 if(got_eof_)
379 return mutable_buffers_type{};
380
381 31 do_body:
382
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
55 if(! is_plain())
383 {
384 // buffered payload
385 auto n = cb0_.capacity() -
386 cb0_.size();
387 if( n > svc_.cfg.max_prepare)
388 n = svc_.cfg.max_prepare;
389 mbp_ = cb0_.prepare(n);
390 nprepare_ = n;
391 return mutable_buffers_type(mbp_);
392 }
393
394 // plain payload
395
396
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 26 times.
55 if(how_ == how::in_place)
397 {
398 auto n =
399 29 body_buf_->capacity() -
400 29 body_buf_->size();
401
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 28 times.
29 if( n > svc_.cfg.max_prepare)
402 1 n = svc_.cfg.max_prepare;
403 29 mbp_ = body_buf_->prepare(n);
404 29 nprepare_ = n;
405 29 return mutable_buffers_type(mbp_);
406 }
407
408
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 if(how_ == how::elastic)
409 {
410 // Overreads are not allowed, or
411 // else the caller will see extra
412 // unrelated data.
413
414
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 17 times.
26 if(h_.md.payload == payload::size)
415 {
416 // set_body moves avail to dyn
417
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 BOOST_ASSERT(body_buf_->size() == 0);
418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 BOOST_ASSERT(body_avail_ == 0);
419 9 auto n = static_cast<std::size_t>(payload_remain_);
420
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if( n > svc_.cfg.max_prepare)
421 1 n = svc_.cfg.max_prepare;
422 9 nprepare_ = n;
423 9 return eb_->prepare(n);
424 }
425
426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 BOOST_ASSERT(
427 h_.md.payload == payload::to_eof);
428 17 std::size_t n = 0;
429
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if(! got_eof_)
430 {
431 // calculate n heuristically
432 17 n = svc_.cfg.min_buffer;
433
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if( n > svc_.cfg.max_prepare)
434 1 n = svc_.cfg.max_prepare;
435 {
436 // apply max_size()
437 auto avail =
438 17 eb_->max_size() -
439 17 eb_->size();
440
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 9 times.
17 if( n > avail)
441 8 n = avail;
442 }
443 // fill capacity() first,
444 // to avoid an allocation
445 {
446 auto avail =
447 17 eb_->capacity() -
448 17 eb_->size();
449
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
17 if( n > avail &&
450 avail != 0)
451 1 n = avail;
452 }
453
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 15 times.
17 if(n == 0)
454 {
455 // dynamic buffer is full
456 // attempt a 1 byte read so
457 // we can detect overflow
458
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 BOOST_ASSERT(
459 body_buf_->size() == 0);
460 // handled in init_dynamic
461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 BOOST_ASSERT(
462 body_avail_ == 0);
463 2 mbp_ = body_buf_->prepare(1);
464 2 nprepare_ = 1;
465 return
466 2 mutable_buffers_type(mbp_);
467 }
468 }
469 15 nprepare_ = n;
470 15 return eb_->prepare(n);
471 }
472
473 // VFALCO TODO
474 if(how_ == how::pull)
475 detail::throw_logic_error();
476
477 // VFALCO TODO
478 detail::throw_logic_error();
479 }
480
481 27 case state::set_body:
482 {
483
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 BOOST_ASSERT(is_plain());
484
485
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 if(how_ == how::elastic)
486 {
487 // attempt to transfer in-place
488 // body into the dynamic buffer.
489 27 system::error_code ec;
490
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 init_dynamic(ec);
491
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 1 times.
27 if(! ec.failed())
492 {
493
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
26 if(st_ == state::body)
494 24 goto do_body;
495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 BOOST_ASSERT(
496 st_ == state::complete);
497 2 return mutable_buffers_type{};
498 }
499
500 // not enough room, so we
501 // return this error from parse()
502 return
503 1 mutable_buffers_type{};
504 }
505
506 if(how_ == how::sink)
507 {
508 // this is a no-op, to get the
509 // caller to call parse next.
510 return mutable_buffers_type{};
511 }
512
513 // VFALCO TODO
514 detail::throw_logic_error();
515 }
516
517 3 case state::complete:
518 // intended no-op
519 3 return mutable_buffers_type{};
520 }
521 }
522
523 void
524 5540 parser::
525 commit(
526 std::size_t n)
527 {
528
6/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5486 times.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
5540 switch(st_)
529 {
530 1 default:
531 case state::reset:
532 {
533 // reset must be called first
534 1 detail::throw_logic_error();
535 }
536
537 1 case state::start:
538 {
539 // forgot to call start()
540 1 detail::throw_logic_error();
541 }
542
543 5486 case state::header:
544 {
545
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5485 times.
5486 if(n > nprepare_)
546 {
547 // n can't be greater than size of
548 // the buffers returned by prepare()
549 1 detail::throw_invalid_argument();
550 }
551
552
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5484 times.
5485 if(got_eof_)
553 {
554 // can't commit after EOF
555 1 detail::throw_logic_error();
556 }
557
558 5484 nprepare_ = 0; // invalidate
559 5484 fb_.commit(n);
560 5484 break;
561 }
562
563 46 case state::body:
564 {
565
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 45 times.
46 if(n > nprepare_)
566 {
567 // n can't be greater than size of
568 // the buffers returned by prepare()
569 1 detail::throw_invalid_argument();
570 }
571
572
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
45 BOOST_ASSERT(! got_eof_ || n == 0);
573
574
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
45 if(! is_plain())
575 {
576 // buffered payload
577 cb0_.commit(n);
578 break;
579 }
580
581 // plain payload
582
583
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 19 times.
45 if(how_ == how::in_place)
584 {
585
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 BOOST_ASSERT(body_buf_ == &cb0_);
586 26 cb0_.commit(n);
587
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 14 times.
26 if(h_.md.payload == payload::size)
588 {
589 12 if(cb0_.size() <
590
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 h_.md.payload_size)
591 {
592 4 body_avail_ += n;
593 4 payload_remain_ -= n;
594 4 break;
595 }
596 8 body_avail_ = h_.md.payload_size;
597 8 payload_remain_ = 0;
598 8 st_ = state::complete;
599 8 break;
600 }
601
602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 BOOST_ASSERT(
603 h_.md.payload == payload::to_eof);
604 14 body_avail_ += n;
605 14 break;
606 }
607
608
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 if(how_ == how::elastic)
609 {
610
2/2
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 1 times.
19 if(eb_->size() < eb_->max_size())
611 {
612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 BOOST_ASSERT(body_avail_ == 0);
613
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
18 BOOST_ASSERT(
614 body_buf_->size() == 0);
615 18 eb_->commit(n);
616 }
617 else
618 {
619 // If we get here then either
620 // n==0 as a no-op, or n==1 for
621 // an intended one byte read.
622
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 BOOST_ASSERT(n <= 1);
623 1 body_buf_->commit(n);
624 1 body_avail_ += n;
625 }
626 19 body_total_ += n;
627
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 13 times.
19 if(h_.md.payload == payload::size)
628 {
629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 BOOST_ASSERT(
630 n <= payload_remain_);
631 6 payload_remain_ -= n;
632
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if(payload_remain_ == 0)
633 6 st_ = state::complete;
634 }
635 19 break;
636 }
637
638 if(how_ == how::sink)
639 {
640 cb0_.commit(n);
641 break;
642 }
643
644 if(how_ == how::pull)
645 {
646 // VFALCO TODO
647 detail::throw_logic_error();
648 }
649 break;
650 }
651
652 2 case state::set_body:
653 {
654
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if(n > nprepare_)
655 {
656 // n can't be greater than size of
657 // the buffers returned by prepare()
658 1 detail::throw_invalid_argument();
659 }
660
661
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 BOOST_ASSERT(is_plain());
662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 BOOST_ASSERT(n == 0);
663
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if( how_ == how::elastic ||
664 how_ == how::sink)
665 {
666 // intended no-op
667 break;
668 }
669
670 // VFALCO TODO
671 detail::throw_logic_error();
672 }
673
674 4 case state::complete:
675 {
676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 BOOST_ASSERT(nprepare_ == 0);
677
678
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if(n > 0)
679 {
680 // n can't be greater than size of
681 // the buffers returned by prepare()
682 1 detail::throw_invalid_argument();
683 }
684
685 // intended no-op
686 3 break;
687 }
688 }
689 5533 }
690
691 void
692 363 parser::
693 commit_eof()
694 {
695 363 nprepare_ = 0; // invalidate
696
697
6/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 127 times.
✓ Branch 4 taken 212 times.
✓ Branch 5 taken 1 times.
363 switch(st_)
698 {
699 1 default:
700 case state::reset:
701 // reset must be called first
702 1 detail::throw_logic_error();
703
704 1 case state::start:
705 // forgot to call prepare()
706 1 detail::throw_logic_error();
707
708 21 case state::header:
709 21 got_eof_ = true;
710 21 break;
711
712 127 case state::body:
713 127 got_eof_ = true;
714 127 break;
715
716 212 case state::set_body:
717 212 got_eof_ = true;
718 212 break;
719
720 1 case state::complete:
721 // can't commit eof when complete
722 1 detail::throw_logic_error();
723 }
724 360 }
725
726 //-----------------------------------------------
727
728 // process input data then
729 // eof if input data runs out.
730 void
731 6462 parser::
732 parse(
733 system::error_code& ec)
734 {
735 6462 ec = {};
736
6/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5500 times.
✓ Branch 3 taken 157 times.
✓ Branch 4 taken 211 times.
✓ Branch 5 taken 592 times.
6462 switch(st_)
737 {
738 1 default:
739 case state::reset:
740 // reset must be called first
741 1 detail::throw_logic_error();
742
743 1 case state::start:
744 // start must be called first
745 1 detail::throw_logic_error();
746
747 5500 case state::header:
748 {
749
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5500 times.
5500 BOOST_ASSERT(h_.buf == static_cast<
750 void const*>(ws_.data()));
751
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5500 times.
5500 BOOST_ASSERT(h_.cbuf == static_cast<
752 void const*>(ws_.data()));
753 5500 auto const new_size = fb_.size();
754 5500 h_.parse(new_size, svc_.cfg.headers, ec);
755
2/2
✓ Branch 2 taken 3792 times.
✓ Branch 3 taken 1708 times.
5500 if(ec == condition::need_more_input)
756 {
757
2/2
✓ Branch 0 taken 3774 times.
✓ Branch 1 taken 18 times.
3792 if(! got_eof_)
758 {
759 // headers incomplete
760 3774 return;
761 }
762
763
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 10 times.
18 if(fb_.size() == 0)
764 {
765 // stream closed cleanly
766 8 st_ = state::complete;
767 16 ec = BOOST_HTTP_PROTO_ERR(
768 error::end_of_stream);
769 8 return;
770 }
771
772 // stream closed with a
773 // partial message received
774 10 st_ = state::reset;
775 20 ec = BOOST_HTTP_PROTO_ERR(
776 error::incomplete);
777 10 return;
778 }
779
2/2
✓ Branch 1 taken 259 times.
✓ Branch 2 taken 1449 times.
1708 if(ec.failed())
780 {
781 // other error,
782 //
783 // VFALCO map this to a bad
784 // request or bad response error?
785 //
786 259 st_ = state::reset; // unrecoverable
787 259 return;
788 }
789
790 // headers are complete
791 1449 on_headers(ec);
792
2/2
✓ Branch 1 taken 120 times.
✓ Branch 2 taken 1329 times.
1449 if(ec.failed())
793 120 return;
794
2/2
✓ Branch 0 taken 844 times.
✓ Branch 1 taken 485 times.
1329 if(st_ == state::complete)
795 844 break;
796 BOOST_FALLTHROUGH;
797 }
798
799 case state::body:
800 {
801 485 do_body:
802
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 744 times.
744 BOOST_ASSERT(st_ == state::body);
803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 744 times.
744 BOOST_ASSERT(
804 h_.md.payload != payload::none);
805
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 744 times.
744 BOOST_ASSERT(
806 h_.md.payload != payload::error);
807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 744 times.
744 if(h_.md.payload == payload::chunked)
808 {
809 // VFALCO parse chunked
810 detail::throw_logic_error();
811 }
812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 744 times.
744 else if(filt_)
813 {
814 // VFALCO TODO apply filter
815 detail::throw_logic_error();
816 }
817
818
2/2
✓ Branch 0 taken 618 times.
✓ Branch 1 taken 126 times.
744 if(how_ == how::in_place)
819 {
820
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 618 times.
618 BOOST_ASSERT(body_avail_ ==
821 body_buf_->size());
822
2/2
✓ Branch 0 taken 255 times.
✓ Branch 1 taken 363 times.
618 if(h_.md.payload == payload::size)
823 {
824 255 if(body_avail_ <
825
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 225 times.
255 h_.md.payload_size)
826 {
827
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 29 times.
30 if(got_eof_)
828 {
829 // incomplete
830 2 ec = BOOST_HTTP_PROTO_ERR(
831 error::incomplete);
832 1 return;
833 }
834
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 28 times.
29 if(body_buf_->capacity() == 0)
835 {
836 // in_place buffer limit
837 2 ec = BOOST_HTTP_PROTO_ERR(
838 error::in_place_overflow);
839 1 return;
840 }
841 56 ec = BOOST_HTTP_PROTO_ERR(
842 error::need_data);
843 28 return;
844 }
845
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 225 times.
225 BOOST_ASSERT(body_avail_ ==
846 h_.md.payload_size);
847 225 st_ = state::complete;
848 225 break;
849 }
850
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 362 times.
363 if(body_avail_ > svc_.cfg.body_limit)
851 {
852 2 ec = BOOST_HTTP_PROTO_ERR(
853 error::body_too_large);
854 1 st_ = state::reset; // unrecoverable
855 1 return;
856 }
857
1/2
✓ Branch 0 taken 362 times.
✗ Branch 1 not taken.
362 if( h_.md.payload == payload::chunked ||
858
2/2
✓ Branch 0 taken 248 times.
✓ Branch 1 taken 114 times.
362 ! got_eof_)
859 {
860 496 ec = BOOST_HTTP_PROTO_ERR(
861 error::need_data);
862 248 return;
863 }
864
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 BOOST_ASSERT(got_eof_);
865 114 st_ = state::complete;
866 114 break;
867 }
868
869
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 if(how_ == how::elastic)
870 {
871 // state already updated in commit
872
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if(h_.md.payload == payload::size)
873 {
874 BOOST_ASSERT(body_total_ <
875 h_.md.payload_size);
876 BOOST_ASSERT(payload_remain_ > 0);
877 if(body_avail_ != 0)
878 {
879 BOOST_ASSERT(
880 eb_->max_size() -
881 eb_->size() <
882 payload_remain_);
883 ec = BOOST_HTTP_PROTO_ERR(
884 error::buffer_overflow);
885 st_ = state::reset; // unrecoverable
886 return;
887 }
888 if(got_eof_)
889 {
890 ec = BOOST_HTTP_PROTO_ERR(
891 error::incomplete);
892 st_ = state::reset; // unrecoverable
893 return;
894 }
895 return;
896 }
897
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 BOOST_ASSERT(
898 h_.md.payload == payload::to_eof);
899
3/4
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 80 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 126 times.
172 if( eb_->size() == eb_->max_size() &&
900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 body_avail_ > 0)
901 {
902 // got here from the 1-byte read
903 ec = BOOST_HTTP_PROTO_ERR(
904 error::buffer_overflow);
905 st_ = state::reset; // unrecoverable
906 return;
907 }
908
2/2
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 13 times.
126 if(got_eof_)
909 {
910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
113 BOOST_ASSERT(body_avail_ == 0);
911 113 st_ = state::complete;
912 113 break;
913 }
914
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 BOOST_ASSERT(body_avail_ == 0);
915 13 break;
916 }
917
918 // VFALCO TODO
919 detail::throw_logic_error();
920 }
921
922 211 case state::set_body:
923 {
924
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 211 times.
211 BOOST_ASSERT(is_plain());
925
926 // transfer in_place data into set body
927
928
1/2
✓ Branch 0 taken 211 times.
✗ Branch 1 not taken.
211 if(how_ == how::elastic)
929 {
930 211 init_dynamic(ec);
931
1/2
✓ Branch 1 taken 211 times.
✗ Branch 2 not taken.
211 if(! ec.failed())
932 {
933
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 109 times.
211 if(st_ == state::body)
934 102 goto do_body;
935
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
109 BOOST_ASSERT(
936 st_ == state::complete);
937 109 break;
938 }
939 st_ = state::reset; // unrecoverable
940 return;
941 }
942
943 if(how_ == how::sink)
944 {
945 auto n = body_buf_->size();
946 if(h_.md.payload == payload::size)
947 {
948 // sink_->size_hint(h_.md.payload_size, ec);
949
950 if(n < h_.md.payload_size)
951 {
952 auto rv = sink_->write(
953 body_buf_->data(), false);
954 BOOST_ASSERT(rv.ec.failed() ||
955 rv.bytes == body_buf_->size());
956 BOOST_ASSERT(
957 rv.bytes >= body_avail_);
958 BOOST_ASSERT(
959 rv.bytes < payload_remain_);
960 body_buf_->consume(rv.bytes);
961 body_avail_ -= rv.bytes;
962 body_total_ += rv.bytes;
963 payload_remain_ -= rv.bytes;
964 if(rv.ec.failed())
965 {
966 ec = rv.ec;
967 st_ = state::reset; // unrecoverable
968 return;
969 }
970 st_ = state::body;
971 goto do_body;
972 }
973
974 n = static_cast<std::size_t>(h_.md.payload_size);
975 }
976 // complete
977 BOOST_ASSERT(body_buf_ == &cb0_);
978 auto rv = sink_->write(
979 body_buf_->data(), true);
980 BOOST_ASSERT(rv.ec.failed() ||
981 rv.bytes == body_buf_->size());
982 body_buf_->consume(rv.bytes);
983 if(rv.ec.failed())
984 {
985 ec = rv.ec;
986 st_ = state::reset; // unrecoverable
987 return;
988 }
989 st_ = state::complete;
990 return;
991 }
992
993 // VFALCO TODO
994 detail::throw_logic_error();
995 }
996
997 592 case state::complete:
998 {
999 // This is a no-op except when set_body
1000 // was called and we have in-place data.
1001
2/4
✓ Branch 0 taken 296 times.
✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
592 switch(how_)
1002 {
1003 296 default:
1004 case how::in_place:
1005 296 break;
1006
1007 296 case how::elastic:
1008 {
1009
1/2
✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
296 if(body_buf_->size() == 0)
1010 296 break;
1011 BOOST_ASSERT(eb_->size() == 0);
1012 auto n = buffers::buffer_copy(
1013 eb_->prepare(
1014 body_buf_->size()),
1015 body_buf_->data());
1016 body_buf_->consume(n);
1017 break;
1018 }
1019
1020 case how::sink:
1021 {
1022 if(body_buf_->size() == 0)
1023 break;
1024 auto rv = sink_->write(
1025 body_buf_->data(), false);
1026 body_buf_->consume(rv.bytes);
1027 if(rv.ec.failed())
1028 {
1029 ec = rv.ec;
1030 st_ = state::reset; // unrecoverable
1031 return;
1032 }
1033 break;
1034 }
1035
1036 case how::pull:
1037 // VFALCO TODO
1038 detail::throw_logic_error();
1039 }
1040 }
1041 }
1042 }
1043
1044 //------------------------------------------------
1045
1046 auto
1047 parser::
1048 pull_some() ->
1049 const_buffers_type
1050 {
1051 return {};
1052 }
1053
1054 core::string_view
1055 1271 parser::
1056 body() const noexcept
1057 {
1058
2/2
✓ Branch 0 taken 349 times.
✓ Branch 1 taken 922 times.
1271 switch(st_)
1059 {
1060 349 default:
1061 case state::reset:
1062 case state::start:
1063 case state::header:
1064 case state::body:
1065 case state::set_body:
1066 // not complete
1067 349 return {};
1068
1069 922 case state::complete:
1070
2/2
✓ Branch 0 taken 346 times.
✓ Branch 1 taken 576 times.
922 if(how_ != how::in_place)
1071 {
1072 // not in_place
1073 346 return {};
1074 }
1075 576 auto cbp = body_buf_->data();
1076
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 576 times.
576 BOOST_ASSERT(cbp[1].size() == 0);
1077
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 576 times.
576 BOOST_ASSERT(cbp[0].size() >= body_avail_);
1078 576 return core::string_view(
1079 static_cast<char const*>(
1080 576 cbp[0].data()),
1081 1152 static_cast<std::size_t>(body_avail_));
1082 }
1083 }
1084
1085 core::string_view
1086 parser::
1087 release_buffered_data() noexcept
1088 {
1089 return {};
1090 }
1091
1092 //------------------------------------------------
1093 //
1094 // Implementation
1095 //
1096 //------------------------------------------------
1097
1098 auto
1099 314 parser::
1100 safe_get_header() const ->
1101 detail::header const*
1102 {
1103 // headers must be received
1104
3/6
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 314 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 314 times.
628 if( ! got_header() ||
1105 314 fb_.size() == 0) // happens on eof
1106 detail::throw_logic_error();
1107
1108 314 return &h_;
1109 }
1110
1111 bool
1112 824 parser::
1113 is_plain() const noexcept
1114 {
1115
1/2
✓ Branch 0 taken 824 times.
✗ Branch 1 not taken.
1648 return ! filt_ &&
1116
1/2
✓ Branch 0 taken 824 times.
✗ Branch 1 not taken.
824 h_.md.payload !=
1117 824 payload::chunked;
1118 }
1119
1120 // Called immediately after complete headers
1121 // are received. We leave fb_ as-is to indicate
1122 // whether any data was received before eof.
1123 //
1124 void
1125 1449 parser::
1126 on_headers(
1127 system::error_code& ec)
1128 {
1129 1449 auto const overread = fb_.size() - h_.size;
1130
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1449 times.
1449 BOOST_ASSERT(
1131 overread <= svc_.max_overread());
1132
1133 // metadata error
1134
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 1329 times.
1449 if(h_.md.payload == payload::error)
1135 {
1136 // VFALCO This needs looking at
1137 240 ec = BOOST_HTTP_PROTO_ERR(
1138 error::bad_payload);
1139 120 st_ = state::reset; // unrecoverable
1140 120 return;
1141 }
1142
1143 // reserve headers + table
1144 1329 ws_.reserve_front(h_.size);
1145 1329 ws_.reserve_back(h_.table_space());
1146
1147 // no payload
1148
2/2
✓ Branch 0 taken 485 times.
✓ Branch 1 taken 844 times.
1329 if( h_.md.payload == payload::none ||
1149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 485 times.
485 head_response_)
1150 {
1151 // set cb0_ to overread
1152 1688 cb0_ = {
1153 844 ws_.data(),
1154 844 fb_.capacity() - h_.size,
1155 overread };
1156 844 body_avail_ = 0;
1157 844 body_total_ = 0;
1158 844 body_buf_ = &cb0_;
1159 844 st_ = state::complete;
1160 844 return;
1161 }
1162
1163 // calculate filter
1164 485 filt_ = nullptr; // VFALCO TODO
1165
1166
1/2
✓ Branch 1 taken 485 times.
✗ Branch 2 not taken.
485 if(is_plain())
1167 {
1168 // plain payload
1169
1170
2/2
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 235 times.
485 if(h_.md.payload == payload::size)
1171 {
1172 250 if(h_.md.payload_size >
1173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 250 times.
250 svc_.cfg.body_limit)
1174 {
1175 ec = BOOST_HTTP_PROTO_ERR(
1176 error::body_too_large);
1177 st_ = state::reset; // unrecoverable
1178 return;
1179 }
1180 auto n0 =
1181 250 fb_.capacity() - h_.size +
1182 250 svc_.cfg.min_buffer +
1183 250 svc_.max_codec;
1184 // limit the capacity of cb0_ so
1185 // that going over max_overread
1186 // is impossible.
1187
6/6
✓ Branch 0 taken 249 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 235 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 236 times.
499 if( n0 > h_.md.payload_size &&
1188 249 n0 - h_.md.payload_size >=
1189 249 svc_.max_overread())
1190 14 n0 = static_cast<std::size_t>(h_.md.payload_size) +
1191 14 svc_.max_overread();
1192
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 250 times.
250 BOOST_ASSERT(n0 <= ws_.size());
1193 250 cb0_ = { ws_.data(), n0, overread };
1194 250 body_buf_ = &cb0_;
1195 250 body_avail_ = cb0_.size();
1196
2/2
✓ Branch 0 taken 225 times.
✓ Branch 1 taken 25 times.
250 if( body_avail_ >= h_.md.payload_size)
1197 225 body_avail_ = h_.md.payload_size;
1198 250 body_total_ = body_avail_;
1199 250 payload_remain_ =
1200 250 h_.md.payload_size - body_total_;
1201 250 st_ = state::body;
1202 250 return;
1203 }
1204
1205 // overread is not applicable
1206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
235 BOOST_ASSERT(
1207 h_.md.payload == payload::to_eof);
1208 auto const n0 =
1209 235 fb_.capacity() - h_.size +
1210 235 svc_.cfg.min_buffer +
1211 235 svc_.max_codec;
1212
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 235 times.
235 BOOST_ASSERT(n0 <= ws_.size());
1213 235 cb0_ = { ws_.data(), n0, overread };
1214 235 body_buf_ = &cb0_;
1215 235 body_avail_ = cb0_.size();
1216 235 body_total_ = body_avail_;
1217 235 st_ = state::body;
1218 235 return;
1219 }
1220
1221 // buffered payload
1222 auto const n0 = fb_.capacity() - h_.size;
1223 BOOST_ASSERT(n0 <= svc_.max_overread());
1224 auto n1 = svc_.cfg.min_buffer;
1225 if(! filt_)
1226 n1 += svc_.max_codec;
1227 BOOST_ASSERT(n0 + n1 <= ws_.size());
1228 cb0_ = { ws_.data(), n0, overread };
1229 cb1_ = { ws_.data() + n0, n1 };
1230 body_buf_ = &cb1_;
1231 body_avail_ = 0;
1232 body_total_ = 0;
1233 st_ = state::body;
1234 }
1235
1236 // Called at the end of set_body
1237 void
1238 299 parser::
1239 on_set_body()
1240 {
1241 // This function is called after all
1242 // limit checking and calculation of
1243 // chunked or filter.
1244
1245
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 299 times.
299 BOOST_ASSERT(got_header());
1246
1247 299 nprepare_ = 0; // invalidate
1248
1249
1/2
✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
299 if(how_ == how::elastic)
1250 {
1251
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 241 times.
299 if(h_.md.payload == payload::none)
1252 {
1253
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 BOOST_ASSERT(st_ == state::complete);
1254 58 return;
1255 }
1256
1257 241 st_ = state::set_body;
1258 241 return;
1259 }
1260
1261 if(how_ == how::sink)
1262 {
1263 if(h_.md.payload == payload::none)
1264 {
1265 BOOST_ASSERT(st_ == state::complete);
1266 // force a trip through parse so
1267 // we can calculate any error.
1268 st_ = state::set_body;
1269 return;
1270 }
1271
1272 st_ = state::set_body;
1273 return;
1274 }
1275
1276 // VFALCO TODO
1277 detail::throw_logic_error();
1278 }
1279
1280 void
1281 238 parser::
1282 init_dynamic(
1283 system::error_code& ec)
1284 {
1285 // attempt to transfer in-place
1286 // body into the dynamic buffer.
1287
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 238 times.
238 BOOST_ASSERT(
1288 body_avail_ == body_buf_->size());
1289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 238 times.
238 BOOST_ASSERT(
1290 body_total_ == body_avail_);
1291 auto const space_left =
1292 238 eb_->max_size() - eb_->size();
1293
1294
2/2
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 117 times.
238 if(h_.md.payload == payload::size)
1295 {
1296
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 120 times.
121 if(space_left < h_.md.payload_size)
1297 {
1298 2 ec = BOOST_HTTP_PROTO_ERR(
1299 error::buffer_overflow);
1300 1 return;
1301 }
1302 // reserve the full size
1303 120 eb_->prepare(static_cast<std::size_t>(h_.md.payload_size));
1304 // transfer in-place body
1305 120 auto n = static_cast<std::size_t>(body_avail_);
1306
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if( n > h_.md.payload_size)
1307 n = static_cast<std::size_t>(h_.md.payload_size);
1308
1/2
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
120 eb_->commit(
1309 buffers::buffer_copy(
1310
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
120 eb_->prepare(n),
1311 120 body_buf_->data()));
1312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 BOOST_ASSERT(body_avail_ == n);
1313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 BOOST_ASSERT(body_total_ == n);
1314
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 BOOST_ASSERT(payload_remain_ ==
1315 h_.md.payload_size - n);
1316 120 body_buf_->consume(n);
1317 120 body_avail_ = 0;
1318
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 111 times.
120 if(n < h_.md.payload_size)
1319 {
1320
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 BOOST_ASSERT(
1321 body_buf_->size() == 0);
1322 9 st_ = state::body;
1323 9 return;
1324 }
1325 // complete
1326 111 st_ = state::complete;
1327 111 return;
1328 }
1329
1330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 BOOST_ASSERT(h_.md.payload ==
1331 payload::to_eof);
1332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if(space_left < body_avail_)
1333 {
1334 ec = BOOST_HTTP_PROTO_ERR(
1335 error::buffer_overflow);
1336 return;
1337 }
1338
1/2
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
117 eb_->commit(
1339 buffers::buffer_copy(
1340
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 eb_->prepare(static_cast<std::size_t>(body_avail_)),
1341 117 body_buf_->data()));
1342 117 body_buf_->consume(static_cast<std::size_t>(body_avail_));
1343 117 body_avail_ = 0;
1344
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
117 BOOST_ASSERT(
1345 body_buf_->size() == 0);
1346 117 st_ = state::body;
1347 }
1348
1349 } // http_proto
1350 } // boost
1351