File indexing completed on 2025-09-15 08:30:16
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_BEAST_HTTP_IMPL_FIELDS_HPP
0011 #define BOOST_BEAST_HTTP_IMPL_FIELDS_HPP
0012
0013 #include <boost/beast/core/buffers_cat.hpp>
0014 #include <boost/beast/core/string.hpp>
0015 #include <boost/beast/core/detail/buffers_ref.hpp>
0016 #include <boost/beast/core/detail/clamp.hpp>
0017 #include <boost/beast/core/detail/static_string.hpp>
0018 #include <boost/beast/core/detail/temporary_buffer.hpp>
0019 #include <boost/beast/core/static_string.hpp>
0020 #include <boost/beast/http/verb.hpp>
0021 #include <boost/beast/http/rfc7230.hpp>
0022 #include <boost/beast/http/status.hpp>
0023 #include <boost/beast/http/chunk_encode.hpp>
0024 #include <boost/core/exchange.hpp>
0025 #include <boost/throw_exception.hpp>
0026
0027 namespace boost {
0028 namespace beast {
0029 namespace http {
0030
0031 template<class Allocator>
0032 class basic_fields<Allocator>::writer
0033 {
0034 public:
0035 using iter_type = typename list_t::const_iterator;
0036
0037 struct field_iterator
0038 {
0039 iter_type it_;
0040
0041 using value_type = net::const_buffer;
0042 using pointer = value_type const*;
0043 using reference = value_type const;
0044 using difference_type = std::ptrdiff_t;
0045 using iterator_category =
0046 std::bidirectional_iterator_tag;
0047
0048 field_iterator() = default;
0049 field_iterator(field_iterator&& other) = default;
0050 field_iterator(field_iterator const& other) = default;
0051 field_iterator& operator=(field_iterator&& other) = default;
0052 field_iterator& operator=(field_iterator const& other) = default;
0053
0054 explicit
0055 field_iterator(iter_type it)
0056 : it_(it)
0057 {
0058 }
0059
0060 bool
0061 operator==(field_iterator const& other) const
0062 {
0063 return it_ == other.it_;
0064 }
0065
0066 bool
0067 operator!=(field_iterator const& other) const
0068 {
0069 return !(*this == other);
0070 }
0071
0072 reference
0073 operator*() const
0074 {
0075 return it_->buffer();
0076 }
0077
0078 field_iterator&
0079 operator++()
0080 {
0081 ++it_;
0082 return *this;
0083 }
0084
0085 field_iterator
0086 operator++(int)
0087 {
0088 auto temp = *this;
0089 ++(*this);
0090 return temp;
0091 }
0092
0093 field_iterator&
0094 operator--()
0095 {
0096 --it_;
0097 return *this;
0098 }
0099
0100 field_iterator
0101 operator--(int)
0102 {
0103 auto temp = *this;
0104 --(*this);
0105 return temp;
0106 }
0107 };
0108
0109 class field_range
0110 {
0111 field_iterator first_;
0112 field_iterator last_;
0113
0114 public:
0115 using const_iterator =
0116 field_iterator;
0117
0118 using value_type =
0119 typename const_iterator::value_type;
0120
0121 field_range(iter_type first, iter_type last)
0122 : first_(first)
0123 , last_(last)
0124 {
0125 }
0126
0127 const_iterator
0128 begin() const
0129 {
0130 return first_;
0131 }
0132
0133 const_iterator
0134 end() const
0135 {
0136 return last_;
0137 }
0138 };
0139
0140 using view_type = buffers_cat_view<
0141 net::const_buffer,
0142 net::const_buffer,
0143 net::const_buffer,
0144 field_range,
0145 chunk_crlf>;
0146
0147 basic_fields const& f_;
0148 boost::optional<view_type> view_;
0149 char buf_[13];
0150
0151 public:
0152 using const_buffers_type =
0153 beast::detail::buffers_ref<view_type>;
0154
0155 writer(basic_fields const& f,
0156 unsigned version, verb v);
0157
0158 writer(basic_fields const& f,
0159 unsigned version, unsigned code);
0160
0161 writer(basic_fields const& f);
0162
0163 const_buffers_type
0164 get() const
0165 {
0166 return const_buffers_type(*view_);
0167 }
0168 };
0169
0170 template<class Allocator>
0171 basic_fields<Allocator>::writer::
0172 writer(basic_fields const& f)
0173 : f_(f)
0174 {
0175 view_.emplace(
0176 net::const_buffer{nullptr, 0},
0177 net::const_buffer{nullptr, 0},
0178 net::const_buffer{nullptr, 0},
0179 field_range(f_.list_.begin(), f_.list_.end()),
0180 chunk_crlf());
0181 }
0182
0183 template<class Allocator>
0184 basic_fields<Allocator>::writer::
0185 writer(basic_fields const& f,
0186 unsigned version, verb v)
0187 : f_(f)
0188 {
0189
0190
0191
0192
0193
0194
0195 string_view sv;
0196 if(v == verb::unknown)
0197 sv = f_.get_method_impl();
0198 else
0199 sv = to_string(v);
0200
0201
0202
0203 buf_[0] = ' ';
0204 buf_[1] = 'H';
0205 buf_[2] = 'T';
0206 buf_[3] = 'T';
0207 buf_[4] = 'P';
0208 buf_[5] = '/';
0209 buf_[6] = '0' + static_cast<char>(version / 10);
0210 buf_[7] = '.';
0211 buf_[8] = '0' + static_cast<char>(version % 10);
0212 buf_[9] = '\r';
0213 buf_[10]= '\n';
0214
0215 view_.emplace(
0216 net::const_buffer{sv.data(), sv.size()},
0217 net::const_buffer{
0218 f_.target_or_reason_.data(),
0219 f_.target_or_reason_.size()},
0220 net::const_buffer{buf_, 11},
0221 field_range(f_.list_.begin(), f_.list_.end()),
0222 chunk_crlf());
0223 }
0224
0225 template<class Allocator>
0226 basic_fields<Allocator>::writer::
0227 writer(basic_fields const& f,
0228 unsigned version, unsigned code)
0229 : f_(f)
0230 {
0231
0232
0233
0234
0235
0236
0237 buf_[0] = 'H';
0238 buf_[1] = 'T';
0239 buf_[2] = 'T';
0240 buf_[3] = 'P';
0241 buf_[4] = '/';
0242 buf_[5] = '0' + static_cast<char>(version / 10);
0243 buf_[6] = '.';
0244 buf_[7] = '0' + static_cast<char>(version % 10);
0245 buf_[8] = ' ';
0246 buf_[9] = '0' + static_cast<char>(code / 100);
0247 buf_[10]= '0' + static_cast<char>((code / 10) % 10);
0248 buf_[11]= '0' + static_cast<char>(code % 10);
0249 buf_[12]= ' ';
0250
0251 string_view sv;
0252 if(! f_.target_or_reason_.empty())
0253 sv = f_.target_or_reason_;
0254 else
0255 sv = obsolete_reason(static_cast<status>(code));
0256
0257 view_.emplace(
0258 net::const_buffer{buf_, 13},
0259 net::const_buffer{sv.data(), sv.size()},
0260 net::const_buffer{"\r\n", 2},
0261 field_range(f_.list_.begin(), f_.list_.end()),
0262 chunk_crlf{});
0263 }
0264
0265
0266
0267 template<class Allocator>
0268 char*
0269 basic_fields<Allocator>::
0270 value_type::
0271 data() const
0272 {
0273 return const_cast<char*>(
0274 reinterpret_cast<char const*>(
0275 static_cast<element const*>(this) + 1));
0276 }
0277
0278 template<class Allocator>
0279 net::const_buffer
0280 basic_fields<Allocator>::
0281 value_type::
0282 buffer() const
0283 {
0284 return net::const_buffer{data(),
0285 static_cast<std::size_t>(off_) + len_ + 2};
0286 }
0287
0288 template<class Allocator>
0289 basic_fields<Allocator>::
0290 value_type::
0291 value_type(field name,
0292 string_view sname, string_view value)
0293 : off_(static_cast<off_t>(sname.size() + 2))
0294 , len_(static_cast<off_t>(value.size()))
0295 , f_(name)
0296 {
0297
0298
0299 char* p = data();
0300 p[off_-2] = ':';
0301 p[off_-1] = ' ';
0302 p[off_ + len_] = '\r';
0303 p[off_ + len_ + 1] = '\n';
0304 sname.copy(p, sname.size());
0305 value.copy(p + off_, value.size());
0306 }
0307
0308 template<class Allocator>
0309 field
0310 basic_fields<Allocator>::
0311 value_type::
0312 name() const
0313 {
0314 return f_;
0315 }
0316
0317 template<class Allocator>
0318 string_view const
0319 basic_fields<Allocator>::
0320 value_type::
0321 name_string() const
0322 {
0323 return {data(),
0324 static_cast<std::size_t>(off_ - 2)};
0325 }
0326
0327 template<class Allocator>
0328 string_view const
0329 basic_fields<Allocator>::
0330 value_type::
0331 value() const
0332 {
0333 return {data() + off_,
0334 static_cast<std::size_t>(len_)};
0335 }
0336
0337 template<class Allocator>
0338 basic_fields<Allocator>::
0339 element::
0340 element(field name,
0341 string_view sname, string_view value)
0342 : value_type(name, sname, value)
0343 {
0344 }
0345
0346
0347
0348 template<class Allocator>
0349 basic_fields<Allocator>::
0350 ~basic_fields()
0351 {
0352 delete_list();
0353 realloc_string(method_, {});
0354 realloc_string(
0355 target_or_reason_, {});
0356 }
0357
0358 template<class Allocator>
0359 basic_fields<Allocator>::
0360 basic_fields(Allocator const& alloc) noexcept
0361 : boost::empty_value<Allocator>(boost::empty_init_t(), alloc)
0362 {
0363 }
0364
0365 template<class Allocator>
0366 basic_fields<Allocator>::
0367 basic_fields(basic_fields&& other) noexcept
0368 : boost::empty_value<Allocator>(boost::empty_init_t(),
0369 std::move(other.get()))
0370 , set_(std::move(other.set_))
0371 , list_(std::move(other.list_))
0372 , method_(boost::exchange(other.method_, {}))
0373 , target_or_reason_(boost::exchange(other.target_or_reason_, {}))
0374 {
0375 }
0376
0377 template<class Allocator>
0378 basic_fields<Allocator>::
0379 basic_fields(basic_fields&& other, Allocator const& alloc)
0380 : boost::empty_value<Allocator>(boost::empty_init_t(), alloc)
0381 {
0382 if(this->get() != other.get())
0383 {
0384 copy_all(other);
0385 }
0386 else
0387 {
0388 set_ = std::move(other.set_);
0389 list_ = std::move(other.list_);
0390 method_ = other.method_;
0391 target_or_reason_ = other.target_or_reason_;
0392 }
0393 }
0394
0395 template<class Allocator>
0396 basic_fields<Allocator>::
0397 basic_fields(basic_fields const& other)
0398 : boost::empty_value<Allocator>(boost::empty_init_t(), alloc_traits::
0399 select_on_container_copy_construction(other.get()))
0400 {
0401 copy_all(other);
0402 }
0403
0404 template<class Allocator>
0405 basic_fields<Allocator>::
0406 basic_fields(basic_fields const& other,
0407 Allocator const& alloc)
0408 : boost::empty_value<Allocator>(boost::empty_init_t(), alloc)
0409 {
0410 copy_all(other);
0411 }
0412
0413 template<class Allocator>
0414 template<class OtherAlloc>
0415 basic_fields<Allocator>::
0416 basic_fields(basic_fields<OtherAlloc> const& other)
0417 {
0418 copy_all(other);
0419 }
0420
0421 template<class Allocator>
0422 template<class OtherAlloc>
0423 basic_fields<Allocator>::
0424 basic_fields(basic_fields<OtherAlloc> const& other,
0425 Allocator const& alloc)
0426 : boost::empty_value<Allocator>(boost::empty_init_t(), alloc)
0427 {
0428 copy_all(other);
0429 }
0430
0431 template<class Allocator>
0432 auto
0433 basic_fields<Allocator>::
0434 operator=(basic_fields&& other) noexcept(
0435 pocma::value && std::is_nothrow_move_assignable<Allocator>::value)
0436 -> basic_fields&
0437 {
0438 if(this == &other)
0439 return *this;
0440 move_assign(other, pocma{});
0441 return *this;
0442 }
0443
0444 template<class Allocator>
0445 auto
0446 basic_fields<Allocator>::
0447 operator=(basic_fields const& other) ->
0448 basic_fields&
0449 {
0450 copy_assign(other, pocca{});
0451 return *this;
0452 }
0453
0454 template<class Allocator>
0455 template<class OtherAlloc>
0456 auto
0457 basic_fields<Allocator>::
0458 operator=(basic_fields<OtherAlloc> const& other) ->
0459 basic_fields&
0460 {
0461 clear_all();
0462 copy_all(other);
0463 return *this;
0464 }
0465
0466
0467
0468
0469
0470
0471
0472 template<class Allocator>
0473 string_view const
0474 basic_fields<Allocator>::
0475 at(field name) const
0476 {
0477 BOOST_ASSERT(name != field::unknown);
0478 auto const it = find(name);
0479 if(it == end())
0480 BOOST_THROW_EXCEPTION(std::out_of_range{
0481 "field not found"});
0482 return it->value();
0483 }
0484
0485 template<class Allocator>
0486 string_view const
0487 basic_fields<Allocator>::
0488 at(string_view name) const
0489 {
0490 auto const it = find(name);
0491 if(it == end())
0492 BOOST_THROW_EXCEPTION(std::out_of_range{
0493 "field not found"});
0494 return it->value();
0495 }
0496
0497 template<class Allocator>
0498 string_view const
0499 basic_fields<Allocator>::
0500 operator[](field name) const
0501 {
0502 BOOST_ASSERT(name != field::unknown);
0503 auto const it = find(name);
0504 if(it == end())
0505 return {};
0506 return it->value();
0507 }
0508
0509 template<class Allocator>
0510 string_view const
0511 basic_fields<Allocator>::
0512 operator[](string_view name) const
0513 {
0514 auto const it = find(name);
0515 if(it == end())
0516 return {};
0517 return it->value();
0518 }
0519
0520
0521
0522
0523
0524
0525
0526 template<class Allocator>
0527 void
0528 basic_fields<Allocator>::
0529 clear()
0530 {
0531 delete_list();
0532 set_.clear();
0533 list_.clear();
0534 }
0535
0536 template<class Allocator>
0537 inline
0538 void
0539 basic_fields<Allocator>::
0540 insert(field name, string_view value)
0541 {
0542 BOOST_ASSERT(name != field::unknown);
0543 insert(name, to_string(name), value);
0544 }
0545
0546 template<class Allocator>
0547 void
0548 basic_fields<Allocator>::
0549 insert(string_view sname, string_view value)
0550 {
0551 insert(
0552 string_to_field(sname), sname, value);
0553 }
0554
0555 template<class Allocator>
0556 void
0557 basic_fields<Allocator>::
0558 insert(
0559 field name,
0560 string_view sname,
0561 string_view value,
0562 error_code& ec)
0563 {
0564 ec = {};
0565 auto* e = try_create_new_element(name, sname, value, ec);
0566 if(ec.failed())
0567 return;
0568 insert_element(*e);
0569 }
0570
0571 template<class Allocator>
0572 void
0573 basic_fields<Allocator>::
0574 insert(field name,
0575 string_view sname, string_view value)
0576 {
0577 insert_element(
0578 new_element(name, sname, value));
0579 }
0580
0581 template<class Allocator>
0582 void
0583 basic_fields<Allocator>::
0584 set(field name, string_view value)
0585 {
0586 BOOST_ASSERT(name != field::unknown);
0587 set_element(
0588 new_element(name, to_string(name), value));
0589 }
0590
0591 template<class Allocator>
0592 void
0593 basic_fields<Allocator>::
0594 set(string_view sname, string_view value)
0595 {
0596 set_element(new_element(
0597 string_to_field(sname), sname, value));
0598 }
0599
0600 template<class Allocator>
0601 auto
0602 basic_fields<Allocator>::
0603 erase(const_iterator pos) ->
0604 const_iterator
0605 {
0606 auto next = pos;
0607 auto& e = *next++;
0608 set_.erase(set_.iterator_to(e));
0609 list_.erase(pos);
0610 delete_element(const_cast<element&>(e));
0611 return next;
0612 }
0613
0614 template<class Allocator>
0615 std::size_t
0616 basic_fields<Allocator>::
0617 erase(field name)
0618 {
0619 BOOST_ASSERT(name != field::unknown);
0620 return erase(to_string(name));
0621 }
0622
0623 template<class Allocator>
0624 std::size_t
0625 basic_fields<Allocator>::
0626 erase(string_view name)
0627 {
0628 std::size_t n =0;
0629 set_.erase_and_dispose(name, key_compare{},
0630 [&](element* e)
0631 {
0632 ++n;
0633 list_.erase(list_.iterator_to(*e));
0634 delete_element(*e);
0635 });
0636 return n;
0637 }
0638
0639 template<class Allocator>
0640 void
0641 basic_fields<Allocator>::
0642 swap(basic_fields<Allocator>& other)
0643 {
0644 swap(other, pocs{});
0645 }
0646
0647 template<class Allocator>
0648 void
0649 swap(
0650 basic_fields<Allocator>& lhs,
0651 basic_fields<Allocator>& rhs)
0652 {
0653 lhs.swap(rhs);
0654 }
0655
0656
0657
0658
0659
0660
0661
0662 template<class Allocator>
0663 inline
0664 std::size_t
0665 basic_fields<Allocator>::
0666 count(field name) const
0667 {
0668 BOOST_ASSERT(name != field::unknown);
0669 return count(to_string(name));
0670 }
0671
0672 template<class Allocator>
0673 std::size_t
0674 basic_fields<Allocator>::
0675 count(string_view name) const
0676 {
0677 return set_.count(name, key_compare{});
0678 }
0679
0680 template<class Allocator>
0681 inline
0682 auto
0683 basic_fields<Allocator>::
0684 find(field name) const ->
0685 const_iterator
0686 {
0687 BOOST_ASSERT(name != field::unknown);
0688 return find(to_string(name));
0689 }
0690
0691 template<class Allocator>
0692 auto
0693 basic_fields<Allocator>::
0694 find(string_view name) const ->
0695 const_iterator
0696 {
0697 auto const it = set_.find(
0698 name, key_compare{});
0699 if(it == set_.end())
0700 return list_.end();
0701 return list_.iterator_to(*it);
0702 }
0703
0704 template<class Allocator>
0705 inline
0706 auto
0707 basic_fields<Allocator>::
0708 equal_range(field name) const ->
0709 std::pair<const_iterator, const_iterator>
0710 {
0711 BOOST_ASSERT(name != field::unknown);
0712 return equal_range(to_string(name));
0713 }
0714
0715 template<class Allocator>
0716 auto
0717 basic_fields<Allocator>::
0718 equal_range(string_view name) const ->
0719 std::pair<const_iterator, const_iterator>
0720 {
0721 auto result =
0722 set_.equal_range(name, key_compare{});
0723 if(result.first == result.second)
0724 return {list_.end(), list_.end()};
0725 return {
0726 list_.iterator_to(*result.first),
0727 ++list_.iterator_to(*(--result.second))};
0728 }
0729
0730
0731
0732 namespace detail {
0733
0734 struct iequals_predicate
0735 {
0736 bool
0737 operator()(string_view s) const
0738 {
0739 return beast::iequals(s, sv1) || beast::iequals(s, sv2);
0740 }
0741
0742 string_view sv1;
0743 string_view sv2;
0744 };
0745
0746
0747 BOOST_BEAST_DECL
0748 void
0749 filter_token_list_last(
0750 beast::detail::temporary_buffer& s,
0751 string_view value,
0752 iequals_predicate const& pred);
0753
0754 BOOST_BEAST_DECL
0755 void
0756 keep_alive_impl(
0757 beast::detail::temporary_buffer& s, string_view value,
0758 unsigned version, bool keep_alive);
0759
0760 }
0761
0762
0763
0764
0765
0766 template<class Allocator>
0767 inline
0768 string_view
0769 basic_fields<Allocator>::
0770 get_method_impl() const
0771 {
0772 return method_;
0773 }
0774
0775 template<class Allocator>
0776 inline
0777 string_view
0778 basic_fields<Allocator>::
0779 get_target_impl() const
0780 {
0781 if(target_or_reason_.empty())
0782 return target_or_reason_;
0783 return {
0784 target_or_reason_.data() + 1,
0785 target_or_reason_.size() - 1};
0786 }
0787
0788 template<class Allocator>
0789 inline
0790 string_view
0791 basic_fields<Allocator>::
0792 get_reason_impl() const
0793 {
0794 return target_or_reason_;
0795 }
0796
0797 template<class Allocator>
0798 bool
0799 basic_fields<Allocator>::
0800 get_chunked_impl() const
0801 {
0802 auto const te = token_list{
0803 (*this)[field::transfer_encoding]};
0804 for(auto it = te.begin(); it != te.end();)
0805 {
0806 auto const next = std::next(it);
0807 if(next == te.end())
0808 return beast::iequals(*it, "chunked");
0809 it = next;
0810 }
0811 return false;
0812 }
0813
0814 template<class Allocator>
0815 bool
0816 basic_fields<Allocator>::
0817 get_keep_alive_impl(unsigned version) const
0818 {
0819 auto const it = find(field::connection);
0820 if(version < 11)
0821 {
0822 if(it == end())
0823 return false;
0824 return token_list{
0825 it->value()}.exists("keep-alive");
0826 }
0827 if(it == end())
0828 return true;
0829 return ! token_list{
0830 it->value()}.exists("close");
0831 }
0832
0833 template<class Allocator>
0834 bool
0835 basic_fields<Allocator>::
0836 has_content_length_impl() const
0837 {
0838 return count(field::content_length) > 0;
0839 }
0840
0841 template<class Allocator>
0842 inline
0843 void
0844 basic_fields<Allocator>::
0845 set_method_impl(string_view s)
0846 {
0847 realloc_string(method_, s);
0848 }
0849
0850 template<class Allocator>
0851 inline
0852 void
0853 basic_fields<Allocator>::
0854 set_target_impl(string_view s)
0855 {
0856 realloc_target(
0857 target_or_reason_, s);
0858 }
0859
0860 template<class Allocator>
0861 inline
0862 void
0863 basic_fields<Allocator>::
0864 set_reason_impl(string_view s)
0865 {
0866 realloc_string(
0867 target_or_reason_, s);
0868 }
0869
0870 template<class Allocator>
0871 void
0872 basic_fields<Allocator>::
0873 set_chunked_impl(bool value)
0874 {
0875 beast::detail::temporary_buffer buf;
0876 auto it = find(field::transfer_encoding);
0877 if(value)
0878 {
0879
0880 if(it == end())
0881 {
0882 set(field::transfer_encoding, "chunked");
0883 return;
0884 }
0885 auto const te = token_list{it->value()};
0886 for(auto itt = te.begin();;)
0887 {
0888 auto const next = std::next(itt);
0889 if(next == te.end())
0890 {
0891 if(beast::iequals(*itt, "chunked"))
0892 return;
0893 break;
0894 }
0895 itt = next;
0896 }
0897
0898 buf.append(it->value(), ", chunked");
0899 set(field::transfer_encoding, buf.view());
0900 return;
0901 }
0902
0903 if(it == end())
0904 return;
0905
0906 detail::filter_token_list_last(buf, it->value(), {"chunked", {}});
0907 if(! buf.empty())
0908 set(field::transfer_encoding, buf.view());
0909 else
0910 erase(field::transfer_encoding);
0911 }
0912
0913 template<class Allocator>
0914 void
0915 basic_fields<Allocator>::
0916 set_content_length_impl(
0917 boost::optional<std::uint64_t> const& value)
0918 {
0919 if(! value)
0920 erase(field::content_length);
0921 else
0922 {
0923 auto s = to_static_string(*value);
0924 set(field::content_length,
0925 to_string_view(s));
0926 }
0927 }
0928
0929 template<class Allocator>
0930 void
0931 basic_fields<Allocator>::
0932 set_keep_alive_impl(
0933 unsigned version, bool keep_alive)
0934 {
0935
0936 auto const value = (*this)[field::connection];
0937 beast::detail::temporary_buffer buf;
0938 detail::keep_alive_impl(buf, value, version, keep_alive);
0939 if(buf.empty())
0940 erase(field::connection);
0941 else
0942 set(field::connection, buf.view());
0943 }
0944
0945
0946
0947 template<class Allocator>
0948 auto
0949 basic_fields<Allocator>::
0950 try_create_new_element(
0951 field name,
0952 string_view sname,
0953 string_view value,
0954 error_code& ec) -> element*
0955 {
0956 if(sname.size() > max_name_size)
0957 {
0958 BOOST_BEAST_ASSIGN_EC(ec, error::header_field_name_too_large);
0959 return nullptr;
0960 }
0961 if(value.size() > max_value_size)
0962 {
0963 BOOST_BEAST_ASSIGN_EC(ec, error::header_field_value_too_large);
0964 return nullptr;
0965 }
0966 value = detail::trim(value);
0967 std::uint16_t const off =
0968 static_cast<off_t>(sname.size() + 2);
0969 std::uint16_t const len =
0970 static_cast<off_t>(value.size());
0971 auto a = rebind_type{this->get()};
0972 auto const p = alloc_traits::allocate(a,
0973 (sizeof(element) + off + len + 2 + sizeof(align_type) - 1) /
0974 sizeof(align_type));
0975 return ::new(p) element(name, sname, value);
0976 }
0977
0978 template<class Allocator>
0979 auto
0980 basic_fields<Allocator>::
0981 new_element(
0982 field name,
0983 string_view sname,
0984 string_view value) -> element&
0985 {
0986 error_code ec;
0987 auto* e = try_create_new_element(name, sname, value, ec);
0988 if(ec.failed())
0989 BOOST_THROW_EXCEPTION(system_error{ec});
0990 return *e;
0991 }
0992
0993 template<class Allocator>
0994 void
0995 basic_fields<Allocator>::
0996 insert_element(element& e)
0997 {
0998 auto const before =
0999 set_.upper_bound(e.name_string(), key_compare{});
1000 if(before == set_.begin())
1001 {
1002 BOOST_ASSERT(count(e.name_string()) == 0);
1003 set_.insert_before(before, e);
1004 list_.push_back(e);
1005 return;
1006 }
1007 auto const last = std::prev(before);
1008
1009 if(! beast::iequals(e.name_string(), last->name_string()))
1010 {
1011 BOOST_ASSERT(count(e.name_string()) == 0);
1012 set_.insert_before(before, e);
1013 list_.push_back(e);
1014 return;
1015 }
1016
1017 set_.insert_before(before, e);
1018 list_.insert(++list_.iterator_to(*last), e);
1019 }
1020
1021 template<class Allocator>
1022 void
1023 basic_fields<Allocator>::
1024 delete_element(element& e)
1025 {
1026 auto a = rebind_type{this->get()};
1027 auto const n =
1028 (sizeof(element) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
1029 sizeof(align_type);
1030 e.~element();
1031 alloc_traits::deallocate(a,
1032 reinterpret_cast<align_type*>(&e), n);
1033 }
1034
1035 template<class Allocator>
1036 void
1037 basic_fields<Allocator>::
1038 set_element(element& e)
1039 {
1040 auto it = set_.lower_bound(
1041 e.name_string(), key_compare{});
1042 if(it == set_.end() || ! beast::iequals(
1043 e.name_string(), it->name_string()))
1044 {
1045 set_.insert_before(it, e);
1046 list_.push_back(e);
1047 return;
1048 }
1049 for(;;)
1050 {
1051 auto next = it;
1052 ++next;
1053 set_.erase(it);
1054 list_.erase(list_.iterator_to(*it));
1055 delete_element(*it);
1056 it = next;
1057 if(it == set_.end() ||
1058 ! beast::iequals(e.name_string(), it->name_string()))
1059 break;
1060 }
1061 set_.insert_before(it, e);
1062 list_.push_back(e);
1063 }
1064
1065 template<class Allocator>
1066 void
1067 basic_fields<Allocator>::
1068 realloc_string(string_view& dest, string_view s)
1069 {
1070 if(dest.empty() && s.empty())
1071 return;
1072 auto a = typename beast::detail::allocator_traits<
1073 Allocator>::template rebind_alloc<
1074 char>(this->get());
1075 char* p = nullptr;
1076 if(! s.empty())
1077 {
1078 p = a.allocate(s.size());
1079 s.copy(p, s.size());
1080 }
1081 if(! dest.empty())
1082 a.deallocate(const_cast<char*>(
1083 dest.data()), dest.size());
1084 if(p)
1085 dest = {p, s.size()};
1086 else
1087 dest = {};
1088 }
1089
1090 template<class Allocator>
1091 void
1092 basic_fields<Allocator>::
1093 realloc_target(
1094 string_view& dest, string_view s)
1095 {
1096
1097
1098
1099 if(dest.empty() && s.empty())
1100 return;
1101 auto a = typename beast::detail::allocator_traits<
1102 Allocator>::template rebind_alloc<
1103 char>(this->get());
1104 char* p = nullptr;
1105 if(! s.empty())
1106 {
1107 p = a.allocate(1 + s.size());
1108 p[0] = ' ';
1109 s.copy(p + 1, s.size());
1110 }
1111 if(! dest.empty())
1112 a.deallocate(const_cast<char*>(
1113 dest.data()), dest.size());
1114 if(p)
1115 dest = {p, 1 + s.size()};
1116 else
1117 dest = {};
1118 }
1119
1120 template<class Allocator>
1121 template<class OtherAlloc>
1122 void
1123 basic_fields<Allocator>::
1124 copy_all(basic_fields<OtherAlloc> const& other)
1125 {
1126 for(auto const& e : other.list_)
1127 insert(e.name(), e.name_string(), e.value());
1128 realloc_string(method_, other.method_);
1129 realloc_string(target_or_reason_,
1130 other.target_or_reason_);
1131 }
1132
1133 template<class Allocator>
1134 void
1135 basic_fields<Allocator>::
1136 clear_all()
1137 {
1138 clear();
1139 realloc_string(method_, {});
1140 realloc_string(target_or_reason_, {});
1141 }
1142
1143 template<class Allocator>
1144 void
1145 basic_fields<Allocator>::
1146 delete_list()
1147 {
1148 for(auto it = list_.begin(); it != list_.end();)
1149 delete_element(*it++);
1150 }
1151
1152
1153
1154 template<class Allocator>
1155 inline
1156 void
1157 basic_fields<Allocator>::
1158 move_assign(basic_fields& other, std::true_type)
1159 {
1160 clear_all();
1161 this->get() = std::move(other.get());
1162 set_ = std::move(other.set_);
1163 list_ = std::move(other.list_);
1164 method_ = other.method_;
1165 target_or_reason_ = other.target_or_reason_;
1166 other.method_ = {};
1167 other.target_or_reason_ = {};
1168 }
1169
1170 template<class Allocator>
1171 inline
1172 void
1173 basic_fields<Allocator>::
1174 move_assign(basic_fields& other, std::false_type)
1175 {
1176 clear_all();
1177 if(this->get() != other.get())
1178 {
1179 copy_all(other);
1180 }
1181 else
1182 {
1183 set_ = std::move(other.set_);
1184 list_ = std::move(other.list_);
1185 method_ = other.method_;
1186 target_or_reason_ = other.target_or_reason_;
1187 other.method_ = {};
1188 other.target_or_reason_ = {};
1189 }
1190 }
1191
1192 template<class Allocator>
1193 inline
1194 void
1195 basic_fields<Allocator>::
1196 copy_assign(basic_fields const& other, std::true_type)
1197 {
1198 clear_all();
1199 this->get() = other.get();
1200 copy_all(other);
1201 }
1202
1203 template<class Allocator>
1204 inline
1205 void
1206 basic_fields<Allocator>::
1207 copy_assign(basic_fields const& other, std::false_type)
1208 {
1209 clear_all();
1210 copy_all(other);
1211 }
1212
1213 template<class Allocator>
1214 inline
1215 void
1216 basic_fields<Allocator>::
1217 swap(basic_fields& other, std::true_type)
1218 {
1219 using std::swap;
1220 swap(this->get(), other.get());
1221 swap(set_, other.set_);
1222 swap(list_, other.list_);
1223 swap(method_, other.method_);
1224 swap(target_or_reason_, other.target_or_reason_);
1225 }
1226
1227 template<class Allocator>
1228 inline
1229 void
1230 basic_fields<Allocator>::
1231 swap(basic_fields& other, std::false_type)
1232 {
1233 BOOST_ASSERT(this->get() == other.get());
1234 using std::swap;
1235 swap(set_, other.set_);
1236 swap(list_, other.list_);
1237 swap(method_, other.method_);
1238 swap(target_or_reason_, other.target_or_reason_);
1239 }
1240
1241 }
1242 }
1243 }
1244
1245 #ifdef BOOST_BEAST_HEADER_ONLY
1246 #include <boost/beast/http/impl/fields.ipp>
1247 #endif
1248
1249 #endif