mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Add HTTP field value parsers:
ext_list:
Iterable container of comma separated extensions, where each extension
is a token followed an optional list of semicolon delimited parameters,
with each parameter consisting of a name / value pair. The value can
be a token or quoted-string.
param_list:
Iterable container of semicolon delimited parameters, where each parameter
is a name / value pair. The value can be a token or quoted-string.
token_list
Iterable container of comma delimited tokens.
* Remove obsolete rfc2616 functions
* Refactor and consolidate case-insensitive string helpers
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
#ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
|
||||
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
|
||||
|
||||
#include <beast/http/detail/rfc7230.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
@@ -257,12 +259,13 @@ template<class Allocator>
|
||||
void
|
||||
basic_headers<Allocator>::
|
||||
insert(boost::string_ref const& name,
|
||||
boost::string_ref const& value)
|
||||
boost::string_ref value)
|
||||
{
|
||||
value = detail::trim(value);
|
||||
typename set_t::insert_commit_data d;
|
||||
auto const result =
|
||||
set_.insert_check(name, less{}, d);
|
||||
if (result.second)
|
||||
if(result.second)
|
||||
{
|
||||
auto const p = alloc_traits::allocate(
|
||||
this->member(), 1);
|
||||
@@ -284,8 +287,9 @@ template<class Allocator>
|
||||
void
|
||||
basic_headers<Allocator>::
|
||||
replace(boost::string_ref const& name,
|
||||
boost::string_ref const& value)
|
||||
boost::string_ref value)
|
||||
{
|
||||
value = detail::trim(value);
|
||||
erase(name);
|
||||
insert(name, value);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef BEAST_HTTP_IMPL_MESSAGE_V1_IPP
|
||||
#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP
|
||||
|
||||
#include <beast/http/rfc2616.hpp>
|
||||
#include <beast/http/rfc7230.hpp>
|
||||
#include <beast/http/detail/has_content_length.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <stdexcept>
|
||||
@@ -22,13 +22,11 @@ is_keep_alive(message_v1<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
if(msg.version >= 11)
|
||||
{
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "close"))
|
||||
if(token_list{msg.headers["Connection"]}.exists("close"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "keep-alive"))
|
||||
if(token_list{msg.headers["Connection"]}.exists("keep-alive"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -39,8 +37,7 @@ is_upgrade(message_v1<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
if(msg.version < 11)
|
||||
return false;
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "upgrade"))
|
||||
if(token_list{msg.headers["Connection"]}.exists("upgrade"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -129,8 +126,7 @@ prepare(message_v1<isRequest, Body, Headers>& msg,
|
||||
throw std::invalid_argument(
|
||||
"prepare called with Content-Length field set");
|
||||
|
||||
if(rfc2616::token_in_list(
|
||||
msg.headers["Transfer-Encoding"], "chunked"))
|
||||
if(token_list{msg.headers["Transfer-Encoding"]}.exists("chunked"))
|
||||
throw std::invalid_argument(
|
||||
"prepare called with Transfer-Encoding: chunked set");
|
||||
|
||||
@@ -175,8 +171,8 @@ prepare(message_v1<isRequest, Body, Headers>& msg,
|
||||
}
|
||||
|
||||
// rfc7230 6.7.
|
||||
if(msg.version < 11 && rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "upgrade"))
|
||||
if(msg.version < 11 && token_list{
|
||||
msg.headers["Connection"]}.exists("upgrade"))
|
||||
throw std::invalid_argument(
|
||||
"invalid version for Connection: upgrade");
|
||||
}
|
||||
|
||||
548
include/beast/http/impl/rfc7230.ipp
Normal file
548
include/beast/http/impl/rfc7230.ipp
Normal file
@@ -0,0 +1,548 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 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)
|
||||
//
|
||||
|
||||
#ifndef BEAST_HTTP_IMPL_RFC7230_IPP
|
||||
#define BEAST_HTTP_IMPL_RFC7230_IPP
|
||||
|
||||
#include <beast/core/detail/ci_char_traits.hpp>
|
||||
#include <beast/http/detail/rfc7230.hpp>
|
||||
#include <iterator>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
class param_list::const_iterator
|
||||
{
|
||||
using iter_type = boost::string_ref::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_.end == pi_.end &&
|
||||
other.pi_.begin == pi_.begin;
|
||||
}
|
||||
|
||||
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 begin, iter_type end)
|
||||
{
|
||||
pi_.it = begin;
|
||||
pi_.begin = begin;
|
||||
pi_.end = end;
|
||||
increment();
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
static
|
||||
std::string
|
||||
unquote(boost::string_ref const& 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(boost::string_ref const& 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_.end;
|
||||
pi_.begin = pi_.end;
|
||||
}
|
||||
else if(pi_.v.second.front() == '"')
|
||||
{
|
||||
s_ = unquote(pi_.v.second);
|
||||
pi_.v.second = boost::string_ref{
|
||||
s_.data(), s_.size()};
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ext_list::const_iterator
|
||||
{
|
||||
ext_list::value_type v_;
|
||||
iter_type it_;
|
||||
iter_type begin_;
|
||||
iter_type end_;
|
||||
|
||||
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.begin_ == begin_ &&
|
||||
other.end_ == end_;
|
||||
}
|
||||
|
||||
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;
|
||||
begin_ = begin;
|
||||
end_ = 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 beast::detail::ci_equal(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_ = end_;
|
||||
begin_ = end_;
|
||||
};
|
||||
auto need_comma = it_ != begin_;
|
||||
v_.first = {};
|
||||
begin_ = it_;
|
||||
for(;;)
|
||||
{
|
||||
detail::skip_ows(it_, end_);
|
||||
if(it_ == end_)
|
||||
return err();
|
||||
auto const c = *it_;
|
||||
if(detail::is_tchar(c))
|
||||
{
|
||||
if(need_comma)
|
||||
return err();
|
||||
auto const p0 = it_;
|
||||
for(;;)
|
||||
{
|
||||
++it_;
|
||||
if(it_ == end_)
|
||||
break;
|
||||
if(! detail::is_tchar(*it_))
|
||||
break;
|
||||
}
|
||||
v_.first = boost::string_ref{&*p0,
|
||||
static_cast<std::size_t>(it_ - p0)};
|
||||
detail::param_iter pi;
|
||||
pi.it = it_;
|
||||
pi.begin = it_;
|
||||
pi.end = end_;
|
||||
for(;;)
|
||||
{
|
||||
pi.increment();
|
||||
if(pi.empty())
|
||||
break;
|
||||
}
|
||||
v_.second = param_list{boost::string_ref{&*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 begin_;
|
||||
iter_type end_;
|
||||
|
||||
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.begin_ == begin_ &&
|
||||
other.end_ == end_;
|
||||
}
|
||||
|
||||
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;
|
||||
begin_ = begin;
|
||||
end_ = 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_ = end_;
|
||||
begin_ = end_;
|
||||
};
|
||||
auto need_comma = it_ != begin_;
|
||||
v_ = {};
|
||||
begin_ = it_;
|
||||
for(;;)
|
||||
{
|
||||
detail::skip_ows(it_, end_);
|
||||
if(it_ == end_)
|
||||
return err();
|
||||
auto const c = *it_;
|
||||
if(detail::is_tchar(c))
|
||||
{
|
||||
if(need_comma)
|
||||
return err();
|
||||
auto const p0 = it_;
|
||||
for(;;)
|
||||
{
|
||||
++it_;
|
||||
if(it_ == end_)
|
||||
break;
|
||||
if(! detail::is_tchar(*it_))
|
||||
break;
|
||||
}
|
||||
v_ = boost::string_ref{&*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 beast::detail::ci_equal(s, v);
|
||||
}
|
||||
) != end();
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
|
||||
@@ -97,10 +97,10 @@ struct write_preparation
|
||||
message_v1<isRequest, Body, Headers> const& msg_)
|
||||
: msg(msg_)
|
||||
, w(msg)
|
||||
, chunked(rfc2616::token_in_list(
|
||||
msg.headers["Transfer-Encoding"], "chunked"))
|
||||
, close(rfc2616::token_in_list(
|
||||
msg.headers["Connection"], "close") ||
|
||||
, chunked(token_list{
|
||||
msg.headers["Transfer-Encoding"]}.exists("chunked"))
|
||||
, close(token_list{
|
||||
msg.headers["Connection"]}.exists("close") ||
|
||||
(msg.version < 11 && ! msg.headers.exists(
|
||||
"Content-Length")))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user