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