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_CHUNK_ENCODE_HPP
0011 #define BOOST_BEAST_HTTP_IMPL_CHUNK_ENCODE_HPP
0012
0013 #include <boost/beast/core/buffer_traits.hpp>
0014 #include <boost/beast/core/detail/varint.hpp>
0015 #include <boost/beast/http/error.hpp>
0016 #include <boost/beast/http/detail/rfc7230.hpp>
0017 #include <algorithm>
0018
0019 namespace boost {
0020 namespace beast {
0021 namespace http {
0022
0023 inline
0024 chunk_header::
0025 chunk_header(std::size_t size)
0026 : view_(
0027 size,
0028 net::const_buffer{nullptr, 0},
0029 chunk_crlf{})
0030 {
0031 BOOST_ASSERT(size > 0);
0032 }
0033
0034 inline
0035 chunk_header::
0036 chunk_header(
0037 std::size_t size,
0038 string_view extensions)
0039 : view_(
0040 size,
0041 net::const_buffer{
0042 extensions.data(), extensions.size()},
0043 chunk_crlf{})
0044 {
0045 BOOST_ASSERT(size > 0);
0046 }
0047
0048 template<class ChunkExtensions, class>
0049 chunk_header::
0050 chunk_header(
0051 std::size_t size,
0052 ChunkExtensions&& extensions)
0053 : exts_(std::make_shared<detail::chunk_extensions_impl<
0054 typename std::decay<ChunkExtensions>::type>>(
0055 std::forward<ChunkExtensions>(extensions)))
0056 , view_(
0057 size,
0058 exts_->str(),
0059 chunk_crlf{})
0060 {
0061 static_assert(
0062 detail::is_chunk_extensions<ChunkExtensions>::value,
0063 "ChunkExtensions requirements not met");
0064 BOOST_ASSERT(size > 0);
0065 }
0066
0067 template<class ChunkExtensions, class Allocator, class>
0068 chunk_header::
0069 chunk_header(
0070 std::size_t size,
0071 ChunkExtensions&& extensions,
0072 Allocator const& allocator)
0073 : exts_(std::allocate_shared<detail::chunk_extensions_impl<
0074 typename std::decay<ChunkExtensions>::type>>(allocator,
0075 std::forward<ChunkExtensions>(extensions)))
0076 , view_(
0077 size,
0078 exts_->str(),
0079 chunk_crlf{})
0080 {
0081 static_assert(
0082 detail::is_chunk_extensions<ChunkExtensions>::value,
0083 "ChunkExtensions requirements not met");
0084 BOOST_ASSERT(size > 0);
0085 }
0086
0087
0088
0089 template<class ConstBufferSequence>
0090 chunk_body<ConstBufferSequence>::
0091 chunk_body(ConstBufferSequence const& buffers)
0092 : view_(
0093 buffer_bytes(buffers),
0094 net::const_buffer{nullptr, 0},
0095 chunk_crlf{},
0096 buffers,
0097 chunk_crlf{})
0098 {
0099 }
0100
0101 template<class ConstBufferSequence>
0102 chunk_body<ConstBufferSequence>::
0103 chunk_body(
0104 ConstBufferSequence const& buffers,
0105 string_view extensions)
0106 : view_(
0107 buffer_bytes(buffers),
0108 net::const_buffer{
0109 extensions.data(), extensions.size()},
0110 chunk_crlf{},
0111 buffers,
0112 chunk_crlf{})
0113 {
0114 }
0115
0116 template<class ConstBufferSequence>
0117 template<class ChunkExtensions, class>
0118 chunk_body<ConstBufferSequence>::
0119 chunk_body(
0120 ConstBufferSequence const& buffers,
0121 ChunkExtensions&& extensions)
0122 : exts_(std::make_shared<detail::chunk_extensions_impl<
0123 typename std::decay<ChunkExtensions>::type>>(
0124 std::forward<ChunkExtensions>(extensions)))
0125 , view_(
0126 buffer_bytes(buffers),
0127 exts_->str(),
0128 chunk_crlf{},
0129 buffers,
0130 chunk_crlf{})
0131 {
0132 }
0133
0134 template<class ConstBufferSequence>
0135 template<class ChunkExtensions, class Allocator, class>
0136 chunk_body<ConstBufferSequence>::
0137 chunk_body(
0138 ConstBufferSequence const& buffers,
0139 ChunkExtensions&& extensions,
0140 Allocator const& allocator)
0141 : exts_(std::allocate_shared<detail::chunk_extensions_impl<
0142 typename std::decay<ChunkExtensions>::type>>(allocator,
0143 std::forward<ChunkExtensions>(extensions)))
0144 , view_(
0145 buffer_bytes(buffers),
0146 exts_->str(),
0147 chunk_crlf{},
0148 buffers,
0149 chunk_crlf{})
0150 {
0151 }
0152
0153
0154
0155 template<class Trailer>
0156 template<class Allocator>
0157 auto
0158 chunk_last<Trailer>::
0159 prepare(Trailer const& trailer, Allocator const& allocator) ->
0160 buffers_type
0161 {
0162 auto sp = std::allocate_shared<typename
0163 Trailer::writer>(allocator, trailer);
0164 sp_ = sp;
0165 return sp->get();
0166 }
0167
0168 template<class Trailer>
0169 auto
0170 chunk_last<Trailer>::
0171 prepare(Trailer const& trailer, std::true_type) ->
0172 buffers_type
0173 {
0174 auto sp = std::make_shared<
0175 typename Trailer::writer>(trailer);
0176 sp_ = sp;
0177 return sp->get();
0178 }
0179
0180 template<class Trailer>
0181 auto
0182 chunk_last<Trailer>::
0183 prepare(Trailer const& trailer, std::false_type) ->
0184 buffers_type
0185 {
0186 return trailer;
0187 }
0188
0189 template<class Trailer>
0190 chunk_last<Trailer>::
0191 chunk_last()
0192 : view_(
0193 detail::chunk_size0{},
0194 Trailer{})
0195 {
0196 }
0197
0198 template<class Trailer>
0199 chunk_last<Trailer>::
0200 chunk_last(Trailer const& trailer)
0201 : view_(
0202 detail::chunk_size0{},
0203 prepare(trailer, is_fields<Trailer>{}))
0204 {
0205 }
0206
0207 template<class Trailer>
0208 template<class DeducedTrailer, class Allocator, class>
0209 chunk_last<Trailer>::
0210 chunk_last(
0211 DeducedTrailer const& trailer, Allocator const& allocator)
0212 : view_(
0213 detail::chunk_size0{},
0214 prepare(trailer, allocator))
0215 {
0216 }
0217
0218
0219
0220 template<class Allocator>
0221 class basic_chunk_extensions<Allocator>::const_iterator
0222 {
0223 friend class basic_chunk_extensions;
0224
0225 using iter_type = char const*;
0226
0227 iter_type it_;
0228 typename basic_chunk_extensions::value_type value_;
0229
0230 explicit
0231 const_iterator(iter_type it)
0232 : it_(it)
0233 {
0234 }
0235
0236 void
0237 increment();
0238
0239 public:
0240 using value_type = typename
0241 basic_chunk_extensions::value_type;
0242 using pointer = value_type const*;
0243 using reference = value_type const&;
0244 using difference_type = std::ptrdiff_t;
0245 using iterator_category =
0246 std::forward_iterator_tag;
0247
0248 const_iterator() = default;
0249 const_iterator(const_iterator&& other) = default;
0250 const_iterator(const_iterator const& other) = default;
0251 const_iterator& operator=(const_iterator&& other) = default;
0252 const_iterator& operator=(const_iterator const& other) = default;
0253
0254 bool
0255 operator==(const_iterator const& other) const
0256 {
0257 return it_ == other.it_;
0258 }
0259
0260 bool
0261 operator!=(const_iterator const& other) const
0262 {
0263 return !(*this == other);
0264 }
0265
0266 reference
0267 operator*();
0268
0269 pointer
0270 operator->()
0271 {
0272 return &(**this);
0273 }
0274
0275 const_iterator&
0276 operator++()
0277 {
0278 increment();
0279 return *this;
0280 }
0281
0282 const_iterator
0283 operator++(int)
0284 {
0285 auto temp = *this;
0286 increment();
0287 return temp;
0288 }
0289 };
0290
0291 template<class Allocator>
0292 void
0293 basic_chunk_extensions<Allocator>::
0294 const_iterator::
0295 increment()
0296 {
0297 using beast::detail::varint_read;
0298 auto n = varint_read(it_);
0299 it_ += n;
0300 n = varint_read(it_);
0301 it_ += n;
0302 }
0303
0304 template<class Allocator>
0305 auto
0306 basic_chunk_extensions<Allocator>::
0307 const_iterator::
0308 operator*() ->
0309 reference
0310 {
0311 using beast::detail::varint_read;
0312 auto it = it_;
0313 auto n = varint_read(it);
0314 value_.first = string_view{it, n};
0315 it += n;
0316 n = varint_read(it);
0317 value_.second = string_view{it, n};
0318 return value_;
0319 }
0320
0321
0322
0323 template<class Allocator>
0324 template<class FwdIt>
0325 FwdIt
0326 basic_chunk_extensions<Allocator>::
0327 do_parse(FwdIt it, FwdIt last, error_code& ec)
0328 {
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342 using beast::detail::varint_size;
0343 using beast::detail::varint_write;
0344 using CharT = char;
0345 using Traits = std::char_traits<CharT>;
0346 range_.reserve(static_cast<std::size_t>(
0347 std::distance(it, last) * 1.2));
0348 range_.resize(0);
0349 auto const emit_string =
0350 [this](FwdIt from, FwdIt to)
0351 {
0352 auto const len =
0353 std::distance(from, to);
0354 auto const offset = range_.size();
0355 range_.resize(
0356 offset +
0357 varint_size(len) +
0358 len);
0359 auto dest = &range_[offset];
0360 varint_write(dest, len);
0361 Traits::copy(dest, from, len);
0362 };
0363 auto const emit_string_plus_empty =
0364 [this](FwdIt from, FwdIt to)
0365 {
0366 auto const len =
0367 std::distance(from, to);
0368 auto const offset = range_.size();
0369 range_.resize(
0370 offset +
0371 varint_size(len) +
0372 len +
0373 varint_size(0));
0374 auto dest = &range_[offset];
0375 varint_write(dest, len);
0376 Traits::copy(dest, from, len);
0377 dest += len;
0378 varint_write(dest, 0);
0379 };
0380 auto const emit_empty_string =
0381 [this]
0382 {
0383 auto const offset = range_.size();
0384 range_.resize(offset + varint_size(0));
0385 auto dest = &range_[offset];
0386 varint_write(dest, 0);
0387 };
0388 loop:
0389 if(it == last)
0390 {
0391 ec = {};
0392 return it;
0393 }
0394
0395 if(*it == ' ' || *it == '\t')
0396 {
0397 for(;;)
0398 {
0399 ++it;
0400 if(it == last)
0401 {
0402 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0403 return it;
0404 }
0405 if(*it != ' ' && *it != '\t')
0406 break;
0407 }
0408 }
0409
0410 if(*it != ';')
0411 {
0412 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0413 return it;
0414 }
0415 semi:
0416 ++it;
0417
0418 for(;;)
0419 {
0420 if(it == last)
0421 {
0422 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0423 return it;
0424 }
0425 if(*it != ' ' && *it != '\t')
0426 break;
0427 ++it;
0428 }
0429
0430 {
0431 if(! detail::is_token_char(*it))
0432 {
0433 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0434 return it;
0435 }
0436 auto const first = it;
0437 for(;;)
0438 {
0439 ++it;
0440 if(it == last)
0441 {
0442 emit_string_plus_empty(first, it);
0443 return it;
0444 }
0445 if(! detail::is_token_char(*it))
0446 break;
0447 }
0448 emit_string(first, it);
0449 }
0450
0451 for(;;)
0452 {
0453 if(*it != ' ' && *it != '\t')
0454 break;
0455 ++it;
0456 if(it == last)
0457 {
0458 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0459 return it;
0460 }
0461 }
0462 if(*it == ';')
0463 {
0464 emit_empty_string();
0465 goto semi;
0466 }
0467 if(*it != '=')
0468 {
0469 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0470 return it;
0471 }
0472 ++it;
0473
0474 for(;;)
0475 {
0476 if(it == last)
0477 {
0478 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0479 return it;
0480 }
0481 if(*it != ' ' && *it != '\t')
0482 break;
0483 ++it;
0484 }
0485
0486 if(*it != '"')
0487 {
0488
0489 if(! detail::is_token_char(*it))
0490 {
0491 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0492 return it;
0493 }
0494 auto const first = it;
0495 for(;;)
0496 {
0497 ++it;
0498 if(it == last)
0499 break;
0500 if(! detail::is_token_char(*it))
0501 break;
0502 }
0503 emit_string(first, it);
0504 if(it == last)
0505 return it;
0506 }
0507 else
0508 {
0509
0510 auto const first = ++it;
0511
0512 std::size_t len = 0;
0513 for(;;)
0514 {
0515 if(it == last)
0516 {
0517 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0518 return it;
0519 }
0520 if(*it == '"')
0521 break;
0522 if(*it == '\\')
0523 {
0524 ++it;
0525 if(it == last)
0526 {
0527 BOOST_BEAST_ASSIGN_EC(ec, error::bad_chunk_extension);
0528 return it;
0529 }
0530 }
0531 ++len;
0532 ++it;
0533 }
0534
0535 auto const offset = range_.size();
0536 range_.resize(
0537 offset +
0538 varint_size(len) +
0539 len);
0540 auto dest = &range_[offset];
0541 varint_write(dest, len);
0542 it = first;
0543 for(;;)
0544 {
0545 BOOST_ASSERT(it != last);
0546 if(*it == '"')
0547 break;
0548 if(*it == '\\')
0549 {
0550 ++it;
0551 BOOST_ASSERT(it != last);
0552 }
0553 Traits::assign(*dest++, *it++);
0554 }
0555 ++it;
0556 }
0557 goto loop;
0558 }
0559
0560 template<class Allocator>
0561 void
0562 basic_chunk_extensions<Allocator>::
0563 do_insert(string_view name, string_view value)
0564 {
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575 if(value.empty())
0576 {
0577 s_.reserve(1 + name.size());
0578 s_.push_back(';');
0579 s_.append(name.data(), name.size());
0580 return;
0581 }
0582
0583 bool is_token = true;
0584 for(auto const c : value)
0585 {
0586 if(! detail::is_token_char(c))
0587 {
0588 is_token = false;
0589 break;
0590 }
0591 }
0592 if(is_token)
0593 {
0594
0595 s_.reserve(1 + name.size() + 1 + value.size());
0596 s_.push_back(';');
0597 s_.append(name.data(), name.size());
0598 s_.push_back('=');
0599 s_.append(value.data(), value.size());
0600 }
0601 else
0602 {
0603
0604 s_.reserve(
0605 1 + name.size() + 1 +
0606 1 + value.size() + 20 + 1);
0607 s_.push_back(';');
0608 s_.append(name.data(), name.size());
0609 s_.append("=\"", 2);
0610 for(auto const c : value)
0611 {
0612 if(c == '\\')
0613 s_.append(R"(\\)", 2);
0614 else if(c == '\"')
0615 s_.append(R"(\")", 2);
0616 else
0617 s_.push_back(c);
0618 }
0619 s_.push_back('"');
0620 }
0621 }
0622
0623 template<class Allocator>
0624 void
0625 basic_chunk_extensions<Allocator>::
0626 parse(string_view s, error_code& ec)
0627 {
0628 do_parse(s.data(), s.data() + s.size(), ec);
0629 if(! ec)
0630 {
0631 s_.clear();
0632 for(auto const& v : *this)
0633 do_insert(v.first, v.second);
0634 }
0635 }
0636
0637 template<class Allocator>
0638 void
0639 basic_chunk_extensions<Allocator>::
0640 insert(string_view name)
0641 {
0642 do_insert(name, {});
0643
0644 using beast::detail::varint_size;
0645 using beast::detail::varint_write;
0646 auto const offset = range_.size();
0647 range_.resize(
0648 offset +
0649 varint_size(name.size()) +
0650 name.size() +
0651 varint_size(0));
0652 auto dest = &range_[offset];
0653 varint_write(dest, name.size());
0654 std::memcpy(dest, name.data(), name.size());
0655 dest += name.size();
0656 varint_write(dest, 0);
0657 }
0658
0659 template<class Allocator>
0660 void
0661 basic_chunk_extensions<Allocator>::
0662 insert(string_view name, string_view value)
0663 {
0664 do_insert(name, value);
0665
0666 using beast::detail::varint_size;
0667 using beast::detail::varint_write;
0668 auto const offset = range_.size();
0669 range_.resize(
0670 offset +
0671 varint_size(name.size()) +
0672 name.size() +
0673 varint_size(value.size()) +
0674 value.size());
0675 auto dest = &range_[offset];
0676 varint_write(dest, name.size());
0677 std::memcpy(dest, name.data(), name.size());
0678 dest += name.size();
0679 varint_write(dest, value.size());
0680 std::memcpy(dest, value.data(), value.size());
0681 }
0682
0683 template<class Allocator>
0684 auto
0685 basic_chunk_extensions<Allocator>::
0686 begin() const ->
0687 const_iterator
0688 {
0689 return const_iterator{range_.data()};
0690 }
0691
0692 template<class Allocator>
0693 auto
0694 basic_chunk_extensions<Allocator>::
0695 end() const ->
0696 const_iterator
0697 {
0698 return const_iterator{
0699 range_.data() + range_.size()};
0700 }
0701
0702 }
0703 }
0704 }
0705
0706 #endif