GCC Code Coverage Report


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