Warning, file /include/boost/beast/http/impl/fields.hpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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 const& 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 const& value)
0550 {
0551 auto const name =
0552 string_to_field(sname);
0553 insert(name, sname, value);
0554 }
0555
0556 template<class Allocator>
0557 void
0558 basic_fields<Allocator>::
0559 insert(field name,
0560 string_view sname, string_view const& value)
0561 {
0562 auto& e = new_element(name, sname,
0563 static_cast<string_view>(value));
0564 auto const before =
0565 set_.upper_bound(sname, key_compare{});
0566 if(before == set_.begin())
0567 {
0568 BOOST_ASSERT(count(sname) == 0);
0569 set_.insert_before(before, e);
0570 list_.push_back(e);
0571 return;
0572 }
0573 auto const last = std::prev(before);
0574
0575 if(! beast::iequals(sname, last->name_string()))
0576 {
0577 BOOST_ASSERT(count(sname) == 0);
0578 set_.insert_before(before, e);
0579 list_.push_back(e);
0580 return;
0581 }
0582
0583 set_.insert_before(before, e);
0584 list_.insert(++list_.iterator_to(*last), e);
0585 }
0586
0587 template<class Allocator>
0588 void
0589 basic_fields<Allocator>::
0590 set(field name, string_view const& value)
0591 {
0592 BOOST_ASSERT(name != field::unknown);
0593 set_element(new_element(name, to_string(name),
0594 static_cast<string_view>(value)));
0595 }
0596
0597 template<class Allocator>
0598 void
0599 basic_fields<Allocator>::
0600 set(string_view sname, string_view const& value)
0601 {
0602 set_element(new_element(
0603 string_to_field(sname), sname, value));
0604 }
0605
0606 template<class Allocator>
0607 auto
0608 basic_fields<Allocator>::
0609 erase(const_iterator pos) ->
0610 const_iterator
0611 {
0612 auto next = pos;
0613 auto& e = *next++;
0614 set_.erase(set_.iterator_to(e));
0615 list_.erase(pos);
0616 delete_element(const_cast<element&>(e));
0617 return next;
0618 }
0619
0620 template<class Allocator>
0621 std::size_t
0622 basic_fields<Allocator>::
0623 erase(field name)
0624 {
0625 BOOST_ASSERT(name != field::unknown);
0626 return erase(to_string(name));
0627 }
0628
0629 template<class Allocator>
0630 std::size_t
0631 basic_fields<Allocator>::
0632 erase(string_view name)
0633 {
0634 std::size_t n =0;
0635 set_.erase_and_dispose(name, key_compare{},
0636 [&](element* e)
0637 {
0638 ++n;
0639 list_.erase(list_.iterator_to(*e));
0640 delete_element(*e);
0641 });
0642 return n;
0643 }
0644
0645 template<class Allocator>
0646 void
0647 basic_fields<Allocator>::
0648 swap(basic_fields<Allocator>& other)
0649 {
0650 swap(other, pocs{});
0651 }
0652
0653 template<class Allocator>
0654 void
0655 swap(
0656 basic_fields<Allocator>& lhs,
0657 basic_fields<Allocator>& rhs)
0658 {
0659 lhs.swap(rhs);
0660 }
0661
0662
0663
0664
0665
0666
0667
0668 template<class Allocator>
0669 inline
0670 std::size_t
0671 basic_fields<Allocator>::
0672 count(field name) const
0673 {
0674 BOOST_ASSERT(name != field::unknown);
0675 return count(to_string(name));
0676 }
0677
0678 template<class Allocator>
0679 std::size_t
0680 basic_fields<Allocator>::
0681 count(string_view name) const
0682 {
0683 return set_.count(name, key_compare{});
0684 }
0685
0686 template<class Allocator>
0687 inline
0688 auto
0689 basic_fields<Allocator>::
0690 find(field name) const ->
0691 const_iterator
0692 {
0693 BOOST_ASSERT(name != field::unknown);
0694 return find(to_string(name));
0695 }
0696
0697 template<class Allocator>
0698 auto
0699 basic_fields<Allocator>::
0700 find(string_view name) const ->
0701 const_iterator
0702 {
0703 auto const it = set_.find(
0704 name, key_compare{});
0705 if(it == set_.end())
0706 return list_.end();
0707 return list_.iterator_to(*it);
0708 }
0709
0710 template<class Allocator>
0711 inline
0712 auto
0713 basic_fields<Allocator>::
0714 equal_range(field name) const ->
0715 std::pair<const_iterator, const_iterator>
0716 {
0717 BOOST_ASSERT(name != field::unknown);
0718 return equal_range(to_string(name));
0719 }
0720
0721 template<class Allocator>
0722 auto
0723 basic_fields<Allocator>::
0724 equal_range(string_view name) const ->
0725 std::pair<const_iterator, const_iterator>
0726 {
0727 auto result =
0728 set_.equal_range(name, key_compare{});
0729 if(result.first == result.second)
0730 return {list_.end(), list_.end()};
0731 return {
0732 list_.iterator_to(*result.first),
0733 ++list_.iterator_to(*(--result.second))};
0734 }
0735
0736
0737
0738 namespace detail {
0739
0740 struct iequals_predicate
0741 {
0742 bool
0743 operator()(string_view s) const
0744 {
0745 return beast::iequals(s, sv1) || beast::iequals(s, sv2);
0746 }
0747
0748 string_view sv1;
0749 string_view sv2;
0750 };
0751
0752
0753 BOOST_BEAST_DECL
0754 void
0755 filter_token_list_last(
0756 beast::detail::temporary_buffer& s,
0757 string_view value,
0758 iequals_predicate const& pred);
0759
0760 BOOST_BEAST_DECL
0761 void
0762 keep_alive_impl(
0763 beast::detail::temporary_buffer& s, string_view value,
0764 unsigned version, bool keep_alive);
0765
0766 }
0767
0768
0769
0770
0771
0772 template<class Allocator>
0773 inline
0774 string_view
0775 basic_fields<Allocator>::
0776 get_method_impl() const
0777 {
0778 return method_;
0779 }
0780
0781 template<class Allocator>
0782 inline
0783 string_view
0784 basic_fields<Allocator>::
0785 get_target_impl() const
0786 {
0787 if(target_or_reason_.empty())
0788 return target_or_reason_;
0789 return {
0790 target_or_reason_.data() + 1,
0791 target_or_reason_.size() - 1};
0792 }
0793
0794 template<class Allocator>
0795 inline
0796 string_view
0797 basic_fields<Allocator>::
0798 get_reason_impl() const
0799 {
0800 return target_or_reason_;
0801 }
0802
0803 template<class Allocator>
0804 bool
0805 basic_fields<Allocator>::
0806 get_chunked_impl() const
0807 {
0808 auto const te = token_list{
0809 (*this)[field::transfer_encoding]};
0810 for(auto it = te.begin(); it != te.end();)
0811 {
0812 auto const next = std::next(it);
0813 if(next == te.end())
0814 return beast::iequals(*it, "chunked");
0815 it = next;
0816 }
0817 return false;
0818 }
0819
0820 template<class Allocator>
0821 bool
0822 basic_fields<Allocator>::
0823 get_keep_alive_impl(unsigned version) const
0824 {
0825 auto const it = find(field::connection);
0826 if(version < 11)
0827 {
0828 if(it == end())
0829 return false;
0830 return token_list{
0831 it->value()}.exists("keep-alive");
0832 }
0833 if(it == end())
0834 return true;
0835 return ! token_list{
0836 it->value()}.exists("close");
0837 }
0838
0839 template<class Allocator>
0840 bool
0841 basic_fields<Allocator>::
0842 has_content_length_impl() const
0843 {
0844 return count(field::content_length) > 0;
0845 }
0846
0847 template<class Allocator>
0848 inline
0849 void
0850 basic_fields<Allocator>::
0851 set_method_impl(string_view s)
0852 {
0853 realloc_string(method_, s);
0854 }
0855
0856 template<class Allocator>
0857 inline
0858 void
0859 basic_fields<Allocator>::
0860 set_target_impl(string_view s)
0861 {
0862 realloc_target(
0863 target_or_reason_, s);
0864 }
0865
0866 template<class Allocator>
0867 inline
0868 void
0869 basic_fields<Allocator>::
0870 set_reason_impl(string_view s)
0871 {
0872 realloc_string(
0873 target_or_reason_, s);
0874 }
0875
0876 template<class Allocator>
0877 void
0878 basic_fields<Allocator>::
0879 set_chunked_impl(bool value)
0880 {
0881 beast::detail::temporary_buffer buf;
0882 auto it = find(field::transfer_encoding);
0883 if(value)
0884 {
0885
0886 if(it == end())
0887 {
0888 set(field::transfer_encoding, "chunked");
0889 return;
0890 }
0891 auto const te = token_list{it->value()};
0892 for(auto itt = te.begin();;)
0893 {
0894 auto const next = std::next(itt);
0895 if(next == te.end())
0896 {
0897 if(beast::iequals(*itt, "chunked"))
0898 return;
0899 break;
0900 }
0901 itt = next;
0902 }
0903
0904 buf.append(it->value(), ", chunked");
0905 set(field::transfer_encoding, buf.view());
0906 return;
0907 }
0908
0909 if(it == end())
0910 return;
0911
0912 detail::filter_token_list_last(buf, it->value(), {"chunked", {}});
0913 if(! buf.empty())
0914 set(field::transfer_encoding, buf.view());
0915 else
0916 erase(field::transfer_encoding);
0917 }
0918
0919 template<class Allocator>
0920 void
0921 basic_fields<Allocator>::
0922 set_content_length_impl(
0923 boost::optional<std::uint64_t> const& value)
0924 {
0925 if(! value)
0926 erase(field::content_length);
0927 else
0928 {
0929 auto s = to_static_string(*value);
0930 set(field::content_length,
0931 to_string_view(s));
0932 }
0933 }
0934
0935 template<class Allocator>
0936 void
0937 basic_fields<Allocator>::
0938 set_keep_alive_impl(
0939 unsigned version, bool keep_alive)
0940 {
0941
0942 auto const value = (*this)[field::connection];
0943 beast::detail::temporary_buffer buf;
0944 detail::keep_alive_impl(buf, value, version, keep_alive);
0945 if(buf.empty())
0946 erase(field::connection);
0947 else
0948 set(field::connection, buf.view());
0949 }
0950
0951
0952
0953 template<class Allocator>
0954 auto
0955 basic_fields<Allocator>::
0956 new_element(field name,
0957 string_view sname, string_view value) ->
0958 element&
0959 {
0960 if(sname.size() + 2 >
0961 (std::numeric_limits<off_t>::max)())
0962 BOOST_THROW_EXCEPTION(std::length_error{
0963 "field name too large"});
0964 if(value.size() + 2 >
0965 (std::numeric_limits<off_t>::max)())
0966 BOOST_THROW_EXCEPTION(std::length_error{
0967 "field value too large"});
0968 value = detail::trim(value);
0969 std::uint16_t const off =
0970 static_cast<off_t>(sname.size() + 2);
0971 std::uint16_t const len =
0972 static_cast<off_t>(value.size());
0973 auto a = rebind_type{this->get()};
0974 auto const p = alloc_traits::allocate(a,
0975 (sizeof(element) + off + len + 2 + sizeof(align_type) - 1) /
0976 sizeof(align_type));
0977 return *(::new(p) element(name, sname, value));
0978 }
0979
0980 template<class Allocator>
0981 void
0982 basic_fields<Allocator>::
0983 delete_element(element& e)
0984 {
0985 auto a = rebind_type{this->get()};
0986 auto const n =
0987 (sizeof(element) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
0988 sizeof(align_type);
0989 e.~element();
0990 alloc_traits::deallocate(a,
0991 reinterpret_cast<align_type*>(&e), n);
0992 }
0993
0994 template<class Allocator>
0995 void
0996 basic_fields<Allocator>::
0997 set_element(element& e)
0998 {
0999 auto it = set_.lower_bound(
1000 e.name_string(), key_compare{});
1001 if(it == set_.end() || ! beast::iequals(
1002 e.name_string(), it->name_string()))
1003 {
1004 set_.insert_before(it, e);
1005 list_.push_back(e);
1006 return;
1007 }
1008 for(;;)
1009 {
1010 auto next = it;
1011 ++next;
1012 set_.erase(it);
1013 list_.erase(list_.iterator_to(*it));
1014 delete_element(*it);
1015 it = next;
1016 if(it == set_.end() ||
1017 ! beast::iequals(e.name_string(), it->name_string()))
1018 break;
1019 }
1020 set_.insert_before(it, e);
1021 list_.push_back(e);
1022 }
1023
1024 template<class Allocator>
1025 void
1026 basic_fields<Allocator>::
1027 realloc_string(string_view& dest, string_view s)
1028 {
1029 if(dest.empty() && s.empty())
1030 return;
1031 auto a = typename beast::detail::allocator_traits<
1032 Allocator>::template rebind_alloc<
1033 char>(this->get());
1034 char* p = nullptr;
1035 if(! s.empty())
1036 {
1037 p = a.allocate(s.size());
1038 s.copy(p, s.size());
1039 }
1040 if(! dest.empty())
1041 a.deallocate(const_cast<char*>(
1042 dest.data()), dest.size());
1043 if(p)
1044 dest = {p, s.size()};
1045 else
1046 dest = {};
1047 }
1048
1049 template<class Allocator>
1050 void
1051 basic_fields<Allocator>::
1052 realloc_target(
1053 string_view& dest, string_view s)
1054 {
1055
1056
1057
1058 if(dest.empty() && s.empty())
1059 return;
1060 auto a = typename beast::detail::allocator_traits<
1061 Allocator>::template rebind_alloc<
1062 char>(this->get());
1063 char* p = nullptr;
1064 if(! s.empty())
1065 {
1066 p = a.allocate(1 + s.size());
1067 p[0] = ' ';
1068 s.copy(p + 1, s.size());
1069 }
1070 if(! dest.empty())
1071 a.deallocate(const_cast<char*>(
1072 dest.data()), dest.size());
1073 if(p)
1074 dest = {p, 1 + s.size()};
1075 else
1076 dest = {};
1077 }
1078
1079 template<class Allocator>
1080 template<class OtherAlloc>
1081 void
1082 basic_fields<Allocator>::
1083 copy_all(basic_fields<OtherAlloc> const& other)
1084 {
1085 for(auto const& e : other.list_)
1086 insert(e.name(), e.name_string(), e.value());
1087 realloc_string(method_, other.method_);
1088 realloc_string(target_or_reason_,
1089 other.target_or_reason_);
1090 }
1091
1092 template<class Allocator>
1093 void
1094 basic_fields<Allocator>::
1095 clear_all()
1096 {
1097 clear();
1098 realloc_string(method_, {});
1099 realloc_string(target_or_reason_, {});
1100 }
1101
1102 template<class Allocator>
1103 void
1104 basic_fields<Allocator>::
1105 delete_list()
1106 {
1107 for(auto it = list_.begin(); it != list_.end();)
1108 delete_element(*it++);
1109 }
1110
1111
1112
1113 template<class Allocator>
1114 inline
1115 void
1116 basic_fields<Allocator>::
1117 move_assign(basic_fields& other, std::true_type)
1118 {
1119 clear_all();
1120 this->get() = std::move(other.get());
1121 set_ = std::move(other.set_);
1122 list_ = std::move(other.list_);
1123 method_ = other.method_;
1124 target_or_reason_ = other.target_or_reason_;
1125 other.method_ = {};
1126 other.target_or_reason_ = {};
1127 }
1128
1129 template<class Allocator>
1130 inline
1131 void
1132 basic_fields<Allocator>::
1133 move_assign(basic_fields& other, std::false_type)
1134 {
1135 clear_all();
1136 if(this->get() != other.get())
1137 {
1138 copy_all(other);
1139 }
1140 else
1141 {
1142 set_ = std::move(other.set_);
1143 list_ = std::move(other.list_);
1144 method_ = other.method_;
1145 target_or_reason_ = other.target_or_reason_;
1146 other.method_ = {};
1147 other.target_or_reason_ = {};
1148 }
1149 }
1150
1151 template<class Allocator>
1152 inline
1153 void
1154 basic_fields<Allocator>::
1155 copy_assign(basic_fields const& other, std::true_type)
1156 {
1157 clear_all();
1158 this->get() = other.get();
1159 copy_all(other);
1160 }
1161
1162 template<class Allocator>
1163 inline
1164 void
1165 basic_fields<Allocator>::
1166 copy_assign(basic_fields const& other, std::false_type)
1167 {
1168 clear_all();
1169 copy_all(other);
1170 }
1171
1172 template<class Allocator>
1173 inline
1174 void
1175 basic_fields<Allocator>::
1176 swap(basic_fields& other, std::true_type)
1177 {
1178 using std::swap;
1179 swap(this->get(), other.get());
1180 swap(set_, other.set_);
1181 swap(list_, other.list_);
1182 swap(method_, other.method_);
1183 swap(target_or_reason_, other.target_or_reason_);
1184 }
1185
1186 template<class Allocator>
1187 inline
1188 void
1189 basic_fields<Allocator>::
1190 swap(basic_fields& other, std::false_type)
1191 {
1192 BOOST_ASSERT(this->get() == other.get());
1193 using std::swap;
1194 swap(set_, other.set_);
1195 swap(list_, other.list_);
1196 swap(method_, other.method_);
1197 swap(target_or_reason_, other.target_or_reason_);
1198 }
1199
1200 }
1201 }
1202 }
1203
1204 #ifdef BOOST_BEAST_HEADER_ONLY
1205 #include <boost/beast/http/impl/fields.ipp>
1206 #endif
1207
1208 #endif