boost/beast/http/impl/rfc7230.ipp
//
// 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_RFC7230_IPP
#define BOOST_BEAST_HTTP_IMPL_RFC7230_IPP
#include <boost/beast/http/detail/rfc7230.hpp>
#include <iterator>
namespace boost {
namespace beast {
namespace http {
class param_list::const_iterator
{
using iter_type = string_view::const_iterator;
std::string s_;
detail::param_iter pi_;
public:
using value_type = param_list::value_type;
using pointer = value_type const*;
using reference = value_type const&;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
const_iterator() = default;
bool
operator==(const_iterator const& other) const
{
return
other.pi_.it == pi_.it &&
other.pi_.last == pi_.last &&
other.pi_.first == pi_.first;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return pi_.v;
}
pointer
operator->() const
{
return &*(*this);
}
const_iterator&
operator++()
{
increment();
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
private:
friend class param_list;
const_iterator(iter_type first, iter_type last)
{
pi_.it = first;
pi_.first = first;
pi_.last = last;
increment();
}
template<class = void>
static
std::string
unquote(string_view sr);
template<class = void>
void
increment();
};
inline
auto
param_list::
begin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
param_list::
end() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
inline
auto
param_list::
cbegin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
param_list::
cend() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
template<class>
std::string
param_list::const_iterator::
unquote(string_view sr)
{
std::string s;
s.reserve(sr.size());
auto it = sr.begin() + 1;
auto end = sr.end() - 1;
while(it != end)
{
if(*it == '\\')
++it;
s.push_back(*it);
++it;
}
return s;
}
template<class>
void
param_list::const_iterator::
increment()
{
s_.clear();
pi_.increment();
if(pi_.empty())
{
pi_.it = pi_.last;
pi_.first = pi_.last;
}
else if(! pi_.v.second.empty() &&
pi_.v.second.front() == '"')
{
s_ = unquote(pi_.v.second);
pi_.v.second = string_view{
s_.data(), s_.size()};
}
}
//------------------------------------------------------------------------------
class ext_list::const_iterator
{
ext_list::value_type v_;
iter_type it_;
iter_type first_;
iter_type last_;
public:
using value_type = ext_list::value_type;
using pointer = value_type const*;
using reference = value_type const&;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
const_iterator() = default;
bool
operator==(const_iterator const& other) const
{
return
other.it_ == it_ &&
other.first_ == first_ &&
other.last_ == last_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return v_;
}
pointer
operator->() const
{
return &*(*this);
}
const_iterator&
operator++()
{
increment();
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
private:
friend class ext_list;
const_iterator(iter_type begin, iter_type end)
{
it_ = begin;
first_ = begin;
last_ = end;
increment();
}
template<class = void>
void
increment();
};
inline
auto
ext_list::
begin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
ext_list::
end() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
inline
auto
ext_list::
cbegin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
ext_list::
cend() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
template<class T>
auto
ext_list::
find(T const& s) ->
const_iterator
{
return std::find_if(begin(), end(),
[&s](value_type const& v)
{
return iequals(s, v.first);
});
}
template<class T>
bool
ext_list::
exists(T const& s)
{
return find(s) != end();
}
template<class>
void
ext_list::const_iterator::
increment()
{
/*
ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] )
ext = token param-list
param-list = *( OWS ";" OWS param )
param = token OWS "=" OWS ( token / quoted-string )
chunked;a=b;i=j,gzip;windowBits=12
x,y
,,,,,chameleon
*/
auto const err =
[&]
{
it_ = last_;
first_ = last_;
};
auto need_comma = it_ != first_;
v_.first = {};
first_ = it_;
for(;;)
{
detail::skip_ows(it_, last_);
if(it_ == last_)
return err();
auto const c = *it_;
if(detail::is_token_char(c))
{
if(need_comma)
return err();
auto const p0 = it_;
for(;;)
{
++it_;
if(it_ == last_)
break;
if(! detail::is_token_char(*it_))
break;
}
v_.first = string_view{&*p0,
static_cast<std::size_t>(it_ - p0)};
detail::param_iter pi;
pi.it = it_;
pi.first = it_;
pi.last = last_;
for(;;)
{
pi.increment();
if(pi.empty())
break;
}
v_.second = param_list{string_view{&*it_,
static_cast<std::size_t>(pi.it - it_)}};
it_ = pi.it;
return;
}
if(c != ',')
return err();
need_comma = false;
++it_;
}
}
//------------------------------------------------------------------------------
class token_list::const_iterator
{
token_list::value_type v_;
iter_type it_;
iter_type first_;
iter_type last_;
public:
using value_type = token_list::value_type;
using pointer = value_type const*;
using reference = value_type const&;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
const_iterator() = default;
bool
operator==(const_iterator const& other) const
{
return
other.it_ == it_ &&
other.first_ == first_ &&
other.last_ == last_;
}
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{
return v_;
}
pointer
operator->() const
{
return &*(*this);
}
const_iterator&
operator++()
{
increment();
return *this;
}
const_iterator
operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
private:
friend class token_list;
const_iterator(iter_type begin, iter_type end)
{
it_ = begin;
first_ = begin;
last_ = end;
increment();
}
template<class = void>
void
increment();
};
inline
auto
token_list::
begin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
token_list::
end() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
inline
auto
token_list::
cbegin() const ->
const_iterator
{
return const_iterator{s_.begin(), s_.end()};
}
inline
auto
token_list::
cend() const ->
const_iterator
{
return const_iterator{s_.end(), s_.end()};
}
template<class>
void
token_list::const_iterator::
increment()
{
/*
token-list = *( "," OWS ) token *( OWS "," [ OWS ext ] )
*/
auto const err =
[&]
{
it_ = last_;
first_ = last_;
};
auto need_comma = it_ != first_;
v_ = {};
first_ = it_;
for(;;)
{
detail::skip_ows(it_, last_);
if(it_ == last_)
return err();
auto const c = *it_;
if(detail::is_token_char(c))
{
if(need_comma)
return err();
auto const p0 = it_;
for(;;)
{
++it_;
if(it_ == last_)
break;
if(! detail::is_token_char(*it_))
break;
}
v_ = string_view{&*p0,
static_cast<std::size_t>(it_ - p0)};
return;
}
if(c != ',')
return err();
need_comma = false;
++it_;
}
}
template<class T>
bool
token_list::
exists(T const& s)
{
return std::find_if(begin(), end(),
[&s](value_type const& v)
{
return iequals(s, v);
}
) != end();
}
template<class Policy>
bool
validate_list(detail::basic_parsed_list<
Policy> const& list)
{
auto const last = list.end();
auto it = list.begin();
if(it.error())
return false;
while(it != last)
{
++it;
if(it.error())
return false;
if(it == last)
break;
}
return true;
}
} // http
} // beast
} // boost
#endif