Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:30:16

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
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     request
0191         "<method>"
0192         " <target>"
0193         " HTTP/X.Y\r\n" (11 chars)
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     // target_or_reason_ has a leading SP
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     response
0233         "HTTP/X.Y ### " (13 chars)
0234         "<reason>"
0235         "\r\n"
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     //BOOST_ASSERT(name == field::unknown ||
0298     //    iequals(sname, to_string(name)));
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 // Element access
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 // Modifiers
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 // Lookup
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 // Filter the last item in a token list
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 } // detail
0761 
0762 //------------------------------------------------------------------------------
0763 
0764 // Fields
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         // append "chunked"
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; // already set
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     // filter "chunked"
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     // VFALCO What about Proxy-Connection ?
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     // VFALCO is it worth comparing `field name` first?
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     // keep duplicate fields together in the list
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     // The target string are stored with an
1097     // extra space at the beginning to help
1098     // the writer class.
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 } // http
1242 } // beast
1243 } // boost
1244 
1245 #ifdef BOOST_BEAST_HEADER_ONLY
1246 #include <boost/beast/http/impl/fields.ipp>
1247 #endif
1248 
1249 #endif