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