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