mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 05:17:26 +02:00
Refactor HTTP operations (API Change):
* Revise stream algorithm javadocs * HTTP stream algorithms now use beast::read and beast::async_read with a custom completion condition. API Changes: * HTTP stream algorithms return the number of bytes transferred from the stream. Previously, they returned the number of bytes consumed by the parser. Actions Required: * Callers depending on the return value of http::read or http::async_read overloads should adjust the usage of the returned value as needed.
This commit is contained in:
10
CHANGELOG.md
10
CHANGELOG.md
@ -3,6 +3,16 @@ Version 197:
|
|||||||
* Improvements to echo-op example
|
* Improvements to echo-op example
|
||||||
* Crawler example clears the response before each read
|
* Crawler example clears the response before each read
|
||||||
|
|
||||||
|
API Changes:
|
||||||
|
|
||||||
|
* Refactor HTTP operations
|
||||||
|
|
||||||
|
Actions Required:
|
||||||
|
|
||||||
|
* Callers depending on the return value of http::read or
|
||||||
|
http::async_read overloads should adjust the usage of
|
||||||
|
the returned value as needed.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Version 196:
|
Version 196:
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
[def __AsyncReadStream__ [@boost:/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]]
|
[def __AsyncReadStream__ [@boost:/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]]
|
||||||
[def __AsyncWriteStream__ [@boost:/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]]
|
[def __AsyncWriteStream__ [@boost:/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]]
|
||||||
[def __CompletionHandler__ [@boost:/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]]
|
[def __CompletionHandler__ [@boost:/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]]
|
||||||
|
[def __CompletionCondition__ [@boost:/doc/html/boost_asio/reference/CompletionCondition.html [*CompletionCondition]]]
|
||||||
[def __ConnectCondition__ [@boost:/doc/html/boost_asio/reference/ConnectCondition.html [*ConnectCondition]]]
|
[def __ConnectCondition__ [@boost:/doc/html/boost_asio/reference/ConnectCondition.html [*ConnectCondition]]]
|
||||||
[def __ConstBufferSequence__ [@boost:/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]]
|
[def __ConstBufferSequence__ [@boost:/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]]
|
||||||
[def __EndpointSequence__ [@boost:/doc/html/boost_asio/reference/EndpointSequence.html [*EndpointSequence]]]
|
[def __EndpointSequence__ [@boost:/doc/html/boost_asio/reference/EndpointSequence.html [*EndpointSequence]]]
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
<xsl:value-of select="type"/>
|
<xsl:value-of select="type"/>
|
||||||
<xsl:text> ``[link beast.concepts.BufferSequence [*BufferSequence]]``</xsl:text>
|
<xsl:text> ``[link beast.concepts.BufferSequence [*BufferSequence]]``</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
<xsl:when test="declname = 'CompletionCondition' or type = 'class CompletionCondition'">
|
||||||
|
<xsl:text>class __CompletionCondition__</xsl:text>
|
||||||
|
</xsl:when>
|
||||||
<xsl:when test="declname = 'CompletionHandler' or type = 'class CompletionHandler'">
|
<xsl:when test="declname = 'CompletionHandler' or type = 'class CompletionHandler'">
|
||||||
<xsl:text>class __CompletionHandler__</xsl:text>
|
<xsl:text>class __CompletionHandler__</xsl:text>
|
||||||
</xsl:when>
|
</xsl:when>
|
||||||
|
578
include/boost/beast/core/detail/impl/read.hpp
Normal file
578
include/boost/beast/core/detail/impl/read.hpp
Normal file
@ -0,0 +1,578 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BOOST_BEAST_DETAIL_IMPL_READ_HPP
|
||||||
|
#define BOOST_BEAST_DETAIL_IMPL_READ_HPP
|
||||||
|
|
||||||
|
#include <boost/beast/core/flat_static_buffer.hpp>
|
||||||
|
#include <boost/asio/basic_stream_socket.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// The number of bytes in the stack buffer when using non-blocking.
|
||||||
|
static std::size_t constexpr default_max_stack_buffer = 16384;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// read into a dynamic buffer until the
|
||||||
|
// condition is met or an error occurs
|
||||||
|
template<
|
||||||
|
class Stream,
|
||||||
|
class DynamicBuffer,
|
||||||
|
class Condition,
|
||||||
|
class Handler>
|
||||||
|
class read_op : public net::coroutine
|
||||||
|
{
|
||||||
|
Stream& s_;
|
||||||
|
net::executor_work_guard<decltype(
|
||||||
|
std::declval<Stream&>().get_executor())> wg_;
|
||||||
|
DynamicBuffer& b_;
|
||||||
|
Condition cond_;
|
||||||
|
Handler h_;
|
||||||
|
std::size_t total_ = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
read_op(read_op&&) = default;
|
||||||
|
read_op(read_op const&) = delete;
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
|
read_op(
|
||||||
|
Stream& s,
|
||||||
|
DynamicBuffer& b,
|
||||||
|
Condition cond,
|
||||||
|
DeducedHandler&& h)
|
||||||
|
: s_(s)
|
||||||
|
, wg_(s_.get_executor())
|
||||||
|
, b_(b)
|
||||||
|
, cond_(cond)
|
||||||
|
, h_(std::forward<DeducedHandler>(h))
|
||||||
|
{
|
||||||
|
(*this)({}, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(
|
||||||
|
error_code ec,
|
||||||
|
std::size_t bytes_transferred,
|
||||||
|
bool cont = true);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
using allocator_type =
|
||||||
|
net::associated_allocator_t<Handler>;
|
||||||
|
|
||||||
|
using executor_type = net::associated_executor_t<
|
||||||
|
Handler, decltype(std::declval<Stream&>().get_executor())>;
|
||||||
|
|
||||||
|
allocator_type
|
||||||
|
get_allocator() const noexcept
|
||||||
|
{
|
||||||
|
return net::get_associated_allocator(h_);
|
||||||
|
}
|
||||||
|
|
||||||
|
executor_type
|
||||||
|
get_executor() const noexcept
|
||||||
|
{
|
||||||
|
return net::get_associated_executor(
|
||||||
|
h_, s_.get_executor());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void* asio_handler_allocate(
|
||||||
|
std::size_t size, read_op* op)
|
||||||
|
{
|
||||||
|
using net::asio_handler_allocate;
|
||||||
|
return asio_handler_allocate(
|
||||||
|
size, std::addressof(op->h_));
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, read_op* op)
|
||||||
|
{
|
||||||
|
using net::asio_handler_deallocate;
|
||||||
|
asio_handler_deallocate(
|
||||||
|
p, size, std::addressof(op->h_));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Function>
|
||||||
|
friend
|
||||||
|
void asio_handler_invoke(Function&& f, read_op* op)
|
||||||
|
{
|
||||||
|
using net::asio_handler_invoke;
|
||||||
|
asio_handler_invoke(f, std::addressof(op->h_));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Stream, class DynamicBuffer,
|
||||||
|
class Condition, class Handler>
|
||||||
|
void
|
||||||
|
read_op<Stream, DynamicBuffer, Condition, Handler>::
|
||||||
|
operator()(
|
||||||
|
error_code ec,
|
||||||
|
std::size_t bytes_transferred,
|
||||||
|
bool cont)
|
||||||
|
{
|
||||||
|
std::size_t max_size;
|
||||||
|
std::size_t max_prepare;
|
||||||
|
BOOST_ASIO_CORO_REENTER(*this)
|
||||||
|
{
|
||||||
|
max_size = cond_(ec, total_, b_);
|
||||||
|
max_prepare = std::min<std::size_t>(
|
||||||
|
std::max<std::size_t>(
|
||||||
|
512, b_.capacity() - b_.size()),
|
||||||
|
std::min<std::size_t>(
|
||||||
|
max_size, b_.max_size() - b_.size()));
|
||||||
|
while(max_prepare > 0)
|
||||||
|
{
|
||||||
|
BOOST_ASIO_CORO_YIELD
|
||||||
|
s_.async_read_some(
|
||||||
|
b_.prepare(max_prepare), std::move(*this));
|
||||||
|
b_.commit(bytes_transferred);
|
||||||
|
total_ += bytes_transferred;
|
||||||
|
max_size = cond_(ec, total_, b_);
|
||||||
|
max_prepare = std::min<std::size_t>(
|
||||||
|
std::max<std::size_t>(
|
||||||
|
512, b_.capacity() - b_.size()),
|
||||||
|
std::min<std::size_t>(
|
||||||
|
max_size, b_.max_size() - b_.size()));
|
||||||
|
}
|
||||||
|
if(! cont)
|
||||||
|
{
|
||||||
|
BOOST_ASIO_CORO_YIELD
|
||||||
|
net::post(s_.get_executor(),
|
||||||
|
beast::bind_front_handler(
|
||||||
|
std::move(*this), ec, total_));
|
||||||
|
}
|
||||||
|
h_(ec, total_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef BOOST_BEAST_ENABLE_NON_BLOCKING
|
||||||
|
// EXPERIMENTAL
|
||||||
|
// optimized non-blocking read algorithm
|
||||||
|
template<
|
||||||
|
class Protocol,
|
||||||
|
class DynamicBuffer,
|
||||||
|
class Condition,
|
||||||
|
class Handler>
|
||||||
|
class read_non_blocking_op : public net::coroutine
|
||||||
|
{
|
||||||
|
net::basic_stream_socket<Protocol>& s_;
|
||||||
|
net::executor_work_guard<decltype(
|
||||||
|
s_.get_executor())> wg_;
|
||||||
|
DynamicBuffer& b_;
|
||||||
|
Condition cond_;
|
||||||
|
Handler h_;
|
||||||
|
std::size_t limit_;
|
||||||
|
std::size_t total_ = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
read_non_blocking_op(read_non_blocking_op&&) = default;
|
||||||
|
read_non_blocking_op(read_non_blocking_op const&) = delete;
|
||||||
|
|
||||||
|
template<class DeducedHandler>
|
||||||
|
read_non_blocking_op(
|
||||||
|
net::basic_stream_socket<Protocol>& s,
|
||||||
|
DynamicBuffer& b,
|
||||||
|
Condition cond,
|
||||||
|
DeducedHandler&& h)
|
||||||
|
: s_(s)
|
||||||
|
, wg_(s_.get_executor())
|
||||||
|
, b_(b)
|
||||||
|
, cond_(cond)
|
||||||
|
, h_(std::forward<DeducedHandler>(h))
|
||||||
|
{
|
||||||
|
(*this)({}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(error_code ec, bool cont = true);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
using allocator_type =
|
||||||
|
net::associated_allocator_t<Handler>;
|
||||||
|
|
||||||
|
using executor_type = net::associated_executor_t<
|
||||||
|
Handler, decltype(s_.get_executor())>;
|
||||||
|
|
||||||
|
allocator_type
|
||||||
|
get_allocator() const noexcept
|
||||||
|
{
|
||||||
|
return net::get_associated_allocator(h_);
|
||||||
|
}
|
||||||
|
|
||||||
|
executor_type
|
||||||
|
get_executor() const noexcept
|
||||||
|
{
|
||||||
|
return net::get_associated_executor(
|
||||||
|
h_, s_.get_executor());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void* asio_handler_allocate(
|
||||||
|
std::size_t size, read_non_blocking_op* op)
|
||||||
|
{
|
||||||
|
using net::asio_handler_allocate;
|
||||||
|
return asio_handler_allocate(
|
||||||
|
size, std::addressof(op->h_));
|
||||||
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void asio_handler_deallocate(void* p,
|
||||||
|
std::size_t size, read_non_blocking_op* op)
|
||||||
|
{
|
||||||
|
using net::asio_handler_deallocate;
|
||||||
|
asio_handler_deallocate(
|
||||||
|
p, size, std::addressof(op->h_));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Function>
|
||||||
|
friend
|
||||||
|
void asio_handler_invoke(
|
||||||
|
Function&& f, read_non_blocking_op* op)
|
||||||
|
{
|
||||||
|
using net::asio_handler_invoke;
|
||||||
|
asio_handler_invoke(f, std::addressof(op->h_));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Protocol, class DynamicBuffer,
|
||||||
|
class Condition, class Handler>
|
||||||
|
void
|
||||||
|
read_non_blocking_op<
|
||||||
|
Protocol, DynamicBuffer, Condition, Handler>::
|
||||||
|
operator()(error_code ec, bool cont)
|
||||||
|
{
|
||||||
|
std::size_t n;
|
||||||
|
std::size_t bytes_transferred;
|
||||||
|
BOOST_ASIO_CORO_REENTER(*this)
|
||||||
|
{
|
||||||
|
limit_ = cond_(ec, total_, b_);
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
n = detail::min<std::size_t>(
|
||||||
|
limit_, b_.max_size() - b_.size());
|
||||||
|
if(n == 0)
|
||||||
|
break;
|
||||||
|
BOOST_ASIO_CORO_YIELD
|
||||||
|
s_.async_wait(
|
||||||
|
net::socket_base::wait_read, std::move(*this));
|
||||||
|
if(b_.size() <= default_max_stack_buffer)
|
||||||
|
{
|
||||||
|
flat_static_buffer<
|
||||||
|
default_max_stack_buffer> sb;
|
||||||
|
bytes_transferred = net::buffer_copy(
|
||||||
|
sb.prepare(b_.size()), b_.data());
|
||||||
|
sb.commit(bytes_transferred);
|
||||||
|
b_.consume(bytes_transferred);
|
||||||
|
//detail::shrink_to_fit(b_);
|
||||||
|
n = detail::min<std::size_t>(
|
||||||
|
limit_,
|
||||||
|
sb.capacity() - sb.size(),
|
||||||
|
b_.max_size() - sb.size());
|
||||||
|
BOOST_ASSERT(n > 0);
|
||||||
|
bytes_transferred =
|
||||||
|
s_.read_some(sb.prepare(n), ec);
|
||||||
|
sb.commit(bytes_transferred);
|
||||||
|
total_ += bytes_transferred;
|
||||||
|
limit_ = cond_(ec, total_, sb);
|
||||||
|
b_.commit(net::buffer_copy(
|
||||||
|
b_.prepare(sb.size()), sb.data()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n = detail::min<std::size_t>(
|
||||||
|
limit_,
|
||||||
|
s_.available(),
|
||||||
|
b_.max_size() - b_.size(),
|
||||||
|
std::max<std::size_t>(
|
||||||
|
512, b_.capacity() - b_.size()));
|
||||||
|
BOOST_ASSERT(n > 0);
|
||||||
|
bytes_transferred = s_.read_some(
|
||||||
|
b_.prepare(n), ec);
|
||||||
|
b_.commit(bytes_transferred);
|
||||||
|
total_ += bytes_transferred;
|
||||||
|
limit_ = cond_(ec, total_, b_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(! cont)
|
||||||
|
{
|
||||||
|
BOOST_ASIO_CORO_YIELD
|
||||||
|
net::post(s_.get_executor(),
|
||||||
|
beast::bind_front_handler(
|
||||||
|
std::move(*this), ec, total_));
|
||||||
|
}
|
||||||
|
h_(ec, total_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<
|
||||||
|
class AsyncReadStream,
|
||||||
|
class DynamicBuffer,
|
||||||
|
class CompletionCondition,
|
||||||
|
class ReadHandler,
|
||||||
|
class>
|
||||||
|
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||||
|
ReadHandler, void(error_code, std::size_t))
|
||||||
|
async_read(
|
||||||
|
AsyncReadStream& stream,
|
||||||
|
DynamicBuffer& buffer,
|
||||||
|
CompletionCondition cond,
|
||||||
|
ReadHandler&& handler)
|
||||||
|
{
|
||||||
|
static_assert(is_async_read_stream<AsyncReadStream>::value,
|
||||||
|
"AsyncReadStream requirements not met");
|
||||||
|
static_assert(
|
||||||
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
|
"DynamicBuffer requirements not met");
|
||||||
|
static_assert(
|
||||||
|
detail::is_invocable<CompletionCondition,
|
||||||
|
void(error_code&, std::size_t, DynamicBuffer&)>::value,
|
||||||
|
"CompletionCondition requirements not met");
|
||||||
|
BOOST_BEAST_HANDLER_INIT(
|
||||||
|
ReadHandler, void(error_code, std::size_t));
|
||||||
|
detail::read_op<
|
||||||
|
AsyncReadStream,
|
||||||
|
DynamicBuffer,
|
||||||
|
CompletionCondition,
|
||||||
|
BOOST_ASIO_HANDLER_TYPE(
|
||||||
|
ReadHandler, void(error_code, std::size_t))>(
|
||||||
|
stream, buffer, std::move(cond),
|
||||||
|
std::move(init.completion_handler));
|
||||||
|
return init.result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BOOST_BEAST_ENABLE_NON_BLOCKING
|
||||||
|
template<
|
||||||
|
class Protocol,
|
||||||
|
class DynamicBuffer,
|
||||||
|
class CompletionCondition,
|
||||||
|
class ReadHandler>
|
||||||
|
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||||
|
ReadHandler, void(error_code, std::size_t))
|
||||||
|
async_read(
|
||||||
|
net::basic_stream_socket<Protocol>& socket,
|
||||||
|
DynamicBuffer& buffer,
|
||||||
|
CompletionCondition cond,
|
||||||
|
ReadHandler&& handler)
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
|
"DynamicBuffer requirements not met");
|
||||||
|
static_assert(
|
||||||
|
detail::is_invocable<CompletionCondition,
|
||||||
|
void(error_code&, std::size_t, DynamicBuffer&)>::value,
|
||||||
|
"CompletionCondition requirements not met");
|
||||||
|
BOOST_BEAST_HANDLER_INIT(
|
||||||
|
ReadHandler, void(error_code, std::size_t));
|
||||||
|
if(socket.non_blocking())
|
||||||
|
{
|
||||||
|
detail::read_non_blocking_op<
|
||||||
|
Protocol,
|
||||||
|
DynamicBuffer,
|
||||||
|
CompletionCondition,
|
||||||
|
BOOST_ASIO_HANDLER_TYPE(
|
||||||
|
ReadHandler, void(error_code, std::size_t))>(
|
||||||
|
socket, buffer, std::move(cond),
|
||||||
|
std::move(init.completion_handler));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
detail::read_op<
|
||||||
|
decltype(socket),
|
||||||
|
DynamicBuffer,
|
||||||
|
CompletionCondition,
|
||||||
|
BOOST_ASIO_HANDLER_TYPE(
|
||||||
|
ReadHandler, void(error_code, std::size_t))>(
|
||||||
|
socket, buffer, std::move(cond),
|
||||||
|
std::move(init.completion_handler));
|
||||||
|
}
|
||||||
|
return init.result.get();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<
|
||||||
|
class SyncReadStream,
|
||||||
|
class DynamicBuffer,
|
||||||
|
class CompletionCondition,
|
||||||
|
class>
|
||||||
|
std::size_t
|
||||||
|
read(
|
||||||
|
SyncReadStream& stream,
|
||||||
|
DynamicBuffer& buffer,
|
||||||
|
CompletionCondition cond)
|
||||||
|
{
|
||||||
|
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
||||||
|
"SyncReadStream requirements not met");
|
||||||
|
static_assert(
|
||||||
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
|
"DynamicBuffer requirements not met");
|
||||||
|
static_assert(
|
||||||
|
detail::is_invocable<CompletionCondition,
|
||||||
|
void(error_code&, std::size_t, DynamicBuffer&)>::value,
|
||||||
|
"CompletionCondition requirements not met");
|
||||||
|
error_code ec;
|
||||||
|
auto const bytes_transferred = read(
|
||||||
|
stream, buffer, std::move(cond), ec);
|
||||||
|
if(ec)
|
||||||
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||||
|
return bytes_transferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class SyncReadStream,
|
||||||
|
class DynamicBuffer,
|
||||||
|
class CompletionCondition,
|
||||||
|
class>
|
||||||
|
std::size_t
|
||||||
|
read(
|
||||||
|
SyncReadStream& stream,
|
||||||
|
DynamicBuffer& buffer,
|
||||||
|
CompletionCondition cond,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
||||||
|
"SyncReadStream requirements not met");
|
||||||
|
static_assert(
|
||||||
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
|
"DynamicBuffer requirements not met");
|
||||||
|
static_assert(
|
||||||
|
detail::is_invocable<CompletionCondition,
|
||||||
|
void(error_code&, std::size_t, DynamicBuffer&)>::value,
|
||||||
|
"CompletionCondition requirements not met");
|
||||||
|
ec = {};
|
||||||
|
std::size_t total = 0;
|
||||||
|
std::size_t max_size;
|
||||||
|
std::size_t max_prepare;
|
||||||
|
max_size = cond(ec, total, buffer);
|
||||||
|
max_prepare = std::min<std::size_t>(
|
||||||
|
std::max<std::size_t>(
|
||||||
|
512, buffer.capacity() - buffer.size()),
|
||||||
|
std::min<std::size_t>(
|
||||||
|
max_size, buffer.max_size() - buffer.size()));
|
||||||
|
while(max_prepare > 0)
|
||||||
|
{
|
||||||
|
std::size_t const bytes_transferred =
|
||||||
|
stream.read_some(buffer.prepare(max_prepare), ec);
|
||||||
|
buffer.commit(bytes_transferred);
|
||||||
|
total += bytes_transferred;
|
||||||
|
max_size = cond(ec, total, buffer);
|
||||||
|
max_prepare = std::min<std::size_t>(
|
||||||
|
std::max<std::size_t>(
|
||||||
|
512, buffer.capacity() - buffer.size()),
|
||||||
|
std::min<std::size_t>(
|
||||||
|
max_size, buffer.max_size() - buffer.size()));
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BOOST_BEAST_ENABLE_NON_BLOCKING
|
||||||
|
template<
|
||||||
|
class Protocol,
|
||||||
|
class DynamicBuffer,
|
||||||
|
class CompletionCondition>
|
||||||
|
std::size_t
|
||||||
|
read(
|
||||||
|
net::basic_stream_socket<Protocol>& socket,
|
||||||
|
DynamicBuffer& buffer,
|
||||||
|
CompletionCondition cond,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
|
"DynamicBuffer requirements not met");
|
||||||
|
static_assert(
|
||||||
|
detail::is_invocable<CompletionCondition,
|
||||||
|
void(error_code&, std::size_t, DynamicBuffer&)>::value,
|
||||||
|
"CompletionCondition requirements not met");
|
||||||
|
ec = {};
|
||||||
|
std::size_t n;
|
||||||
|
std::size_t limit;
|
||||||
|
std::size_t total = 0;
|
||||||
|
std::size_t bytes_transferred;
|
||||||
|
limit = cond(ec, total, buffer);
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
n = detail::min<std::size_t>(
|
||||||
|
limit, buffer.max_size() - buffer.size());
|
||||||
|
if(n == 0)
|
||||||
|
break;
|
||||||
|
socket.non_blocking(false);
|
||||||
|
socket.wait(net::socket_base::wait_read, ec);
|
||||||
|
socket.non_blocking(true);
|
||||||
|
if(ec)
|
||||||
|
{
|
||||||
|
limit = cond(ec, total, buffer);
|
||||||
|
}
|
||||||
|
else if(buffer.size() <= default_max_stack_buffer)
|
||||||
|
{
|
||||||
|
flat_static_buffer<
|
||||||
|
default_max_stack_buffer> sb;
|
||||||
|
bytes_transferred = net::buffer_copy(
|
||||||
|
sb.prepare(buffer.size()), buffer.data());
|
||||||
|
sb.commit(bytes_transferred);
|
||||||
|
buffer.consume(bytes_transferred);
|
||||||
|
//detail::shrink_to_fit(buffer);
|
||||||
|
n = detail::min<std::size_t>(
|
||||||
|
limit,
|
||||||
|
sb.capacity() - sb.size(),
|
||||||
|
buffer.max_size() - sb.size());
|
||||||
|
BOOST_ASSERT(n > 0);
|
||||||
|
bytes_transferred =
|
||||||
|
socket.read_some(sb.prepare(n), ec);
|
||||||
|
if(ec != net::error::would_block)
|
||||||
|
{
|
||||||
|
sb.commit(bytes_transferred);
|
||||||
|
total += bytes_transferred;
|
||||||
|
limit = cond(ec, total, sb);
|
||||||
|
}
|
||||||
|
buffer.commit(net::buffer_copy(
|
||||||
|
buffer.prepare(sb.size()), sb.data()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n = detail::min<std::size_t>(
|
||||||
|
limit,
|
||||||
|
socket.available(),
|
||||||
|
buffer.max_size() - buffer.size(),
|
||||||
|
std::max<std::size_t>(
|
||||||
|
512, buffer.capacity() - buffer.size()));
|
||||||
|
BOOST_ASSERT(n > 0);
|
||||||
|
bytes_transferred = socket.read_some(
|
||||||
|
buffer.prepare(n), ec);
|
||||||
|
if(ec != net::error::would_block)
|
||||||
|
{
|
||||||
|
buffer.commit(bytes_transferred);
|
||||||
|
total += bytes_transferred;
|
||||||
|
limit = cond(ec, total, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // beast
|
||||||
|
} // boost
|
||||||
|
|
||||||
|
#endif
|
241
include/boost/beast/core/detail/read.hpp
Normal file
241
include/boost/beast/core/detail/read.hpp
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BOOST_BEAST_DETAIL_READ_HPP
|
||||||
|
#define BOOST_BEAST_DETAIL_READ_HPP
|
||||||
|
|
||||||
|
#include <boost/beast/core/detail/config.hpp>
|
||||||
|
#include <boost/beast/core/detail/stream_algorithm.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Read data into a dynamic buffer from a stream until a condition is met.
|
||||||
|
|
||||||
|
This function is used to read from a stream into a dynamic buffer until
|
||||||
|
a condition is met. The call will block until one of the following is true:
|
||||||
|
|
||||||
|
@li The specified dynamic buffer sequence is full (that is, it has
|
||||||
|
reached its currently configured maximum size).
|
||||||
|
|
||||||
|
@li The `completion_condition` function object returns 0.
|
||||||
|
|
||||||
|
This operation is implemented in terms of zero or more calls to the
|
||||||
|
stream's `read_some` function.
|
||||||
|
|
||||||
|
@param stream The stream from which the data is to be read. The type
|
||||||
|
must support the <em>SyncReadStream</em> requirements.
|
||||||
|
|
||||||
|
@param buffer The dynamic buffer sequence into which the data will be read.
|
||||||
|
|
||||||
|
@param completion_condition The function object to be called to determine
|
||||||
|
whether the read operation is complete. The function object must be invocable
|
||||||
|
with this signature:
|
||||||
|
@code
|
||||||
|
std::size_t
|
||||||
|
completion_condition(
|
||||||
|
// Modifiable result of latest read_some operation.
|
||||||
|
error_code& ec,
|
||||||
|
|
||||||
|
// Number of bytes transferred so far.
|
||||||
|
std::size_t bytes_transferred
|
||||||
|
|
||||||
|
// The dynamic buffer used to store the bytes read
|
||||||
|
DynamicBuffer& buffer
|
||||||
|
);
|
||||||
|
@endcode
|
||||||
|
A non-zero return value indicates the maximum number of bytes to be read on
|
||||||
|
the next call to the stream's `read_some` function. A return value of 0
|
||||||
|
from the completion condition indicates that the read operation is complete;
|
||||||
|
in this case the optionally modifiable error passed to the completion
|
||||||
|
condition will be delivered to the caller as an exception.
|
||||||
|
|
||||||
|
@returns The number of bytes transferred from the stream.
|
||||||
|
|
||||||
|
@throws net::system_error Thrown on failure.
|
||||||
|
*/
|
||||||
|
template<
|
||||||
|
class SyncReadStream,
|
||||||
|
class DynamicBuffer,
|
||||||
|
class CompletionCondition
|
||||||
|
#if ! BOOST_BEAST_DOXYGEN
|
||||||
|
, class = typename std::enable_if<
|
||||||
|
is_sync_read_stream<SyncReadStream>::value &&
|
||||||
|
net::is_dynamic_buffer<DynamicBuffer>::value &&
|
||||||
|
detail::is_invocable<CompletionCondition,
|
||||||
|
void(error_code&, std::size_t, DynamicBuffer&)>::value
|
||||||
|
>::type
|
||||||
|
#endif
|
||||||
|
>
|
||||||
|
std::size_t
|
||||||
|
read(
|
||||||
|
SyncReadStream& stream,
|
||||||
|
DynamicBuffer& buffer,
|
||||||
|
CompletionCondition completion_condition);
|
||||||
|
|
||||||
|
/** Read data into a dynamic buffer from a stream until a condition is met.
|
||||||
|
|
||||||
|
This function is used to read from a stream into a dynamic buffer until
|
||||||
|
a condition is met. The call will block until one of the following is true:
|
||||||
|
|
||||||
|
@li The specified dynamic buffer sequence is full (that is, it has
|
||||||
|
reached its currently configured maximum size).
|
||||||
|
|
||||||
|
@li The `completion_condition` function object returns 0.
|
||||||
|
|
||||||
|
This operation is implemented in terms of zero or more calls to the
|
||||||
|
stream's `read_some` function.
|
||||||
|
|
||||||
|
@param stream The stream from which the data is to be read. The type
|
||||||
|
must support the <em>SyncReadStream</em> requirements.
|
||||||
|
|
||||||
|
@param buffer The dynamic buffer sequence into which the data will be read.
|
||||||
|
|
||||||
|
@param completion_condition The function object to be called to determine
|
||||||
|
whether the read operation is complete. The function object must be invocable
|
||||||
|
with this signature:
|
||||||
|
@code
|
||||||
|
std::size_t
|
||||||
|
completion_condition(
|
||||||
|
// Modifiable result of latest read_some operation.
|
||||||
|
error_code& ec,
|
||||||
|
|
||||||
|
// Number of bytes transferred so far.
|
||||||
|
std::size_t bytes_transferred
|
||||||
|
|
||||||
|
// The dynamic buffer used to store the bytes read
|
||||||
|
DynamicBuffer& buffer
|
||||||
|
);
|
||||||
|
@endcode
|
||||||
|
A non-zero return value indicates the maximum number of bytes to be read on
|
||||||
|
the next call to the stream's `read_some` function. A return value of 0
|
||||||
|
from the completion condition indicates that the read operation is complete;
|
||||||
|
in this case the optionally modifiable error passed to the completion
|
||||||
|
condition will be delivered to the caller.
|
||||||
|
|
||||||
|
@returns The number of bytes transferred from the stream.
|
||||||
|
*/
|
||||||
|
template<
|
||||||
|
class SyncReadStream,
|
||||||
|
class DynamicBuffer,
|
||||||
|
class CompletionCondition
|
||||||
|
#if ! BOOST_BEAST_DOXYGEN
|
||||||
|
, class = typename std::enable_if<
|
||||||
|
is_sync_read_stream<SyncReadStream>::value &&
|
||||||
|
net::is_dynamic_buffer<DynamicBuffer>::value &&
|
||||||
|
detail::is_invocable<CompletionCondition,
|
||||||
|
void(error_code&, std::size_t, DynamicBuffer&)>::value
|
||||||
|
>::type
|
||||||
|
#endif
|
||||||
|
>
|
||||||
|
std::size_t
|
||||||
|
read(
|
||||||
|
SyncReadStream& stream,
|
||||||
|
DynamicBuffer& buffer,
|
||||||
|
CompletionCondition completion_condition,
|
||||||
|
error_code& ec);
|
||||||
|
|
||||||
|
/** Asynchronously read data into a dynamic buffer from a stream until a condition is met.
|
||||||
|
|
||||||
|
This function is used to asynchronously read from a stream into a dynamic
|
||||||
|
buffer until a condition is met. The function call always returns immediately.
|
||||||
|
The asynchronous operation will continue until one of the following is true:
|
||||||
|
|
||||||
|
@li The specified dynamic buffer sequence is full (that is, it has
|
||||||
|
reached its currently configured maximum size).
|
||||||
|
|
||||||
|
@li The `completion_condition` function object returns 0.
|
||||||
|
|
||||||
|
This operation is implemented in terms of zero or more calls to the stream's
|
||||||
|
`async_read_some` function, and is known as a <em>composed operation</em>. The
|
||||||
|
program must ensure that the stream performs no other read operations (such
|
||||||
|
as `async_read`, the stream's `async_read_some` function, or any other composed
|
||||||
|
operations that perform reads) until this operation completes.
|
||||||
|
|
||||||
|
@param stream The stream from which the data is to be read. The type must
|
||||||
|
support the <em>AsyncReadStream</em> requirements.
|
||||||
|
|
||||||
|
@param buffer The dynamic buffer sequence into which the data will be read.
|
||||||
|
Ownership of the object is retained by the caller, which must guarantee
|
||||||
|
that it remains valid until the handler is called.
|
||||||
|
|
||||||
|
@param completion_condition The function object to be called to determine
|
||||||
|
whether the read operation is complete. The function object must be invocable
|
||||||
|
with this signature:
|
||||||
|
@code
|
||||||
|
std::size_t
|
||||||
|
completion_condition(
|
||||||
|
// Modifiable result of latest async_read_some operation.
|
||||||
|
error_code& ec,
|
||||||
|
|
||||||
|
// Number of bytes transferred so far.
|
||||||
|
std::size_t bytes_transferred,
|
||||||
|
|
||||||
|
// The dynamic buffer used to store the bytes read
|
||||||
|
DynamicBuffer& buffer
|
||||||
|
);
|
||||||
|
@endcode
|
||||||
|
A non-zero return value indicates the maximum number of bytes to be read on
|
||||||
|
the next call to the stream's `async_read_some` function. A return value of 0
|
||||||
|
from the completion condition indicates that the read operation is complete;
|
||||||
|
in this case the optionally modifiable error passed to the completion
|
||||||
|
condition will be delivered to the completion handler.
|
||||||
|
|
||||||
|
@param handler The handler to be called when the read operation completes.
|
||||||
|
The handler will be moved as needed. The handler must be invocable with
|
||||||
|
this function signature:
|
||||||
|
@code
|
||||||
|
void
|
||||||
|
handler(
|
||||||
|
error_code const& ec, // Result of operation.
|
||||||
|
|
||||||
|
std::size_t bytes_transferred // Number of bytes copied into
|
||||||
|
// the dynamic buffer. If an error
|
||||||
|
// occurred, this will be the number
|
||||||
|
// of bytes successfully transferred
|
||||||
|
// prior to the error.
|
||||||
|
);
|
||||||
|
@endcode
|
||||||
|
Regardless of whether the asynchronous operation completes immediately or
|
||||||
|
not, the handler will not be invoked from within this function. Invocation
|
||||||
|
of the handler will be performed in a manner equivalent to using
|
||||||
|
`net::io_context::post()`.
|
||||||
|
*/
|
||||||
|
template<
|
||||||
|
class AsyncReadStream,
|
||||||
|
class DynamicBuffer,
|
||||||
|
class CompletionCondition,
|
||||||
|
class ReadHandler
|
||||||
|
#if ! BOOST_BEAST_DOXYGEN
|
||||||
|
, class = typename std::enable_if<
|
||||||
|
is_async_read_stream<AsyncReadStream>::value &&
|
||||||
|
net::is_dynamic_buffer<DynamicBuffer>::value &&
|
||||||
|
detail::is_invocable<CompletionCondition,
|
||||||
|
void(error_code&, std::size_t, DynamicBuffer&)>::value
|
||||||
|
>::type
|
||||||
|
#endif
|
||||||
|
>
|
||||||
|
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||||
|
ReadHandler, void(error_code, std::size_t))
|
||||||
|
async_read(
|
||||||
|
AsyncReadStream& stream,
|
||||||
|
DynamicBuffer& buffer,
|
||||||
|
CompletionCondition completion_condition,
|
||||||
|
ReadHandler&& handler);
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // beast
|
||||||
|
} // boost
|
||||||
|
|
||||||
|
#include <boost/beast/core/detail/impl/read.hpp>
|
||||||
|
|
||||||
|
#endif
|
31
include/boost/beast/core/detail/stream_algorithm.hpp
Normal file
31
include/boost/beast/core/detail/stream_algorithm.hpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BOOST_BEAST_DETAIL_STREAM_ALGORITHM_HPP
|
||||||
|
#define BOOST_BEAST_DETAIL_STREAM_ALGORITHM_HPP
|
||||||
|
|
||||||
|
// Include most of what is needed to write stream algorithms
|
||||||
|
|
||||||
|
#include <boost/beast/core/bind_handler.hpp>
|
||||||
|
#include <boost/beast/core/error.hpp>
|
||||||
|
#include <boost/beast/core/type_traits.hpp>
|
||||||
|
#include <boost/beast/core/detail/buffer.hpp>
|
||||||
|
#include <boost/asio/associated_allocator.hpp>
|
||||||
|
#include <boost/asio/associated_executor.hpp>
|
||||||
|
#include <boost/asio/async_result.hpp>
|
||||||
|
#include <boost/asio/coroutine.hpp>
|
||||||
|
#include <boost/asio/executor_work_guard.hpp>
|
||||||
|
#include <boost/asio/handler_continuation_hook.hpp>
|
||||||
|
#include <boost/asio/handler_invoke_hook.hpp>
|
||||||
|
#include <boost/asio/post.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/throw_exception.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#endif
|
@ -24,8 +24,22 @@ namespace boost {
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
// variadic min
|
||||||
|
template<class T>
|
||||||
|
T constexpr min(T t)
|
||||||
|
{
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T, class...Tn>
|
||||||
|
T constexpr min(T t0, T t1, Tn... tn)
|
||||||
|
{
|
||||||
|
return (t0 < t1) ?
|
||||||
|
(detail::min)(t0, tn...) :
|
||||||
|
(detail::min)(t1, tn...);
|
||||||
|
}
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
inline
|
|
||||||
std::size_t constexpr
|
std::size_t constexpr
|
||||||
max_sizeof()
|
max_sizeof()
|
||||||
{
|
{
|
||||||
@ -33,7 +47,6 @@ max_sizeof()
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class U0, class U1, class... Us>
|
template<class U0, class U1, class... Us>
|
||||||
inline
|
|
||||||
std::size_t constexpr
|
std::size_t constexpr
|
||||||
max_sizeof()
|
max_sizeof()
|
||||||
{
|
{
|
||||||
@ -43,7 +56,6 @@ max_sizeof()
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
inline
|
|
||||||
std::size_t constexpr
|
std::size_t constexpr
|
||||||
max_alignof()
|
max_alignof()
|
||||||
{
|
{
|
||||||
@ -85,7 +97,6 @@ using aligned_union_t =
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
|
||||||
void
|
void
|
||||||
accept_rv(T){}
|
accept_rv(T){}
|
||||||
|
|
||||||
|
@ -14,23 +14,10 @@
|
|||||||
#include <boost/beast/http/error.hpp>
|
#include <boost/beast/http/error.hpp>
|
||||||
#include <boost/beast/http/parser.hpp>
|
#include <boost/beast/http/parser.hpp>
|
||||||
#include <boost/beast/http/read.hpp>
|
#include <boost/beast/http/read.hpp>
|
||||||
#include <boost/beast/core/bind_handler.hpp>
|
|
||||||
#include <boost/beast/core/handler_ptr.hpp>
|
#include <boost/beast/core/handler_ptr.hpp>
|
||||||
#include <boost/beast/core/read_size.hpp>
|
#include <boost/beast/core/detail/read.hpp>
|
||||||
#include <boost/beast/core/type_traits.hpp>
|
#include <boost/beast/core/detail/stream_algorithm.hpp>
|
||||||
#include <boost/beast/core/detail/buffer.hpp>
|
|
||||||
#include <boost/asio/associated_allocator.hpp>
|
|
||||||
#include <boost/asio/associated_executor.hpp>
|
|
||||||
#include <boost/asio/coroutine.hpp>
|
|
||||||
#include <boost/asio/error.hpp>
|
#include <boost/asio/error.hpp>
|
||||||
#include <boost/asio/executor_work_guard.hpp>
|
|
||||||
#include <boost/asio/handler_continuation_hook.hpp>
|
|
||||||
#include <boost/asio/handler_invoke_hook.hpp>
|
|
||||||
#include <boost/asio/post.hpp>
|
|
||||||
#include <boost/assert.hpp>
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#include <boost/optional.hpp>
|
|
||||||
#include <boost/throw_exception.hpp>
|
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
namespace beast {
|
||||||
@ -38,297 +25,129 @@ namespace http {
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
// The default maximum number of bytes to transfer in a single operation.
|
||||||
|
static std::size_t constexpr default_max_transfer_size = 65536;
|
||||||
|
|
||||||
template<class Stream, class DynamicBuffer,
|
template<
|
||||||
bool isRequest, class Derived, class Handler>
|
class DynamicBuffer,
|
||||||
class read_some_op
|
bool isRequest, class Derived,
|
||||||
: public net::coroutine
|
class Condition>
|
||||||
|
static
|
||||||
|
std::size_t
|
||||||
|
parse_until(
|
||||||
|
DynamicBuffer& buffer,
|
||||||
|
basic_parser<isRequest, Derived>& parser,
|
||||||
|
error_code& ec,
|
||||||
|
Condition cond)
|
||||||
{
|
{
|
||||||
Stream& s_;
|
if(ec == net::error::eof)
|
||||||
net::executor_work_guard<decltype(
|
|
||||||
std::declval<Stream&>().get_executor())> wg_;
|
|
||||||
DynamicBuffer& b_;
|
|
||||||
basic_parser<isRequest, Derived>& p_;
|
|
||||||
std::size_t bytes_transferred_ = 0;
|
|
||||||
Handler h_;
|
|
||||||
bool cont_ = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
read_some_op(read_some_op&&) = default;
|
|
||||||
read_some_op(read_some_op const&) = delete;
|
|
||||||
|
|
||||||
template<class DeducedHandler>
|
|
||||||
read_some_op(DeducedHandler&& h, Stream& s,
|
|
||||||
DynamicBuffer& b, basic_parser<isRequest, Derived>& p)
|
|
||||||
: s_(s)
|
|
||||||
, wg_(s_.get_executor())
|
|
||||||
, b_(b)
|
|
||||||
, p_(p)
|
|
||||||
, h_(std::forward<DeducedHandler>(h))
|
|
||||||
{
|
{
|
||||||
}
|
if(parser.got_some())
|
||||||
|
|
||||||
using allocator_type =
|
|
||||||
net::associated_allocator_t<Handler>;
|
|
||||||
|
|
||||||
allocator_type
|
|
||||||
get_allocator() const noexcept
|
|
||||||
{
|
|
||||||
return (net::get_associated_allocator)(h_);
|
|
||||||
}
|
|
||||||
|
|
||||||
using executor_type = net::associated_executor_t<
|
|
||||||
Handler, decltype(std::declval<Stream&>().get_executor())>;
|
|
||||||
|
|
||||||
executor_type
|
|
||||||
get_executor() const noexcept
|
|
||||||
{
|
|
||||||
return (net::get_associated_executor)(
|
|
||||||
h_, s_.get_executor());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
operator()(
|
|
||||||
error_code ec,
|
|
||||||
std::size_t bytes_transferred = 0,
|
|
||||||
bool cont = true);
|
|
||||||
|
|
||||||
friend
|
|
||||||
bool asio_handler_is_continuation(read_some_op* op)
|
|
||||||
{
|
|
||||||
using net::asio_handler_is_continuation;
|
|
||||||
return op->cont_ ? true :
|
|
||||||
asio_handler_is_continuation(
|
|
||||||
std::addressof(op->h_));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Function>
|
|
||||||
friend
|
|
||||||
void asio_handler_invoke(Function&& f, read_some_op* op)
|
|
||||||
{
|
|
||||||
using net::asio_handler_invoke;
|
|
||||||
asio_handler_invoke(f, std::addressof(op->h_));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class Stream, class DynamicBuffer,
|
|
||||||
bool isRequest, class Derived, class Handler>
|
|
||||||
void
|
|
||||||
read_some_op<Stream, DynamicBuffer,
|
|
||||||
isRequest, Derived, Handler>::
|
|
||||||
operator()(
|
|
||||||
error_code ec,
|
|
||||||
std::size_t bytes_transferred,
|
|
||||||
bool cont)
|
|
||||||
{
|
|
||||||
cont_ = cont;
|
|
||||||
BOOST_ASIO_CORO_REENTER(*this)
|
|
||||||
{
|
|
||||||
if(b_.size() == 0)
|
|
||||||
goto do_read;
|
|
||||||
for(;;)
|
|
||||||
{
|
{
|
||||||
// parse
|
// caller sees EOF on next read
|
||||||
{
|
ec = {};
|
||||||
auto const used = p_.put(b_.data(), ec);
|
parser.put_eof(ec);
|
||||||
bytes_transferred_ += used;
|
BOOST_ASSERT(ec || parser.is_done());
|
||||||
b_.consume(used);
|
|
||||||
}
|
|
||||||
if(ec != http::error::need_more)
|
|
||||||
break;
|
|
||||||
|
|
||||||
do_read:
|
|
||||||
BOOST_ASIO_CORO_YIELD
|
|
||||||
{
|
|
||||||
// VFALCO This was read_size_or_throw
|
|
||||||
auto const size = read_size(b_, 65536);
|
|
||||||
if(size == 0)
|
|
||||||
{
|
|
||||||
ec = error::buffer_overflow;
|
|
||||||
goto upcall;
|
|
||||||
}
|
|
||||||
auto const mb =
|
|
||||||
beast::detail::dynamic_buffer_prepare(
|
|
||||||
b_, size, ec, error::buffer_overflow);
|
|
||||||
if(ec)
|
|
||||||
goto upcall;
|
|
||||||
s_.async_read_some(*mb, std::move(*this));
|
|
||||||
}
|
|
||||||
if(ec == net::error::eof)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(bytes_transferred == 0);
|
|
||||||
if(p_.got_some())
|
|
||||||
{
|
|
||||||
// caller sees EOF on next read
|
|
||||||
ec.assign(0, ec.category());
|
|
||||||
p_.put_eof(ec);
|
|
||||||
if(ec)
|
|
||||||
goto upcall;
|
|
||||||
BOOST_ASSERT(p_.is_done());
|
|
||||||
goto upcall;
|
|
||||||
}
|
|
||||||
ec = error::end_of_stream;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(ec)
|
|
||||||
break;
|
|
||||||
b_.commit(bytes_transferred);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
upcall:
|
|
||||||
if(! cont_)
|
|
||||||
{
|
{
|
||||||
BOOST_ASIO_CORO_YIELD
|
ec = error::end_of_stream;
|
||||||
net::post(
|
|
||||||
s_.get_executor(),
|
|
||||||
beast::bind_front_handler(std::move(*this),
|
|
||||||
ec, bytes_transferred_));
|
|
||||||
}
|
}
|
||||||
h_(ec, bytes_transferred_);
|
return 0;
|
||||||
}
|
}
|
||||||
|
if(ec)
|
||||||
|
return 0;
|
||||||
|
if(parser.is_done())
|
||||||
|
return 0;
|
||||||
|
if(buffer.size() > 0)
|
||||||
|
{
|
||||||
|
auto const bytes_used =
|
||||||
|
parser.put(buffer.data(), ec);
|
||||||
|
// total = total + bytes_used; // VFALCO Can't do this in a condition
|
||||||
|
buffer.consume(bytes_used);
|
||||||
|
if(ec == http::error::need_more)
|
||||||
|
{
|
||||||
|
if(buffer.size() >= buffer.max_size())
|
||||||
|
{
|
||||||
|
ec = http::error::buffer_overflow;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ec = {};
|
||||||
|
}
|
||||||
|
else if(ec || cond())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return default_max_transfer_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
// predicate is true on any forward parser progress
|
||||||
|
template<bool isRequest, class Derived>
|
||||||
struct parser_is_done
|
struct read_some_condition
|
||||||
{
|
{
|
||||||
template<bool isRequest, class Derived>
|
basic_parser<isRequest, Derived>& parser;
|
||||||
bool
|
|
||||||
operator()(basic_parser<
|
template<class DynamicBuffer>
|
||||||
isRequest, Derived> const& p) const
|
std::size_t
|
||||||
|
operator()(error_code& ec, std::size_t,
|
||||||
|
DynamicBuffer& buffer)
|
||||||
{
|
{
|
||||||
return p.is_done();
|
return detail::parse_until(
|
||||||
|
buffer, parser, ec,
|
||||||
|
[]
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct parser_is_header_done
|
// predicate is true when parser header is complete
|
||||||
|
template<bool isRequest, class Derived>
|
||||||
|
struct read_header_condition
|
||||||
{
|
{
|
||||||
template<bool isRequest, class Derived>
|
basic_parser<isRequest, Derived>& parser;
|
||||||
bool
|
|
||||||
operator()(basic_parser<
|
template<class DynamicBuffer>
|
||||||
isRequest, Derived> const& p) const
|
std::size_t
|
||||||
|
operator()(error_code& ec, std::size_t,
|
||||||
|
DynamicBuffer& buffer)
|
||||||
{
|
{
|
||||||
return p.is_header_done();
|
return detail::parse_until(
|
||||||
|
buffer, parser, ec,
|
||||||
|
[this]
|
||||||
|
{
|
||||||
|
return parser.is_header_done();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Stream, class DynamicBuffer,
|
// predicate is true when parser message is complete
|
||||||
bool isRequest, class Derived, class Condition,
|
template<bool isRequest, class Derived>
|
||||||
class Handler>
|
struct read_all_condition
|
||||||
class read_op
|
|
||||||
: public net::coroutine
|
|
||||||
{
|
{
|
||||||
Stream& s_;
|
basic_parser<isRequest, Derived>& parser;
|
||||||
net::executor_work_guard<decltype(
|
|
||||||
std::declval<Stream&>().get_executor())> wg_;
|
|
||||||
DynamicBuffer& b_;
|
|
||||||
basic_parser<isRequest, Derived>& p_;
|
|
||||||
std::size_t bytes_transferred_ = 0;
|
|
||||||
Handler h_;
|
|
||||||
bool cont_ = false;
|
|
||||||
|
|
||||||
public:
|
template<class DynamicBuffer>
|
||||||
read_op(read_op&&) = default;
|
std::size_t
|
||||||
read_op(read_op const&) = delete;
|
operator()(error_code& ec, std::size_t,
|
||||||
|
DynamicBuffer& buffer)
|
||||||
template<class DeducedHandler>
|
|
||||||
read_op(DeducedHandler&& h, Stream& s,
|
|
||||||
DynamicBuffer& b, basic_parser<isRequest,
|
|
||||||
Derived>& p)
|
|
||||||
: s_(s)
|
|
||||||
, wg_(s_.get_executor())
|
|
||||||
, b_(b)
|
|
||||||
, p_(p)
|
|
||||||
, h_(std::forward<DeducedHandler>(h))
|
|
||||||
{
|
{
|
||||||
}
|
return detail::parse_until(
|
||||||
|
buffer, parser, ec,
|
||||||
using allocator_type =
|
[this]
|
||||||
net::associated_allocator_t<Handler>;
|
{
|
||||||
|
return parser.is_done();
|
||||||
allocator_type
|
});
|
||||||
get_allocator() const noexcept
|
|
||||||
{
|
|
||||||
return (net::get_associated_allocator)(h_);
|
|
||||||
}
|
|
||||||
|
|
||||||
using executor_type = net::associated_executor_t<
|
|
||||||
Handler, decltype(std::declval<Stream&>().get_executor())>;
|
|
||||||
|
|
||||||
executor_type
|
|
||||||
get_executor() const noexcept
|
|
||||||
{
|
|
||||||
return (net::get_associated_executor)(
|
|
||||||
h_, s_.get_executor());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
operator()(
|
|
||||||
error_code ec,
|
|
||||||
std::size_t bytes_transferred = 0,
|
|
||||||
bool cont = true);
|
|
||||||
|
|
||||||
friend
|
|
||||||
bool asio_handler_is_continuation(read_op* op)
|
|
||||||
{
|
|
||||||
using net::asio_handler_is_continuation;
|
|
||||||
return op->cont_ ? true :
|
|
||||||
asio_handler_is_continuation(
|
|
||||||
std::addressof(op->h_));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Function>
|
|
||||||
friend
|
|
||||||
void asio_handler_invoke(Function&& f, read_op* op)
|
|
||||||
{
|
|
||||||
using net::asio_handler_invoke;
|
|
||||||
asio_handler_invoke(f, std::addressof(op->h_));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Stream, class DynamicBuffer,
|
|
||||||
bool isRequest, class Derived, class Condition,
|
|
||||||
class Handler>
|
|
||||||
void
|
|
||||||
read_op<Stream, DynamicBuffer,
|
|
||||||
isRequest, Derived, Condition, Handler>::
|
|
||||||
operator()(
|
|
||||||
error_code ec,
|
|
||||||
std::size_t bytes_transferred,
|
|
||||||
bool cont)
|
|
||||||
{
|
|
||||||
cont_ = cont;
|
|
||||||
BOOST_ASIO_CORO_REENTER(*this)
|
|
||||||
{
|
|
||||||
if(Condition{}(p_))
|
|
||||||
{
|
|
||||||
BOOST_ASIO_CORO_YIELD
|
|
||||||
net::post(s_.get_executor(),
|
|
||||||
beast::bind_front_handler(std::move(*this), ec));
|
|
||||||
goto upcall;
|
|
||||||
}
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
BOOST_ASIO_CORO_YIELD
|
|
||||||
async_read_some(
|
|
||||||
s_, b_, p_, std::move(*this));
|
|
||||||
bytes_transferred_ += bytes_transferred;
|
|
||||||
if(ec)
|
|
||||||
goto upcall;
|
|
||||||
if(Condition{}(p_))
|
|
||||||
goto upcall;
|
|
||||||
}
|
|
||||||
upcall:
|
|
||||||
h_(ec, bytes_transferred_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class Stream, class DynamicBuffer,
|
template<
|
||||||
|
class Stream, class DynamicBuffer,
|
||||||
bool isRequest, class Body, class Allocator,
|
bool isRequest, class Body, class Allocator,
|
||||||
class Handler>
|
class Handler>
|
||||||
class read_msg_op
|
class read_msg_op
|
||||||
: public net::coroutine
|
: public net::coroutine
|
||||||
{
|
{
|
||||||
@ -341,23 +160,17 @@ class read_msg_op
|
|||||||
struct data
|
struct data
|
||||||
{
|
{
|
||||||
Stream& s;
|
Stream& s;
|
||||||
net::executor_work_guard<decltype(
|
|
||||||
std::declval<Stream&>().get_executor())> wg;
|
|
||||||
DynamicBuffer& b;
|
|
||||||
message_type& m;
|
message_type& m;
|
||||||
parser_type p;
|
parser_type p;
|
||||||
std::size_t bytes_transferred = 0;
|
|
||||||
bool cont = false;
|
|
||||||
|
|
||||||
data(Handler const&, Stream& s_,
|
data(
|
||||||
DynamicBuffer& b_, message_type& m_)
|
Handler const&,
|
||||||
|
Stream& s_,
|
||||||
|
message_type& m_)
|
||||||
: s(s_)
|
: s(s_)
|
||||||
, wg(s.get_executor())
|
|
||||||
, b(b_)
|
|
||||||
, m(m_)
|
, m(m_)
|
||||||
, p(std::move(m))
|
, p(std::move(m))
|
||||||
{
|
{
|
||||||
p.eager(true);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -367,45 +180,59 @@ public:
|
|||||||
read_msg_op(read_msg_op&&) = default;
|
read_msg_op(read_msg_op&&) = default;
|
||||||
read_msg_op(read_msg_op const&) = delete;
|
read_msg_op(read_msg_op const&) = delete;
|
||||||
|
|
||||||
template<class DeducedHandler, class... Args>
|
template<class DeducedHandler>
|
||||||
read_msg_op(DeducedHandler&& h, Stream& s, Args&&... args)
|
read_msg_op(
|
||||||
: d_(std::forward<DeducedHandler>(h),
|
Stream& s,
|
||||||
s, std::forward<Args>(args)...)
|
DynamicBuffer& b,
|
||||||
|
message_type& m,
|
||||||
|
DeducedHandler&& h)
|
||||||
|
: d_(std::forward<DeducedHandler>(h), s, m)
|
||||||
{
|
{
|
||||||
}
|
http::async_read(s, b, d_->p, std::move(*this));
|
||||||
|
|
||||||
using allocator_type =
|
|
||||||
net::associated_allocator_t<Handler>;
|
|
||||||
|
|
||||||
allocator_type
|
|
||||||
get_allocator() const noexcept
|
|
||||||
{
|
|
||||||
return (net::get_associated_allocator)(d_.handler());
|
|
||||||
}
|
|
||||||
|
|
||||||
using executor_type = net::associated_executor_t<
|
|
||||||
Handler, decltype(std::declval<Stream&>().get_executor())>;
|
|
||||||
|
|
||||||
executor_type
|
|
||||||
get_executor() const noexcept
|
|
||||||
{
|
|
||||||
return (net::get_associated_executor)(
|
|
||||||
d_.handler(), d_->s.get_executor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
operator()(
|
operator()(
|
||||||
error_code ec,
|
error_code ec,
|
||||||
std::size_t bytes_transferred = 0,
|
std::size_t bytes_transferred);
|
||||||
bool cont = true);
|
|
||||||
|
//
|
||||||
|
|
||||||
|
using allocator_type =
|
||||||
|
net::associated_allocator_t<Handler>;
|
||||||
|
|
||||||
|
using executor_type = net::associated_executor_t<
|
||||||
|
Handler, decltype(std::declval<Stream&>().get_executor())>;
|
||||||
|
|
||||||
|
allocator_type
|
||||||
|
get_allocator() const noexcept
|
||||||
|
{
|
||||||
|
return net::get_associated_allocator(d_.handler());
|
||||||
|
}
|
||||||
|
|
||||||
|
executor_type
|
||||||
|
get_executor() const noexcept
|
||||||
|
{
|
||||||
|
return net::get_associated_executor(
|
||||||
|
d_.handler(), d_->s.get_executor());
|
||||||
|
}
|
||||||
|
|
||||||
friend
|
friend
|
||||||
bool asio_handler_is_continuation(read_msg_op* op)
|
void* asio_handler_allocate(
|
||||||
|
std::size_t size, read_msg_op* op)
|
||||||
{
|
{
|
||||||
using net::asio_handler_is_continuation;
|
using net::asio_handler_allocate;
|
||||||
return op->d_->cont ? true :
|
return asio_handler_allocate(
|
||||||
asio_handler_is_continuation(
|
size, std::addressof(op->d_.handler()));
|
||||||
std::addressof(op->d_.handler()));
|
}
|
||||||
|
|
||||||
|
friend
|
||||||
|
void asio_handler_deallocate(
|
||||||
|
void* p, std::size_t size, read_msg_op* op)
|
||||||
|
{
|
||||||
|
using net::asio_handler_deallocate;
|
||||||
|
asio_handler_deallocate(
|
||||||
|
p, size, std::addressof(op->d_.handler()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Function>
|
template<class Function>
|
||||||
@ -425,35 +252,12 @@ read_msg_op<Stream, DynamicBuffer,
|
|||||||
isRequest, Body, Allocator, Handler>::
|
isRequest, Body, Allocator, Handler>::
|
||||||
operator()(
|
operator()(
|
||||||
error_code ec,
|
error_code ec,
|
||||||
std::size_t bytes_transferred,
|
std::size_t bytes_transferred)
|
||||||
bool cont)
|
|
||||||
{
|
{
|
||||||
auto& d = *d_;
|
auto& d = *d_;
|
||||||
d.cont = cont;
|
if(! ec)
|
||||||
BOOST_ASIO_CORO_REENTER(*this)
|
d.m = d.p.release();
|
||||||
{
|
d_.invoke(ec, bytes_transferred);
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
BOOST_ASIO_CORO_YIELD
|
|
||||||
async_read_some(
|
|
||||||
d.s, d.b, d.p, std::move(*this));
|
|
||||||
if(ec)
|
|
||||||
goto upcall;
|
|
||||||
d.bytes_transferred +=
|
|
||||||
bytes_transferred;
|
|
||||||
if(d.p.is_done())
|
|
||||||
{
|
|
||||||
d.m = d.p.release();
|
|
||||||
goto upcall;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
upcall:
|
|
||||||
bytes_transferred = d.bytes_transferred;
|
|
||||||
{
|
|
||||||
auto wg = std::move(d.wg);
|
|
||||||
d_.invoke(ec, bytes_transferred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
@ -470,12 +274,12 @@ read_some(
|
|||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser)
|
basic_parser<isRequest, Derived>& parser)
|
||||||
{
|
{
|
||||||
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
static_assert(
|
||||||
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
"SyncReadStream requirements not met");
|
"SyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
"DynamicBuffer requirements not met");
|
"DynamicBuffer requirements not met");
|
||||||
BOOST_ASSERT(! parser.is_done());
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
read_some(stream, buffer, parser, ec);
|
read_some(stream, buffer, parser, ec);
|
||||||
@ -495,60 +299,15 @@ read_some(
|
|||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest, Derived>& parser,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
static_assert(
|
||||||
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
"SyncReadStream requirements not met");
|
"SyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
"DynamicBuffer requirements not met");
|
"DynamicBuffer requirements not met");
|
||||||
BOOST_ASSERT(! parser.is_done());
|
return beast::detail::read(stream, buffer,
|
||||||
std::size_t bytes_transferred = 0;
|
detail::read_some_condition<
|
||||||
if(buffer.size() == 0)
|
isRequest, Derived>{parser}, ec);
|
||||||
goto do_read;
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
// invoke parser
|
|
||||||
{
|
|
||||||
auto const n = parser.put(buffer.data(), ec);
|
|
||||||
bytes_transferred += n;
|
|
||||||
buffer.consume(n);
|
|
||||||
if(! ec)
|
|
||||||
break;
|
|
||||||
if(ec != http::error::need_more)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
do_read:
|
|
||||||
auto const size = read_size(buffer, 65536);
|
|
||||||
if(size == 0)
|
|
||||||
{
|
|
||||||
ec = error::buffer_overflow;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
auto const mb =
|
|
||||||
beast::detail::dynamic_buffer_prepare(
|
|
||||||
buffer, size, ec, error::buffer_overflow);
|
|
||||||
if(ec)
|
|
||||||
break;
|
|
||||||
auto const n = stream.read_some(*mb, ec);
|
|
||||||
if(ec == net::error::eof)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(n == 0);
|
|
||||||
if(parser.got_some())
|
|
||||||
{
|
|
||||||
// caller sees EOF on next read
|
|
||||||
parser.put_eof(ec);
|
|
||||||
if(ec)
|
|
||||||
break;
|
|
||||||
BOOST_ASSERT(parser.is_done());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ec = error::end_of_stream;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(ec)
|
|
||||||
break;
|
|
||||||
buffer.commit(n);
|
|
||||||
}
|
|
||||||
return bytes_transferred;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
@ -564,19 +323,18 @@ async_read_some(
|
|||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest, Derived>& parser,
|
||||||
ReadHandler&& handler)
|
ReadHandler&& handler)
|
||||||
{
|
{
|
||||||
static_assert(is_async_read_stream<AsyncReadStream>::value,
|
static_assert(
|
||||||
|
is_async_read_stream<AsyncReadStream>::value,
|
||||||
"AsyncReadStream requirements not met");
|
"AsyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
"DynamicBuffer requirements not met");
|
"DynamicBuffer requirements not met");
|
||||||
BOOST_ASSERT(! parser.is_done());
|
|
||||||
BOOST_BEAST_HANDLER_INIT(
|
BOOST_BEAST_HANDLER_INIT(
|
||||||
ReadHandler, void(error_code, std::size_t));
|
ReadHandler, void(error_code, std::size_t));
|
||||||
detail::read_some_op<AsyncReadStream,
|
beast::detail::async_read(stream, buffer,
|
||||||
DynamicBuffer, isRequest, Derived, BOOST_ASIO_HANDLER_TYPE(
|
detail::read_some_condition<
|
||||||
ReadHandler, void(error_code, std::size_t))>{
|
isRequest, Derived>{parser}, std::move(
|
||||||
std::move(init.completion_handler), stream, buffer, parser}(
|
init.completion_handler));
|
||||||
{}, 0, false);
|
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -592,7 +350,8 @@ read_header(
|
|||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser)
|
basic_parser<isRequest, Derived>& parser)
|
||||||
{
|
{
|
||||||
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
static_assert(
|
||||||
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
"SyncReadStream requirements not met");
|
"SyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
@ -616,27 +375,16 @@ read_header(
|
|||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest, Derived>& parser,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
static_assert(
|
||||||
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
"SyncReadStream requirements not met");
|
"SyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
"DynamicBuffer requirements not met");
|
"DynamicBuffer requirements not met");
|
||||||
parser.eager(false);
|
parser.eager(false);
|
||||||
if(parser.is_header_done())
|
return beast::detail::read(stream, buffer,
|
||||||
{
|
detail::read_header_condition<
|
||||||
ec.assign(0, ec.category());
|
isRequest, Derived>{parser}, ec);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
std::size_t bytes_transferred = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
bytes_transferred += read_some(
|
|
||||||
stream, buffer, parser, ec);
|
|
||||||
if(ec)
|
|
||||||
return bytes_transferred;
|
|
||||||
}
|
|
||||||
while(! parser.is_header_done());
|
|
||||||
return bytes_transferred;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
@ -652,19 +400,19 @@ async_read_header(
|
|||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest, Derived>& parser,
|
||||||
ReadHandler&& handler)
|
ReadHandler&& handler)
|
||||||
{
|
{
|
||||||
static_assert(is_async_read_stream<AsyncReadStream>::value,
|
static_assert(
|
||||||
|
is_async_read_stream<AsyncReadStream>::value,
|
||||||
"AsyncReadStream requirements not met");
|
"AsyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
"DynamicBuffer requirements not met");
|
"DynamicBuffer requirements not met");
|
||||||
parser.eager(false);
|
|
||||||
BOOST_BEAST_HANDLER_INIT(
|
BOOST_BEAST_HANDLER_INIT(
|
||||||
ReadHandler, void(error_code, std::size_t));
|
ReadHandler, void(error_code, std::size_t));
|
||||||
detail::read_op<AsyncReadStream, DynamicBuffer,
|
parser.eager(false);
|
||||||
isRequest, Derived, detail::parser_is_header_done,
|
beast::detail::async_read(stream, buffer,
|
||||||
BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
|
detail::read_header_condition<
|
||||||
std::move(init.completion_handler), stream,
|
isRequest, Derived>{parser}, std::move(
|
||||||
buffer, parser}({}, 0, false);
|
init.completion_handler));
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,7 +428,8 @@ read(
|
|||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser)
|
basic_parser<isRequest, Derived>& parser)
|
||||||
{
|
{
|
||||||
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
static_assert(
|
||||||
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
"SyncReadStream requirements not met");
|
"SyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
@ -704,27 +453,16 @@ read(
|
|||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest, Derived>& parser,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
static_assert(
|
||||||
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
"SyncReadStream requirements not met");
|
"SyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
"DynamicBuffer requirements not met");
|
"DynamicBuffer requirements not met");
|
||||||
parser.eager(true);
|
parser.eager(true);
|
||||||
if(parser.is_done())
|
return beast::detail::read(stream, buffer,
|
||||||
{
|
detail::read_all_condition<
|
||||||
ec.assign(0, ec.category());
|
isRequest, Derived>{parser}, ec);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
std::size_t bytes_transferred = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
bytes_transferred += read_some(
|
|
||||||
stream, buffer, parser, ec);
|
|
||||||
if(ec)
|
|
||||||
return bytes_transferred;
|
|
||||||
}
|
|
||||||
while(! parser.is_done());
|
|
||||||
return bytes_transferred;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
@ -740,19 +478,19 @@ async_read(
|
|||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest, Derived>& parser,
|
||||||
ReadHandler&& handler)
|
ReadHandler&& handler)
|
||||||
{
|
{
|
||||||
static_assert(is_async_read_stream<AsyncReadStream>::value,
|
static_assert(
|
||||||
|
is_async_read_stream<AsyncReadStream>::value,
|
||||||
"AsyncReadStream requirements not met");
|
"AsyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
"DynamicBuffer requirements not met");
|
"DynamicBuffer requirements not met");
|
||||||
parser.eager(true);
|
|
||||||
BOOST_BEAST_HANDLER_INIT(
|
BOOST_BEAST_HANDLER_INIT(
|
||||||
ReadHandler, void(error_code, std::size_t));
|
ReadHandler, void(error_code, std::size_t));
|
||||||
detail::read_op<AsyncReadStream, DynamicBuffer,
|
parser.eager(true);
|
||||||
isRequest, Derived, detail::parser_is_done,
|
beast::detail::async_read(stream, buffer,
|
||||||
BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
|
detail::read_all_condition<
|
||||||
std::move(init.completion_handler), stream, buffer, parser}(
|
isRequest, Derived>{parser}, std::move(
|
||||||
{}, 0, false);
|
init.completion_handler));
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -768,7 +506,8 @@ read(
|
|||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
message<isRequest, Body, basic_fields<Allocator>>& msg)
|
message<isRequest, Body, basic_fields<Allocator>>& msg)
|
||||||
{
|
{
|
||||||
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
static_assert(
|
||||||
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
"SyncReadStream requirements not met");
|
"SyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
@ -796,7 +535,8 @@ read(
|
|||||||
message<isRequest, Body, basic_fields<Allocator>>& msg,
|
message<isRequest, Body, basic_fields<Allocator>>& msg,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
static_assert(is_sync_read_stream<SyncReadStream>::value,
|
static_assert(
|
||||||
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
"SyncReadStream requirements not met");
|
"SyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
@ -805,7 +545,7 @@ read(
|
|||||||
"Body requirements not met");
|
"Body requirements not met");
|
||||||
static_assert(is_body_reader<Body>::value,
|
static_assert(is_body_reader<Body>::value,
|
||||||
"BodyReader requirements not met");
|
"BodyReader requirements not met");
|
||||||
parser<isRequest, Body, Allocator> p{std::move(msg)};
|
parser<isRequest, Body, Allocator> p(std::move(msg));
|
||||||
p.eager(true);
|
p.eager(true);
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
read(stream, buffer, p.base(), ec);
|
read(stream, buffer, p.base(), ec);
|
||||||
@ -828,7 +568,8 @@ async_read(
|
|||||||
message<isRequest, Body, basic_fields<Allocator>>& msg,
|
message<isRequest, Body, basic_fields<Allocator>>& msg,
|
||||||
ReadHandler&& handler)
|
ReadHandler&& handler)
|
||||||
{
|
{
|
||||||
static_assert(is_async_read_stream<AsyncReadStream>::value,
|
static_assert(
|
||||||
|
is_async_read_stream<AsyncReadStream>::value,
|
||||||
"AsyncReadStream requirements not met");
|
"AsyncReadStream requirements not met");
|
||||||
static_assert(
|
static_assert(
|
||||||
net::is_dynamic_buffer<DynamicBuffer>::value,
|
net::is_dynamic_buffer<DynamicBuffer>::value,
|
||||||
@ -844,9 +585,9 @@ async_read(
|
|||||||
DynamicBuffer,
|
DynamicBuffer,
|
||||||
isRequest, Body, Allocator,
|
isRequest, Body, Allocator,
|
||||||
BOOST_ASIO_HANDLER_TYPE(
|
BOOST_ASIO_HANDLER_TYPE(
|
||||||
ReadHandler, void(error_code, std::size_t))>{
|
ReadHandler, void(error_code, std::size_t))>(
|
||||||
std::move(init.completion_handler), stream, buffer, msg}(
|
stream, buffer, msg, std::move(
|
||||||
{}, 0, false);
|
init.completion_handler));
|
||||||
return init.result.get();
|
return init.result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,7 @@ add_executable (tests-beast-core
|
|||||||
static_buffer.cpp
|
static_buffer.cpp
|
||||||
string_param.cpp
|
string_param.cpp
|
||||||
type_traits.cpp
|
type_traits.cpp
|
||||||
|
detail_read.cpp
|
||||||
detail/base64.cpp
|
detail/base64.cpp
|
||||||
detail/clamp.cpp
|
detail/clamp.cpp
|
||||||
detail/lean_tuple.cpp
|
detail/lean_tuple.cpp
|
||||||
|
@ -34,6 +34,7 @@ local SOURCES =
|
|||||||
string.cpp
|
string.cpp
|
||||||
string_param.cpp
|
string_param.cpp
|
||||||
type_traits.cpp
|
type_traits.cpp
|
||||||
|
detail_read.cpp
|
||||||
detail/base64.cpp
|
detail/base64.cpp
|
||||||
detail/clamp.cpp
|
detail/clamp.cpp
|
||||||
detail/lean_tuple.cpp
|
detail/lean_tuple.cpp
|
||||||
|
111
test/beast/core/detail_read.cpp
Normal file
111
test/beast/core/detail_read.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
// Official repository: https://github.com/boostorg/beast
|
||||||
|
//
|
||||||
|
|
||||||
|
// Test that header file is self-contained.
|
||||||
|
#include <boost/beast/core/detail/read.hpp>
|
||||||
|
|
||||||
|
#include <boost/beast/core/buffers_to_string.hpp>
|
||||||
|
#include <boost/beast/core/flat_buffer.hpp>
|
||||||
|
#include <boost/beast/core/ostream.hpp>
|
||||||
|
#include <boost/beast/_experimental/test/stream.hpp>
|
||||||
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||||
|
#include <boost/asio/completion_condition.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
class read_test : public unit_test::suite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
testRead()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
net::io_context ioc;
|
||||||
|
test::stream ts(ioc);
|
||||||
|
ostream(ts.buffer()) << "test";
|
||||||
|
error_code ec;
|
||||||
|
flat_buffer b;
|
||||||
|
read(ts, b, boost::asio::transfer_at_least(4), ec);
|
||||||
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
|
BEAST_EXPECT(buffers_to_string(b.data()) == "test");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
net::io_context ioc;
|
||||||
|
test::stream ts(ioc);
|
||||||
|
auto tc = connect(ts);
|
||||||
|
ostream(ts.buffer()) << "test";
|
||||||
|
tc.close();
|
||||||
|
error_code ec;
|
||||||
|
flat_buffer b;
|
||||||
|
read(ts, b, boost::asio::transfer_all(), ec);
|
||||||
|
BEAST_EXPECTS(ec == boost::asio::error::eof, ec.message());
|
||||||
|
BEAST_EXPECT(buffers_to_string(b.data()) == "test");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testAsyncRead()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
net::io_context ioc;
|
||||||
|
test::stream ts(ioc);
|
||||||
|
ostream(ts.buffer()) << "test";
|
||||||
|
flat_buffer b;
|
||||||
|
error_code ec;
|
||||||
|
bool invoked = false;
|
||||||
|
async_read(ts, b, boost::asio::transfer_at_least(4),
|
||||||
|
[&invoked, &ec](error_code ec_, std::size_t)
|
||||||
|
{
|
||||||
|
ec = ec_;
|
||||||
|
invoked = true;
|
||||||
|
});
|
||||||
|
ioc.run();
|
||||||
|
BEAST_EXPECT(invoked);
|
||||||
|
BEAST_EXPECTS(! ec, ec.message());
|
||||||
|
BEAST_EXPECT(buffers_to_string(b.data()) == "test");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
net::io_context ioc;
|
||||||
|
test::stream ts(ioc);
|
||||||
|
auto tc = connect(ts);
|
||||||
|
ostream(ts.buffer()) << "test";
|
||||||
|
tc.close();
|
||||||
|
flat_buffer b;
|
||||||
|
error_code ec;
|
||||||
|
bool invoked = false;
|
||||||
|
async_read(ts, b, boost::asio::transfer_all(),
|
||||||
|
[&invoked, &ec](error_code ec_, std::size_t)
|
||||||
|
{
|
||||||
|
ec = ec_;
|
||||||
|
invoked = true;
|
||||||
|
});
|
||||||
|
ioc.run();
|
||||||
|
BEAST_EXPECT(invoked);
|
||||||
|
BEAST_EXPECTS(ec == boost::asio::error::eof, ec.message());
|
||||||
|
BEAST_EXPECT(buffers_to_string(b.data()) == "test");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void
|
||||||
|
run() override
|
||||||
|
{
|
||||||
|
pass();
|
||||||
|
//testRead();
|
||||||
|
//testAsyncRead();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE(beast,core,read);
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
} // beast
|
||||||
|
} // boost
|
@ -23,6 +23,7 @@
|
|||||||
#include <boost/beast/test/yield_to.hpp>
|
#include <boost/beast/test/yield_to.hpp>
|
||||||
#include <boost/asio/io_context.hpp>
|
#include <boost/asio/io_context.hpp>
|
||||||
#include <boost/asio/strand.hpp>
|
#include <boost/asio/strand.hpp>
|
||||||
|
#include <boost/asio/ip/tcp.hpp>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
Reference in New Issue
Block a user