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 :
72 : //------------------------------------------------
73 : /*
74 : Buffer Usage
75 :
76 : | | begin
77 : | H | p | | f | read headers
78 : | H | p | | T | f | set T body
79 : | H | p | | C | T | f | make codec C
80 : | H | p | b | C | T | f | decode p into b
81 : | H | p | b | C | T | f | read/parse loop
82 : | H | | T | f | destroy codec
83 : | H | | T | f | finished
84 :
85 : H headers
86 : C codec
87 : T body
88 : f table
89 : p partial payload
90 : b body data
91 :
92 : "payload" is the bytes coming in from
93 : the stream.
94 :
95 : "body" is the logical body, after transfer
96 : encoding is removed. This can be the
97 : same as the payload.
98 :
99 : A "plain payload" is when the payload and
100 : body are identical (no transfer encodings).
101 :
102 : A "buffered payload" is any payload which is
103 : not plain. A second buffer is required
104 : for reading.
105 : */
106 : //------------------------------------------------
107 :
108 : class parser_service
109 : : public service
110 : {
111 : public:
112 : parser::config_base cfg;
113 : std::size_t space_needed = 0;
114 : std::size_t max_codec = 0;
115 : zlib::deflate_decoder_service const*
116 : deflate_svc = nullptr;
117 :
118 : parser_service(
119 : context& ctx,
120 : parser::config_base const& cfg_);
121 :
122 : std::size_t
123 83721 : max_overread() const noexcept
124 : {
125 : return
126 83721 : cfg.headers.max_size +
127 83721 : cfg.min_buffer;
128 : }
129 : };
130 :
131 6 : parser_service::
132 : parser_service(
133 : context& ctx,
134 6 : parser::config_base const& cfg_)
135 6 : : cfg(cfg_)
136 : {
137 : /*
138 : | fb | cb0 | cb1 | C | T | f |
139 :
140 : fb flat_buffer headers.max_size
141 : cb0 circular_buffer min_buffer
142 : cb1 circular_buffer min_buffer
143 : C codec max_codec
144 : T body max_type_erase
145 : f table max_table_space
146 :
147 : */
148 : // validate
149 : //if(cfg.min_prepare > cfg.max_prepare)
150 : //detail::throw_invalid_argument();
151 :
152 6 : if( cfg.min_buffer < 1 ||
153 6 : cfg.min_buffer > cfg.body_limit)
154 0 : detail::throw_invalid_argument();
155 :
156 6 : if(cfg.max_prepare < 1)
157 0 : detail::throw_invalid_argument();
158 :
159 : // VFALCO TODO OVERFLOW CHECING
160 : {
161 : //fb_.size() - h_.size +
162 : //svc_.cfg.min_buffer +
163 : //svc_.cfg.min_buffer +
164 : //svc_.max_codec;
165 : }
166 :
167 : // VFALCO OVERFLOW CHECKING ON THIS
168 6 : space_needed +=
169 6 : cfg.headers.valid_space_needed();
170 :
171 : // cb0_, cb1_
172 : // VFALCO OVERFLOW CHECKING ON THIS
173 6 : space_needed +=
174 6 : cfg.min_buffer +
175 : cfg.min_buffer;
176 :
177 : // T
178 6 : space_needed += cfg.max_type_erase;
179 :
180 : // max_codec
181 : {
182 6 : if(cfg.apply_deflate_decoder)
183 : {
184 0 : deflate_svc = &ctx.get_service<
185 0 : zlib::deflate_decoder_service>();
186 : auto const n =
187 0 : deflate_svc->space_needed();
188 0 : if( max_codec < n)
189 0 : max_codec = n;
190 : }
191 : }
192 6 : space_needed += max_codec;
193 6 : }
194 :
195 : void
196 6 : install_parser_service(
197 : context& ctx,
198 : parser::config_base const& cfg)
199 : {
200 : ctx.make_service<
201 6 : parser_service>(cfg);
202 6 : }
203 :
204 : //------------------------------------------------
205 :
206 738 : parser::
207 : parser(
208 : context& ctx,
209 738 : detail::kind k)
210 : : ctx_(ctx)
211 : , svc_(ctx.get_service<
212 1476 : parser_service>())
213 : , h_(detail::empty{k})
214 738 : , st_(state::reset)
215 : {
216 738 : auto const n =
217 738 : svc_.space_needed;
218 738 : ws_.allocate(n);
219 738 : h_.cap = n;
220 738 : }
221 :
222 : //------------------------------------------------
223 : //
224 : // Special Members
225 : //
226 : //------------------------------------------------
227 :
228 738 : parser::
229 738 : ~parser()
230 : {
231 738 : }
232 :
233 : parser::
234 : parser(
235 : parser&&) noexcept = default;
236 :
237 : //------------------------------------------------
238 : //
239 : // Modifiers
240 : //
241 : //------------------------------------------------
242 :
243 : // prepare for a new stream
244 : void
245 5355 : parser::
246 : reset() noexcept
247 : {
248 5355 : ws_.clear();
249 5355 : st_ = state::start;
250 5355 : got_eof_ = false;
251 5355 : }
252 :
253 : void
254 14280 : parser::
255 : start_impl(
256 : bool head_response)
257 : {
258 14280 : std::size_t leftover = 0;
259 14280 : switch(st_)
260 : {
261 0 : default:
262 : case state::reset:
263 : // reset must be called first
264 0 : detail::throw_logic_error();
265 :
266 5355 : case state::start:
267 : // reset required on eof
268 5355 : if(got_eof_)
269 0 : detail::throw_logic_error();
270 5355 : break;
271 :
272 0 : case state::header:
273 : // start() called twice
274 0 : detail::throw_logic_error();
275 :
276 0 : case state::body:
277 : case state::body_set:
278 : // current message is incomplete
279 0 : detail::throw_logic_error();
280 :
281 8925 : case state::complete:
282 : {
283 : // remove partial body.
284 8925 : if(body_buf_ == &cb0_)
285 8925 : cb0_.consume(body_avail_);
286 :
287 8925 : if(cb0_.size() > 0)
288 : {
289 :
290 : // headers with no body
291 0 : BOOST_ASSERT(h_.size > 0);
292 0 : fb_.consume(h_.size);
293 0 : leftover = fb_.size();
294 : // move unused octets to front
295 0 : buffers::buffer_copy(
296 0 : buffers::mutable_buffer(
297 0 : ws_.data(),
298 : leftover),
299 0 : fb_.data());
300 : }
301 : else
302 : {
303 : // leftover data after body
304 : }
305 8925 : break;
306 : }
307 : }
308 :
309 14280 : ws_.clear();
310 :
311 28560 : fb_ = {
312 14280 : ws_.data(),
313 14280 : svc_.cfg.headers.max_size +
314 14280 : svc_.cfg.min_buffer,
315 : leftover };
316 14280 : BOOST_ASSERT(
317 : fb_.capacity() == svc_.max_overread());
318 :
319 28560 : h_ = detail::header(
320 14280 : detail::empty{h_.kind});
321 14280 : h_.buf = reinterpret_cast<
322 14280 : char*>(ws_.data());
323 14280 : h_.cbuf = h_.buf;
324 14280 : h_.cap = ws_.size();
325 :
326 14280 : BOOST_ASSERT(! head_response ||
327 : h_.kind == detail::kind::response);
328 14280 : head_response_ = head_response;
329 :
330 14280 : how_ = how::in_place;
331 14280 : st_ = state::header;
332 14280 : }
333 :
334 : auto
335 42962 : parser::
336 : prepare() ->
337 : mutable_buffers_type
338 : {
339 42962 : switch(st_)
340 : {
341 0 : default:
342 : case state::reset:
343 : // reset must be called first
344 0 : detail::throw_logic_error();
345 :
346 0 : case state::start:
347 : // start must be called first
348 0 : detail::throw_logic_error();
349 :
350 40397 : case state::header:
351 : {
352 40397 : BOOST_ASSERT(h_.size <
353 : svc_.cfg.headers.max_size);
354 40397 : auto n = fb_.capacity() - fb_.size();
355 40397 : BOOST_ASSERT(n <= svc_.max_overread());
356 40397 : if( n > svc_.cfg.max_prepare)
357 0 : n = svc_.cfg.max_prepare;
358 40397 : mbp_[0] = fb_.prepare(n);
359 40397 : return mutable_buffers_type(
360 80794 : &mbp_[0], 1);
361 : }
362 :
363 2565 : case state::body:
364 : {
365 : // buffered payload
366 2565 : if(body_buf_ != &cb0_)
367 : {
368 0 : auto n = cb0_.capacity() -
369 0 : cb0_.size();
370 0 : if( n > svc_.cfg.max_prepare)
371 0 : n = svc_.cfg.max_prepare;
372 0 : mbp_ = cb0_.prepare(n);
373 0 : return mutable_buffers_type(mbp_);
374 : }
375 2565 : BOOST_ASSERT(is_plain());
376 :
377 : // plain payload
378 :
379 2565 : if(how_ == how::in_place)
380 : {
381 : auto n =
382 1191 : body_buf_->capacity() -
383 1191 : body_buf_->size();
384 1191 : if( n > svc_.cfg.max_prepare)
385 0 : n = svc_.cfg.max_prepare;
386 1191 : mbp_ = body_buf_->prepare(n);
387 1191 : return mutable_buffers_type(mbp_);
388 : }
389 :
390 1374 : if(how_ == how::dynamic)
391 : {
392 : // Overreads are not allowed, or
393 : // else the caller will see extra
394 : // unrelated data.
395 :
396 1374 : if(h_.md.payload == payload::size)
397 : {
398 : // set_body moves avail to dyn
399 615 : BOOST_ASSERT(body_buf_->size() == 0);
400 615 : BOOST_ASSERT(body_avail_ == 0);
401 615 : auto n = payload_remain_;
402 615 : if( n > svc_.cfg.max_prepare)
403 0 : n = svc_.cfg.max_prepare;
404 615 : return dyn_->prepare(n);
405 : }
406 :
407 : // heuristic size
408 759 : std::size_t n = 0;
409 759 : if(! got_eof_)
410 : {
411 759 : n = svc_.cfg.min_buffer;
412 759 : if( n > svc_.cfg.max_prepare)
413 0 : n = svc_.cfg.max_prepare;
414 : std::size_t avail;
415 759 : avail =
416 759 : dyn_->max_size() - dyn_->size();
417 759 : if( n > avail)
418 759 : n = avail;
419 759 : avail =
420 759 : dyn_->capacity() - dyn_->size();
421 759 : if( n > avail &&
422 : avail != 0)
423 0 : n = avail;
424 759 : if(n == 0)
425 : {
426 : // dynamic buffer is full
427 308 : if(body_avail_ == 0)
428 : {
429 : // attempt a 1 byte read so
430 : // we can detect overflow
431 273 : BOOST_ASSERT(
432 : body_buf_->size() == 0);
433 273 : mbp_ = body_buf_->prepare(1);
434 : return
435 273 : mutable_buffers_type(mbp_);
436 : }
437 : return
438 35 : mutable_buffers_type{};
439 : }
440 : }
441 451 : return dyn_->prepare(n);
442 : }
443 :
444 : // VFALCO TODO
445 0 : if(how_ == how::pull)
446 0 : detail::throw_logic_error();
447 :
448 : // VFALCO TODO
449 0 : detail::throw_logic_error();
450 : }
451 :
452 0 : case state::body_set:
453 : {
454 0 : BOOST_ASSERT(how_ != how::in_place);
455 0 : BOOST_ASSERT(how_ != how::dynamic);
456 0 : if(how_ == how::sink)
457 : {
458 : // this is a no-op, to get the
459 : // caller to call parse next.
460 0 : return mutable_buffers_type{};
461 : }
462 0 : detail::throw_logic_error();
463 : }
464 :
465 0 : case state::complete:
466 : // We allow the call for callers
467 : // who want normalized usage, but
468 : // just return a 0-sized sequence.
469 0 : return mutable_buffers_type{};
470 : }
471 : }
472 :
473 : void
474 42962 : parser::
475 : commit(
476 : std::size_t n)
477 : {
478 : // Can't commit after eof
479 42962 : if(got_eof_)
480 0 : detail::throw_logic_error();
481 :
482 42962 : switch(st_)
483 : {
484 0 : default:
485 : case state::reset:
486 : // reset must be called first
487 0 : detail::throw_logic_error();
488 :
489 0 : case state::start:
490 : // forgot to call start()
491 0 : detail::throw_logic_error();
492 :
493 40397 : case state::header:
494 40397 : fb_.commit(n);
495 40397 : break;
496 :
497 2565 : case state::body:
498 2565 : if(! is_plain())
499 : {
500 : // buffered payload
501 0 : cb0_.commit(n);
502 0 : break;
503 : }
504 :
505 : // plain payload
506 :
507 2565 : if(how_ == how::in_place)
508 : {
509 1191 : cb0_.commit(n);
510 1191 : break;
511 : }
512 :
513 1374 : if(how_ == how::dynamic)
514 : {
515 1374 : if(dyn_->size() < dyn_->max_size())
516 : {
517 1066 : BOOST_ASSERT(body_avail_ == 0);
518 1066 : BOOST_ASSERT(
519 : body_buf_->size() == 0);
520 1066 : dyn_->commit(n);
521 : }
522 : else
523 : {
524 308 : body_buf_->commit(n);
525 308 : body_avail_ += n;
526 : }
527 1374 : body_total_ += n;
528 1374 : if(h_.md.payload == payload::size)
529 : {
530 615 : BOOST_ASSERT(
531 : n <= payload_remain_);
532 615 : payload_remain_ -= n;
533 615 : if(payload_remain_ == 0)
534 585 : st_ = state::complete;
535 : }
536 1374 : break;
537 : }
538 0 : if(how_ == how::sink)
539 : {
540 0 : cb0_.commit(n);
541 0 : break;
542 : }
543 0 : if(how_ == how::pull)
544 : {
545 : // VFALCO TODO
546 0 : detail::throw_logic_error();
547 : }
548 0 : break;
549 :
550 0 : case state::body_set:
551 0 : BOOST_ASSERT(n == 0);
552 0 : break;
553 :
554 0 : case state::complete:
555 : // intended no-op
556 0 : break;
557 : }
558 42962 : }
559 :
560 : void
561 4356 : parser::
562 : commit_eof()
563 : {
564 4356 : switch(st_)
565 : {
566 0 : default:
567 : case state::reset:
568 : // reset must be called first
569 0 : detail::throw_logic_error();
570 :
571 0 : case state::start:
572 : // forgot to call prepare()
573 0 : detail::throw_logic_error();
574 :
575 0 : case state::header:
576 0 : got_eof_ = true;
577 0 : break;
578 :
579 4356 : case state::body:
580 4356 : got_eof_ = true;
581 4356 : break;
582 :
583 0 : case state::body_set:
584 0 : got_eof_ = true;
585 0 : break;
586 :
587 0 : case state::complete:
588 : // can't commit eof when complete
589 0 : detail::throw_logic_error();
590 : }
591 4356 : }
592 :
593 : //-----------------------------------------------
594 :
595 : // process input data then
596 : // eof if input data runs out.
597 : void
598 60007 : parser::
599 : parse(
600 : system::error_code& ec)
601 : {
602 60007 : ec = {};
603 60007 : switch(st_)
604 : {
605 0 : default:
606 : case state::reset:
607 : // reset must be called first
608 0 : detail::throw_logic_error();
609 :
610 0 : case state::start:
611 : // start must be called first
612 0 : detail::throw_logic_error();
613 :
614 40397 : case state::header:
615 : {
616 40397 : BOOST_ASSERT(h_.buf == static_cast<
617 : void const*>(ws_.data()));
618 40397 : BOOST_ASSERT(h_.cbuf == static_cast<
619 : void const*>(ws_.data()));
620 40397 : auto const new_size = fb_.size();
621 40397 : h_.parse(new_size, svc_.cfg.headers, ec);
622 40397 : if(ec == condition::need_more_input)
623 : {
624 26117 : if(! got_eof_)
625 : {
626 : // headers incomplete
627 26117 : return;
628 : }
629 0 : if(h_.size == 0)
630 : {
631 : // stream closed cleanly
632 0 : ec = BOOST_HTTP_PROTO_ERR(
633 : error::end_of_stream);
634 0 : return;
635 : }
636 :
637 : // stream closed with a
638 : // partial message received
639 0 : ec = BOOST_HTTP_PROTO_ERR(
640 : error::incomplete);
641 0 : return;
642 : }
643 14280 : if(ec.failed())
644 : {
645 : // other error,
646 : //
647 : // VFALCO map this to a bad
648 : // request or bad response error?
649 : //
650 128 : st_ = state::reset; // unrecoverable
651 128 : return;
652 : }
653 :
654 : // headers are complete
655 14152 : on_headers(ec);
656 14152 : if(ec.failed())
657 0 : return;
658 14152 : if(st_ == state::complete)
659 2084 : break;
660 : BOOST_FALLTHROUGH;
661 : }
662 :
663 : case state::body:
664 : {
665 12068 : do_body:
666 18404 : BOOST_ASSERT(st_ == state::body);
667 18404 : BOOST_ASSERT(
668 : h_.md.payload != payload::none);
669 18404 : BOOST_ASSERT(
670 : h_.md.payload != payload::error);
671 18404 : if(h_.md.payload == payload::chunked)
672 : {
673 : // VFALCO parse chunked
674 0 : detail::throw_logic_error();
675 : }
676 18404 : else if(filt_)
677 : {
678 : // VFALCO TODO apply filter
679 0 : detail::throw_logic_error();
680 : }
681 :
682 18404 : if(how_ == how::in_place)
683 : {
684 15570 : if(h_.md.payload == payload::size)
685 : {
686 8061 : if(cb0_.size() <
687 8061 : h_.md.payload_size)
688 : {
689 1200 : body_avail_ = cb0_.size();
690 1200 : if(cb0_.capacity() == 0)
691 : {
692 : // in_place buffer limit
693 0 : ec = BOOST_HTTP_PROTO_ERR(
694 : error::in_place_overflow);
695 0 : return;
696 : }
697 2400 : ec = BOOST_HTTP_PROTO_ERR(
698 : error::need_data);
699 1200 : return;
700 : }
701 6861 : body_avail_ = h_.md.payload_size;
702 6861 : st_ = state::complete;
703 6861 : break;
704 : }
705 7509 : body_avail_ = cb0_.size();
706 7509 : if(body_avail_ > svc_.cfg.body_limit)
707 : {
708 0 : ec = BOOST_HTTP_PROTO_ERR(
709 : error::body_too_large);
710 0 : st_ = state::reset; // unrecoverable
711 0 : return;
712 : }
713 7509 : if( h_.md.payload == payload::chunked ||
714 7509 : ! got_eof_)
715 : {
716 10396 : ec = BOOST_HTTP_PROTO_ERR(
717 : error::need_data);
718 5198 : return;
719 : }
720 2311 : st_ = state::complete;
721 2311 : break;
722 : }
723 :
724 2834 : if(how_ == how::dynamic)
725 : {
726 : // state already updated in commit
727 2834 : if(h_.md.payload == payload::size)
728 : {
729 30 : BOOST_ASSERT(body_avail_ == 0);
730 30 : BOOST_ASSERT(body_total_ <
731 : h_.md.payload_size);
732 30 : BOOST_ASSERT(
733 : payload_remain_ > 0);
734 30 : if(got_eof_)
735 : {
736 0 : ec = BOOST_HTTP_PROTO_ERR(
737 : error::incomplete);
738 0 : return;
739 : }
740 30 : return;
741 : }
742 2804 : BOOST_ASSERT(
743 : h_.md.payload == payload::to_eof);
744 4912 : if( dyn_->size() == dyn_->max_size() &&
745 2108 : body_avail_ > 0)
746 : {
747 1722 : ec = BOOST_HTTP_PROTO_ERR(
748 : error::buffer_overflow);
749 861 : st_ = state::reset; // unrecoverable
750 861 : return;
751 : }
752 1943 : if(got_eof_)
753 : {
754 1450 : BOOST_ASSERT(body_avail_ == 0);
755 1450 : st_ = state::complete;
756 1450 : break;
757 : }
758 493 : BOOST_ASSERT(body_avail_ == 0);
759 493 : break;
760 : }
761 :
762 : // VFALCO TODO
763 0 : detail::throw_logic_error();
764 : }
765 :
766 0 : case state::body_set:
767 : {
768 : // transfer in_place data into set body
769 :
770 : // this is handled in on_set_body
771 0 : BOOST_ASSERT(how_ != how::dynamic);
772 :
773 0 : if(how_ == how::sink)
774 : {
775 0 : auto n = body_buf_->size();
776 0 : if(h_.md.payload == payload::size)
777 : {
778 : // sink_->size_hint(h_.md.payload_size, ec);
779 :
780 0 : if(n < h_.md.payload_size)
781 : {
782 0 : auto rv = sink_->write(
783 0 : body_buf_->data(), false);
784 0 : BOOST_ASSERT(rv.ec.failed() ||
785 : rv.bytes == body_buf_->size());
786 0 : BOOST_ASSERT(
787 : rv.bytes >= body_avail_);
788 0 : BOOST_ASSERT(
789 : rv.bytes < payload_remain_);
790 0 : body_buf_->consume(rv.bytes);
791 0 : body_avail_ -= rv.bytes;
792 0 : body_total_ += rv.bytes;
793 0 : payload_remain_ -= rv.bytes;
794 0 : if(rv.ec.failed())
795 : {
796 0 : ec = rv.ec;
797 0 : st_ = state::reset; // unrecoverable
798 0 : return;
799 : }
800 0 : st_ = state::body;
801 0 : goto do_body;
802 : }
803 :
804 0 : n = h_.md.payload_size;
805 : }
806 : // complete
807 0 : BOOST_ASSERT(body_buf_ == &cb0_);
808 0 : auto rv = sink_->write(
809 0 : body_buf_->data(), true);
810 0 : BOOST_ASSERT(rv.ec.failed() ||
811 : rv.bytes == body_buf_->size());
812 0 : body_buf_->consume(rv.bytes);
813 0 : if(rv.ec.failed())
814 : {
815 0 : ec = rv.ec;
816 0 : st_ = state::reset; // unrecoverable
817 0 : return;
818 : }
819 0 : st_ = state::complete;
820 0 : return;
821 : }
822 :
823 : // VFALCO TODO
824 0 : detail::throw_logic_error();
825 : }
826 :
827 13274 : case state::complete:
828 : {
829 : // This is a no-op except when set_body
830 : // was called and we have in-place data.
831 13274 : switch(how_)
832 : {
833 6775 : default:
834 : case how::in_place:
835 6775 : break;
836 :
837 6499 : case how::dynamic:
838 : {
839 6499 : if(body_buf_->size() == 0)
840 6499 : break;
841 0 : BOOST_ASSERT(dyn_->size() == 0);
842 0 : auto n = buffers::buffer_copy(
843 0 : dyn_->prepare(
844 0 : body_buf_->size()),
845 0 : body_buf_->data());
846 0 : body_buf_->consume(n);
847 0 : break;
848 : }
849 :
850 0 : case how::sink:
851 : {
852 0 : if(body_buf_->size() == 0)
853 0 : break;
854 0 : auto rv = sink_->write(
855 0 : body_buf_->data(), false);
856 0 : body_buf_->consume(rv.bytes);
857 0 : if(rv.ec.failed())
858 : {
859 0 : ec = rv.ec;
860 0 : st_ = state::reset; // unrecoverable
861 0 : return;
862 : }
863 0 : break;
864 : }
865 :
866 0 : case how::pull:
867 : // VFALCO TODO
868 0 : detail::throw_logic_error();
869 : }
870 : }
871 : }
872 : }
873 :
874 : //------------------------------------------------
875 :
876 : auto
877 0 : parser::
878 : pull_some() ->
879 : const_buffers_type
880 : {
881 0 : return {};
882 : }
883 :
884 : core::string_view
885 29135 : parser::
886 : body() const noexcept
887 : {
888 29135 : switch(st_)
889 : {
890 5792 : default:
891 : case state::reset:
892 : case state::start:
893 : case state::header:
894 : case state::body:
895 : case state::body_set:
896 : // not complete
897 5792 : return {};
898 :
899 23343 : case state::complete:
900 23343 : if(how_ != how::in_place)
901 : {
902 : // not in_place
903 9793 : return {};
904 : }
905 13550 : auto cbp = body_buf_->data();
906 13550 : BOOST_ASSERT(cbp[1].size() == 0);
907 13550 : BOOST_ASSERT(cbp[0].size() >= body_avail_);
908 13550 : return core::string_view(
909 : static_cast<char const*>(
910 13550 : cbp[0].data()),
911 27100 : body_avail_);
912 : }
913 : }
914 :
915 : core::string_view
916 0 : parser::
917 : release_buffered_data() noexcept
918 : {
919 0 : return {};
920 : }
921 :
922 : //------------------------------------------------
923 : //
924 : // Implementation
925 : //
926 : //------------------------------------------------
927 :
928 : auto
929 55 : parser::
930 : safe_get_header() const ->
931 : detail::header const*
932 : {
933 55 : switch(st_)
934 : {
935 0 : default:
936 : case state::start:
937 : case state::header:
938 : // Headers not received yet
939 0 : detail::throw_logic_error();
940 :
941 55 : case state::body:
942 : case state::complete:
943 : // VFALCO check if headers are discarded?
944 55 : break;
945 : }
946 55 : return &h_;
947 : }
948 :
949 : // return true if payload is plain
950 : bool
951 23973 : parser::
952 : is_plain() const noexcept
953 : {
954 : return
955 47946 : h_.md.payload != payload::chunked &&
956 47946 : ! filt_;
957 : }
958 :
959 : // Called immediately after
960 : // complete headers are received
961 : void
962 14152 : parser::
963 : on_headers(
964 : system::error_code& ec)
965 : {
966 : auto const overread =
967 14152 : fb_.size() - h_.size;
968 14152 : BOOST_ASSERT(
969 : overread <= svc_.max_overread());
970 :
971 : // reserve headers + table
972 14152 : ws_.reserve_front(h_.size);
973 14152 : ws_.reserve_back(h_.table_space());
974 :
975 : // no payload
976 14152 : if( h_.md.payload == payload::none ||
977 12068 : head_response_)
978 : {
979 : // set cb0_ to overread
980 4168 : cb0_ = {
981 2084 : ws_.data(),
982 2084 : fb_.capacity() - h_.size,
983 : overread };
984 2084 : body_avail_ = 0;
985 2084 : body_total_ = 0;
986 2084 : body_buf_ = &cb0_;
987 2084 : st_ = state::complete;
988 2084 : return;
989 : }
990 :
991 : // metadata error
992 12068 : if(h_.md.payload == payload::error)
993 : {
994 : // VFALCO This needs looking at
995 0 : ec = BOOST_HTTP_PROTO_ERR(
996 : error::bad_payload);
997 0 : st_ = state::reset; // unrecoverable
998 0 : return;
999 : }
1000 :
1001 : // calculate filter
1002 12068 : filt_ = nullptr;
1003 :
1004 : // plain payload
1005 12068 : if(is_plain())
1006 : {
1007 : // payload size is known
1008 12068 : if(h_.md.payload == payload::size)
1009 : {
1010 7446 : if(h_.md.payload_size >
1011 7446 : svc_.cfg.body_limit)
1012 : {
1013 0 : ec = BOOST_HTTP_PROTO_ERR(
1014 : error::body_too_large);
1015 0 : st_ = state::reset; // unrecoverable
1016 0 : return;
1017 : }
1018 : auto n0 =
1019 7446 : fb_.capacity() - h_.size +
1020 7446 : svc_.cfg.min_buffer +
1021 7446 : svc_.max_codec;
1022 : // limit the capacity of cb0_ so
1023 : // that going over max_overread
1024 : // is impossible.
1025 14892 : if( n0 > h_.md.payload_size &&
1026 7446 : n0 - h_.md.payload_size >=
1027 7446 : svc_.max_overread())
1028 7446 : n0 =
1029 7446 : h_.md.payload_size +
1030 7446 : svc_.max_overread();
1031 7446 : BOOST_ASSERT(n0 <= ws_.size());
1032 7446 : cb0_ = {
1033 7446 : ws_.data(),
1034 : n0,
1035 : overread };
1036 7446 : body_buf_ = &cb0_;
1037 7446 : body_avail_ = cb0_.size();
1038 7446 : if( body_avail_ >= h_.md.payload_size)
1039 6276 : body_avail_ = h_.md.payload_size;
1040 7446 : body_total_ = body_avail_;
1041 7446 : payload_remain_ =
1042 7446 : h_.md.payload_size - body_total_;
1043 7446 : st_ = state::body;
1044 7446 : return;
1045 : }
1046 :
1047 : // payload to eof
1048 : // overread is not applicable
1049 : auto const n0 =
1050 4622 : fb_.capacity() - h_.size +
1051 4622 : svc_.cfg.min_buffer +
1052 4622 : svc_.max_codec;
1053 4622 : BOOST_ASSERT(n0 <= ws_.size());
1054 4622 : cb0_ = {
1055 4622 : ws_.data(),
1056 : n0,
1057 : overread };
1058 4622 : body_buf_ = &cb0_;
1059 4622 : body_avail_ = cb0_.size();
1060 4622 : body_total_ = body_avail_;
1061 4622 : st_ = state::body;
1062 4622 : return;
1063 : }
1064 :
1065 : // buffered payload
1066 : auto const n0 =
1067 0 : fb_.capacity() - h_.size;
1068 0 : BOOST_ASSERT(
1069 : n0 <= svc_.max_overread());
1070 0 : auto n1 = svc_.cfg.min_buffer;
1071 0 : if(! filt_)
1072 0 : n1 += svc_.max_codec;
1073 0 : BOOST_ASSERT(
1074 : n0 + n1 <= ws_.size());
1075 0 : cb0_ = {
1076 0 : ws_.data(),
1077 : n0,
1078 : overread };
1079 0 : cb1_ = {
1080 0 : ws_.data() + n0,
1081 : n1 };
1082 0 : body_buf_ = &cb1_;
1083 0 : body_avail_ = 0;
1084 0 : body_total_ = 0;
1085 0 : st_ = state::body;
1086 0 : return;
1087 : }
1088 :
1089 : // Called at the end of set_body
1090 : void
1091 6775 : parser::
1092 : on_set_body()
1093 : {
1094 : // This function is called after all
1095 : // limit checking and calculation of
1096 : // chunked or filter.
1097 :
1098 6775 : BOOST_ASSERT(got_header());
1099 :
1100 : // VFALCO review this hack
1101 6775 : if(! is_plain())
1102 741 : return;
1103 :
1104 : // plain payload
1105 :
1106 6034 : if(how_ == how::dynamic)
1107 : {
1108 6034 : if(h_.md.payload == payload::none)
1109 : {
1110 0 : st_ = state::complete;
1111 0 : return;
1112 : }
1113 6034 : auto n = body_avail_;
1114 6034 : BOOST_ASSERT(n <= body_buf_->size());
1115 : auto const space_left =
1116 6034 : dyn_->max_size() - dyn_->size();
1117 6034 : if( n > space_left)
1118 630 : n = space_left;
1119 6034 : if(h_.md.payload == payload::size)
1120 : {
1121 3723 : if( n > h_.md.payload_size)
1122 0 : n = h_.md.payload_size;
1123 : // reserve space
1124 3723 : if(space_left >= h_.md.payload_size)
1125 3723 : dyn_->prepare(h_.md.payload_size);
1126 : else
1127 0 : dyn_->prepare(space_left);
1128 : }
1129 6034 : dyn_->commit(
1130 : buffers::buffer_copy(
1131 6034 : dyn_->prepare(n),
1132 6034 : body_buf_->data()));
1133 6034 : body_buf_->consume(n);
1134 6034 : body_avail_ -= n;
1135 : // VFALCO maybe update payload_remain_ here
1136 6034 : if( h_.md.payload == payload::size)
1137 : {
1138 3723 : if(n < h_.md.payload_size)
1139 : {
1140 585 : BOOST_ASSERT(
1141 : payload_remain_ > 0);
1142 585 : return;
1143 : }
1144 3138 : BOOST_ASSERT(
1145 : n == h_.md.payload_size);
1146 : // complete
1147 3138 : BOOST_ASSERT(
1148 : payload_remain_ == 0);
1149 3138 : BOOST_ASSERT(body_avail_ == 0);
1150 3138 : BOOST_ASSERT(body_total_ == n);
1151 3138 : st_ = state::complete;
1152 3138 : return;
1153 : }
1154 :
1155 2311 : st_ = state::body;
1156 2311 : return;
1157 : }
1158 :
1159 0 : if(how_ == how::sink)
1160 : {
1161 : // handle this in prepare() where
1162 : // we can return an error_code.
1163 0 : st_ = state::body_set;
1164 0 : return;
1165 : }
1166 :
1167 : // VFALCO TODO
1168 0 : st_ = state::body_set;
1169 0 : detail::throw_logic_error();
1170 : }
1171 :
1172 : } // http_proto
1173 : } // boost
1174 :
1175 : #endif
|