mirror of
https://github.com/boostorg/beast.git
synced 2025-07-29 20:37:31 +02:00
Rework HTTP concepts (API Change):
fix #139, fix #140 * Writer uses write instead of operator() * Refactor traits to use void_t * Remove is_ReadableBody, is_WritableBody * Add has_reader, has_writer, is_Reader, is_Writer * More friendly compile errors on failed concept checks
This commit is contained in:
@ -6,13 +6,20 @@
|
||||
* Add basic_streambuf::alloc_size
|
||||
* Parser callbacks may not throw
|
||||
* Fix Reader concept doc typo
|
||||
* Add is_Reader trait
|
||||
|
||||
API Changes:
|
||||
|
||||
* Added init() to Reader requirements
|
||||
* Reader must be nothrow constructible
|
||||
* Reader is now constructed right before reading the body
|
||||
- The message passed on construction is filled in
|
||||
- The message passed on construction is filled in
|
||||
* Rework HTTP concepts:
|
||||
- Writer uses write instead of operator()
|
||||
- Refactor traits to use void_t
|
||||
- Remove is_ReadableBody, is_WritableBody
|
||||
- Add has_reader, has_writer, is_Reader, is_Writer
|
||||
- More friendly compile errors on failed concept checks
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -50,8 +50,10 @@
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="beast.ref.http__is_Body">is_Body</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Parser">is_Parser</link></member>
|
||||
<member><link linkend="beast.ref.http__is_ReadableBody">is_ReadableBody</link></member>
|
||||
<member><link linkend="beast.ref.http__is_WritableBody">is_WritableBody</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Reader">is_Reader</link></member>
|
||||
<member><link linkend="beast.ref.http__is_Writer">is_Reader</link></member>
|
||||
<member><link linkend="beast.ref.http__has_reader">has_reader</link></member>
|
||||
<member><link linkend="beast.ref.http__has_writer">has_writer</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
|
@ -72,7 +72,7 @@ In this table:
|
||||
]
|
||||
]
|
||||
[
|
||||
[`a(rc, ec, wf)`]
|
||||
[`a.write(rc, ec, wf)`]
|
||||
[`boost::tribool`]
|
||||
[
|
||||
Called repeatedly after `init` succeeds. `wf` is a function object
|
||||
@ -175,10 +175,10 @@ public:
|
||||
*/
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(
|
||||
write(
|
||||
resume_context&&,
|
||||
error_code&,
|
||||
WriteFunction&& write) noexcept;
|
||||
WriteFunction&& wf) noexcept;
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -58,14 +58,15 @@ struct file_body
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
content_length() const noexcept
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
write(resume_context&&, error_code&,
|
||||
WriteFunction&& wf) noexcept
|
||||
{
|
||||
if(size_ - offset_ < sizeof(buf_))
|
||||
buf_len_ = static_cast<std::size_t>(
|
||||
@ -75,7 +76,7 @@ struct file_body
|
||||
auto const nread = fread(buf_, 1, sizeof(buf_), file_);
|
||||
(void)nread;
|
||||
offset_ += buf_len_;
|
||||
write(boost::asio::buffer(buf_, buf_len_));
|
||||
wf(boost::asio::buffer(buf_, buf_len_));
|
||||
return offset_ >= size_;
|
||||
}
|
||||
};
|
||||
|
26
include/beast/core/detail/type_traits.hpp
Normal file
26
include/beast/core/detail/type_traits.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// 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_DETAIL_VOID_T_HPP
|
||||
#define BEAST_DETAIL_VOID_T_HPP
|
||||
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
template<class... Ts>
|
||||
struct make_void
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template<class... Ts>
|
||||
using void_t = typename make_void<Ts...>::type;
|
||||
|
||||
} // detail
|
||||
} // beast
|
||||
|
||||
#endif
|
@ -62,33 +62,31 @@ private:
|
||||
DynamicBuffer const& body_;
|
||||
|
||||
public:
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
writer(message<
|
||||
isRequest, basic_dynabuf_body, Headers> const& m)
|
||||
isRequest, basic_dynabuf_body, Headers> const& m) noexcept
|
||||
: body_(m.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
init(error_code& ec) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
content_length() const noexcept
|
||||
{
|
||||
return body_.size();
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
write(resume_context&&, error_code&,
|
||||
WriteFunction&& wf) noexcept
|
||||
{
|
||||
write(body_.data());
|
||||
wf(body_.data());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -9,7 +9,10 @@
|
||||
#define BEAST_HTTP_TYPE_CHECK_HPP
|
||||
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/detail/type_traits.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
@ -18,63 +21,107 @@ namespace http {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
class has_value_type
|
||||
struct write_function
|
||||
{
|
||||
template<class U, class R =
|
||||
typename U::value_type>
|
||||
static std::true_type check(int);
|
||||
template<class ConstBufferSequence>
|
||||
void
|
||||
operator()(ConstBufferSequence const&);
|
||||
};
|
||||
|
||||
template<class T, class = beast::detail::void_t<>>
|
||||
struct has_value_type : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct has_value_type<T, beast::detail::void_t<
|
||||
typename T::value_type
|
||||
> > : std::true_type {};
|
||||
|
||||
template<class T, class = beast::detail::void_t<>>
|
||||
struct has_content_length : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct has_content_length<T, beast::detail::void_t<decltype(
|
||||
std::declval<T>().content_length()
|
||||
)> > : std::true_type
|
||||
{
|
||||
static_assert(std::is_convertible<
|
||||
decltype(std::declval<T>().content_length()),
|
||||
std::uint64_t>::value,
|
||||
"Writer::content_length requirements not met");
|
||||
};
|
||||
|
||||
#if 0
|
||||
template<class T, class M, class = beast::detail::void_t<>>
|
||||
struct is_Writer : std::false_type {};
|
||||
|
||||
template<class T, class M>
|
||||
struct is_Writer<T, M, beast::detail::void_t<decltype(
|
||||
std::declval<T>().init(
|
||||
std::declval<error_code&>())
|
||||
// VFALCO This is unfortunate, we have to provide the template
|
||||
// argument type because this is not a deduced context?
|
||||
//
|
||||
,std::declval<T>().template write<detail::write_function>(
|
||||
std::declval<resume_context>(),
|
||||
std::declval<error_code&>(),
|
||||
std::declval<detail::write_function>())
|
||||
)> > : std::integral_constant<bool,
|
||||
std::is_nothrow_constructible<T, M const&>::value &&
|
||||
std::is_convertible<decltype(
|
||||
std::declval<T>().template write<detail::write_function>(
|
||||
std::declval<resume_context>(),
|
||||
std::declval<error_code&>(),
|
||||
std::declval<detail::write_function>())),
|
||||
boost::tribool>::value
|
||||
>
|
||||
{
|
||||
static_assert(std::is_same<
|
||||
typename M::body_type::writer, T>::value,
|
||||
"Mismatched writer and message");
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template<class T, class M>
|
||||
class is_Writer
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().init(std::declval<error_code&>()),
|
||||
std::true_type{})>
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
using type = decltype(check<T>(0));
|
||||
public:
|
||||
static bool constexpr value = type::value;
|
||||
};
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
template<class T, bool B = has_value_type<T>::value>
|
||||
struct extract_value_type
|
||||
{
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct extract_value_type<T, true>
|
||||
{
|
||||
using type = typename T::value_type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class has_reader
|
||||
{
|
||||
// VFALCO This is unfortunate, we have to provide the template
|
||||
// argument type because this is not a deduced context?
|
||||
//
|
||||
template<class U, class R =
|
||||
typename U::reader>
|
||||
static std::true_type check(int);
|
||||
std::is_convertible<decltype(
|
||||
std::declval<U>().template write<detail::write_function>(
|
||||
std::declval<resume_context>(),
|
||||
std::declval<error_code&>(),
|
||||
std::declval<detail::write_function>()))
|
||||
, boost::tribool>>
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
public:
|
||||
using type = decltype(check<T>(0));
|
||||
};
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
template<class T>
|
||||
class has_writer
|
||||
{
|
||||
template<class U, class R =
|
||||
typename U::writer>
|
||||
static std::true_type check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
public:
|
||||
using type = decltype(check<T>(0));
|
||||
};
|
||||
static_assert(std::is_same<
|
||||
typename M::body_type::writer, T>::value,
|
||||
"Mismatched writer and message");
|
||||
|
||||
template<class T>
|
||||
struct is_Body
|
||||
{
|
||||
using type = std::integral_constant<bool,
|
||||
has_value_type<T>::value
|
||||
std::is_nothrow_constructible<T, M const&>::value
|
||||
&& type1::value
|
||||
&& type2::value
|
||||
>;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
class is_Parser
|
||||
{
|
||||
@ -116,31 +163,97 @@ public:
|
||||
|
||||
} // detail
|
||||
|
||||
/// Determine if `T` meets the requirements of `Body`.
|
||||
/// Determine if `T` meets the requirements of @b Body.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_Body : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_Body = typename detail::is_Body<T>::type;
|
||||
using is_Body = detail::has_value_type<T>;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of `ReadableBody`.
|
||||
template<class T>
|
||||
/** Determine if a @ref Body has a nested type `reader`.
|
||||
|
||||
@tparam T The type to check, which must meet the
|
||||
requirements of @b Body.
|
||||
*/
|
||||
#if GENERATING_DOCS
|
||||
struct is_ReadableBody : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_ReadableBody = typename detail::has_reader<T>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of `WritableBody`.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_WritableBody : std::integral_constant<bool, ...>{};
|
||||
struct has_reader : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
using is_WritableBody = typename detail::has_writer<T>::type;
|
||||
template<class T, class = beast::detail::void_t<>>
|
||||
struct has_reader : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct has_reader<T, beast::detail::void_t<
|
||||
typename T::reader
|
||||
> > : std::true_type {};
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of `Parser`.
|
||||
/** Determine if a @ref Body has a nested type `writer`.
|
||||
|
||||
@tparam T The type to check, which must meet the
|
||||
requirements of @b Body.
|
||||
*/
|
||||
#if GENERATING_DOCS
|
||||
template<class T>
|
||||
struct has_writer : std::integral_constant<bool, ...>{};
|
||||
#else
|
||||
template<class T, class = beast::detail::void_t<>>
|
||||
struct has_writer : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct has_writer<T, beast::detail::void_t<
|
||||
typename T::writer
|
||||
> > : std::true_type {};
|
||||
#endif
|
||||
|
||||
/** Determine if `T` meets the requirements of @b Reader for `M`.
|
||||
|
||||
@tparam T The type to test.
|
||||
|
||||
@tparam M The message type to test with, which must be of
|
||||
type `message`.
|
||||
*/
|
||||
#if GENERATING_DOCS
|
||||
template<class T, class M>
|
||||
struct is_Reader : std::integral_constant<bool, ...> {};
|
||||
#else
|
||||
template<class T, class M, class = beast::detail::void_t<>>
|
||||
struct is_Reader : std::false_type {};
|
||||
|
||||
template<class T, class M>
|
||||
struct is_Reader<T, M, beast::detail::void_t<decltype(
|
||||
std::declval<T>().init(
|
||||
std::declval<error_code&>()),
|
||||
std::declval<T>().write(
|
||||
std::declval<void const*>(),
|
||||
std::declval<std::size_t>(),
|
||||
std::declval<error_code&>())
|
||||
)> > : std::integral_constant<bool,
|
||||
std::is_nothrow_constructible<T, M&>::value
|
||||
>
|
||||
{
|
||||
static_assert(std::is_same<
|
||||
typename M::body_type::reader, T>::value,
|
||||
"Mismatched reader and message");
|
||||
};
|
||||
#endif
|
||||
|
||||
/** Determine if `T` meets the requirements of @b Writer for `M`.
|
||||
|
||||
@tparam T The type to test.
|
||||
|
||||
@tparam M The message type to test with, which must be of
|
||||
type `message`.
|
||||
*/
|
||||
template<class T, class M>
|
||||
#if GENERATING_DOCS
|
||||
struct is_Writer : std::integral_constant<bool, ...> {};
|
||||
#else
|
||||
using is_Writer = typename detail::is_Writer<T, M>::type;
|
||||
#endif
|
||||
|
||||
/// Determine if `T` meets the requirements of @b Parser.
|
||||
template<class T>
|
||||
#if GENERATING_DOCS
|
||||
struct is_Parser : std::integral_constant<bool, ...>{};
|
||||
|
@ -1,43 +0,0 @@
|
||||
//
|
||||
// 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_DETAIL_HAS_CONTENT_LENGTH_HPP
|
||||
#define BEAST_HTTP_DETAIL_HAS_CONTENT_LENGTH_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
class has_content_length_value
|
||||
{
|
||||
template<class U, class R = typename std::is_convertible<
|
||||
decltype(std::declval<U>().content_length()),
|
||||
std::uint64_t>>
|
||||
static R check(int);
|
||||
template<class>
|
||||
static std::false_type check(...);
|
||||
using type = decltype(check<T>(0));
|
||||
public:
|
||||
// `true` if `T` meets the requirements.
|
||||
static bool const value = type::value;
|
||||
};
|
||||
|
||||
// Determines if the writer can provide the content length
|
||||
template<class T>
|
||||
using has_content_length =
|
||||
std::integral_constant<bool,
|
||||
has_content_length_value<T>::value>;
|
||||
|
||||
} // detail
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
@ -35,31 +35,29 @@ private:
|
||||
|
||||
struct writer
|
||||
{
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
writer(message<isRequest, empty_body, Headers> const& m)
|
||||
writer(message<isRequest, empty_body, Headers> const& m) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
init(error_code& ec) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
content_length() const noexcept
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
write(resume_context&&, error_code&,
|
||||
WriteFunction&& wf) noexcept
|
||||
{
|
||||
write(boost::asio::null_buffers{});
|
||||
wf(boost::asio::null_buffers{});
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -9,9 +9,9 @@
|
||||
#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP
|
||||
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/http/concepts.hpp>
|
||||
#include <beast/http/rfc7230.hpp>
|
||||
#include <beast/core/detail/ci_char_traits.hpp>
|
||||
#include <beast/http/detail/has_content_length.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
@ -116,8 +116,13 @@ prepare(message_v1<isRequest, Body, Headers>& msg,
|
||||
Options&&... options)
|
||||
{
|
||||
// VFALCO TODO
|
||||
//static_assert(is_WritableBody<Body>::value,
|
||||
// "WritableBody requirements not met");
|
||||
static_assert(is_Body<Body>::value,
|
||||
"Body requirements not met");
|
||||
static_assert(has_writer<Body>::value,
|
||||
"Body has no writer");
|
||||
static_assert(is_Writer<typename Body::writer,
|
||||
message_v1<isRequest, Body, Headers>>::value,
|
||||
"Writer requirements not met");
|
||||
detail::prepare_info pi;
|
||||
detail::prepare_content_length(pi, msg,
|
||||
detail::has_content_length<typename Body::writer>{});
|
||||
|
@ -150,8 +150,13 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
static_assert(is_ReadableBody<Body>::value,
|
||||
"ReadableBody requirements not met");
|
||||
static_assert(is_Body<Body>::value,
|
||||
"Body requirements not met");
|
||||
static_assert(has_reader<Body>::value,
|
||||
"Body has no reader");
|
||||
static_assert(is_Reader<typename Body::reader,
|
||||
message_v1<isRequest, Body, Headers>>::value,
|
||||
"Reader requirements not met");
|
||||
error_code ec;
|
||||
beast::http::read(stream, dynabuf, msg, ec);
|
||||
if(ec)
|
||||
@ -169,8 +174,13 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
"SyncReadStream requirements not met");
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
static_assert(is_ReadableBody<Body>::value,
|
||||
"ReadableBody requirements not met");
|
||||
static_assert(is_Body<Body>::value,
|
||||
"Body requirements not met");
|
||||
static_assert(has_reader<Body>::value,
|
||||
"Body has no reader");
|
||||
static_assert(is_Reader<typename Body::reader,
|
||||
message_v1<isRequest, Body, Headers>>::value,
|
||||
"Reader requirements not met");
|
||||
parser_v1<isRequest, Body, Headers> p;
|
||||
beast::http::parse(stream, dynabuf, p, ec);
|
||||
if(ec)
|
||||
@ -192,8 +202,13 @@ async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
|
||||
"AsyncReadStream requirements not met");
|
||||
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
|
||||
"DynamicBuffer requirements not met");
|
||||
static_assert(is_ReadableBody<Body>::value,
|
||||
"ReadableBody requirements not met");
|
||||
static_assert(is_Body<Body>::value,
|
||||
"Body requirements not met");
|
||||
static_assert(has_reader<Body>::value,
|
||||
"Body has no reader");
|
||||
static_assert(is_Reader<typename Body::reader,
|
||||
message_v1<isRequest, Body, Headers>>::value,
|
||||
"Reader requirements not met");
|
||||
beast::async_completion<ReadHandler,
|
||||
void(error_code)> completion(handler);
|
||||
detail::read_op<AsyncReadStream, DynamicBuffer,
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <beast/http/concepts.hpp>
|
||||
#include <beast/http/resume_context.hpp>
|
||||
#include <beast/http/detail/chunk_encode.hpp>
|
||||
#include <beast/http/detail/has_content_length.hpp>
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/core/bind_handler.hpp>
|
||||
#include <beast/core/buffer_concepts.hpp>
|
||||
@ -184,7 +183,7 @@ class write_op
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
void operator()(ConstBufferSequence const& buffers)
|
||||
void operator()(ConstBufferSequence const& buffers) const
|
||||
{
|
||||
auto& d = *self_.d_;
|
||||
// write headers and body
|
||||
@ -212,7 +211,7 @@ class write_op
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
void operator()(ConstBufferSequence const& buffers)
|
||||
void operator()(ConstBufferSequence const& buffers) const
|
||||
{
|
||||
auto& d = *self_.d_;
|
||||
// write body
|
||||
@ -323,7 +322,7 @@ operator()(error_code ec, std::size_t, bool again)
|
||||
|
||||
case 1:
|
||||
{
|
||||
auto const result = d.wp.w(
|
||||
boost::tribool const result = d.wp.w.write(
|
||||
std::move(d.copy), ec, writef0_lambda{*this});
|
||||
if(ec)
|
||||
{
|
||||
@ -354,7 +353,7 @@ operator()(error_code ec, std::size_t, bool again)
|
||||
|
||||
case 3:
|
||||
{
|
||||
auto const result = d.wp.w(
|
||||
boost::tribool result = d.wp.w.write(
|
||||
std::move(d.copy), ec, writef_lambda{*this});
|
||||
if(ec)
|
||||
{
|
||||
@ -420,7 +419,7 @@ public:
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
void operator()(ConstBufferSequence const& buffers)
|
||||
void operator()(ConstBufferSequence const& buffers) const
|
||||
{
|
||||
// write headers and body
|
||||
if(chunked_)
|
||||
@ -449,7 +448,7 @@ public:
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
void operator()(ConstBufferSequence const& buffers)
|
||||
void operator()(ConstBufferSequence const& buffers) const
|
||||
{
|
||||
// write body
|
||||
if(chunked_)
|
||||
@ -472,8 +471,13 @@ write(SyncWriteStream& stream,
|
||||
{
|
||||
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
static_assert(is_WritableBody<Body>::value,
|
||||
"WritableBody requirements not met");
|
||||
static_assert(is_Body<Body>::value,
|
||||
"Body requirements not met");
|
||||
static_assert(has_writer<Body>::value,
|
||||
"Body has no writer");
|
||||
static_assert(is_Writer<typename Body::writer,
|
||||
message_v1<isRequest, Body, Headers>>::value,
|
||||
"Writer requirements not met");
|
||||
error_code ec;
|
||||
write(stream, msg, ec);
|
||||
if(ec)
|
||||
@ -489,8 +493,13 @@ write(SyncWriteStream& stream,
|
||||
{
|
||||
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
|
||||
"SyncWriteStream requirements not met");
|
||||
static_assert(is_WritableBody<Body>::value,
|
||||
"WritableBody requirements not met");
|
||||
static_assert(is_Body<Body>::value,
|
||||
"Body requirements not met");
|
||||
static_assert(has_writer<Body>::value,
|
||||
"Body has no writer");
|
||||
static_assert(is_Writer<typename Body::writer,
|
||||
message_v1<isRequest, Body, Headers>>::value,
|
||||
"Writer requirements not met");
|
||||
detail::write_preparation<isRequest, Body, Headers> wp(msg);
|
||||
wp.init(ec);
|
||||
if(ec)
|
||||
@ -506,9 +515,11 @@ write(SyncWriteStream& stream,
|
||||
cv.notify_one();
|
||||
}};
|
||||
auto copy = resume;
|
||||
boost::tribool result = wp.w(std::move(copy),
|
||||
ec, detail::writef0_lambda<SyncWriteStream,
|
||||
decltype(wp.sb)>{stream, wp.sb, wp.chunked, ec});
|
||||
boost::tribool result =
|
||||
wp.w.write(std::move(copy), ec,
|
||||
detail::writef0_lambda<SyncWriteStream,
|
||||
decltype(wp.sb)>{stream,
|
||||
wp.sb, wp.chunked, ec});
|
||||
if(ec)
|
||||
return;
|
||||
if(boost::indeterminate(result))
|
||||
@ -527,11 +538,16 @@ write(SyncWriteStream& stream,
|
||||
wp.sb.consume(wp.sb.size());
|
||||
if(! result)
|
||||
{
|
||||
detail::writef_lambda<SyncWriteStream> wf{
|
||||
stream, wp.chunked, ec};
|
||||
for(;;)
|
||||
{
|
||||
result = wp.w(std::move(copy), ec,
|
||||
detail::writef_lambda<SyncWriteStream>{
|
||||
stream, wp.chunked, ec});
|
||||
#if 0
|
||||
result = wp.w.write(std::move(copy), ec, wf);
|
||||
#else
|
||||
result = wp.w.write(std::move(copy), ec,
|
||||
detail::writef_lambda<SyncWriteStream>{stream, wp.chunked, ec});
|
||||
#endif
|
||||
if(ec)
|
||||
return;
|
||||
if(result)
|
||||
@ -573,8 +589,13 @@ async_write(AsyncWriteStream& stream,
|
||||
{
|
||||
static_assert(is_AsyncWriteStream<AsyncWriteStream>::value,
|
||||
"AsyncWriteStream requirements not met");
|
||||
static_assert(is_WritableBody<Body>::value,
|
||||
"WritableBody requirements not met");
|
||||
static_assert(is_Body<Body>::value,
|
||||
"Body requirements not met");
|
||||
static_assert(has_writer<Body>::value,
|
||||
"Body has no writer");
|
||||
static_assert(is_Writer<typename Body::writer,
|
||||
message_v1<isRequest, Body, Headers>>::value,
|
||||
"Writer requirements not met");
|
||||
beast::async_completion<WriteHandler,
|
||||
void(error_code)> completion(handler);
|
||||
detail::write_op<AsyncWriteStream, decltype(completion.handler),
|
||||
@ -636,8 +657,13 @@ std::ostream&
|
||||
operator<<(std::ostream& os,
|
||||
message_v1<isRequest, Body, Headers> const& msg)
|
||||
{
|
||||
static_assert(is_WritableBody<Body>::value,
|
||||
"WritableBody requirements not met");
|
||||
static_assert(is_Body<Body>::value,
|
||||
"Body requirements not met");
|
||||
static_assert(has_writer<Body>::value,
|
||||
"Body has no writer");
|
||||
static_assert(is_Writer<typename Body::writer,
|
||||
message_v1<isRequest, Body, Headers>>::value,
|
||||
"Writer requirements not met");
|
||||
detail::ostream_SyncStream oss(os);
|
||||
error_code ec;
|
||||
write(oss, msg, ec);
|
||||
|
@ -91,13 +91,12 @@ private:
|
||||
using reader =
|
||||
typename message_type::body_type::reader;
|
||||
|
||||
static_assert(is_ReadableBody<Body>::value,
|
||||
"ReadableBody requirements not met");
|
||||
|
||||
// Reader must be nothrow constructible
|
||||
static_assert(std::is_nothrow_constructible<
|
||||
reader, message_type&>::value,
|
||||
"Reader requirements not met");
|
||||
static_assert(is_Body<Body>::value,
|
||||
"Body requirements not met");
|
||||
static_assert(has_reader<Body>::value,
|
||||
"Body has no reader");
|
||||
static_assert(is_Reader<reader, message_type>::value,
|
||||
"Reader requirements not met");
|
||||
|
||||
std::string field_;
|
||||
std::string value_;
|
||||
|
@ -62,33 +62,31 @@ private:
|
||||
value_type const& body_;
|
||||
|
||||
public:
|
||||
writer(writer const&) = delete;
|
||||
writer& operator=(writer const&) = delete;
|
||||
|
||||
template<bool isRequest, class Headers>
|
||||
explicit
|
||||
writer(message<
|
||||
isRequest, string_body, Headers> const& msg)
|
||||
isRequest, string_body, Headers> const& msg) noexcept
|
||||
: body_(msg.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
init(error_code& ec) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
content_length() const noexcept
|
||||
{
|
||||
return body_.size();
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
write(resume_context&&, error_code&,
|
||||
WriteFunction&& wf) noexcept
|
||||
{
|
||||
write(boost::asio::buffer(body_));
|
||||
wf(boost::asio::buffer(body_));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -104,21 +104,22 @@ public:
|
||||
public:
|
||||
template<bool isRequest, class Allocator>
|
||||
explicit
|
||||
writer(message<isRequest, unsized_body, Allocator> const& msg)
|
||||
writer(message<isRequest, unsized_body, Allocator> const& msg) noexcept
|
||||
: body_(msg.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
init(error_code& ec) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class Write>
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(resume_context&&, error_code&, Write&& write)
|
||||
write(resume_context&&, error_code&,
|
||||
WriteFunction&& wf) noexcept
|
||||
{
|
||||
write(boost::asio::buffer(body_));
|
||||
wf(boost::asio::buffer(body_));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -168,13 +169,13 @@ public:
|
||||
public:
|
||||
template<bool isRequest, class Allocator>
|
||||
explicit
|
||||
writer(message<isRequest, fail_body, Allocator> const& msg)
|
||||
writer(message<isRequest, fail_body, Allocator> const& msg) noexcept
|
||||
: body_(msg.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec)
|
||||
init(error_code& ec) noexcept
|
||||
{
|
||||
body_.fc_.fail(ec);
|
||||
}
|
||||
@ -197,9 +198,10 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<class Write>
|
||||
template<class WriteFunction>
|
||||
boost::tribool
|
||||
operator()(resume_context&& rc, error_code& ec, Write&& write)
|
||||
write(resume_context&& rc, error_code& ec,
|
||||
WriteFunction&& wf) noexcept
|
||||
{
|
||||
if(body_.fc_.fail(ec))
|
||||
return false;
|
||||
@ -211,7 +213,7 @@ public:
|
||||
}
|
||||
if(n_ >= body_.s_.size())
|
||||
return true;
|
||||
write(boost::asio::buffer(body_.s_.data() + n_, 1));
|
||||
wf(boost::asio::buffer(body_.s_.data() + n_, 1));
|
||||
++n_;
|
||||
return n_ == body_.s_.size();
|
||||
}
|
||||
|
Reference in New Issue
Block a user