File indexing completed on 2025-01-18 09:29:29
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_IPP
0011 #define BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_IPP
0012
0013 #include <boost/beast/http/basic_parser.hpp>
0014 #include <boost/beast/http/error.hpp>
0015 #include <boost/beast/http/rfc7230.hpp>
0016 #include <boost/beast/core/buffer_traits.hpp>
0017 #include <boost/beast/core/detail/clamp.hpp>
0018 #include <boost/beast/core/detail/config.hpp>
0019 #include <boost/beast/core/detail/string.hpp>
0020 #include <boost/asio/buffer.hpp>
0021 #include <algorithm>
0022 #include <utility>
0023
0024 namespace boost {
0025 namespace beast {
0026 namespace http {
0027
0028 template<bool isRequest>
0029 bool
0030 basic_parser<isRequest>::
0031 keep_alive() const
0032 {
0033 BOOST_ASSERT(is_header_done());
0034 if(f_ & flagHTTP11)
0035 {
0036 if(f_ & flagConnectionClose)
0037 return false;
0038 }
0039 else
0040 {
0041 if(! (f_ & flagConnectionKeepAlive))
0042 return false;
0043 }
0044 return (f_ & flagNeedEOF) == 0;
0045 }
0046
0047 template<bool isRequest>
0048 boost::optional<std::uint64_t>
0049 basic_parser<isRequest>::
0050 content_length() const
0051 {
0052 BOOST_ASSERT(is_header_done());
0053 return content_length_unchecked();
0054 }
0055
0056 template<bool isRequest>
0057 boost::optional<std::uint64_t>
0058 basic_parser<isRequest>::
0059 content_length_remaining() const
0060 {
0061 BOOST_ASSERT(is_header_done());
0062 if(! (f_ & flagContentLength))
0063 return boost::none;
0064 return len_;
0065 }
0066
0067 template<bool isRequest>
0068 void
0069 basic_parser<isRequest>::
0070 skip(bool v)
0071 {
0072 BOOST_ASSERT(! got_some());
0073 if(v)
0074 f_ |= flagSkipBody;
0075 else
0076 f_ &= ~flagSkipBody;
0077 }
0078
0079 template<bool isRequest>
0080 std::size_t
0081 basic_parser<isRequest>::
0082 put(net::const_buffer buffer,
0083 error_code& ec)
0084 {
0085
0086
0087
0088
0089
0090 BOOST_ASSERT(!is_done());
0091 if (is_done())
0092 {
0093 BOOST_BEAST_ASSIGN_EC(ec, error::stale_parser);
0094 return 0;
0095 }
0096 auto p = static_cast<char const*>(buffer.data());
0097 auto n = buffer.size();
0098 auto const p0 = p;
0099 auto const p1 = p0 + n;
0100 ec = {};
0101 loop:
0102 switch(state_)
0103 {
0104 case state::nothing_yet:
0105 if(n == 0)
0106 {
0107 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0108 return 0;
0109 }
0110 state_ = state::start_line;
0111 BOOST_FALLTHROUGH;
0112
0113 case state::start_line:
0114 {
0115 maybe_need_more(p, n, ec);
0116 if(ec)
0117 goto done;
0118 parse_start_line(p, p + (std::min<std::size_t>)(
0119 header_limit_, n), ec, is_request{});
0120 if(ec)
0121 {
0122 if(ec == error::need_more)
0123 {
0124 if(n >= header_limit_)
0125 {
0126 BOOST_BEAST_ASSIGN_EC(ec, error::header_limit);
0127 goto done;
0128 }
0129 if(p + 3 <= p1)
0130 skip_ = static_cast<
0131 std::size_t>(p1 - p - 3);
0132 }
0133 goto done;
0134 }
0135 BOOST_ASSERT(! is_done());
0136 n = static_cast<std::size_t>(p1 - p);
0137 if(p >= p1)
0138 {
0139 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0140 goto done;
0141 }
0142 BOOST_FALLTHROUGH;
0143 }
0144
0145 case state::fields:
0146 maybe_need_more(p, n, ec);
0147 if(ec)
0148 goto done;
0149 parse_fields(p, p + (std::min<std::size_t>)(
0150 header_limit_, n), ec);
0151 if(ec)
0152 {
0153 if(ec == error::need_more)
0154 {
0155 if(n >= header_limit_)
0156 {
0157 BOOST_BEAST_ASSIGN_EC(ec, error::header_limit);
0158 goto done;
0159 }
0160 if(p + 3 <= p1)
0161 skip_ = static_cast<
0162 std::size_t>(p1 - p - 3);
0163 }
0164 goto done;
0165 }
0166 finish_header(ec, is_request{});
0167 if(ec)
0168 goto done;
0169 break;
0170
0171 case state::body0:
0172 BOOST_ASSERT(! skip_);
0173 this->on_body_init_impl(content_length(), ec);
0174 if(ec)
0175 goto done;
0176 state_ = state::body;
0177 BOOST_FALLTHROUGH;
0178
0179 case state::body:
0180 BOOST_ASSERT(! skip_);
0181 parse_body(p, n, ec);
0182 if(ec)
0183 goto done;
0184 break;
0185
0186 case state::body_to_eof0:
0187 BOOST_ASSERT(! skip_);
0188 this->on_body_init_impl(content_length(), ec);
0189 if(ec)
0190 goto done;
0191 state_ = state::body_to_eof;
0192 BOOST_FALLTHROUGH;
0193
0194 case state::body_to_eof:
0195 BOOST_ASSERT(! skip_);
0196 parse_body_to_eof(p, n, ec);
0197 if(ec)
0198 goto done;
0199 break;
0200
0201 case state::chunk_header0:
0202 this->on_body_init_impl(content_length(), ec);
0203 if(ec)
0204 goto done;
0205 state_ = state::chunk_header;
0206 BOOST_FALLTHROUGH;
0207
0208 case state::chunk_header:
0209 parse_chunk_header(p, n, ec);
0210 if(ec)
0211 goto done;
0212 break;
0213
0214 case state::chunk_body:
0215 parse_chunk_body(p, n, ec);
0216 if(ec)
0217 goto done;
0218 break;
0219
0220 case state::complete:
0221 ec = {};
0222 goto done;
0223 }
0224 if(p < p1 && ! is_done() && eager())
0225 {
0226 n = static_cast<std::size_t>(p1 - p);
0227 goto loop;
0228 }
0229 done:
0230 return static_cast<std::size_t>(p - p0);
0231 }
0232
0233 template<bool isRequest>
0234 void
0235 basic_parser<isRequest>::
0236 put_eof(error_code& ec)
0237 {
0238 BOOST_ASSERT(got_some());
0239 if( state_ == state::start_line ||
0240 state_ == state::fields)
0241 {
0242 BOOST_BEAST_ASSIGN_EC(ec, error::partial_message);
0243 return;
0244 }
0245 if(f_ & (flagContentLength | flagChunked))
0246 {
0247 if(state_ != state::complete)
0248 {
0249 BOOST_BEAST_ASSIGN_EC(ec, error::partial_message);
0250 return;
0251 }
0252 ec = {};
0253 return;
0254 }
0255 ec = {};
0256 this->on_finish_impl(ec);
0257 if(ec)
0258 return;
0259 state_ = state::complete;
0260 }
0261
0262 template<bool isRequest>
0263 void
0264 basic_parser<isRequest>::
0265 maybe_need_more(
0266 char const* p, std::size_t n,
0267 error_code& ec)
0268 {
0269 if(skip_ == 0)
0270 return;
0271 if( n > header_limit_)
0272 n = header_limit_;
0273 if(n < skip_ + 4)
0274 {
0275 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0276 return;
0277 }
0278 auto const term =
0279 find_eom(p + skip_, p + n);
0280 if(! term)
0281 {
0282 skip_ = n - 3;
0283 if(skip_ + 4 > header_limit_)
0284 {
0285 BOOST_BEAST_ASSIGN_EC(ec, error::header_limit);
0286 return;
0287 }
0288 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0289 return;
0290 }
0291 skip_ = 0;
0292 }
0293
0294 template<bool isRequest>
0295 void
0296 basic_parser<isRequest>::
0297 parse_start_line(
0298 char const*& in, char const* last,
0299 error_code& ec, std::true_type)
0300 {
0301
0302
0303
0304
0305 auto p = in;
0306
0307 string_view method;
0308 parse_method(p, last, method, ec);
0309 if(ec)
0310 return;
0311
0312 string_view target;
0313 parse_target(p, last, target, ec);
0314 if(ec)
0315 return;
0316
0317 int version = 0;
0318 parse_version(p, last, version, ec);
0319 if(ec)
0320 return;
0321 if(version < 10 || version > 11)
0322 {
0323 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0324 return;
0325 }
0326
0327 if(p + 2 > last)
0328 {
0329 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0330 return;
0331 }
0332 if(p[0] != '\r' || p[1] != '\n')
0333 {
0334 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0335 return;
0336 }
0337 p += 2;
0338
0339 if(version >= 11)
0340 f_ |= flagHTTP11;
0341
0342 this->on_request_impl(string_to_verb(method),
0343 method, target, version, ec);
0344 if(ec)
0345 return;
0346
0347 in = p;
0348 state_ = state::fields;
0349 }
0350
0351 template<bool isRequest>
0352 void
0353 basic_parser<isRequest>::
0354 parse_start_line(
0355 char const*& in, char const* last,
0356 error_code& ec, std::false_type)
0357 {
0358
0359
0360
0361
0362
0363 auto p = in;
0364
0365 int version = 0;
0366 parse_version(p, last, version, ec);
0367 if(ec)
0368 return;
0369 if(version < 10 || version > 11)
0370 {
0371 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0372 return;
0373 }
0374
0375
0376 if(p + 1 > last)
0377 {
0378 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0379 return;
0380 }
0381 if(*p++ != ' ')
0382 {
0383 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0384 return;
0385 }
0386
0387 parse_status(p, last, status_, ec);
0388 if(ec)
0389 return;
0390
0391
0392 string_view reason;
0393 parse_reason(p, last, reason, ec);
0394 if(ec)
0395 return;
0396
0397 if(version >= 11)
0398 f_ |= flagHTTP11;
0399
0400 this->on_response_impl(
0401 status_, reason, version, ec);
0402 if(ec)
0403 return;
0404
0405 in = p;
0406 state_ = state::fields;
0407 }
0408
0409 template<bool isRequest>
0410 void
0411 basic_parser<isRequest>::
0412 parse_fields(char const*& in,
0413 char const* last, error_code& ec)
0414 {
0415 string_view name;
0416 string_view value;
0417
0418 beast::detail::char_buffer<max_obs_fold> buf;
0419 auto p = in;
0420 for(;;)
0421 {
0422 if(p + 2 > last)
0423 {
0424 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0425 return;
0426 }
0427 if(p[0] == '\r')
0428 {
0429 if(p[1] != '\n')
0430 {
0431 BOOST_BEAST_ASSIGN_EC(ec, error::bad_line_ending);
0432 }
0433 in = p + 2;
0434 return;
0435 }
0436 parse_field(p, last, name, value, buf, ec);
0437 if(ec)
0438 return;
0439 auto const f = string_to_field(name);
0440 do_field(f, value, ec);
0441 if(ec)
0442 return;
0443 this->on_field_impl(f, name, value, ec);
0444 if(ec)
0445 return;
0446 in = p;
0447 }
0448 }
0449
0450 template<bool isRequest>
0451 void
0452 basic_parser<isRequest>::
0453 finish_header(error_code& ec, std::true_type)
0454 {
0455
0456
0457
0458 if(f_ & flagSkipBody)
0459 {
0460 state_ = state::complete;
0461 }
0462 else if(f_ & flagContentLength)
0463 {
0464 if(body_limit_.has_value() &&
0465 len_ > body_limit_)
0466 {
0467 BOOST_BEAST_ASSIGN_EC(ec, error::body_limit);
0468 return;
0469 }
0470 if(len_ > 0)
0471 {
0472 f_ |= flagHasBody;
0473 state_ = state::body0;
0474 }
0475 else
0476 {
0477 state_ = state::complete;
0478 }
0479 }
0480 else if(f_ & flagChunked)
0481 {
0482 f_ |= flagHasBody;
0483 state_ = state::chunk_header0;
0484 }
0485 else
0486 {
0487 len_ = 0;
0488 len0_ = 0;
0489 state_ = state::complete;
0490 }
0491
0492 ec = {};
0493 this->on_header_impl(ec);
0494 if(ec)
0495 return;
0496 if(state_ == state::complete)
0497 {
0498 this->on_finish_impl(ec);
0499 if(ec)
0500 return;
0501 }
0502 }
0503
0504 template<bool isRequest>
0505 void
0506 basic_parser<isRequest>::
0507 finish_header(error_code& ec, std::false_type)
0508 {
0509
0510
0511
0512 if( (f_ & flagSkipBody) ||
0513 status_ / 100 == 1 ||
0514 status_ == 204 ||
0515 status_ == 304)
0516 {
0517
0518
0519
0520 state_ = state::complete;
0521 }
0522 else if(f_ & flagContentLength)
0523 {
0524 if(len_ > 0)
0525 {
0526 f_ |= flagHasBody;
0527 state_ = state::body0;
0528
0529 if(body_limit_.has_value() &&
0530 len_ > body_limit_)
0531 {
0532 BOOST_BEAST_ASSIGN_EC(ec, error::body_limit);
0533 return;
0534 }
0535 }
0536 else
0537 {
0538 state_ = state::complete;
0539 }
0540 }
0541 else if(f_ & flagChunked)
0542 {
0543 f_ |= flagHasBody;
0544 state_ = state::chunk_header0;
0545 }
0546 else
0547 {
0548 f_ |= flagHasBody;
0549 f_ |= flagNeedEOF;
0550 state_ = state::body_to_eof0;
0551 }
0552
0553 ec = {};
0554 this->on_header_impl(ec);
0555 if(ec)
0556 return;
0557 if(state_ == state::complete)
0558 {
0559 this->on_finish_impl(ec);
0560 if(ec)
0561 return;
0562 }
0563 }
0564
0565 template<bool isRequest>
0566 void
0567 basic_parser<isRequest>::
0568 parse_body(char const*& p,
0569 std::size_t n, error_code& ec)
0570 {
0571 ec = {};
0572 n = this->on_body_impl(string_view{p,
0573 beast::detail::clamp(len_, n)}, ec);
0574 p += n;
0575 len_ -= n;
0576 if(ec)
0577 return;
0578 if(len_ > 0)
0579 return;
0580 this->on_finish_impl(ec);
0581 if(ec)
0582 return;
0583 state_ = state::complete;
0584 }
0585
0586 template<bool isRequest>
0587 void
0588 basic_parser<isRequest>::
0589 parse_body_to_eof(char const*& p,
0590 std::size_t n, error_code& ec)
0591 {
0592 if(body_limit_.has_value())
0593 {
0594 if (n > *body_limit_)
0595 {
0596 BOOST_BEAST_ASSIGN_EC(ec, error::body_limit);
0597 return;
0598 }
0599 *body_limit_ -= n;
0600 }
0601 ec = {};
0602 n = this->on_body_impl(string_view{p, n}, ec);
0603 p += n;
0604 if(ec)
0605 return;
0606 }
0607
0608 template<bool isRequest>
0609 void
0610 basic_parser<isRequest>::
0611 parse_chunk_header(char const*& p0,
0612 std::size_t n, error_code& ec)
0613 {
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628 auto p = p0;
0629 auto const pend = p + n;
0630 char const* eol;
0631
0632 if(! (f_ & flagFinalChunk))
0633 {
0634 if(n < skip_ + 2)
0635 {
0636 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0637 return;
0638 }
0639 if(f_ & flagExpectCRLF)
0640 {
0641
0642
0643
0644 if(! parse_crlf(p))
0645 {
0646 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk);
0647 return;
0648 }
0649 }
0650 eol = find_eol(p0 + skip_, pend, ec);
0651 if(ec)
0652 return;
0653 if(! eol)
0654 {
0655 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0656 skip_ = n - 1;
0657 return;
0658 }
0659 skip_ = static_cast<
0660 std::size_t>(eol - 2 - p0);
0661
0662 std::uint64_t size;
0663 if(! parse_hex(p, size))
0664 {
0665 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk);
0666 return;
0667 }
0668 if(size != 0)
0669 {
0670 if (body_limit_.has_value())
0671 {
0672 if (size > *body_limit_)
0673 {
0674 BOOST_BEAST_ASSIGN_EC(ec, error::body_limit);
0675 return;
0676 }
0677 *body_limit_ -= size;
0678 }
0679 auto const start = p;
0680 parse_chunk_extensions(p, pend, ec);
0681 if(ec)
0682 return;
0683 if(p != eol -2 )
0684 {
0685 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0686 return;
0687 }
0688 auto const ext = make_string(start, p);
0689 this->on_chunk_header_impl(size, ext, ec);
0690 if(ec)
0691 return;
0692 len_ = size;
0693 skip_ = 2;
0694 p0 = eol;
0695 f_ |= flagExpectCRLF;
0696 state_ = state::chunk_body;
0697 return;
0698 }
0699
0700 f_ |= flagFinalChunk;
0701 }
0702 else
0703 {
0704 BOOST_ASSERT(n >= 5);
0705 if(f_ & flagExpectCRLF)
0706 BOOST_VERIFY(parse_crlf(p));
0707 std::uint64_t size;
0708 BOOST_VERIFY(parse_hex(p, size));
0709 eol = find_eol(p, pend, ec);
0710 BOOST_ASSERT(! ec);
0711 }
0712
0713 auto eom = find_eom(p0 + skip_, pend);
0714 if(! eom)
0715 {
0716 BOOST_ASSERT(n >= 3);
0717 skip_ = n - 3;
0718 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0719 return;
0720 }
0721
0722 auto const start = p;
0723 parse_chunk_extensions(p, pend, ec);
0724 if(ec)
0725 return;
0726 if(p != eol - 2)
0727 {
0728 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0729 return;
0730 }
0731 auto const ext = make_string(start, p);
0732 this->on_chunk_header_impl(0, ext, ec);
0733 if(ec)
0734 return;
0735 p = eol;
0736 parse_fields(p, eom, ec);
0737 if(ec)
0738 return;
0739 BOOST_ASSERT(p == eom);
0740 p0 = eom;
0741
0742 this->on_finish_impl(ec);
0743 if(ec)
0744 return;
0745 state_ = state::complete;
0746 }
0747
0748 template<bool isRequest>
0749 void
0750 basic_parser<isRequest>::
0751 parse_chunk_body(char const*& p,
0752 std::size_t n, error_code& ec)
0753 {
0754 ec = {};
0755 n = this->on_chunk_body_impl(
0756 len_, string_view{p,
0757 beast::detail::clamp(len_, n)}, ec);
0758 p += n;
0759 len_ -= n;
0760 if(len_ == 0)
0761 state_ = state::chunk_header;
0762 }
0763
0764 template<bool isRequest>
0765 void
0766 basic_parser<isRequest>::
0767 do_field(field f,
0768 string_view value, error_code& ec)
0769 {
0770 using namespace beast::detail::string_literals;
0771
0772 if(f == field::connection ||
0773 f == field::proxy_connection)
0774 {
0775 auto const list = opt_token_list{value};
0776 if(! validate_list(list))
0777 {
0778
0779 BOOST_BEAST_ASSIGN_EC(ec, error::bad_value);
0780 return;
0781 }
0782 for(auto const& s : list)
0783 {
0784 if(beast::iequals("close"_sv, s))
0785 {
0786 f_ |= flagConnectionClose;
0787 continue;
0788 }
0789
0790 if(beast::iequals("keep-alive"_sv, s))
0791 {
0792 f_ |= flagConnectionKeepAlive;
0793 continue;
0794 }
0795
0796 if(beast::iequals("upgrade"_sv, s))
0797 {
0798 f_ |= flagConnectionUpgrade;
0799 continue;
0800 }
0801 }
0802 ec = {};
0803 return;
0804 }
0805
0806
0807 if(f == field::content_length)
0808 {
0809 auto bad_content_length = [&ec]
0810 {
0811 BOOST_BEAST_ASSIGN_EC(ec, error::bad_content_length);
0812 };
0813
0814 auto multiple_content_length = [&ec]
0815 {
0816 BOOST_BEAST_ASSIGN_EC(ec, error::multiple_content_length);
0817 };
0818
0819
0820 if(f_ & flagChunked)
0821 return bad_content_length();
0822
0823
0824 auto tokens_unprocessed = 1 +
0825 std::count(value.begin(), value.end(), ',');
0826 auto tokens = opt_token_list(value);
0827 if (tokens.begin() == tokens.end() ||
0828 !validate_list(tokens))
0829 return bad_content_length();
0830
0831 auto existing = this->content_length_unchecked();
0832 for (auto tok : tokens)
0833 {
0834 std::uint64_t v;
0835 if (!parse_dec(tok, v))
0836 return bad_content_length();
0837 --tokens_unprocessed;
0838 if (existing.has_value())
0839 {
0840 if (v != *existing)
0841 return multiple_content_length();
0842 }
0843 else
0844 {
0845 existing = v;
0846 }
0847 }
0848
0849 if (tokens_unprocessed)
0850 return bad_content_length();
0851
0852 BOOST_ASSERT(existing.has_value());
0853 ec = {};
0854 len_ = *existing;
0855 len0_ = *existing;
0856 f_ |= flagContentLength;
0857 return;
0858 }
0859
0860
0861 if(f == field::transfer_encoding)
0862 {
0863 if(f_ & flagChunked)
0864 {
0865
0866 BOOST_BEAST_ASSIGN_EC(ec, error::bad_transfer_encoding);
0867 return;
0868 }
0869
0870 if(f_ & flagContentLength)
0871 {
0872
0873 BOOST_BEAST_ASSIGN_EC(ec, error::bad_transfer_encoding);
0874 return;
0875 }
0876
0877 ec = {};
0878 auto const v = token_list{value};
0879 auto const p = std::find_if(v.begin(), v.end(),
0880 [&](string_view const& s)
0881 {
0882 return beast::iequals("chunked"_sv, s);
0883 });
0884 if(p == v.end())
0885 return;
0886 if(std::next(p) != v.end())
0887 return;
0888 len_ = 0;
0889 f_ |= flagChunked;
0890 return;
0891 }
0892
0893
0894 if(f == field::upgrade)
0895 {
0896 ec = {};
0897 f_ |= flagUpgrade;
0898 return;
0899 }
0900
0901 ec = {};
0902 }
0903
0904 #ifdef BOOST_BEAST_SOURCE
0905 template class http::basic_parser<true>;
0906 template class http::basic_parser<false>;
0907 #endif
0908
0909 }
0910 }
0911 }
0912
0913 #endif