forked from boostorg/beast
Fields concept work
This commit is contained in:
1 parent
f363654300
commit
943830f6ed
20 files changed
+675
-343
No files matched your search
@@ -21,6 +21,12 @@ namespace beast {
|
||||
template<class... Buffers>
|
||||
class buffer_cat_view
|
||||
{
|
||||
#if 0
|
||||
static_assert(
|
||||
detail::is_all_const_buffer_sequence<Buffers...>::value,
|
||||
"BufferSequence requirements not met");
|
||||
#endif
|
||||
|
||||
std::tuple<Buffers...> bn_;
|
||||
|
||||
public:
|
||||
|
||||
@@ -24,6 +24,12 @@ namespace beast {
|
||||
template<class... Bn>
|
||||
class buffer_cat_view<Bn...>::const_iterator
|
||||
{
|
||||
#if 0
|
||||
static_assert(
|
||||
detail::is_all_const_buffer_sequence<Bn...>::value,
|
||||
"BufferSequence requirements not met");
|
||||
#endif
|
||||
|
||||
std::size_t n_;
|
||||
std::tuple<Bn...> const* bn_;
|
||||
std::array<char, detail::max_sizeof<
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <beast/core/detail/ci_char_traits.hpp>
|
||||
#include <beast/http/connection.hpp>
|
||||
#include <beast/http/field.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
@@ -40,7 +41,7 @@ namespace http {
|
||||
as a `std::multiset`; there will be a separate value for each occurrence
|
||||
of the field name.
|
||||
|
||||
@note Meets the requirements of @b FieldSequence.
|
||||
@note Meets the requirements of @b Fields
|
||||
*/
|
||||
template<class Allocator>
|
||||
class basic_fields
|
||||
@@ -259,8 +260,6 @@ public:
|
||||
|
||||
@param f The known field constant.
|
||||
|
||||
@param name The name of the field.
|
||||
|
||||
@param value A string holding the value of the field.
|
||||
*/
|
||||
void
|
||||
@@ -337,54 +336,55 @@ public:
|
||||
void
|
||||
swap(basic_fields<Alloc>& lhs, basic_fields<Alloc>& rhs);
|
||||
|
||||
/// The algorithm used to serialize the header
|
||||
class reader;
|
||||
|
||||
protected:
|
||||
/// Returns `true` if the value for Connection has "close" in the list.
|
||||
bool has_close_impl() const;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// for serializing
|
||||
//
|
||||
/// Returns `true` if "chunked" is the last Transfer-Encoding
|
||||
bool has_chunked_impl() const;
|
||||
|
||||
/** Returns the stored request-method string.
|
||||
/// Returns `true` if the Content-Length field is present
|
||||
bool has_content_length_impl() const;
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
*/
|
||||
string_view get_method_impl() const;
|
||||
/** Set or clear the method string.
|
||||
|
||||
/** Returns the stored request-target string.
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
*/
|
||||
string_view get_target_impl() const;
|
||||
|
||||
/** Returns the stored obsolete reason-phrase string.
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
*/
|
||||
string_view get_reason_impl() const;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// for parsing
|
||||
//
|
||||
|
||||
/** Set or clear the stored request-method string.
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
@note Only called for requests.
|
||||
*/
|
||||
void set_method_impl(string_view s);
|
||||
|
||||
/** Set or clear the stored request-target string.
|
||||
/** Set or clear the target string.
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
@note Only called for requests.
|
||||
*/
|
||||
void set_target_impl(string_view s);
|
||||
|
||||
/** Set or clear the stored obsolete reason-phrase string.
|
||||
/** Set or clear the reason string.
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
@note Only called for responses.
|
||||
*/
|
||||
void set_reason_impl(string_view s);
|
||||
|
||||
/** Returns the request-method string.
|
||||
|
||||
@note Only called for requests.
|
||||
*/
|
||||
string_view get_method_impl() const;
|
||||
|
||||
/** Returns the request-target string.
|
||||
|
||||
@note Only called for requests.
|
||||
*/
|
||||
string_view get_target_impl() const;
|
||||
|
||||
/** Returns the response reason-phrase string.
|
||||
|
||||
@note Only called for responses.
|
||||
*/
|
||||
string_view get_reason_impl() const;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// for container
|
||||
@@ -418,7 +418,7 @@ protected:
|
||||
|
||||
@note This is called by the @ref header implementation.
|
||||
*/
|
||||
void chunked_impl();
|
||||
void set_chunked_impl(bool v);
|
||||
|
||||
private:
|
||||
class element
|
||||
@@ -441,6 +441,9 @@ private:
|
||||
string_view
|
||||
value() const;
|
||||
|
||||
boost::asio::const_buffer
|
||||
buffer() const;
|
||||
|
||||
value_type data;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,8 +8,13 @@
|
||||
#ifndef BEAST_HTTP_IMPL_FIELDS_IPP
|
||||
#define BEAST_HTTP_IMPL_FIELDS_IPP
|
||||
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/core/static_string.hpp>
|
||||
#include <beast/http/detail/rfc7230.hpp>
|
||||
#include <beast/core/detail/ci_char_traits.hpp>
|
||||
#include <beast/http/verb.hpp>
|
||||
#include <beast/http/rfc7230.hpp>
|
||||
#include <beast/http/status.hpp>
|
||||
#include <beast/http/detail/chunk_encode.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -106,6 +111,177 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
class basic_fields<Allocator>::reader
|
||||
{
|
||||
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(field_range const&) = default;
|
||||
|
||||
field_range(iter_type first, iter_type last)
|
||||
: first_(first)
|
||||
, last_(last)
|
||||
{
|
||||
}
|
||||
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return first_;
|
||||
}
|
||||
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return last_;
|
||||
}
|
||||
};
|
||||
|
||||
basic_fields const& f_;
|
||||
std::string s_;
|
||||
|
||||
public:
|
||||
using const_buffers_type =
|
||||
buffer_cat_view<
|
||||
boost::asio::const_buffers_1,
|
||||
field_range,
|
||||
boost::asio::const_buffers_1>;
|
||||
|
||||
reader(basic_fields const& f, int version, verb v)
|
||||
: f_(f)
|
||||
{
|
||||
s_ = v == verb::unknown ?
|
||||
f_.get_method_impl().to_string() :
|
||||
to_string(v).to_string();
|
||||
s_ += " ";
|
||||
s_ += f_.get_target_impl().to_string();
|
||||
if(version == 11)
|
||||
s_ += " HTTP/1.1";
|
||||
else if(version == 10)
|
||||
s_ += " HTTP/1.0";
|
||||
else
|
||||
s_ += " HTTP/" +
|
||||
std::to_string(version / 10) + "." +
|
||||
std::to_string(version % 10);
|
||||
s_ += "\r\n";
|
||||
}
|
||||
|
||||
reader(basic_fields const& f, int version, int code)
|
||||
: f_(f)
|
||||
{
|
||||
if(version == 11)
|
||||
s_ += "HTTP/1.1 ";
|
||||
else if(version == 10)
|
||||
s_ += "HTTP/1.0 ";
|
||||
else
|
||||
s_ += "HTTP/" +
|
||||
std::to_string(version / 10) + "." +
|
||||
std::to_string(version % 10) + " ";
|
||||
s_ += std::to_string(code) + " ";
|
||||
if(int_to_status(code) == status::unknown)
|
||||
s_ += f_.get_reason_impl().to_string();
|
||||
else
|
||||
s_ += obsolete_reason(int_to_status(code)).to_string();
|
||||
s_ += "\r\n";
|
||||
}
|
||||
|
||||
const_buffers_type
|
||||
get() const
|
||||
{
|
||||
return buffer_cat(
|
||||
boost::asio::buffer(s_.data(), s_.size()),
|
||||
field_range(f_.list_.begin(), f_.list_.end()),
|
||||
detail::chunk_crlf());
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
basic_fields<Allocator>::
|
||||
element::
|
||||
@@ -150,6 +326,18 @@ value() const
|
||||
static_cast<std::size_t>(len_)};
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
boost::asio::const_buffer
|
||||
basic_fields<Allocator>::
|
||||
element::
|
||||
buffer() const
|
||||
{
|
||||
return boost::asio::const_buffer{
|
||||
reinterpret_cast<char const*>(this + 1),
|
||||
static_cast<std::size_t>(off_) + len_ + 2};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class Allocator>
|
||||
@@ -361,31 +549,50 @@ replace(string_view name, string_view value)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Fields
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
bool
|
||||
basic_fields<Allocator>::
|
||||
get_method_impl() const
|
||||
has_close_impl() const
|
||||
{
|
||||
return method_;
|
||||
auto const fit = set_.find(
|
||||
to_string(field::connection), less{});
|
||||
if(fit == set_.end())
|
||||
return false;
|
||||
return token_list{fit->value()}.exists("close");
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
bool
|
||||
basic_fields<Allocator>::
|
||||
get_target_impl() const
|
||||
has_chunked_impl() const
|
||||
{
|
||||
return target_or_reason_;
|
||||
auto const fit = set_.find(to_string(
|
||||
field::transfer_encoding), less{});
|
||||
if(fit == set_.end())
|
||||
return false;
|
||||
token_list const v{fit->value()};
|
||||
auto it = v.begin();
|
||||
if(it == v.end())
|
||||
return false;
|
||||
for(;;)
|
||||
{
|
||||
auto cur = it++;
|
||||
if(it == v.end())
|
||||
return beast::detail::ci_equal(
|
||||
*cur, "chunked");
|
||||
}
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
bool
|
||||
basic_fields<Allocator>::
|
||||
get_reason_impl() const
|
||||
has_content_length_impl() const
|
||||
{
|
||||
return target_or_reason_;
|
||||
auto const fit = set_.find(
|
||||
to_string(field::content_length), less{});
|
||||
return fit != set_.end();
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
@@ -415,6 +622,33 @@ set_reason_impl(string_view s)
|
||||
realloc_string(target_or_reason_, s);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return target_or_reason_;
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
inline
|
||||
string_view
|
||||
basic_fields<Allocator>::
|
||||
get_reason_impl() const
|
||||
{
|
||||
return target_or_reason_;
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
template<class Allocator>
|
||||
@@ -474,8 +708,9 @@ template<class Allocator>
|
||||
inline
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
chunked_impl()
|
||||
set_chunked_impl(bool v)
|
||||
{
|
||||
BOOST_ASSERT(v);
|
||||
auto it = find("Transfer-Encoding");
|
||||
if(it == end())
|
||||
this->insert("Transfer-Encoding", "chunked");
|
||||
@@ -682,7 +917,6 @@ swap(basic_fields& other, std::false_type)
|
||||
swap(target_or_reason_, other.target_or_reason_);
|
||||
}
|
||||
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ method_string() const
|
||||
template<class Fields>
|
||||
void
|
||||
header<true, Fields>::
|
||||
method(string_view s)
|
||||
method_string(string_view s)
|
||||
{
|
||||
method_ = string_to_verb(s);
|
||||
if(method_ != verb::unknown)
|
||||
@@ -190,21 +190,85 @@ swap(
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class... Args>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(header_type&& base, Args&&... args)
|
||||
: header_type(std::move(base))
|
||||
, body(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class... Args>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(header_type const& base, Args&&... args)
|
||||
: header_type(base)
|
||||
, body(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class U, class>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(U&& u)
|
||||
: body(std::forward<U>(u))
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class U, class V, class>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(U&& u, V&& v)
|
||||
: header_type(std::forward<V>(v))
|
||||
, body(std::forward<U>(u))
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class... Un>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(std::piecewise_construct_t, std::tuple<Un...> un)
|
||||
: message(std::piecewise_construct, un,
|
||||
beast::detail::make_index_sequence<sizeof...(Un)>{})
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
template<class... Un, class... Vn>
|
||||
message<isRequest, Body, Fields>::
|
||||
message(std::piecewise_construct_t,
|
||||
std::tuple<Un...>&& un, std::tuple<Vn...>&& vn)
|
||||
: message(std::piecewise_construct, un, vn,
|
||||
beast::detail::make_index_sequence<sizeof...(Un)>{},
|
||||
beast::detail::make_index_sequence<sizeof...(Vn)>{})
|
||||
{
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
inline
|
||||
bool
|
||||
message<isRequest, Body, Fields>::
|
||||
chunked() const
|
||||
has_close() const
|
||||
{
|
||||
auto const it0 = this->find("Transfer-Encoding");
|
||||
if(it0 == this->end())
|
||||
return false;
|
||||
token_list value{*it0};
|
||||
for(auto it = value.begin(); it != value.end();)
|
||||
{
|
||||
auto cur = it++;
|
||||
if(it == value.end())
|
||||
return *cur == "chunked";
|
||||
}
|
||||
return false;
|
||||
return this->has_close_impl();
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
inline
|
||||
bool
|
||||
message<isRequest, Body, Fields>::
|
||||
has_chunked() const
|
||||
{
|
||||
return this->has_chunked_impl();
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
inline
|
||||
bool
|
||||
message<isRequest, Body, Fields>::
|
||||
has_content_length() const
|
||||
{
|
||||
return this->has_content_length_impl();
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
@@ -326,7 +390,7 @@ prepare_payload(std::true_type)
|
||||
}
|
||||
else if(this->version >= 11)
|
||||
{
|
||||
this->chunked_impl();
|
||||
this->set_chunked_impl(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +414,7 @@ prepare_payload(std::false_type)
|
||||
if(n)
|
||||
this->content_length_impl(*n);
|
||||
else if(this->version >= 11)
|
||||
this->chunked_impl();
|
||||
this->set_chunked_impl(true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -15,59 +15,27 @@
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
template<class Fields>
|
||||
template<bool isRequest, class Body, class Fields,
|
||||
class ChunkDecorator, class Allocator>
|
||||
void
|
||||
write_start_line(std::ostream& os,
|
||||
header<true, Fields> const& msg)
|
||||
serializer<isRequest, Body, Fields,
|
||||
ChunkDecorator, Allocator>::
|
||||
frdinit(std::true_type)
|
||||
{
|
||||
// VFALCO This should all be done without dynamic allocation
|
||||
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
||||
os << msg.method() << " " << msg.target();
|
||||
switch(msg.version)
|
||||
{
|
||||
case 10: os << " HTTP/1.0\r\n"; break;
|
||||
case 11: os << " HTTP/1.1\r\n"; break;
|
||||
}
|
||||
frd_.emplace(m_, m_.version, m_.method());
|
||||
}
|
||||
|
||||
template<class Fields>
|
||||
template<bool isRequest, class Body, class Fields,
|
||||
class ChunkDecorator, class Allocator>
|
||||
void
|
||||
write_start_line(std::ostream& os,
|
||||
header<false, Fields> const& msg)
|
||||
serializer<isRequest, Body, Fields,
|
||||
ChunkDecorator, Allocator>::
|
||||
frdinit(std::false_type)
|
||||
{
|
||||
// VFALCO This should all be done without dynamic allocation
|
||||
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
||||
switch(msg.version)
|
||||
{
|
||||
case 10: os << "HTTP/1.0 "; break;
|
||||
case 11: os << "HTTP/1.1 "; break;
|
||||
}
|
||||
os << msg.result_int() << " " << msg.reason() << "\r\n";
|
||||
frd_.emplace(m_, m_.version, m_.result_int());
|
||||
}
|
||||
|
||||
template<class FieldSequence>
|
||||
void
|
||||
write_fields(std::ostream& os,
|
||||
FieldSequence const& fields)
|
||||
{
|
||||
//static_assert(is_FieldSequence<FieldSequence>::value,
|
||||
// "FieldSequence requirements not met");
|
||||
for(auto const& field : fields)
|
||||
{
|
||||
auto const name = field.name();
|
||||
BOOST_ASSERT(! name.empty());
|
||||
if(name[0] == ':')
|
||||
continue;
|
||||
os << field.name() << ": " << field.value() << "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<bool isRequest, class Body, class Fields,
|
||||
class ChunkDecorator, class Allocator>
|
||||
serializer<isRequest, Body, Fields,
|
||||
@@ -76,7 +44,6 @@ serializer(message<isRequest, Body, Fields> const& m,
|
||||
ChunkDecorator const& d, Allocator const& alloc)
|
||||
: m_(m)
|
||||
, d_(d)
|
||||
, b_(1024, alloc)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -93,15 +60,11 @@ get(error_code& ec, Visit&& visit)
|
||||
{
|
||||
case do_construct:
|
||||
{
|
||||
chunked_ = token_list{
|
||||
m_["Transfer-Encoding"]}.exists("chunked");
|
||||
close_ = token_list{m_["Connection"]}.exists("close") ||
|
||||
(m_.version < 11 && ! m_.exists("Content-Length"));
|
||||
auto os = ostream(b_);
|
||||
detail::write_start_line(os, m_);
|
||||
detail::write_fields(os, m_);
|
||||
os << "\r\n";
|
||||
if(chunked_)
|
||||
frdinit(std::integral_constant<bool,
|
||||
isRequest>{});
|
||||
close_ = m_.has_close() || (
|
||||
m_.version < 11 && ! m_.has_content_length());
|
||||
if(m_.has_chunked())
|
||||
goto go_init_c;
|
||||
s_ = do_init;
|
||||
// [[fallthrough]]
|
||||
@@ -127,7 +90,7 @@ get(error_code& ec, Visit&& visit)
|
||||
more_ = result->second;
|
||||
v_ = cb0_t{
|
||||
boost::in_place_init,
|
||||
b_.data(),
|
||||
frd_->get(),
|
||||
result->first};
|
||||
s_ = do_header;
|
||||
// [[fallthrough]]
|
||||
@@ -137,10 +100,11 @@ get(error_code& ec, Visit&& visit)
|
||||
visit(ec, boost::get<cb0_t>(v_));
|
||||
break;
|
||||
|
||||
go_header_only:
|
||||
s_ = do_header_only;
|
||||
go_header_only:
|
||||
v_ = ch_t{frd_->get()};
|
||||
s_ = do_header_only;
|
||||
case do_header_only:
|
||||
visit(ec, b_.data());
|
||||
visit(ec, boost::get<ch_t>(v_));
|
||||
break;
|
||||
|
||||
case do_body:
|
||||
@@ -193,7 +157,7 @@ get(error_code& ec, Visit&& visit)
|
||||
more_ = result->second;
|
||||
v_ = ch0_t{
|
||||
boost::in_place_init,
|
||||
b_.data(),
|
||||
frd_->get(),
|
||||
detail::chunk_header{
|
||||
buffer_size(result->first)},
|
||||
[&]()
|
||||
@@ -214,10 +178,11 @@ get(error_code& ec, Visit&& visit)
|
||||
visit(ec, boost::get<ch0_t>(v_));
|
||||
break;
|
||||
|
||||
go_header_only_c:
|
||||
s_ = do_header_only_c;
|
||||
go_header_only_c:
|
||||
v_ = ch_t{frd_->get()};
|
||||
s_ = do_header_only_c;
|
||||
case do_header_only_c:
|
||||
visit(ec, b_.data());
|
||||
visit(ec, boost::get<ch_t>(v_));
|
||||
break;
|
||||
|
||||
case do_body_c:
|
||||
@@ -311,18 +276,18 @@ consume(std::size_t n)
|
||||
break;
|
||||
header_done_ = true;
|
||||
v_ = boost::blank{};
|
||||
b_.consume(b_.size()); // VFALCO delete b_?
|
||||
if(! more_)
|
||||
goto go_complete;
|
||||
s_ = do_body + 1;
|
||||
break;
|
||||
|
||||
case do_header_only:
|
||||
BOOST_ASSERT(n <= b_.size());
|
||||
b_.consume(n);
|
||||
if(buffer_size(b_.data()) > 0)
|
||||
BOOST_ASSERT(n <= buffer_size(
|
||||
boost::get<ch_t>(v_)));
|
||||
boost::get<ch_t>(v_).consume(n);
|
||||
if(buffer_size(boost::get<ch_t>(v_)) > 0)
|
||||
break;
|
||||
// VFALCO delete b_?
|
||||
frd_ = boost::none;
|
||||
header_done_ = true;
|
||||
if(! split_)
|
||||
goto go_complete;
|
||||
@@ -353,7 +318,6 @@ consume(std::size_t n)
|
||||
break;
|
||||
header_done_ = true;
|
||||
v_ = boost::blank{};
|
||||
b_.consume(b_.size()); // VFALCO delete b_?
|
||||
if(more_)
|
||||
s_ = do_body_c + 1;
|
||||
else
|
||||
@@ -362,11 +326,12 @@ consume(std::size_t n)
|
||||
|
||||
case do_header_only_c:
|
||||
{
|
||||
BOOST_ASSERT(n <= buffer_size(b_.data()));
|
||||
b_.consume(n);
|
||||
if(buffer_size(b_.data()) > 0)
|
||||
BOOST_ASSERT(n <= buffer_size(
|
||||
boost::get<ch_t>(v_)));
|
||||
boost::get<ch_t>(v_).consume(n);
|
||||
if(buffer_size(boost::get<ch_t>(v_)) > 0)
|
||||
break;
|
||||
// VFALCO delete b_?
|
||||
frd_ = boost::none;
|
||||
header_done_ = true;
|
||||
if(! split_)
|
||||
{
|
||||
|
||||
@@ -822,16 +822,15 @@ public:
|
||||
|
||||
} // detail
|
||||
|
||||
#if 0
|
||||
template<bool isRequest, class Fields>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os,
|
||||
header<isRequest, Fields> const& msg)
|
||||
{
|
||||
detail::write_start_line(os, msg);
|
||||
detail::write_fields(os, msg);
|
||||
os << "\r\n";
|
||||
return os;
|
||||
// VFALCO TODO
|
||||
}
|
||||
#endif
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
std::ostream&
|
||||
|
||||
@@ -119,7 +119,7 @@ struct header<true, Fields> : Fields
|
||||
verb
|
||||
method() const;
|
||||
|
||||
/** Set the request-method verb.
|
||||
/** Set the request-method.
|
||||
|
||||
This function will set the method for requests to a known verb.
|
||||
|
||||
@@ -127,11 +127,13 @@ struct header<true, Fields> : Fields
|
||||
This may not be @ref verb::unknown.
|
||||
|
||||
@throw std::invalid_argument when `v == verb::unknown`.
|
||||
|
||||
@note This function is only available when `isRequest == true`.
|
||||
*/
|
||||
void
|
||||
method(verb v);
|
||||
|
||||
/** Return the request-method string.
|
||||
/** Return the request-method as a string.
|
||||
|
||||
@note This function is only available when `isRequest == true`.
|
||||
|
||||
@@ -140,18 +142,18 @@ struct header<true, Fields> : Fields
|
||||
string_view
|
||||
method_string() const;
|
||||
|
||||
/** Set the request-method string.
|
||||
/** Set the request-method.
|
||||
|
||||
This function will set the method for requests to a verb
|
||||
if the string matches a known verb, otherwise it will
|
||||
store a copy of the passed string as the method.
|
||||
This function will set the request-method a known verb
|
||||
if the string matches, otherwise it will store a copy of
|
||||
the passed string.
|
||||
|
||||
@param s A string representing the request-method.
|
||||
|
||||
@note This function is only available when `isRequest == true`.
|
||||
*/
|
||||
void
|
||||
method(string_view s);
|
||||
method_string(string_view s);
|
||||
|
||||
/** Returns the request-target string.
|
||||
|
||||
@@ -382,31 +384,27 @@ struct message : header<isRequest, Fields>
|
||||
/// Copy assignment
|
||||
message& operator=(message const&) = default;
|
||||
|
||||
/** Construct a message from a header.
|
||||
/** Constructor.
|
||||
|
||||
Additional arguments, if any, are forwarded to
|
||||
the constructor of the body member.
|
||||
@param h The header to move construct from.
|
||||
|
||||
@param args Optional arguments forwarded
|
||||
to the body constructor.
|
||||
*/
|
||||
template<class... Args>
|
||||
explicit
|
||||
message(header_type&& base, Args&&... args)
|
||||
: header_type(std::move(base))
|
||||
, body(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
message(header_type&& h, Args&&... args);
|
||||
|
||||
/** Construct a message from a header.
|
||||
/** Constructor.
|
||||
|
||||
Additional arguments, if any, are forwarded to
|
||||
the constructor of the body member.
|
||||
@param h The header to copy construct from.
|
||||
|
||||
@param args Optional arguments forwarded
|
||||
to the body constructor.
|
||||
*/
|
||||
template<class... Args>
|
||||
explicit
|
||||
message(header_type const& base, Args&&... args)
|
||||
: header_type(base)
|
||||
, body(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
message(header_type const& h, Args&&... args);
|
||||
|
||||
/** Construct a message.
|
||||
|
||||
@@ -423,10 +421,7 @@ struct message : header<isRequest, Fields>
|
||||
#endif
|
||||
>
|
||||
explicit
|
||||
message(U&& u)
|
||||
: body(std::forward<U>(u))
|
||||
{
|
||||
}
|
||||
message(U&& u);
|
||||
|
||||
/** Construct a message.
|
||||
|
||||
@@ -443,22 +438,14 @@ struct message : header<isRequest, Fields>
|
||||
typename std::decay<U>::type, header_type>::value>::type
|
||||
#endif
|
||||
>
|
||||
message(U&& u, V&& v)
|
||||
: header_type(std::forward<V>(v))
|
||||
, body(std::forward<U>(u))
|
||||
{
|
||||
}
|
||||
message(U&& u, V&& v);
|
||||
|
||||
/** Construct a message.
|
||||
|
||||
@param un A tuple forwarded as a parameter pack to the body constructor.
|
||||
*/
|
||||
template<class... Un>
|
||||
message(std::piecewise_construct_t, std::tuple<Un...> un)
|
||||
: message(std::piecewise_construct, un,
|
||||
beast::detail::make_index_sequence<sizeof...(Un)>{})
|
||||
{
|
||||
}
|
||||
message(std::piecewise_construct_t, std::tuple<Un...> un);
|
||||
|
||||
/** Construct a message.
|
||||
|
||||
@@ -468,17 +455,25 @@ struct message : header<isRequest, Fields>
|
||||
*/
|
||||
template<class... Un, class... Vn>
|
||||
message(std::piecewise_construct_t,
|
||||
std::tuple<Un...>&& un, std::tuple<Vn...>&& vn)
|
||||
: message(std::piecewise_construct, un, vn,
|
||||
beast::detail::make_index_sequence<sizeof...(Un)>{},
|
||||
beast::detail::make_index_sequence<sizeof...(Vn)>{})
|
||||
{
|
||||
}
|
||||
std::tuple<Un...>&& un, std::tuple<Vn...>&& vn);
|
||||
|
||||
/** Returns `true` if Transfer-Encoding is present, and chunked appears last.
|
||||
/// Returns `true` if "close" is specified in the Connection field.
|
||||
bool
|
||||
has_close() const;
|
||||
|
||||
/// Returns `true` if "chunked" is the last Transfer-Encoding.
|
||||
bool
|
||||
has_chunked() const;
|
||||
|
||||
/** Returns `true` if the Content-Length field is present.
|
||||
|
||||
This function checks the fields to determine if the content
|
||||
length field is present, regardless of the actual value.
|
||||
|
||||
@note The contents of the body payload are not inspected.
|
||||
*/
|
||||
bool
|
||||
chunked() const;
|
||||
has_content_length() const;
|
||||
|
||||
/** Returns the payload size of the body in octets if possible.
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ private:
|
||||
if(method != verb::unknown)
|
||||
m_.method(method);
|
||||
else
|
||||
m_.method(method_str);
|
||||
m_.method_string(method_str);
|
||||
m_.version = version;
|
||||
}
|
||||
|
||||
@@ -241,17 +241,15 @@ private:
|
||||
}
|
||||
|
||||
void
|
||||
on_data(string_view s,
|
||||
error_code& ec)
|
||||
on_data(string_view s, error_code& ec)
|
||||
{
|
||||
wr_->put(boost::asio::buffer(
|
||||
s.data(), s.size()), ec);
|
||||
}
|
||||
|
||||
void
|
||||
on_chunk(
|
||||
std::uint64_t, string_view,
|
||||
error_code&)
|
||||
on_chunk(std::uint64_t,
|
||||
string_view, error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <beast/core/async_result.hpp>
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/core/consuming_buffers.hpp>
|
||||
#include <beast/core/multi_buffer.hpp>
|
||||
#include <beast/core/string_view.hpp>
|
||||
#include <beast/core/type_traits.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
@@ -155,24 +154,26 @@ class serializer
|
||||
|
||||
void split(bool, std::true_type) {}
|
||||
void split(bool v, std::false_type) { split_ = v; }
|
||||
|
||||
using buffer_type =
|
||||
basic_multi_buffer<Allocator>;
|
||||
void frdinit(std::true_type);
|
||||
void frdinit(std::false_type);
|
||||
|
||||
using reader = typename Body::reader;
|
||||
|
||||
using is_deferred =
|
||||
typename reader::is_deferred;
|
||||
|
||||
using ch_t = consuming_buffers<typename
|
||||
Fields::reader::const_buffers_type>; // header
|
||||
|
||||
using cb0_t = consuming_buffers<buffer_cat_view<
|
||||
typename buffer_type::const_buffers_type, // header
|
||||
typename Fields::reader::const_buffers_type,// header
|
||||
typename reader::const_buffers_type>>; // body
|
||||
|
||||
using cb1_t = consuming_buffers<
|
||||
typename reader::const_buffers_type>; // body
|
||||
|
||||
using ch0_t = consuming_buffers<buffer_cat_view<
|
||||
typename buffer_type::const_buffers_type, // header
|
||||
typename Fields::reader::const_buffers_type,// header
|
||||
detail::chunk_header, // chunk-header
|
||||
boost::asio::const_buffers_1, // chunk-ext
|
||||
boost::asio::const_buffers_1, // crlf
|
||||
@@ -192,11 +193,11 @@ class serializer
|
||||
boost::asio::const_buffers_1>>; // crlf
|
||||
|
||||
message<isRequest, Body, Fields> const& m_;
|
||||
boost::optional<typename Fields::reader> frd_;
|
||||
ChunkDecorator d_;
|
||||
boost::optional<reader> rd_;
|
||||
buffer_type b_;
|
||||
boost::variant<boost::blank,
|
||||
cb0_t, cb1_t, ch0_t, ch1_t, ch2_t> v_;
|
||||
ch_t, cb0_t, cb1_t, ch0_t, ch1_t, ch2_t> v_;
|
||||
int s_ = do_construct;
|
||||
bool split_ = is_deferred::value;
|
||||
bool header_done_ = false;
|
||||
|
||||
Reference in new issue
Block a user