Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2024 Mohammad Nejati
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/http_proto
9 : //
10 :
11 : #include <boost/http_proto/context.hpp>
12 : #include <boost/http_proto/detail/except.hpp>
13 : #include <boost/http_proto/error.hpp>
14 : #include <boost/http_proto/parser.hpp>
15 : #include <boost/http_proto/rfc/detail/rules.hpp>
16 : #include <boost/http_proto/service/zlib_service.hpp>
17 :
18 : #include <boost/assert.hpp>
19 : #include <boost/buffers/copy.hpp>
20 : #include <boost/buffers/prefix.hpp>
21 : #include <boost/buffers/size.hpp>
22 : #include <boost/buffers/make_buffer.hpp>
23 : #include <boost/url/grammar/ci_string.hpp>
24 : #include <boost/url/grammar/hexdig_chars.hpp>
25 :
26 : #include "detail/filter.hpp"
27 :
28 : namespace boost {
29 : namespace http_proto {
30 :
31 : /*
32 : Principles for fixed-size buffer design
33 :
34 : axiom 1:
35 : To read data you must have a buffer.
36 :
37 : axiom 2:
38 : The size of the HTTP header is not
39 : known in advance.
40 :
41 : conclusion 3:
42 : A single I/O can produce a complete
43 : HTTP header and additional payload
44 : data.
45 :
46 : conclusion 4:
47 : A single I/O can produce multiple
48 : complete HTTP headers, complete
49 : payloads, and a partial header or
50 : payload.
51 :
52 : axiom 5:
53 : A process is in one of two states:
54 : 1. at or below capacity
55 : 2. above capacity
56 :
57 : axiom 6:
58 : A program which can allocate an
59 : unbounded number of resources can
60 : go above capacity.
61 :
62 : conclusion 7:
63 : A program can guarantee never going
64 : above capacity if all resources are
65 : provisioned at program startup.
66 :
67 : corollary 8:
68 : `parser` and `serializer` should each
69 : allocate a single buffer of calculated
70 : size, and never resize it.
71 :
72 : axiom #:
73 : A parser and a serializer are always
74 : used in pairs.
75 :
76 : Buffer Usage
77 :
78 : | | begin
79 : | H | p | | f | read headers
80 : | H | p | | T | f | set T body
81 : | H | p | | C | T | f | make codec C
82 : | H | p | b | C | T | f | decode p into b
83 : | H | p | b | C | T | f | read/parse loop
84 : | H | | T | f | destroy codec
85 : | H | | T | f | finished
86 :
87 : H headers
88 : C codec
89 : T body
90 : f table
91 : p partial payload
92 : b body data
93 :
94 : "payload" is the bytes coming in from
95 : the stream.
96 :
97 : "body" is the logical body, after transfer
98 : encoding is removed. This can be the
99 : same as the payload.
100 :
101 : A "plain payload" is when the payload and
102 : body are identical (no transfer encodings).
103 :
104 : A "buffered payload" is any payload which is
105 : not plain. A second buffer is required
106 : for reading.
107 :
108 : "overread" is additional data received past
109 : the end of the headers when reading headers,
110 : or additional data received past the end of
111 : the message payload.
112 : */
113 :
114 : namespace {
115 : class inflator_filter
116 : : public http_proto::detail::filter
117 : {
118 : zlib::stream& inflator_;
119 :
120 : public:
121 73 : inflator_filter(
122 : context& ctx,
123 : http_proto::detail::workspace& ws,
124 : bool use_gzip)
125 292 : : inflator_{ ctx.get_service<zlib::service>()
126 73 : .make_inflator(ws, use_gzip ? 31 : 15) }
127 : {
128 73 : }
129 :
130 : virtual filter::results
131 119418 : on_process(
132 : buffers::mutable_buffer out,
133 : buffers::const_buffer in,
134 : bool more) override
135 : {
136 119418 : auto flush =
137 119418 : more ? zlib::flush::none : zlib::flush::finish;
138 119418 : filter::results results;
139 :
140 : for(;;)
141 : {
142 119418 : auto params = zlib::params{in.data(), in.size(),
143 119418 : out.data(), out.size() };
144 119418 : auto ec = inflator_.write(params, flush);
145 :
146 119418 : results.in_bytes += in.size() - params.avail_in;
147 119418 : results.out_bytes += out.size() - params.avail_out;
148 :
149 178340 : if( ec.failed() &&
150 178340 : ec != zlib::error::buf_err )
151 : {
152 1 : results.ec = ec;
153 119418 : return results;
154 : }
155 :
156 119417 : if( ec == zlib::error::stream_end )
157 : {
158 120 : results.finished = true;
159 120 : return results;
160 : }
161 :
162 119297 : in = buffers::suffix(in, params.avail_in);
163 119297 : out = buffers::suffix(out, params.avail_out);
164 :
165 119297 : if( in.size() == 0 || out.size() == 0 )
166 119297 : return results;
167 0 : }
168 : }
169 : };
170 :
171 : class chained_sequence
172 : {
173 : char const* pos_;
174 : char const* end_;
175 : char const* begin_b_;
176 : char const* end_b_;
177 :
178 : public:
179 125668 : chained_sequence(buffers::const_buffer_pair const& cbp)
180 125668 : : pos_(static_cast<char const*>(cbp[0].data()))
181 125668 : , end_(pos_ + cbp[0].size())
182 125668 : , begin_b_(static_cast<char const*>(cbp[1].data()))
183 125668 : , end_b_(begin_b_ + cbp[1].size())
184 : {
185 125668 : }
186 :
187 : char const*
188 651569 : next() noexcept
189 : {
190 651569 : ++pos_;
191 : // most frequently taken branch
192 651569 : if(pos_ < end_)
193 630246 : return pos_;
194 :
195 : // swap with the second range
196 21323 : if(begin_b_ != end_b_)
197 : {
198 39 : pos_ = begin_b_;
199 39 : end_ = end_b_;
200 39 : begin_b_ = end_b_;
201 39 : return pos_;
202 : }
203 :
204 : // undo the increament
205 21284 : pos_ = end_;
206 21284 : return nullptr;
207 : }
208 :
209 : bool
210 432880 : empty() const noexcept
211 : {
212 432880 : return pos_ == end_;
213 : }
214 :
215 : char
216 637061 : value() const noexcept
217 : {
218 637061 : return *pos_;
219 : }
220 :
221 : std::size_t
222 446856 : size() const noexcept
223 : {
224 446856 : return (end_ - pos_) + (end_b_ - begin_b_);
225 : }
226 : };
227 :
228 : std::uint64_t
229 121428 : parse_hex(
230 : chained_sequence& cs,
231 : system::error_code& ec) noexcept
232 : {
233 121428 : std::uint64_t v = 0;
234 121428 : std::size_t init_size = cs.size();
235 319189 : while(!cs.empty())
236 : {
237 299906 : auto n = grammar::hexdig_value(cs.value());
238 299906 : if(n < 0)
239 : {
240 102144 : if(init_size == cs.size())
241 : {
242 2 : ec = BOOST_HTTP_PROTO_ERR(
243 : error::bad_payload);
244 1 : return 0;
245 : }
246 102143 : return v;
247 : }
248 :
249 : // at least 4 significant bits are free
250 197762 : if(v > (std::numeric_limits<std::uint64_t>::max)() >> 4)
251 : {
252 2 : ec = BOOST_HTTP_PROTO_ERR(
253 : error::bad_payload);
254 1 : return 0;
255 : }
256 :
257 197761 : v = (v << 4) | static_cast<std::uint64_t>(n);
258 197761 : cs.next();
259 : }
260 38566 : ec = BOOST_HTTP_PROTO_ERR(
261 : error::need_data);
262 19283 : return 0;
263 : }
264 :
265 : void
266 102495 : find_eol(
267 : chained_sequence& cs,
268 : system::error_code& ec) noexcept
269 : {
270 109184 : while(!cs.empty())
271 : {
272 109096 : if(cs.value() == '\r')
273 : {
274 102407 : if(!cs.next())
275 10 : break;
276 102397 : if(cs.value() != '\n')
277 : {
278 4 : ec = BOOST_HTTP_PROTO_ERR(
279 : error::bad_payload);
280 2 : return;
281 : }
282 102395 : cs.next();
283 102395 : return;
284 : }
285 6689 : cs.next();
286 : }
287 196 : ec = BOOST_HTTP_PROTO_ERR(
288 : error::need_data);
289 : }
290 :
291 : void
292 117028 : parse_eol(
293 : chained_sequence& cs,
294 : system::error_code& ec) noexcept
295 : {
296 117028 : if(cs.size() >= 2)
297 : {
298 : // we are sure size is at least 2
299 117014 : if(cs.value() == '\r' && *cs.next() == '\n')
300 : {
301 117011 : cs.next();
302 117011 : return;
303 : }
304 6 : ec = BOOST_HTTP_PROTO_ERR(
305 : error::bad_payload);
306 3 : return;
307 : }
308 28 : ec = BOOST_HTTP_PROTO_ERR(
309 : error::need_data);
310 : }
311 :
312 : void
313 4223 : skip_trailer_headers(
314 : chained_sequence& cs,
315 : system::error_code& ec) noexcept
316 : {
317 4507 : while(!cs.empty())
318 : {
319 4501 : if(cs.value() == '\r')
320 : {
321 4149 : if(!cs.next())
322 2 : break;
323 4147 : if(cs.value() != '\n')
324 : {
325 4 : ec = BOOST_HTTP_PROTO_ERR(
326 : error::bad_payload);
327 2 : return;
328 : }
329 4145 : cs.next();
330 4145 : return;
331 : }
332 : // skip to the end of field
333 352 : find_eol(cs, ec);
334 352 : if(ec)
335 68 : return;
336 : }
337 16 : ec = BOOST_HTTP_PROTO_ERR(
338 : error::need_data);
339 : }
340 :
341 : template<class UInt>
342 : std::size_t
343 377847 : clamp(
344 : UInt x,
345 : std::size_t limit = (std::numeric_limits<
346 : std::size_t>::max)()) noexcept
347 : {
348 377847 : if(x >= limit)
349 105520 : return limit;
350 272327 : return static_cast<std::size_t>(x);
351 : }
352 : } // namespace
353 :
354 : class parser_service
355 : : public service
356 : {
357 : public:
358 : parser::config_base cfg;
359 : std::size_t space_needed = 0;
360 : std::size_t max_codec = 0;
361 : zlib::service const* zlib_svc = nullptr;
362 :
363 : parser_service(
364 : context& ctx,
365 : parser::config_base const& cfg_);
366 :
367 : std::size_t
368 55253 : max_overread() const noexcept
369 : {
370 : return
371 55253 : cfg.headers.max_size +
372 55253 : cfg.min_buffer;
373 : }
374 : };
375 :
376 40 : parser_service::
377 : parser_service(
378 : context& ctx,
379 40 : parser::config_base const& cfg_)
380 40 : : cfg(cfg_)
381 : {
382 : /*
383 : | fb | cb0 | cb1 | C | T | f |
384 :
385 : fb flat_buffer headers.max_size
386 : cb0 circular_buffer min_buffer
387 : cb1 circular_buffer min_buffer
388 : C codec max_codec
389 : T body max_type_erase
390 : f table max_table_space
391 :
392 : */
393 : // validate
394 : //if(cfg.min_prepare > cfg.max_prepare)
395 : //detail::throw_invalid_argument();
396 :
397 40 : if(cfg.max_prepare < 1)
398 0 : detail::throw_invalid_argument();
399 :
400 : // VFALCO TODO OVERFLOW CHECING
401 : {
402 : //fb_.size() - h_.size +
403 : //svc_.cfg.min_buffer +
404 : //svc_.cfg.min_buffer +
405 : //svc_.max_codec;
406 : }
407 :
408 : // VFALCO OVERFLOW CHECKING ON THIS
409 40 : space_needed +=
410 40 : cfg.headers.valid_space_needed();
411 :
412 : // cb0_, cb1_
413 : // VFALCO OVERFLOW CHECKING ON THIS
414 40 : space_needed +=
415 40 : cfg.min_buffer +
416 : cfg.min_buffer;
417 :
418 : // T
419 40 : space_needed += cfg.max_type_erase;
420 :
421 : // max_codec
422 : {
423 40 : if(cfg.apply_deflate_decoder)
424 : {
425 : auto const n = ctx.get_service<
426 3 : zlib::service>().inflator_space_needed(15);
427 3 : if( max_codec < n)
428 3 : max_codec = n;
429 : }
430 : }
431 40 : space_needed += max_codec;
432 :
433 : // round up to alignof(detail::header::entry)
434 40 : auto const al = alignof(
435 : detail::header::entry);
436 40 : space_needed = al * ((
437 40 : space_needed + al - 1) / al);
438 40 : }
439 :
440 : void
441 40 : install_parser_service(
442 : context& ctx,
443 : parser::config_base const& cfg)
444 : {
445 : ctx.make_service<
446 40 : parser_service>(cfg);
447 40 : }
448 :
449 : //------------------------------------------------
450 : //
451 : // Special Members
452 : //
453 : //------------------------------------------------
454 :
455 1052 : parser::
456 1052 : parser(context& ctx, detail::kind k)
457 1052 : : ctx_(ctx)
458 1052 : , svc_(ctx.get_service<parser_service>())
459 1052 : , h_(detail::empty{ k })
460 1052 : , st_(state::reset)
461 2104 : , got_header_(false)
462 : {
463 1052 : auto const n = svc_.space_needed;
464 1052 : ws_.allocate(n);
465 1052 : h_.cap = n;
466 1052 : }
467 :
468 1052 : parser::
469 : ~parser()
470 : {
471 1052 : }
472 :
473 : //--------------------------------------------
474 : //
475 : // Observers
476 : //
477 : //--------------------------------------------
478 :
479 : bool
480 11938 : parser::got_header() const noexcept
481 : {
482 11938 : return got_header_;
483 : }
484 :
485 : bool
486 51343 : parser::is_complete() const noexcept
487 : {
488 51343 : return st_ >= state::complete_in_place;
489 : }
490 :
491 : //------------------------------------------------
492 : //
493 : // Modifiers
494 : //
495 : //------------------------------------------------
496 :
497 : void
498 2480 : parser::
499 : reset() noexcept
500 : {
501 2480 : ws_.clear();
502 2480 : st_ = state::start;
503 2480 : got_header_ = false;
504 2480 : got_eof_ = false;
505 2480 : }
506 :
507 : void
508 10307 : parser::start()
509 : {
510 10307 : start_impl(false);
511 10302 : }
512 :
513 : void
514 10307 : parser::
515 : start_impl(
516 : bool head_response)
517 : {
518 10307 : std::size_t leftover = 0;
519 10307 : switch(st_)
520 : {
521 1 : default:
522 : case state::reset:
523 : // reset must be called first
524 1 : detail::throw_logic_error();
525 :
526 2255 : case state::start:
527 : // reset required on eof
528 2255 : if(got_eof_)
529 0 : detail::throw_logic_error();
530 2255 : break;
531 :
532 3 : case state::header:
533 3 : if(fb_.size() == 0)
534 : {
535 : // start() called twice
536 2 : detail::throw_logic_error();
537 : }
538 : BOOST_FALLTHROUGH;
539 :
540 : case state::header_done:
541 : case state::body:
542 : case state::set_body:
543 : // current message is incomplete
544 2 : detail::throw_logic_error();
545 :
546 8015 : case state::complete_in_place:
547 : // remove available body.
548 8015 : if(is_plain())
549 4000 : cb0_.consume(body_avail_);
550 : BOOST_FALLTHROUGH;
551 :
552 : case state::complete:
553 : {
554 : // move leftovers to front
555 :
556 8047 : ws_.clear();
557 8047 : leftover = cb0_.size();
558 :
559 8047 : auto* dest = reinterpret_cast<char*>(ws_.data());
560 8047 : auto cbp = cb0_.data();
561 8047 : auto* a = static_cast<char const*>(cbp[0].data());
562 8047 : auto* b = static_cast<char const*>(cbp[1].data());
563 8047 : auto an = cbp[0].size();
564 8047 : auto bn = cbp[1].size();
565 :
566 8047 : if(bn == 0)
567 : {
568 7609 : std::memmove(dest, a, an);
569 : }
570 : else
571 : {
572 : // if `a` can fit between `dest` and `b`, shift `b` to the left
573 : // and copy `a` to its position. if `a` fits perfectly, the
574 : // shift will be of size 0.
575 : // if `a` requires more space, shift `b` to the right and
576 : // copy `a` to its position. this process may require multiple
577 : // iterations and should be done chunk by chunk to prevent `b`
578 : // from overlapping with `a`.
579 : do
580 : {
581 : // clamp right shifts to prevent overlap with `a`
582 438 : auto* bp = (std::min)(dest + an, const_cast<char*>(a) - bn);
583 438 : b = static_cast<char const*>(std::memmove(bp, b, bn));
584 :
585 : // a chunk or all of `a` based on available space
586 438 : auto chunk_a = static_cast<std::size_t>(b - dest);
587 438 : std::memcpy(dest, a, chunk_a); // never overlap
588 438 : an -= chunk_a;
589 438 : dest += chunk_a;
590 438 : a += chunk_a;
591 438 : } while(an);
592 : }
593 :
594 8047 : break;
595 : }
596 : }
597 :
598 10302 : ws_.clear();
599 :
600 20604 : fb_ = {
601 10302 : ws_.data(),
602 10302 : svc_.cfg.headers.max_size + svc_.cfg.min_buffer,
603 : leftover };
604 :
605 10302 : BOOST_ASSERT(
606 : fb_.capacity() == svc_.max_overread() - leftover);
607 :
608 10302 : BOOST_ASSERT(
609 : head_response == false ||
610 : h_.kind == detail::kind::response);
611 :
612 10302 : h_ = detail::header(detail::empty{h_.kind});
613 10302 : h_.buf = reinterpret_cast<char*>(ws_.data());
614 10302 : h_.cbuf = h_.buf;
615 10302 : h_.cap = ws_.size();
616 :
617 10302 : st_ = state::header;
618 10302 : how_ = how::in_place;
619 :
620 : // reset to the configured default
621 10302 : body_limit_ = svc_.cfg.body_limit;
622 :
623 10302 : body_total_ = 0;
624 10302 : payload_remain_ = 0;
625 10302 : chunk_remain_ = 0;
626 10302 : body_avail_ = 0;
627 10302 : nprepare_ = 0;
628 :
629 10302 : filter_ = nullptr;
630 10302 : eb_ = nullptr;
631 10302 : sink_ = nullptr;
632 :
633 10302 : got_header_ = false;
634 10302 : head_response_ = head_response;
635 10302 : needs_chunk_close_ = false;
636 10302 : trailer_headers_ = false;
637 10302 : chunked_body_ended = false;
638 10302 : }
639 :
640 : auto
641 51100 : parser::
642 : prepare() ->
643 : mutable_buffers_type
644 : {
645 51100 : nprepare_ = 0;
646 :
647 51100 : switch(st_)
648 : {
649 1 : default:
650 : case state::reset:
651 : // reset must be called first
652 1 : detail::throw_logic_error();
653 :
654 1 : case state::start:
655 : // start must be called first
656 1 : detail::throw_logic_error();
657 :
658 10374 : case state::header:
659 : {
660 10374 : BOOST_ASSERT(
661 : h_.size < svc_.cfg.headers.max_size);
662 10374 : std::size_t n = fb_.capacity() - fb_.size();
663 10374 : BOOST_ASSERT(n <= svc_.max_overread());
664 10374 : n = clamp(n, svc_.cfg.max_prepare);
665 10374 : mbp_[0] = fb_.prepare(n);
666 10374 : nprepare_ = n;
667 10374 : return mutable_buffers_type(&mbp_[0], 1);
668 : }
669 :
670 0 : case state::header_done:
671 : // forgot to call parse()
672 0 : detail::throw_logic_error();
673 :
674 40723 : case state::body:
675 : {
676 40723 : if(got_eof_)
677 : {
678 : // forgot to call parse()
679 0 : detail::throw_logic_error();
680 : }
681 :
682 40723 : if(! is_plain())
683 : {
684 : // buffered payload
685 21673 : std::size_t n = cb0_.capacity();
686 21673 : n = clamp(n, svc_.cfg.max_prepare);
687 21673 : nprepare_ = n;
688 21673 : mbp_ = cb0_.prepare(n);
689 21673 : return mutable_buffers_type(mbp_);
690 : }
691 : else
692 : {
693 19050 : switch(how_)
694 : {
695 19029 : default:
696 : case how::in_place:
697 : case how::sink:
698 : {
699 19029 : std::size_t n = cb0_.capacity();
700 19029 : n = clamp(n, svc_.cfg.max_prepare);
701 :
702 19029 : if(h_.md.payload == payload::size)
703 : {
704 19004 : if(n > payload_remain_)
705 : {
706 17797 : std::size_t overread =
707 17797 : n - static_cast<std::size_t>(payload_remain_);
708 17797 : if(overread > svc_.max_overread())
709 7877 : n = static_cast<std::size_t>(payload_remain_) +
710 7877 : svc_.max_overread();
711 : }
712 : }
713 : else
714 : {
715 25 : BOOST_ASSERT(
716 : h_.md.payload == payload::to_eof);
717 25 : n = clamp(body_limit_remain() + 1, n);
718 : }
719 :
720 19029 : nprepare_ = n;
721 19029 : mbp_ = cb0_.prepare(n);
722 19029 : return mutable_buffers_type(mbp_);
723 : }
724 21 : case how::elastic:
725 : {
726 21 : BOOST_ASSERT(cb0_.size() == 0);
727 21 : BOOST_ASSERT(body_avail_ == 0);
728 :
729 21 : std::size_t n = svc_.cfg.min_buffer;
730 :
731 21 : if(h_.md.payload == payload::size)
732 : {
733 : // Overreads are not allowed, or
734 : // else the caller will see extra
735 : // unrelated data.
736 6 : n = clamp(payload_remain_, n);
737 : }
738 : else
739 : {
740 15 : BOOST_ASSERT(
741 : h_.md.payload == payload::to_eof);
742 15 : n = clamp(body_limit_remain() + 1, n);
743 15 : n = clamp(n, eb_->max_size() - eb_->size());
744 : // fill capacity first to avoid an allocation
745 : std::size_t avail =
746 15 : eb_->capacity() - eb_->size();
747 15 : if(avail != 0)
748 15 : n = clamp(n, avail);
749 :
750 15 : if(n == 0)
751 : {
752 : // dynamic buffer is full
753 : // attempt a 1 byte read so
754 : // we can detect overflow
755 1 : nprepare_ = 1;
756 1 : mbp_ = cb0_.prepare(1);
757 1 : return mutable_buffers_type(mbp_);
758 : }
759 : }
760 :
761 20 : n = clamp(n, svc_.cfg.max_prepare);
762 20 : BOOST_ASSERT(n != 0);
763 20 : nprepare_ = n;
764 20 : return eb_->prepare(n);
765 : }
766 : }
767 : }
768 : }
769 :
770 0 : case state::set_body:
771 : // forgot to call parse()
772 0 : detail::throw_logic_error();
773 :
774 1 : case state::complete_in_place:
775 : case state::complete:
776 : // already complete
777 1 : detail::throw_logic_error();
778 : }
779 : }
780 :
781 : void
782 51097 : parser::
783 : commit(
784 : std::size_t n)
785 : {
786 51097 : switch(st_)
787 : {
788 1 : default:
789 : case state::reset:
790 : {
791 : // reset must be called first
792 1 : detail::throw_logic_error();
793 : }
794 :
795 1 : case state::start:
796 : {
797 : // forgot to call start()
798 1 : detail::throw_logic_error();
799 : }
800 :
801 10374 : case state::header:
802 : {
803 10374 : if(n > nprepare_)
804 : {
805 : // n can't be greater than size of
806 : // the buffers returned by prepare()
807 1 : detail::throw_invalid_argument();
808 : }
809 :
810 10373 : if(got_eof_)
811 : {
812 : // can't commit after EOF
813 1 : detail::throw_logic_error();
814 : }
815 :
816 10372 : nprepare_ = 0; // invalidate
817 10372 : fb_.commit(n);
818 10372 : break;
819 : }
820 :
821 0 : case state::header_done:
822 : {
823 : // forgot to call parse()
824 0 : detail::throw_logic_error();
825 : }
826 :
827 40720 : case state::body:
828 : {
829 40720 : if(n > nprepare_)
830 : {
831 : // n can't be greater than size of
832 : // the buffers returned by prepare()
833 2 : detail::throw_invalid_argument();
834 : }
835 :
836 40718 : if(got_eof_)
837 : {
838 : // can't commit after EOF
839 0 : detail::throw_logic_error();
840 : }
841 :
842 40718 : nprepare_ = 0; // invalidate
843 40718 : if(is_plain() && how_ == how::elastic)
844 : {
845 20 : if(eb_->max_size() == eb_->size())
846 : {
847 : // borrowed 1 byte from
848 : // cb0_ in prepare()
849 1 : BOOST_ASSERT(n <= 1);
850 1 : cb0_.commit(n);
851 : }
852 : else
853 : {
854 19 : eb_->commit(n);
855 19 : payload_remain_ -= n;
856 19 : body_total_ += n;
857 : }
858 : }
859 : else
860 : {
861 40698 : cb0_.commit(n);
862 : }
863 40718 : break;
864 : }
865 :
866 0 : case state::set_body:
867 : {
868 : // forgot to call parse()
869 0 : detail::throw_logic_error();
870 : }
871 :
872 1 : case state::complete_in_place:
873 : case state::complete:
874 : {
875 : // already complete
876 1 : detail::throw_logic_error();
877 : }
878 : }
879 51090 : }
880 :
881 : void
882 402 : parser::
883 : commit_eof()
884 : {
885 402 : nprepare_ = 0; // invalidate
886 :
887 402 : switch(st_)
888 : {
889 1 : default:
890 : case state::reset:
891 : // reset must be called first
892 1 : detail::throw_logic_error();
893 :
894 1 : case state::start:
895 : // forgot to call prepare()
896 1 : detail::throw_logic_error();
897 :
898 31 : case state::header:
899 31 : got_eof_ = true;
900 31 : break;
901 :
902 0 : case state::header_done:
903 : // forgot to call parse()
904 0 : detail::throw_logic_error();
905 :
906 368 : case state::body:
907 368 : got_eof_ = true;
908 368 : break;
909 :
910 0 : case state::set_body:
911 : // forgot to call parse()
912 0 : detail::throw_logic_error();
913 :
914 1 : case state::complete_in_place:
915 : case state::complete:
916 : // can't commit eof when complete
917 1 : detail::throw_logic_error();
918 : }
919 399 : }
920 :
921 : void
922 69899 : parser::
923 : parse(
924 : system::error_code& ec)
925 : {
926 69899 : ec = {};
927 69899 : switch(st_)
928 : {
929 1 : default:
930 : case state::reset:
931 : // reset must be called first
932 1 : detail::throw_logic_error();
933 :
934 1 : case state::start:
935 : // start must be called first
936 1 : detail::throw_logic_error();
937 :
938 16649 : case state::header:
939 : {
940 16649 : BOOST_ASSERT(h_.buf == static_cast<
941 : void const*>(ws_.data()));
942 16649 : BOOST_ASSERT(h_.cbuf == static_cast<
943 : void const*>(ws_.data()));
944 :
945 16649 : h_.parse(fb_.size(), svc_.cfg.headers, ec);
946 :
947 16649 : if(ec == condition::need_more_input)
948 : {
949 6384 : if(! got_eof_)
950 : {
951 : // headers incomplete
952 6357 : return;
953 : }
954 :
955 27 : if(fb_.size() == 0)
956 : {
957 : // stream closed cleanly
958 12 : st_ = state::reset;
959 24 : ec = BOOST_HTTP_PROTO_ERR(
960 : error::end_of_stream);
961 12 : return;
962 : }
963 :
964 : // stream closed with a
965 : // partial message received
966 15 : st_ = state::reset;
967 30 : ec = BOOST_HTTP_PROTO_ERR(
968 : error::incomplete);
969 15 : return;
970 : }
971 10265 : else if(ec.failed())
972 : {
973 : // other error,
974 : //
975 : // VFALCO map this to a bad
976 : // request or bad response error?
977 : //
978 259 : st_ = state::reset; // unrecoverable
979 259 : return;
980 : }
981 :
982 10006 : got_header_ = true;
983 :
984 : // reserve headers + table
985 10006 : ws_.reserve_front(h_.size);
986 10006 : ws_.reserve_back(h_.table_space());
987 :
988 : // no payload
989 10006 : if(h_.md.payload == payload::none ||
990 9084 : head_response_)
991 : {
992 : // octets of the next message
993 922 : auto overread = fb_.size() - h_.size;
994 922 : cb0_ = { ws_.data(), overread, overread };
995 922 : ws_.reserve_front(overread);
996 922 : st_ = state::complete_in_place;
997 922 : return;
998 : }
999 :
1000 9084 : st_ = state::header_done;
1001 9084 : break;
1002 : }
1003 :
1004 9083 : case state::header_done:
1005 : {
1006 : // metadata error
1007 9083 : if(h_.md.payload == payload::error)
1008 : {
1009 : // VFALCO This needs looking at
1010 360 : ec = BOOST_HTTP_PROTO_ERR(
1011 : error::bad_payload);
1012 180 : st_ = state::reset; // unrecoverable
1013 180 : return;
1014 : }
1015 :
1016 : // overread currently includes any and all octets that
1017 : // extend beyond the current end of the header
1018 : // this can include associated body octets for the
1019 : // current message or octets of the next message in the
1020 : // stream, e.g. pipelining is being used
1021 8903 : auto const overread = fb_.size() - h_.size;
1022 8903 : BOOST_ASSERT(overread <= svc_.max_overread());
1023 :
1024 8903 : auto cap = fb_.capacity() + overread +
1025 8903 : svc_.cfg.min_buffer;
1026 :
1027 : // reserve body buffers first, as the decoder
1028 : // must be installed after them.
1029 8903 : auto const p = ws_.reserve_front(cap);
1030 :
1031 8903 : if(svc_.cfg.apply_deflate_decoder &&
1032 73 : h_.md.content_encoding.encoding == encoding::deflate)
1033 : {
1034 37 : filter_ = &ws_.emplace<inflator_filter>(ctx_, ws_, false);
1035 : }
1036 8866 : else if(svc_.cfg.apply_gzip_decoder &&
1037 36 : h_.md.content_encoding.encoding == encoding::gzip)
1038 : {
1039 36 : filter_ = &ws_.emplace<inflator_filter>(ctx_, ws_, true);
1040 : }
1041 : else
1042 : {
1043 8830 : cap += svc_.max_codec;
1044 8830 : ws_.reserve_front(svc_.max_codec);
1045 : }
1046 :
1047 8903 : if(is_plain() || how_ == how::elastic)
1048 : {
1049 4721 : cb0_ = { p, cap, overread };
1050 4721 : cb1_ = {};
1051 : }
1052 : else
1053 : {
1054 : // buffered payload
1055 8364 : std::size_t n0 = (overread > svc_.cfg.min_buffer)
1056 4182 : ? overread
1057 4158 : : svc_.cfg.min_buffer;
1058 4182 : std::size_t n1 = svc_.cfg.min_buffer;
1059 :
1060 4182 : cb0_ = { p , n0, overread };
1061 4182 : cb1_ = { p + n0 , n1 };
1062 : }
1063 :
1064 8903 : if(h_.md.payload == payload::size)
1065 : {
1066 4373 : if(!filter_ &&
1067 4349 : body_limit_ < h_.md.payload_size)
1068 : {
1069 2 : ec = BOOST_HTTP_PROTO_ERR(
1070 : error::body_too_large);
1071 1 : st_ = state::reset;
1072 1 : return;
1073 : }
1074 4372 : payload_remain_ = h_.md.payload_size;
1075 : }
1076 :
1077 8902 : st_ = state::body;
1078 : BOOST_FALLTHROUGH;
1079 : }
1080 :
1081 : case state::body:
1082 : {
1083 50274 : do_body:
1084 50274 : BOOST_ASSERT(st_ == state::body);
1085 50274 : BOOST_ASSERT(h_.md.payload != payload::none);
1086 50274 : BOOST_ASSERT(h_.md.payload != payload::error);
1087 :
1088 8796 : auto set_state_to_complete = [&]()
1089 : {
1090 8796 : if(how_ == how::in_place)
1091 : {
1092 8336 : st_ = state::complete_in_place;
1093 8336 : return;
1094 : }
1095 460 : st_ = state::complete;
1096 50274 : };
1097 :
1098 50274 : if(h_.md.payload == payload::chunked)
1099 : {
1100 : for(;;)
1101 : {
1102 131016 : if(chunk_remain_ == 0
1103 129813 : && !chunked_body_ended)
1104 : {
1105 125668 : auto cs = chained_sequence(cb0_.data());
1106 19412 : auto check_ec = [&]()
1107 : {
1108 19412 : if(ec == condition::need_more_input && got_eof_)
1109 : {
1110 0 : ec = BOOST_HTTP_PROTO_ERR(error::incomplete);
1111 0 : st_ = state::reset;
1112 : }
1113 145080 : };
1114 :
1115 125668 : if(needs_chunk_close_)
1116 : {
1117 117028 : parse_eol(cs, ec);
1118 117028 : if(ec)
1119 : {
1120 17 : check_ec();
1121 19412 : return;
1122 : }
1123 : }
1124 8640 : else if(trailer_headers_)
1125 : {
1126 4223 : skip_trailer_headers(cs, ec);
1127 4223 : if(ec)
1128 : {
1129 78 : check_ec();
1130 78 : return;
1131 : }
1132 4145 : cb0_.consume(cb0_.size() - cs.size());
1133 4145 : chunked_body_ended = true;
1134 8292 : continue;
1135 : }
1136 :
1137 121428 : auto chunk_size = parse_hex(cs, ec);
1138 121428 : if(ec)
1139 : {
1140 19285 : check_ec();
1141 19285 : return;
1142 : }
1143 :
1144 : // skip chunk extensions
1145 102143 : find_eol(cs, ec);
1146 102143 : if(ec)
1147 : {
1148 32 : check_ec();
1149 32 : return;
1150 : }
1151 :
1152 102111 : cb0_.consume(cb0_.size() - cs.size());
1153 102111 : chunk_remain_ = chunk_size;
1154 :
1155 102111 : needs_chunk_close_ = true;
1156 102111 : if(chunk_remain_ == 0)
1157 : {
1158 4147 : needs_chunk_close_ = false;
1159 4147 : trailer_headers_ = true;
1160 4147 : continue;
1161 : }
1162 : }
1163 :
1164 103312 : if(cb0_.size() == 0 && !chunked_body_ended)
1165 : {
1166 365 : if(got_eof_)
1167 : {
1168 2 : ec = BOOST_HTTP_PROTO_ERR(
1169 : error::incomplete);
1170 1 : st_ = state::reset;
1171 1 : return;
1172 : }
1173 :
1174 728 : ec = BOOST_HTTP_PROTO_ERR(
1175 : error::need_data);
1176 364 : return;
1177 : }
1178 :
1179 102947 : if(filter_)
1180 : {
1181 56565 : chunk_remain_ -= apply_filter(
1182 : ec,
1183 : clamp(chunk_remain_, cb0_.size()),
1184 56565 : !chunked_body_ended);
1185 :
1186 56565 : if(ec || chunked_body_ended)
1187 564 : return;
1188 : }
1189 : else
1190 : {
1191 : const std::size_t chunk_avail =
1192 46382 : clamp(chunk_remain_, cb0_.size());
1193 : const auto chunk =
1194 46382 : buffers::prefix(cb0_.data(), chunk_avail);
1195 :
1196 46382 : if(body_limit_remain() < chunk_avail)
1197 : {
1198 0 : ec = BOOST_HTTP_PROTO_ERR(
1199 : error::body_too_large);
1200 0 : st_ = state::reset;
1201 4121 : return;
1202 : }
1203 :
1204 46382 : switch(how_)
1205 : {
1206 46382 : case how::in_place:
1207 : {
1208 46382 : auto copied = buffers::copy(
1209 46382 : cb1_.prepare(cb1_.capacity()),
1210 : chunk);
1211 46382 : chunk_remain_ -= copied;
1212 46382 : body_avail_ += copied;
1213 46382 : body_total_ += copied;
1214 46382 : cb0_.consume(copied);
1215 46382 : cb1_.commit(copied);
1216 46382 : if(cb1_.capacity() == 0
1217 46382 : && !chunked_body_ended)
1218 : {
1219 0 : ec = BOOST_HTTP_PROTO_ERR(
1220 : error::in_place_overflow);
1221 0 : return;
1222 : }
1223 46382 : break;
1224 : }
1225 0 : case how::sink:
1226 : {
1227 0 : auto sink_rs = sink_->write(
1228 0 : chunk, !chunked_body_ended);
1229 0 : chunk_remain_ -= sink_rs.bytes;
1230 0 : body_total_ += sink_rs.bytes;
1231 0 : cb0_.consume(sink_rs.bytes);
1232 0 : if(sink_rs.ec.failed())
1233 : {
1234 0 : body_avail_ +=
1235 0 : chunk_avail - sink_rs.bytes;
1236 0 : ec = sink_rs.ec;
1237 0 : st_ = state::reset;
1238 0 : return;
1239 : }
1240 0 : break;
1241 : }
1242 0 : case how::elastic:
1243 : {
1244 0 : if(eb_->max_size() - eb_->size()
1245 0 : < chunk_avail)
1246 : {
1247 0 : ec = BOOST_HTTP_PROTO_ERR(
1248 : error::buffer_overflow);
1249 0 : st_ = state::reset;
1250 0 : return;
1251 : }
1252 0 : buffers::copy(
1253 0 : eb_->prepare(chunk_avail),
1254 : chunk);
1255 0 : chunk_remain_ -= chunk_avail;
1256 0 : body_total_ += chunk_avail;
1257 0 : cb0_.consume(chunk_avail);
1258 0 : eb_->commit(chunk_avail);
1259 0 : break;
1260 : }
1261 : }
1262 :
1263 46382 : if(chunked_body_ended)
1264 : {
1265 4121 : set_state_to_complete();
1266 4121 : return;
1267 : }
1268 : }
1269 106554 : }
1270 : }
1271 : else
1272 : {
1273 : // non-chunked payload
1274 :
1275 77436 : const std::size_t payload_avail = [&]()
1276 : {
1277 25812 : auto ret = cb0_.size();
1278 25812 : if(!filter_)
1279 24119 : ret -= body_avail_;
1280 25812 : if(h_.md.payload == payload::size)
1281 24181 : return clamp(payload_remain_, ret);
1282 : // payload::eof
1283 1631 : return ret;
1284 25812 : }();
1285 :
1286 77436 : const bool is_complete = [&]()
1287 : {
1288 25812 : if(h_.md.payload == payload::size)
1289 24181 : return payload_avail == payload_remain_;
1290 : // payload::eof
1291 1631 : return got_eof_;
1292 25812 : }();
1293 :
1294 25812 : if(filter_)
1295 : {
1296 3386 : payload_remain_ -= apply_filter(
1297 1693 : ec, payload_avail, !is_complete);
1298 1693 : if(ec || is_complete)
1299 1129 : return;
1300 : }
1301 : else
1302 : {
1303 : // plain body
1304 :
1305 24119 : if(h_.md.payload == payload::to_eof)
1306 : {
1307 764 : if(body_limit_remain() < payload_avail)
1308 : {
1309 2 : ec = BOOST_HTTP_PROTO_ERR(
1310 : error::body_too_large);
1311 1 : st_ = state::reset;
1312 1 : return;
1313 : }
1314 : }
1315 :
1316 24118 : switch(how_)
1317 : {
1318 23361 : case how::in_place:
1319 : {
1320 23361 : payload_remain_ -= payload_avail;
1321 23361 : body_avail_ += payload_avail;
1322 23361 : body_total_ += payload_avail;
1323 23361 : if(cb0_.capacity() == 0 && !is_complete)
1324 : {
1325 2 : ec = BOOST_HTTP_PROTO_ERR(
1326 : error::in_place_overflow);
1327 1 : return;
1328 : }
1329 23360 : break;
1330 : }
1331 371 : case how::sink:
1332 : {
1333 371 : payload_remain_ -= payload_avail;
1334 371 : body_total_ += payload_avail;
1335 371 : auto sink_rs = sink_->write(
1336 371 : buffers::prefix(
1337 0 : cb0_.data(),
1338 : payload_avail),
1339 371 : !is_complete);
1340 371 : cb0_.consume(sink_rs.bytes);
1341 371 : if(sink_rs.ec.failed())
1342 : {
1343 0 : body_avail_ +=
1344 0 : payload_avail - sink_rs.bytes;
1345 0 : ec = sink_rs.ec;
1346 0 : st_ = state::reset;
1347 0 : return;
1348 : }
1349 371 : break;
1350 : }
1351 386 : case how::elastic:
1352 : {
1353 : // payload_remain_ and body_total_
1354 : // are already updated in commit()
1355 :
1356 : // cb0_ contains data
1357 386 : if(payload_avail != 0)
1358 : {
1359 193 : if(eb_->max_size() - eb_->size()
1360 193 : < payload_avail)
1361 : {
1362 2 : ec = BOOST_HTTP_PROTO_ERR(
1363 : error::buffer_overflow);
1364 1 : st_ = state::reset;
1365 1 : return;
1366 : }
1367 : // only happens when an elastic body
1368 : // is attached in header_done state
1369 192 : buffers::copy(
1370 192 : eb_->prepare(payload_avail),
1371 192 : cb0_.data());
1372 192 : cb0_.consume(payload_avail);
1373 192 : eb_->commit(payload_avail);
1374 192 : payload_remain_ -= payload_avail;
1375 192 : body_total_ += payload_avail;
1376 : }
1377 385 : break;
1378 : }
1379 : }
1380 :
1381 24116 : if(is_complete)
1382 : {
1383 4675 : set_state_to_complete();
1384 4675 : return;
1385 : }
1386 : }
1387 :
1388 20005 : if(h_.md.payload == payload::size && got_eof_)
1389 : {
1390 2 : ec = BOOST_HTTP_PROTO_ERR(
1391 : error::incomplete);
1392 1 : st_ = state::reset;
1393 1 : return;
1394 : }
1395 :
1396 40008 : ec = BOOST_HTTP_PROTO_ERR(
1397 : error::need_data);
1398 20004 : return;
1399 : }
1400 :
1401 : break;
1402 : }
1403 :
1404 2333 : case state::set_body:
1405 : case state::complete_in_place:
1406 : {
1407 2333 : auto& body_buf = is_plain() ? cb0_ : cb1_;
1408 :
1409 2333 : switch(how_)
1410 : {
1411 2216 : case how::in_place:
1412 2216 : return; // no-op
1413 58 : case how::sink:
1414 : {
1415 58 : auto rs = sink_->write(
1416 58 : buffers::prefix(
1417 0 : body_buf.data(),
1418 : body_avail_),
1419 58 : st_ == state::set_body);
1420 58 : body_buf.consume(rs.bytes);
1421 58 : body_avail_ -= rs.bytes;
1422 58 : if(rs.ec.failed())
1423 : {
1424 0 : ec = rs.ec;
1425 0 : st_ = state::reset;
1426 0 : return;
1427 : }
1428 58 : break;
1429 : }
1430 59 : case how::elastic:
1431 : {
1432 59 : if(eb_->max_size() - eb_->size()
1433 59 : < body_avail_)
1434 : {
1435 0 : ec = BOOST_HTTP_PROTO_ERR(
1436 : error::buffer_overflow);
1437 0 : return;
1438 : }
1439 59 : buffers::copy(
1440 59 : eb_->prepare(body_avail_),
1441 59 : body_buf.data());
1442 59 : body_buf.consume(body_avail_);
1443 59 : eb_->commit(body_avail_);
1444 59 : body_avail_ = 0;
1445 : // TODO: expand cb0_ when possible?
1446 59 : break;
1447 : }
1448 : }
1449 :
1450 117 : if(st_ == state::set_body)
1451 : {
1452 0 : st_ = state::body;
1453 0 : goto do_body;
1454 : }
1455 :
1456 117 : st_ = state::complete;
1457 117 : break;
1458 : }
1459 :
1460 460 : case state::complete:
1461 460 : break;
1462 : }
1463 : }
1464 :
1465 : auto
1466 41250 : parser::
1467 : pull_body() ->
1468 : const_buffers_type
1469 : {
1470 41250 : switch(st_)
1471 : {
1472 0 : case state::header_done:
1473 0 : return {};
1474 41250 : case state::body:
1475 : case state::complete_in_place:
1476 41250 : cbp_ = buffers::prefix(
1477 41250 : (is_plain() ? cb0_ : cb1_).data(),
1478 : body_avail_);
1479 41250 : return const_buffers_type(cbp_);
1480 0 : default:
1481 0 : detail::throw_logic_error();
1482 : }
1483 : }
1484 :
1485 : void
1486 39606 : parser::
1487 : consume_body(std::size_t n)
1488 : {
1489 39606 : switch(st_)
1490 : {
1491 0 : case state::header_done:
1492 0 : return;
1493 39606 : case state::body:
1494 : case state::complete_in_place:
1495 39606 : n = clamp(n, body_avail_);
1496 39606 : (is_plain() ? cb0_ : cb1_).consume(n);
1497 39606 : body_avail_ -= n;
1498 39606 : return;
1499 0 : default:
1500 0 : detail::throw_logic_error();
1501 : }
1502 : }
1503 :
1504 : core::string_view
1505 699 : parser::
1506 : body() const noexcept
1507 : {
1508 699 : if(st_ != state::complete_in_place)
1509 : {
1510 : // Precondition violation
1511 0 : detail::throw_logic_error();
1512 : }
1513 :
1514 699 : if(body_avail_ != body_total_)
1515 : {
1516 : // Precondition violation
1517 0 : detail::throw_logic_error();
1518 : }
1519 :
1520 699 : auto cbp = (is_plain() ? cb0_ : cb1_).data();
1521 699 : BOOST_ASSERT(cbp[1].size() == 0);
1522 699 : BOOST_ASSERT(cbp[0].size() == body_avail_);
1523 699 : return core::string_view(
1524 699 : static_cast<char const*>(cbp[0].data()),
1525 1398 : body_avail_);
1526 : }
1527 :
1528 : core::string_view
1529 0 : parser::
1530 : release_buffered_data() noexcept
1531 : {
1532 0 : return {};
1533 : }
1534 :
1535 : void
1536 77 : parser::
1537 : set_body_limit(std::uint64_t n)
1538 : {
1539 77 : switch(st_)
1540 : {
1541 73 : case state::header:
1542 : case state::header_done:
1543 73 : body_limit_ = n;
1544 73 : break;
1545 2 : case state::complete_in_place:
1546 : // only allowed for empty bodies
1547 2 : if(body_total_ == 0)
1548 1 : break;
1549 : BOOST_FALLTHROUGH;
1550 : default:
1551 : // set body_limit before parsing the body
1552 3 : detail::throw_logic_error();
1553 : }
1554 74 : }
1555 :
1556 : //------------------------------------------------
1557 : //
1558 : // Implementation
1559 : //
1560 : //------------------------------------------------
1561 :
1562 : void
1563 755 : parser::
1564 : on_set_body() noexcept
1565 : {
1566 755 : BOOST_ASSERT(
1567 : st_ == state::header_done ||
1568 : st_ == state::body ||
1569 : st_ == state::complete_in_place);
1570 :
1571 755 : nprepare_ = 0; // invalidate
1572 :
1573 755 : if(st_ == state::body)
1574 0 : st_ = state::set_body;
1575 755 : }
1576 :
1577 : std::size_t
1578 58258 : parser::
1579 : apply_filter(
1580 : system::error_code& ec,
1581 : std::size_t payload_avail,
1582 : bool more)
1583 : {
1584 58258 : std::size_t p0 = payload_avail;
1585 : for(;;)
1586 : {
1587 116601 : if(payload_avail == 0 && more)
1588 56638 : break;
1589 :
1590 0 : auto f_rs = [&](){
1591 60084 : BOOST_ASSERT(filter_ != nullptr);
1592 60084 : if(how_ == how::elastic)
1593 : {
1594 19887 : std::size_t n = clamp(body_limit_remain());
1595 19887 : n = clamp(n, svc_.cfg.min_buffer);
1596 19887 : n = clamp(n, eb_->max_size() - eb_->size());
1597 :
1598 : // fill capacity first to avoid
1599 : // an allocation
1600 : std::size_t avail =
1601 19887 : eb_->capacity() - eb_->size();
1602 19887 : if(avail != 0)
1603 19886 : n = clamp(n, avail);
1604 :
1605 19887 : return filter_->process(
1606 19887 : eb_->prepare(n),
1607 19887 : buffers::prefix(
1608 19887 : cb0_.data(),
1609 : payload_avail),
1610 39774 : more);
1611 : }
1612 : else // in-place and sink
1613 : {
1614 40197 : std::size_t n = clamp(body_limit_remain());
1615 40197 : n = clamp(n, cb1_.capacity());
1616 :
1617 40197 : return filter_->process(
1618 40197 : cb1_.prepare(n),
1619 40197 : buffers::prefix(
1620 40197 : cb0_.data(),
1621 : payload_avail),
1622 80394 : more);
1623 : }
1624 60084 : }();
1625 :
1626 60084 : cb0_.consume(f_rs.in_bytes);
1627 60084 : payload_avail -= f_rs.in_bytes;
1628 60084 : body_total_ += f_rs.out_bytes;
1629 :
1630 120048 : bool needs_more_space = !f_rs.finished &&
1631 59964 : payload_avail != 0;
1632 :
1633 60084 : switch(how_)
1634 : {
1635 20238 : case how::in_place:
1636 : {
1637 20238 : cb1_.commit(f_rs.out_bytes);
1638 20238 : body_avail_ += f_rs.out_bytes;
1639 20238 : if(cb1_.capacity() == 0 &&
1640 : needs_more_space)
1641 : {
1642 3240 : ec = BOOST_HTTP_PROTO_ERR(
1643 : error::in_place_overflow);
1644 1620 : goto done;
1645 : }
1646 18618 : break;
1647 : }
1648 19959 : case how::sink:
1649 : {
1650 19959 : cb1_.commit(f_rs.out_bytes);
1651 19959 : auto sink_rs = sink_->write(
1652 19959 : cb1_.data(), !f_rs.finished);
1653 19959 : cb1_.consume(sink_rs.bytes);
1654 19959 : if(sink_rs.ec.failed())
1655 : {
1656 0 : ec = sink_rs.ec;
1657 0 : st_ = state::reset;
1658 0 : goto done;
1659 : }
1660 19959 : break;
1661 : }
1662 19887 : case how::elastic:
1663 : {
1664 19887 : eb_->commit(f_rs.out_bytes);
1665 19887 : if(eb_->max_size() - eb_->size() == 0 &&
1666 : needs_more_space)
1667 : {
1668 0 : ec = BOOST_HTTP_PROTO_ERR(
1669 : error::buffer_overflow);
1670 0 : st_ = state::reset;
1671 0 : goto done;
1672 : }
1673 19887 : break;
1674 : }
1675 : }
1676 :
1677 58464 : if(f_rs.ec.failed())
1678 : {
1679 1 : ec = f_rs.ec;
1680 1 : st_ = state::reset;
1681 1 : break;
1682 : }
1683 :
1684 58463 : if(body_limit_remain() == 0 &&
1685 : needs_more_space)
1686 : {
1687 0 : ec = BOOST_HTTP_PROTO_ERR(
1688 : error::body_too_large);
1689 0 : st_ = state::reset;
1690 0 : break;
1691 : }
1692 :
1693 58463 : if(f_rs.finished)
1694 : {
1695 120 : if(!more)
1696 : {
1697 72 : st_ = (how_ == how::in_place)
1698 72 : ? state::complete_in_place
1699 : : state::complete;
1700 : }
1701 120 : break;
1702 : }
1703 58343 : }
1704 :
1705 58258 : done:
1706 58258 : return p0 - payload_avail;
1707 : }
1708 :
1709 : detail::header const*
1710 315 : parser::
1711 : safe_get_header() const
1712 : {
1713 : // headers must be received
1714 315 : if(! got_header_)
1715 0 : detail::throw_logic_error();
1716 :
1717 315 : return &h_;
1718 : }
1719 :
1720 : bool
1721 182247 : parser::
1722 : is_plain() const noexcept
1723 : {
1724 354589 : return ! filter_ &&
1725 354589 : h_.md.payload != payload::chunked;
1726 : }
1727 :
1728 : std::uint64_t
1729 165733 : parser::
1730 : body_limit_remain() const noexcept
1731 : {
1732 165733 : return body_limit_ - body_total_;
1733 : }
1734 :
1735 : } // http_proto
1736 : } // boost
|