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