Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:29

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 #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     request
0193         "<method>"
0194         " <target>"
0195         " HTTP/X.Y\r\n" (11 chars)
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     // target_or_reason_ has a leading SP
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     response
0235         "HTTP/X.Y ### " (13 chars)
0236         "<reason>"
0237         "\r\n"
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     //BOOST_ASSERT(name == field::unknown ||
0300     //    iequals(sname, to_string(name)));
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 // Element access
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 // Modifiers
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     // VFALCO is it worth comparing `field name` first?
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     // keep duplicate fields together in the list
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 // Lookup
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 // Filter the last item in a token list
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 } // detail
0774 
0775 //------------------------------------------------------------------------------
0776 
0777 // Fields
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         // append "chunked"
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; // already set
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     // filter "chunked"
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     // VFALCO What about Proxy-Connection ?
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     // The target string are stored with an
1063     // extra space at the beginning to help
1064     // the writer class.
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 } // http
1208 } // beast
1209 } // boost
1210 
1211 #ifdef BOOST_BEAST_HEADER_ONLY
1212 #include <boost/beast/http/impl/fields.ipp>
1213 #endif
1214 
1215 #endif