| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393 |
- //
- // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/beast
- //
- #ifndef BOOST_BEAST_HTTP_IMPL_FIELDS_IPP
- #define BOOST_BEAST_HTTP_IMPL_FIELDS_IPP
- #include <boost/beast/core/buffers_cat.hpp>
- #include <boost/beast/core/string.hpp>
- #include <boost/beast/core/static_string.hpp>
- #include <boost/beast/core/detail/buffers_ref.hpp>
- #include <boost/beast/http/verb.hpp>
- #include <boost/beast/http/rfc7230.hpp>
- #include <boost/beast/http/status.hpp>
- #include <boost/beast/http/chunk_encode.hpp>
- #include <boost/core/exchange.hpp>
- #include <boost/throw_exception.hpp>
- #include <stdexcept>
- #include <string>
- #if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000
- // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
- #ifndef BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
- #define BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
- #endif
- #endif
- namespace boost {
- namespace beast {
- namespace http {
- template<class Allocator>
- class basic_fields<Allocator>::writer
- {
- public:
- using iter_type = typename list_t::const_iterator;
- struct field_iterator
- {
- iter_type it_;
- using value_type = boost::asio::const_buffer;
- using pointer = value_type const*;
- using reference = value_type const;
- using difference_type = std::ptrdiff_t;
- using iterator_category =
- std::bidirectional_iterator_tag;
- field_iterator() = default;
- field_iterator(field_iterator&& other) = default;
- field_iterator(field_iterator const& other) = default;
- field_iterator& operator=(field_iterator&& other) = default;
- field_iterator& operator=(field_iterator const& other) = default;
- explicit
- field_iterator(iter_type it)
- : it_(it)
- {
- }
- bool
- operator==(field_iterator const& other) const
- {
- return it_ == other.it_;
- }
- bool
- operator!=(field_iterator const& other) const
- {
- return !(*this == other);
- }
- reference
- operator*() const
- {
- return it_->buffer();
- }
- field_iterator&
- operator++()
- {
- ++it_;
- return *this;
- }
- field_iterator
- operator++(int)
- {
- auto temp = *this;
- ++(*this);
- return temp;
- }
- field_iterator&
- operator--()
- {
- --it_;
- return *this;
- }
- field_iterator
- operator--(int)
- {
- auto temp = *this;
- --(*this);
- return temp;
- }
- };
- class field_range
- {
- field_iterator first_;
- field_iterator last_;
- public:
- using const_iterator =
- field_iterator;
- using value_type =
- typename const_iterator::value_type;
- field_range(iter_type first, iter_type last)
- : first_(first)
- , last_(last)
- {
- }
- const_iterator
- begin() const
- {
- return first_;
- }
- const_iterator
- end() const
- {
- return last_;
- }
- };
- using view_type = buffers_cat_view<
- boost::asio::const_buffer,
- boost::asio::const_buffer,
- boost::asio::const_buffer,
- field_range,
- chunk_crlf>;
- basic_fields const& f_;
- boost::optional<view_type> view_;
- char buf_[13];
- public:
- using const_buffers_type =
- beast::detail::buffers_ref<view_type>;
- writer(basic_fields const& f,
- unsigned version, verb v);
- writer(basic_fields const& f,
- unsigned version, unsigned code);
- writer(basic_fields const& f);
- const_buffers_type
- get() const
- {
- return const_buffers_type(*view_);
- }
- };
- template<class Allocator>
- basic_fields<Allocator>::writer::
- writer(basic_fields const& f)
- : f_(f)
- {
- view_.emplace(
- boost::asio::const_buffer{nullptr, 0},
- boost::asio::const_buffer{nullptr, 0},
- boost::asio::const_buffer{nullptr, 0},
- field_range(f_.list_.begin(), f_.list_.end()),
- chunk_crlf());
- }
- template<class Allocator>
- basic_fields<Allocator>::writer::
- writer(basic_fields const& f,
- unsigned version, verb v)
- : f_(f)
- {
- /*
- request
- "<method>"
- " <target>"
- " HTTP/X.Y\r\n" (11 chars)
- */
- string_view sv;
- if(v == verb::unknown)
- sv = f_.get_method_impl();
- else
- sv = to_string(v);
- // target_or_reason_ has a leading SP
- buf_[0] = ' ';
- buf_[1] = 'H';
- buf_[2] = 'T';
- buf_[3] = 'T';
- buf_[4] = 'P';
- buf_[5] = '/';
- buf_[6] = '0' + static_cast<char>(version / 10);
- buf_[7] = '.';
- buf_[8] = '0' + static_cast<char>(version % 10);
- buf_[9] = '\r';
- buf_[10]= '\n';
- view_.emplace(
- boost::asio::const_buffer{sv.data(), sv.size()},
- boost::asio::const_buffer{
- f_.target_or_reason_.data(),
- f_.target_or_reason_.size()},
- boost::asio::const_buffer{buf_, 11},
- field_range(f_.list_.begin(), f_.list_.end()),
- chunk_crlf());
- }
- template<class Allocator>
- basic_fields<Allocator>::writer::
- writer(basic_fields const& f,
- unsigned version, unsigned code)
- : f_(f)
- {
- /*
- response
- "HTTP/X.Y ### " (13 chars)
- "<reason>"
- "\r\n"
- */
- buf_[0] = 'H';
- buf_[1] = 'T';
- buf_[2] = 'T';
- buf_[3] = 'P';
- buf_[4] = '/';
- buf_[5] = '0' + static_cast<char>(version / 10);
- buf_[6] = '.';
- buf_[7] = '0' + static_cast<char>(version % 10);
- buf_[8] = ' ';
- buf_[9] = '0' + static_cast<char>(code / 100);
- buf_[10]= '0' + static_cast<char>((code / 10) % 10);
- buf_[11]= '0' + static_cast<char>(code % 10);
- buf_[12]= ' ';
- string_view sv;
- if(! f_.target_or_reason_.empty())
- sv = f_.target_or_reason_;
- else
- sv = obsolete_reason(static_cast<status>(code));
- view_.emplace(
- boost::asio::const_buffer{buf_, 13},
- boost::asio::const_buffer{sv.data(), sv.size()},
- boost::asio::const_buffer{"\r\n", 2},
- field_range(f_.list_.begin(), f_.list_.end()),
- chunk_crlf{});
- }
- //------------------------------------------------------------------------------
- template<class Allocator>
- basic_fields<Allocator>::
- value_type::
- value_type(
- field name,
- string_view sname,
- string_view value)
- : off_(static_cast<off_t>(sname.size() + 2))
- , len_(static_cast<off_t>(value.size()))
- , f_(name)
- {
- //BOOST_ASSERT(name == field::unknown ||
- // iequals(sname, to_string(name)));
- char* p = reinterpret_cast<char*>(this + 1);
- p[off_-2] = ':';
- p[off_-1] = ' ';
- p[off_ + len_] = '\r';
- p[off_ + len_ + 1] = '\n';
- sname.copy(p, sname.size());
- value.copy(p + off_, value.size());
- }
- template<class Allocator>
- inline
- field
- basic_fields<Allocator>::
- value_type::
- name() const
- {
- return f_;
- }
- template<class Allocator>
- inline
- string_view const
- basic_fields<Allocator>::
- value_type::
- name_string() const
- {
- return {reinterpret_cast<
- char const*>(this + 1),
- static_cast<std::size_t>(off_ - 2)};
- }
- template<class Allocator>
- inline
- string_view const
- basic_fields<Allocator>::
- value_type::
- value() const
- {
- return {reinterpret_cast<
- char const*>(this + 1) + off_,
- static_cast<std::size_t>(len_)};
- }
- template<class Allocator>
- inline
- boost::asio::const_buffer
- basic_fields<Allocator>::
- value_type::
- buffer() const
- {
- return boost::asio::const_buffer{
- reinterpret_cast<char const*>(this + 1),
- static_cast<std::size_t>(off_) + len_ + 2};
- }
- //------------------------------------------------------------------------------
- template<class Allocator>
- basic_fields<Allocator>::
- ~basic_fields()
- {
- delete_list();
- realloc_string(method_, {});
- realloc_string(
- target_or_reason_, {});
- }
- template<class Allocator>
- basic_fields<Allocator>::
- basic_fields(Allocator const& alloc) noexcept
- : beast::detail::empty_base_optimization<Allocator>(alloc)
- {
- }
- template<class Allocator>
- basic_fields<Allocator>::
- basic_fields(basic_fields&& other) noexcept
- : beast::detail::empty_base_optimization<Allocator>(
- std::move(other.member()))
- , set_(std::move(other.set_))
- , list_(std::move(other.list_))
- , method_(boost::exchange(other.method_, {}))
- , target_or_reason_(boost::exchange(other.target_or_reason_, {}))
- {
- }
- template<class Allocator>
- basic_fields<Allocator>::
- basic_fields(basic_fields&& other, Allocator const& alloc)
- : beast::detail::empty_base_optimization<Allocator>(alloc)
- {
- if(this->member() != other.member())
- {
- copy_all(other);
- other.clear_all();
- }
- else
- {
- set_ = std::move(other.set_);
- list_ = std::move(other.list_);
- method_ = other.method_;
- target_or_reason_ = other.target_or_reason_;
- }
- }
- template<class Allocator>
- basic_fields<Allocator>::
- basic_fields(basic_fields const& other)
- : beast::detail::empty_base_optimization<Allocator>(alloc_traits::
- select_on_container_copy_construction(other.member()))
- {
- copy_all(other);
- }
- template<class Allocator>
- basic_fields<Allocator>::
- basic_fields(basic_fields const& other,
- Allocator const& alloc)
- : beast::detail::empty_base_optimization<Allocator>(alloc)
- {
- copy_all(other);
- }
- template<class Allocator>
- template<class OtherAlloc>
- basic_fields<Allocator>::
- basic_fields(basic_fields<OtherAlloc> const& other)
- {
- copy_all(other);
- }
- template<class Allocator>
- template<class OtherAlloc>
- basic_fields<Allocator>::
- basic_fields(basic_fields<OtherAlloc> const& other,
- Allocator const& alloc)
- : beast::detail::empty_base_optimization<Allocator>(alloc)
- {
- copy_all(other);
- }
- template<class Allocator>
- auto
- basic_fields<Allocator>::
- operator=(basic_fields&& other) noexcept(
- alloc_traits::propagate_on_container_move_assignment::value)
- -> basic_fields&
- {
- static_assert(is_nothrow_move_assignable<Allocator>::value,
- "Allocator must be noexcept assignable.");
- if(this == &other)
- return *this;
- move_assign(other, std::integral_constant<bool,
- alloc_traits:: propagate_on_container_move_assignment::value>{});
- return *this;
- }
- template<class Allocator>
- auto
- basic_fields<Allocator>::
- operator=(basic_fields const& other) ->
- basic_fields&
- {
- copy_assign(other, std::integral_constant<bool,
- alloc_traits::propagate_on_container_copy_assignment::value>{});
- return *this;
- }
- template<class Allocator>
- template<class OtherAlloc>
- auto
- basic_fields<Allocator>::
- operator=(basic_fields<OtherAlloc> const& other) ->
- basic_fields&
- {
- clear_all();
- copy_all(other);
- return *this;
- }
- //------------------------------------------------------------------------------
- //
- // Element access
- //
- //------------------------------------------------------------------------------
- template<class Allocator>
- string_view const
- basic_fields<Allocator>::
- at(field name) const
- {
- BOOST_ASSERT(name != field::unknown);
- auto const it = find(name);
- if(it == end())
- BOOST_THROW_EXCEPTION(std::out_of_range{
- "field not found"});
- return it->value();
- }
- template<class Allocator>
- string_view const
- basic_fields<Allocator>::
- at(string_view name) const
- {
- auto const it = find(name);
- if(it == end())
- BOOST_THROW_EXCEPTION(std::out_of_range{
- "field not found"});
- return it->value();
- }
- template<class Allocator>
- string_view const
- basic_fields<Allocator>::
- operator[](field name) const
- {
- BOOST_ASSERT(name != field::unknown);
- auto const it = find(name);
- if(it == end())
- return {};
- return it->value();
- }
- template<class Allocator>
- string_view const
- basic_fields<Allocator>::
- operator[](string_view name) const
- {
- auto const it = find(name);
- if(it == end())
- return {};
- return it->value();
- }
- //------------------------------------------------------------------------------
- //
- // Modifiers
- //
- //------------------------------------------------------------------------------
- template<class Allocator>
- void
- basic_fields<Allocator>::
- clear()
- {
- delete_list();
- set_.clear();
- list_.clear();
- }
- template<class Allocator>
- inline
- void
- basic_fields<Allocator>::
- insert(field name, string_param const& value)
- {
- BOOST_ASSERT(name != field::unknown);
- insert(name, to_string(name), value);
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- insert(string_view sname, string_param const& value)
- {
- auto const name =
- string_to_field(sname);
- insert(name, sname, value);
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- insert(field name,
- string_view sname, string_param const& value)
- {
- auto& e = new_element(name, sname,
- static_cast<string_view>(value));
- auto const before =
- set_.upper_bound(sname, key_compare{});
- if(before == set_.begin())
- {
- BOOST_ASSERT(count(sname) == 0);
- set_.insert_before(before, e);
- list_.push_back(e);
- return;
- }
- auto const last = std::prev(before);
- // VFALCO is it worth comparing `field name` first?
- if(! iequals(sname, last->name_string()))
- {
- BOOST_ASSERT(count(sname) == 0);
- set_.insert_before(before, e);
- list_.push_back(e);
- return;
- }
- // keep duplicate fields together in the list
- set_.insert_before(before, e);
- list_.insert(++list_.iterator_to(*last), e);
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- set(field name, string_param const& value)
- {
- BOOST_ASSERT(name != field::unknown);
- set_element(new_element(name, to_string(name),
- static_cast<string_view>(value)));
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- set(string_view sname, string_param const& value)
- {
- set_element(new_element(
- string_to_field(sname), sname,
- static_cast<string_view>(value)));
- }
- template<class Allocator>
- auto
- basic_fields<Allocator>::
- erase(const_iterator pos) ->
- const_iterator
- {
- auto next = pos;
- auto& e = *next++;
- set_.erase(e);
- list_.erase(pos);
- delete_element(const_cast<value_type&>(e));
- return next;
- }
- template<class Allocator>
- std::size_t
- basic_fields<Allocator>::
- erase(field name)
- {
- BOOST_ASSERT(name != field::unknown);
- return erase(to_string(name));
- }
- template<class Allocator>
- std::size_t
- basic_fields<Allocator>::
- erase(string_view name)
- {
- std::size_t n =0;
- set_.erase_and_dispose(name, key_compare{},
- [&](value_type* e)
- {
- ++n;
- list_.erase(list_.iterator_to(*e));
- delete_element(*e);
- });
- return n;
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- swap(basic_fields<Allocator>& other)
- {
- swap(other, std::integral_constant<bool,
- alloc_traits::propagate_on_container_swap::value>{});
- }
- template<class Allocator>
- void
- swap(
- basic_fields<Allocator>& lhs,
- basic_fields<Allocator>& rhs)
- {
- lhs.swap(rhs);
- }
- //------------------------------------------------------------------------------
- //
- // Lookup
- //
- //------------------------------------------------------------------------------
- template<class Allocator>
- inline
- std::size_t
- basic_fields<Allocator>::
- count(field name) const
- {
- BOOST_ASSERT(name != field::unknown);
- return count(to_string(name));
- }
- template<class Allocator>
- std::size_t
- basic_fields<Allocator>::
- count(string_view name) const
- {
- return set_.count(name, key_compare{});
- }
- template<class Allocator>
- inline
- auto
- basic_fields<Allocator>::
- find(field name) const ->
- const_iterator
- {
- BOOST_ASSERT(name != field::unknown);
- return find(to_string(name));
- }
- template<class Allocator>
- auto
- basic_fields<Allocator>::
- find(string_view name) const ->
- const_iterator
- {
- auto const it = set_.find(
- name, key_compare{});
- if(it == set_.end())
- return list_.end();
- return list_.iterator_to(*it);
- }
- template<class Allocator>
- inline
- auto
- basic_fields<Allocator>::
- equal_range(field name) const ->
- std::pair<const_iterator, const_iterator>
- {
- BOOST_ASSERT(name != field::unknown);
- return equal_range(to_string(name));
- }
- template<class Allocator>
- auto
- basic_fields<Allocator>::
- equal_range(string_view name) const ->
- std::pair<const_iterator, const_iterator>
- {
- auto result =
- set_.equal_range(name, key_compare{});
- if(result.first == result.second)
- return {list_.end(), list_.end()};
- return {
- list_.iterator_to(*result.first),
- ++list_.iterator_to(*(--result.second))};
- }
- //------------------------------------------------------------------------------
- namespace detail {
- // Filter a token list
- //
- template<class String, class Pred>
- void
- filter_token_list(
- String& s,
- string_view value,
- Pred&& pred)
- {
- token_list te{value};
- auto it = te.begin();
- auto last = te.end();
- if(it == last)
- return;
- while(pred(*it))
- if(++it == last)
- return;
- s.append(it->data(), it->size());
- while(++it != last)
- {
- if(! pred(*it))
- {
- s.append(", ");
- s.append(it->data(), it->size());
- }
- }
- }
- // Filter the last item in a token list
- template<class String, class Pred>
- void
- filter_token_list_last(
- String& s,
- string_view value,
- Pred&& pred)
- {
- token_list te{value};
- if(te.begin() != te.end())
- {
- auto it = te.begin();
- auto next = std::next(it);
- if(next == te.end())
- {
- if(! pred(*it))
- s.append(it->data(), it->size());
- return;
- }
- s.append(it->data(), it->size());
- for(;;)
- {
- it = next;
- next = std::next(it);
- if(next == te.end())
- {
- if(! pred(*it))
- {
- s.append(", ");
- s.append(it->data(), it->size());
- }
- return;
- }
- s.append(", ");
- s.append(it->data(), it->size());
- }
- }
- }
- template<class String>
- void
- keep_alive_impl(
- String& s, string_view value,
- unsigned version, bool keep_alive)
- {
- if(version < 11)
- {
- if(keep_alive)
- {
- // remove close
- filter_token_list(s, value,
- [](string_view s)
- {
- return iequals(s, "close");
- });
- // add keep-alive
- if(s.empty())
- s.append("keep-alive");
- else if(! token_list{value}.exists("keep-alive"))
- s.append(", keep-alive");
- }
- else
- {
- // remove close and keep-alive
- filter_token_list(s, value,
- [](string_view s)
- {
- return
- iequals(s, "close") ||
- iequals(s, "keep-alive");
- });
- }
- }
- else
- {
- if(keep_alive)
- {
- // remove close and keep-alive
- filter_token_list(s, value,
- [](string_view s)
- {
- return
- iequals(s, "close") ||
- iequals(s, "keep-alive");
- });
- }
- else
- {
- // remove keep-alive
- filter_token_list(s, value,
- [](string_view s)
- {
- return iequals(s, "keep-alive");
- });
- // add close
- if(s.empty())
- s.append("close");
- else if(! token_list{value}.exists("close"))
- s.append(", close");
- }
- }
- }
- } // detail
- //------------------------------------------------------------------------------
- // Fields
- template<class Allocator>
- inline
- string_view
- basic_fields<Allocator>::
- get_method_impl() const
- {
- return method_;
- }
- template<class Allocator>
- inline
- string_view
- basic_fields<Allocator>::
- get_target_impl() const
- {
- if(target_or_reason_.empty())
- return target_or_reason_;
- return {
- target_or_reason_.data() + 1,
- target_or_reason_.size() - 1};
- }
- template<class Allocator>
- inline
- string_view
- basic_fields<Allocator>::
- get_reason_impl() const
- {
- return target_or_reason_;
- }
- template<class Allocator>
- bool
- basic_fields<Allocator>::
- get_chunked_impl() const
- {
- auto const te = token_list{
- (*this)[field::transfer_encoding]};
- for(auto it = te.begin(); it != te.end();)
- {
- auto const next = std::next(it);
- if(next == te.end())
- return iequals(*it, "chunked");
- it = next;
- }
- return false;
- }
- template<class Allocator>
- bool
- basic_fields<Allocator>::
- get_keep_alive_impl(unsigned version) const
- {
- auto const it = find(field::connection);
- if(version < 11)
- {
- if(it == end())
- return false;
- return token_list{
- it->value()}.exists("keep-alive");
- }
- if(it == end())
- return true;
- return ! token_list{
- it->value()}.exists("close");
- }
- template<class Allocator>
- bool
- basic_fields<Allocator>::
- has_content_length_impl() const
- {
- return count(field::content_length) > 0;
- }
- template<class Allocator>
- inline
- void
- basic_fields<Allocator>::
- set_method_impl(string_view s)
- {
- realloc_string(method_, s);
- }
- template<class Allocator>
- inline
- void
- basic_fields<Allocator>::
- set_target_impl(string_view s)
- {
- realloc_target(
- target_or_reason_, s);
- }
- template<class Allocator>
- inline
- void
- basic_fields<Allocator>::
- set_reason_impl(string_view s)
- {
- realloc_string(
- target_or_reason_, s);
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- set_chunked_impl(bool value)
- {
- auto it = find(field::transfer_encoding);
- if(value)
- {
- // append "chunked"
- if(it == end())
- {
- set(field::transfer_encoding, "chunked");
- return;
- }
- auto const te = token_list{it->value()};
- for(auto itt = te.begin();;)
- {
- auto const next = std::next(itt);
- if(next == te.end())
- {
- if(iequals(*itt, "chunked"))
- return; // already set
- break;
- }
- itt = next;
- }
- static_string<max_static_buffer> buf;
- if(it->value().size() <= buf.size() + 9)
- {
- buf.append(it->value().data(), it->value().size());
- buf.append(", chunked", 9);
- set(field::transfer_encoding, buf);
- }
- else
- {
- #ifdef BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
- // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
- std::string s;
- #else
- using A =
- typename beast::detail::allocator_traits<
- Allocator>::template rebind_alloc<char>;
- std::basic_string<
- char,
- std::char_traits<char>,
- A> s{A{this->member()}};
- #endif
- s.reserve(it->value().size() + 9);
- s.append(it->value().data(), it->value().size());
- s.append(", chunked", 9);
- set(field::transfer_encoding, s);
- }
- return;
- }
- // filter "chunked"
- if(it == end())
- return;
- try
- {
- static_string<max_static_buffer> buf;
- detail::filter_token_list_last(buf, it->value(),
- [](string_view s)
- {
- return iequals(s, "chunked");
- });
- if(! buf.empty())
- set(field::transfer_encoding, buf);
- else
- erase(field::transfer_encoding);
- }
- catch(std::length_error const&)
- {
- #ifdef BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
- // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
- std::string s;
- #else
- using A =
- typename beast::detail::allocator_traits<
- Allocator>::template rebind_alloc<char>;
- std::basic_string<
- char,
- std::char_traits<char>,
- A> s{A{this->member()}};
- #endif
- s.reserve(it->value().size());
- detail::filter_token_list_last(s, it->value(),
- [](string_view s)
- {
- return iequals(s, "chunked");
- });
- if(! s.empty())
- set(field::transfer_encoding, s);
- else
- erase(field::transfer_encoding);
- }
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- set_content_length_impl(
- boost::optional<std::uint64_t> const& value)
- {
- if(! value)
- erase(field::content_length);
- else
- set(field::content_length, *value);
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- set_keep_alive_impl(
- unsigned version, bool keep_alive)
- {
- // VFALCO What about Proxy-Connection ?
- auto const value = (*this)[field::connection];
- try
- {
- static_string<max_static_buffer> buf;
- detail::keep_alive_impl(
- buf, value, version, keep_alive);
- if(buf.empty())
- erase(field::connection);
- else
- set(field::connection, buf);
- }
- catch(std::length_error const&)
- {
- #ifdef BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR
- // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
- std::string s;
- #else
- using A =
- typename beast::detail::allocator_traits<
- Allocator>::template rebind_alloc<char>;
- std::basic_string<
- char,
- std::char_traits<char>,
- A> s{A{this->member()}};
- #endif
- s.reserve(value.size());
- detail::keep_alive_impl(
- s, value, version, keep_alive);
- if(s.empty())
- erase(field::connection);
- else
- set(field::connection, s);
- }
- }
- //------------------------------------------------------------------------------
- template<class Allocator>
- auto
- basic_fields<Allocator>::
- new_element(field name,
- string_view sname, string_view value) ->
- value_type&
- {
- if(sname.size() + 2 >
- (std::numeric_limits<off_t>::max)())
- BOOST_THROW_EXCEPTION(std::length_error{
- "field name too large"});
- if(value.size() + 2 >
- (std::numeric_limits<off_t>::max)())
- BOOST_THROW_EXCEPTION(std::length_error{
- "field value too large"});
- value = detail::trim(value);
- std::uint16_t const off =
- static_cast<off_t>(sname.size() + 2);
- std::uint16_t const len =
- static_cast<off_t>(value.size());
- auto a = rebind_type{this->member()};
- auto const p = alloc_traits::allocate(a,
- (sizeof(value_type) + off + len + 2 + sizeof(align_type) - 1) /
- sizeof(align_type));
- // VFALCO allocator can't call the constructor because its private
- //alloc_traits::construct(a, p, name, sname, value);
- new(p) value_type{name, sname, value};
- return *reinterpret_cast<value_type*>(p);
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- delete_element(value_type& e)
- {
- auto a = rebind_type{this->member()};
- auto const n =
- (sizeof(value_type) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
- sizeof(align_type);
- //alloc_traits::destroy(a, &e);
- e.~value_type();
- alloc_traits::deallocate(a,
- reinterpret_cast<align_type*>(&e), n);
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- set_element(value_type& e)
- {
- auto it = set_.lower_bound(
- e.name_string(), key_compare{});
- if(it == set_.end() || ! iequals(
- e.name_string(), it->name_string()))
- {
- set_.insert_before(it, e);
- list_.push_back(e);
- return;
- }
- for(;;)
- {
- auto next = it;
- ++next;
- set_.erase(it);
- list_.erase(list_.iterator_to(*it));
- delete_element(*it);
- it = next;
- if(it == set_.end() ||
- ! iequals(e.name_string(), it->name_string()))
- break;
- }
- set_.insert_before(it, e);
- list_.push_back(e);
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- realloc_string(string_view& dest, string_view s)
- {
- if(dest.empty() && s.empty())
- return;
- auto a = typename beast::detail::allocator_traits<
- Allocator>::template rebind_alloc<
- char>(this->member());
- char* p = nullptr;
- if(! s.empty())
- {
- p = a.allocate(s.size());
- s.copy(p, s.size());
- }
- if(! dest.empty())
- a.deallocate(const_cast<char*>(
- dest.data()), dest.size());
- if(p)
- dest = {p, s.size()};
- else
- dest = {};
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- realloc_target(
- string_view& dest, string_view s)
- {
- // The target string are stored with an
- // extra space at the beginning to help
- // the writer class.
- if(dest.empty() && s.empty())
- return;
- auto a = typename beast::detail::allocator_traits<
- Allocator>::template rebind_alloc<
- char>(this->member());
- char* p = nullptr;
- if(! s.empty())
- {
- p = a.allocate(1 + s.size());
- p[0] = ' ';
- s.copy(p + 1, s.size());
- }
- if(! dest.empty())
- a.deallocate(const_cast<char*>(
- dest.data()), dest.size());
- if(p)
- dest = {p, 1 + s.size()};
- else
- dest = {};
- }
- template<class Allocator>
- template<class OtherAlloc>
- void
- basic_fields<Allocator>::
- copy_all(basic_fields<OtherAlloc> const& other)
- {
- for(auto const& e : other.list_)
- insert(e.name(), e.name_string(), e.value());
- realloc_string(method_, other.method_);
- realloc_string(target_or_reason_,
- other.target_or_reason_);
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- clear_all()
- {
- clear();
- realloc_string(method_, {});
- realloc_string(target_or_reason_, {});
- }
- template<class Allocator>
- void
- basic_fields<Allocator>::
- delete_list()
- {
- for(auto it = list_.begin(); it != list_.end();)
- delete_element(*it++);
- }
- //------------------------------------------------------------------------------
- template<class Allocator>
- inline
- void
- basic_fields<Allocator>::
- move_assign(basic_fields& other, std::true_type)
- {
- clear_all();
- set_ = std::move(other.set_);
- list_ = std::move(other.list_);
- method_ = other.method_;
- target_or_reason_ = other.target_or_reason_;
- other.method_ = {};
- other.target_or_reason_ = {};
- this->member() = other.member();
- }
- template<class Allocator>
- inline
- void
- basic_fields<Allocator>::
- move_assign(basic_fields& other, std::false_type)
- {
- clear_all();
- if(this->member() != other.member())
- {
- copy_all(other);
- other.clear_all();
- }
- else
- {
- set_ = std::move(other.set_);
- list_ = std::move(other.list_);
- method_ = other.method_;
- target_or_reason_ = other.target_or_reason_;
- other.method_ = {};
- other.target_or_reason_ = {};
- }
- }
- template<class Allocator>
- inline
- void
- basic_fields<Allocator>::
- copy_assign(basic_fields const& other, std::true_type)
- {
- clear_all();
- this->member() = other.member();
- copy_all(other);
- }
- template<class Allocator>
- inline
- void
- basic_fields<Allocator>::
- copy_assign(basic_fields const& other, std::false_type)
- {
- clear_all();
- copy_all(other);
- }
- template<class Allocator>
- inline
- void
- basic_fields<Allocator>::
- swap(basic_fields& other, std::true_type)
- {
- using std::swap;
- swap(this->member(), other.member());
- swap(set_, other.set_);
- swap(list_, other.list_);
- swap(method_, other.method_);
- swap(target_or_reason_, other.target_or_reason_);
- }
- template<class Allocator>
- inline
- void
- basic_fields<Allocator>::
- swap(basic_fields& other, std::false_type)
- {
- BOOST_ASSERT(this->member() == other.member());
- using std::swap;
- swap(set_, other.set_);
- swap(list_, other.list_);
- swap(method_, other.method_);
- swap(target_or_reason_, other.target_or_reason_);
- }
- } // http
- } // beast
- } // boost
- #endif
|