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