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