Back to home page

EIC code displayed by LXR

 
 

    


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 // 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 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     // VFALCO is it worth comparing `field name` first?
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     // keep duplicate fields together in the list
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 // Lookup
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 // Filter the last item in a token list
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 } // detail
0767 
0768 //------------------------------------------------------------------------------
0769 
0770 // Fields
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         // append "chunked"
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; // already set
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     // filter "chunked"
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     // VFALCO What about Proxy-Connection ?
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     // The target string are stored with an
1056     // extra space at the beginning to help
1057     // the writer class.
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 } // http
1201 } // beast
1202 } // boost
1203 
1204 #ifdef BOOST_BEAST_HEADER_ONLY
1205 #include <boost/beast/http/impl/fields.ipp>
1206 #endif
1207 
1208 #endif