GCC Code Coverage Report


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