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