File indexing completed on 2025-12-16 09:43:59
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_HTTP_DETAIL_BASIC_PARSER_IPP
0011 #define BOOST_BEAST_HTTP_DETAIL_BASIC_PARSER_IPP
0012
0013 #include <boost/beast/http/detail/basic_parser.hpp>
0014 #include <limits>
0015
0016 namespace boost {
0017 namespace beast {
0018 namespace http {
0019 namespace detail {
0020
0021 char const*
0022 basic_parser_base::
0023 trim_front(char const* it, char const* end)
0024 {
0025 while(it != end)
0026 {
0027 if(*it != ' ' && *it != '\t')
0028 break;
0029 ++it;
0030 }
0031 return it;
0032 }
0033
0034 char const*
0035 basic_parser_base::
0036 trim_back(
0037 char const* it, char const* first)
0038 {
0039 while(it != first)
0040 {
0041 auto const c = it[-1];
0042 if(c != ' ' && c != '\t')
0043 break;
0044 --it;
0045 }
0046 return it;
0047 }
0048
0049 bool
0050 basic_parser_base::
0051 is_pathchar(char c)
0052 {
0053
0054
0055
0056 static bool constexpr tab[256] = {
0057 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0058 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0059 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0060 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0061 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0062 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0063 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0064 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0065 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0066 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0067 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0068 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0069 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0070 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0071 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0072 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
0073 };
0074 return tab[static_cast<unsigned char>(c)];
0075 }
0076
0077 bool
0078 basic_parser_base::
0079 unhex(unsigned char& d, char c)
0080 {
0081 static signed char constexpr tab[256] = {
0082 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0083 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0084 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0085 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
0086 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0087 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0088 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0089 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0090
0091 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0092 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0093 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0094 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0095 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0096 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0097 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0098 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
0099 };
0100 d = static_cast<unsigned char>(
0101 tab[static_cast<unsigned char>(c)]);
0102 return d != static_cast<unsigned char>(-1);
0103 }
0104
0105
0106
0107 std::pair<char const*, bool>
0108 basic_parser_base::
0109 find_fast(
0110 char const* buf,
0111 char const* buf_end,
0112 char const* ranges,
0113 size_t ranges_size)
0114 {
0115 bool found = false;
0116 boost::ignore_unused(buf_end, ranges, ranges_size);
0117 return {buf, found};
0118 }
0119
0120
0121 char const*
0122 basic_parser_base::
0123 find_eol(
0124 char const* it, char const* last,
0125 error_code& ec)
0126 {
0127 for(;;)
0128 {
0129 if(it == last)
0130 {
0131 ec = {};
0132 return nullptr;
0133 }
0134 if(*it == '\r')
0135 {
0136 if(++it == last)
0137 {
0138 ec = {};
0139 return nullptr;
0140 }
0141 if(*it != '\n')
0142 {
0143 BOOST_BEAST_ASSIGN_EC(ec, error::bad_line_ending);
0144 return nullptr;
0145 }
0146 ec = {};
0147 return ++it;
0148 }
0149
0150
0151 ++it;
0152 }
0153 }
0154
0155 bool
0156 basic_parser_base::
0157 parse_dec(
0158 string_view s,
0159 std::uint64_t& v)
0160 {
0161 char const* it = s.data();
0162 char const* last = it + s.size();
0163 if(it == last)
0164 return false;
0165 std::uint64_t tmp = 0;
0166 do
0167 {
0168 if((! is_digit(*it)) ||
0169 tmp > (std::numeric_limits<std::uint64_t>::max)() / 10)
0170 return false;
0171 tmp *= 10;
0172 std::uint64_t const d = *it - '0';
0173 if((std::numeric_limits<std::uint64_t>::max)() - tmp < d)
0174 return false;
0175 tmp += d;
0176 }
0177 while(++it != last);
0178 v = tmp;
0179 return true;
0180 }
0181
0182 bool
0183 basic_parser_base::
0184 parse_hex(char const*& it, std::uint64_t& v)
0185 {
0186 unsigned char d;
0187 if(! unhex(d, *it))
0188 return false;
0189 std::uint64_t tmp = 0;
0190 do
0191 {
0192 if(tmp > (std::numeric_limits<std::uint64_t>::max)() / 16)
0193 return false;
0194 tmp *= 16;
0195 if((std::numeric_limits<std::uint64_t>::max)() - tmp < d)
0196 return false;
0197 tmp += d;
0198 }
0199 while(unhex(d, *++it));
0200 v = tmp;
0201 return true;
0202 }
0203
0204
0205
0206 char const*
0207 basic_parser_base::
0208 parse_token_to_eol(
0209 char const* p,
0210 char const* last,
0211 char const*& token_last,
0212 error_code& ec)
0213 {
0214 for(;; ++p)
0215 {
0216 if(p >= last)
0217 {
0218 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0219 return p;
0220 }
0221 if(BOOST_UNLIKELY(! is_print(*p)))
0222 if((BOOST_LIKELY(static_cast<
0223 unsigned char>(*p) < '\040') &&
0224 BOOST_LIKELY(*p != 9)) ||
0225 BOOST_UNLIKELY(*p == 127))
0226 goto found_control;
0227 }
0228 found_control:
0229 if(BOOST_LIKELY(*p == '\r'))
0230 {
0231 if(++p >= last)
0232 {
0233 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0234 return last;
0235 }
0236 if(*p++ != '\n')
0237 {
0238 BOOST_BEAST_ASSIGN_EC(ec, error::bad_line_ending);
0239 return last;
0240 }
0241 token_last = p - 2;
0242 }
0243 #if 0
0244
0245
0246 else if(*p == '\n')
0247 {
0248 token_last = p;
0249 ++p;
0250 }
0251 #endif
0252 else
0253 {
0254
0255 return nullptr;
0256 }
0257 return p;
0258 }
0259
0260 bool
0261 basic_parser_base::
0262 parse_crlf(char const*& it)
0263 {
0264 if( it[0] != '\r' || it[1] != '\n')
0265 return false;
0266 it += 2;
0267 return true;
0268 }
0269
0270 void
0271 basic_parser_base::
0272 parse_method(
0273 char const*& it, char const* last,
0274 string_view& result, error_code& ec)
0275 {
0276
0277 auto const first = it;
0278 for(;; ++it)
0279 {
0280 if(it + 1 > last)
0281 {
0282 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0283 return;
0284 }
0285 if(! detail::is_token_char(*it))
0286 break;
0287 }
0288 if(it + 1 > last)
0289 {
0290 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0291 return;
0292 }
0293 if(*it != ' ')
0294 {
0295 BOOST_BEAST_ASSIGN_EC(ec, error::bad_method);
0296 return;
0297 }
0298 if(it == first)
0299 {
0300
0301 BOOST_BEAST_ASSIGN_EC(ec, error::bad_method);
0302 return;
0303 }
0304 result = make_string(first, it++);
0305 }
0306
0307 void
0308 basic_parser_base::
0309 parse_target(
0310 char const*& it, char const* last,
0311 string_view& result, error_code& ec)
0312 {
0313
0314 auto const first = it;
0315 for(;; ++it)
0316 {
0317 if(it + 1 > last)
0318 {
0319 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0320 return;
0321 }
0322 if(! is_pathchar(*it))
0323 break;
0324 }
0325 if(it + 1 > last)
0326 {
0327 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0328 return;
0329 }
0330 if(*it != ' ')
0331 {
0332 BOOST_BEAST_ASSIGN_EC(ec, error::bad_target);
0333 return;
0334 }
0335 if(it == first)
0336 {
0337
0338 BOOST_BEAST_ASSIGN_EC(ec, error::bad_target);
0339 return;
0340 }
0341 result = make_string(first, it++);
0342 }
0343
0344 void
0345 basic_parser_base::
0346 parse_version(
0347 char const*& it, char const* last,
0348 int& result, error_code& ec)
0349 {
0350 if(it + 8 > last)
0351 {
0352 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0353 return;
0354 }
0355 if(*it++ != 'H')
0356 {
0357 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0358 return;
0359 }
0360 if(*it++ != 'T')
0361 {
0362 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0363 return;
0364 }
0365 if(*it++ != 'T')
0366 {
0367 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0368 return;
0369 }
0370 if(*it++ != 'P')
0371 {
0372 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0373 return;
0374 }
0375 if(*it++ != '/')
0376 {
0377 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0378 return;
0379 }
0380 if(! is_digit(*it))
0381 {
0382 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0383 return;
0384 }
0385 result = 10 * (*it++ - '0');
0386 if(*it++ != '.')
0387 {
0388 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0389 return;
0390 }
0391 if(! is_digit(*it))
0392 {
0393 BOOST_BEAST_ASSIGN_EC(ec, error::bad_version);
0394 return;
0395 }
0396 result += *it++ - '0';
0397 }
0398
0399 void
0400 basic_parser_base::
0401 parse_status(
0402 char const*& it, char const* last,
0403 unsigned short& result, error_code& ec)
0404 {
0405
0406 if(it + 4 > last)
0407 {
0408 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0409 return;
0410 }
0411 if(! is_digit(*it))
0412 {
0413 BOOST_BEAST_ASSIGN_EC(ec, error::bad_status);
0414 return;
0415 }
0416 result = 100 * (*it++ - '0');
0417 if(! is_digit(*it))
0418 {
0419 BOOST_BEAST_ASSIGN_EC(ec, error::bad_status);
0420 return;
0421 }
0422 result += 10 * (*it++ - '0');
0423 if(! is_digit(*it))
0424 {
0425 BOOST_BEAST_ASSIGN_EC(ec, error::bad_status);
0426 return;
0427 }
0428 result += *it++ - '0';
0429 if(*it++ != ' ')
0430 {
0431 BOOST_BEAST_ASSIGN_EC(ec, error::bad_status);
0432 return;
0433 }
0434 }
0435
0436 void
0437 basic_parser_base::
0438 parse_reason(
0439 char const*& it, char const* last,
0440 string_view& result, error_code& ec)
0441 {
0442 auto const first = it;
0443 char const* token_last = nullptr;
0444 auto p = parse_token_to_eol(
0445 it, last, token_last, ec);
0446 if(ec)
0447 return;
0448 if(! p)
0449 {
0450 BOOST_BEAST_ASSIGN_EC(ec, error::bad_reason);
0451 return;
0452 }
0453 result = make_string(first, token_last);
0454 it = p;
0455 }
0456
0457 void
0458 basic_parser_base::
0459 parse_field(
0460 char const*& p,
0461 char const* last,
0462 string_view& name,
0463 string_view& value,
0464 beast::detail::char_buffer<max_obs_fold>& buf,
0465 error_code& ec)
0466 {
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485 static char const* is_token =
0486 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
0487 "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0"
0488 "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1"
0489 "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0"
0490 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
0491 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
0492 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
0493 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
0494
0495
0496 BOOST_ALIGNMENT(16) static const char ranges1[] =
0497 "\x00 "
0498 "\"\""
0499 "()"
0500 ",,"
0501 "//"
0502 ":@"
0503 "[]"
0504 "{\377";
0505 auto first = p;
0506 bool found;
0507 std::tie(p, found) = find_fast(
0508 p, last, ranges1, sizeof(ranges1)-1);
0509 if(! found && p >= last)
0510 {
0511 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0512 return;
0513 }
0514 for(;;)
0515 {
0516 if(*p == ':')
0517 break;
0518 if(! is_token[static_cast<
0519 unsigned char>(*p)])
0520 {
0521 BOOST_BEAST_ASSIGN_EC(ec, error::bad_field);
0522 return;
0523 }
0524 ++p;
0525 if(p >= last)
0526 {
0527 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0528 return;
0529 }
0530 }
0531 if(p == first)
0532 {
0533
0534 BOOST_BEAST_ASSIGN_EC(ec, error::bad_field);
0535 return;
0536 }
0537 name = make_string(first, p);
0538 ++p;
0539 char const* token_last = nullptr;
0540 for(;;)
0541 {
0542
0543 for(;;++p)
0544 {
0545 if(p + 1 > last)
0546 {
0547 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0548 return;
0549 }
0550 if(! (*p == ' ' || *p == '\t'))
0551 break;
0552 }
0553
0554 first = p;
0555 p = parse_token_to_eol(p, last, token_last, ec);
0556 if(ec)
0557 return;
0558 if(! p)
0559 {
0560 BOOST_BEAST_ASSIGN_EC(ec, error::bad_value);
0561 return;
0562 }
0563
0564 if(p + 1 > last)
0565 {
0566 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0567 return;
0568 }
0569 token_last =
0570 trim_back(token_last, first);
0571 if(*p != ' ' && *p != '\t')
0572 {
0573 value = make_string(first, token_last);
0574 return;
0575 }
0576 ++p;
0577 if(token_last != first)
0578 break;
0579 }
0580 buf.clear();
0581 if (!buf.try_append(first, token_last))
0582 {
0583 BOOST_BEAST_ASSIGN_EC(ec, error::header_limit);
0584 return;
0585 }
0586
0587 BOOST_ASSERT(! buf.empty());
0588 for(;;)
0589 {
0590
0591 for(;;++p)
0592 {
0593 if(p + 1 > last)
0594 {
0595 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0596 return;
0597 }
0598 if(! (*p == ' ' || *p == '\t'))
0599 break;
0600 }
0601
0602 first = p;
0603 p = parse_token_to_eol(p, last, token_last, ec);
0604 if(ec)
0605 return;
0606 if(! p)
0607 {
0608 BOOST_BEAST_ASSIGN_EC(ec, error::bad_value);
0609 return;
0610 }
0611
0612 if(p + 1 > last)
0613 {
0614 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0615 return;
0616 }
0617 token_last = trim_back(token_last, first);
0618 if(first != token_last)
0619 {
0620 if (!buf.try_push_back(' ') ||
0621 !buf.try_append(first, token_last))
0622 {
0623 BOOST_BEAST_ASSIGN_EC(ec, error::header_limit);
0624 return;
0625 }
0626 }
0627 if(*p != ' ' && *p != '\t')
0628 {
0629 value = {buf.data(), buf.size()};
0630 return;
0631 }
0632 ++p;
0633 }
0634 }
0635
0636
0637 void
0638 basic_parser_base::
0639 parse_chunk_extensions(
0640 char const*& it,
0641 char const* last,
0642 error_code& ec)
0643 {
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657 loop:
0658 if(it == last)
0659 {
0660 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0661 return;
0662 }
0663 if(*it != ' ' && *it != '\t' && *it != ';')
0664 return;
0665
0666 if(*it == ' ' || *it == '\t')
0667 {
0668 for(;;)
0669 {
0670 ++it;
0671 if(it == last)
0672 {
0673 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0674 return;
0675 }
0676 if(*it != ' ' && *it != '\t')
0677 break;
0678 }
0679 }
0680
0681 if(*it != ';')
0682 {
0683 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0684 return;
0685 }
0686 semi:
0687 ++it;
0688
0689 for(;;)
0690 {
0691 if(it == last)
0692 {
0693 BOOST_BEAST_ASSIGN_EC(ec, error::need_more);
0694 return;
0695 }
0696 if(*it != ' ' && *it != '\t')
0697 break;
0698 ++it;
0699 }
0700
0701 if(! detail::is_token_char(*it))
0702 {
0703 ec = error::bad_chunk_extension;
0704 return;
0705 }
0706 for(;;)
0707 {
0708 ++it;
0709 if(it == last)
0710 {
0711 ec = error::need_more;
0712 return;
0713 }
0714 if(! detail::is_token_char(*it))
0715 break;
0716 }
0717
0718 {
0719 bool bws;
0720 if(*it == ' ' || *it == '\t')
0721 {
0722 for(;;)
0723 {
0724 ++it;
0725 if(it == last)
0726 {
0727 ec = error::need_more;
0728 return;
0729 }
0730 if(*it != ' ' && *it != '\t')
0731 break;
0732 }
0733 bws = true;
0734 }
0735 else
0736 {
0737 bws = false;
0738 }
0739 if(*it == ';')
0740 goto semi;
0741 if(*it != '=')
0742 {
0743 if(bws)
0744 ec = error::bad_chunk_extension;
0745 return;
0746 }
0747 ++it;
0748 }
0749
0750 for(;;)
0751 {
0752 if(it == last)
0753 {
0754 ec = error::need_more;
0755 return;
0756 }
0757 if(*it != ' ' && *it != '\t')
0758 break;
0759 ++it;
0760 }
0761
0762 if(*it != '"')
0763 {
0764
0765 if(! detail::is_token_char(*it))
0766 {
0767 ec = error::bad_chunk_extension;
0768 return;
0769 }
0770 for(;;)
0771 {
0772 ++it;
0773 if(it == last)
0774 {
0775 ec = error::need_more;
0776 return;
0777 }
0778 if(! detail::is_token_char(*it))
0779 break;
0780 }
0781 }
0782 else
0783 {
0784
0785 for(;;)
0786 {
0787 ++it;
0788 if(it == last)
0789 {
0790 ec = error::need_more;
0791 return;
0792 }
0793 if(*it == '"')
0794 break;
0795 if(*it == '\\')
0796 {
0797 ++it;
0798 if(it == last)
0799 {
0800 ec = error::need_more;
0801 return;
0802 }
0803 }
0804 }
0805 ++it;
0806 }
0807 goto loop;
0808 }
0809
0810 }
0811 }
0812 }
0813 }
0814
0815 #endif