Don't use dynamic_buffer_ref

This commit is contained in:
Vinnie Falco
2019-03-06 16:22:19 -08:00
parent 4ad9d4a0ba
commit f4e2a327c8
3 changed files with 119 additions and 325 deletions

View File

@ -1,3 +1,9 @@
Version 230:
* Don't use dynamic_buffer_ref
--------------------------------------------------------------------------------
Version 229: Version 229:
* Rename to buffer_bytes * Rename to buffer_bytes

View File

@ -14,6 +14,7 @@
#include <boost/beast/core/error.hpp> #include <boost/beast/core/error.hpp>
#include <boost/asio/async_result.hpp> #include <boost/asio/async_result.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/logic/tribool.hpp>
#include <type_traits> #include <type_traits>
namespace boost { namespace boost {
@ -60,12 +61,12 @@ namespace http {
template<class NextLayer> template<class NextLayer>
class icy_stream class icy_stream
{ {
struct ops;
NextLayer stream_; NextLayer stream_;
bool detect_ = true;
unsigned char copy_ = 0;
char buf_[8]; char buf_[8];
unsigned char n_ = 0;
bool detect_ = true;
struct ops;
static static
net::const_buffer net::const_buffer

View File

@ -11,22 +11,13 @@
#define BOOST_BEAST_CORE_IMPL_ICY_STREAM_HPP #define BOOST_BEAST_CORE_IMPL_ICY_STREAM_HPP
#include <boost/beast/core/async_base.hpp> #include <boost/beast/core/async_base.hpp>
#include <boost/beast/core/bind_handler.hpp>
#include <boost/beast/core/buffer_traits.hpp> #include <boost/beast/core/buffer_traits.hpp>
#include <boost/beast/core/buffers_adaptor.hpp> #include <boost/beast/core/error.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/buffers_suffix.hpp>
#include <boost/beast/core/dynamic_buffer_ref.hpp>
#include <boost/beast/core/stream_traits.hpp> #include <boost/beast/core/stream_traits.hpp>
#include <boost/beast/core/detail/buffers_ref.hpp> #include <boost/beast/core/detail/is_invocable.hpp>
#include <boost/asio/buffers_iterator.hpp>
#include <boost/asio/coroutine.hpp> #include <boost/asio/coroutine.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <algorithm>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <utility> #include <utility>
@ -37,84 +28,25 @@ namespace http {
namespace detail { namespace detail {
template<class MutableBuffers, class ConstBuffers> template<class ConstBufferSequence>
void boost::tribool
buffer_shift(MutableBuffers const& out, ConstBuffers const& in) is_icy(ConstBufferSequence const& buffers)
{ {
auto in_pos = net::buffer_sequence_end(in); char buf[3];
auto out_pos = net::buffer_sequence_end(out); auto const n = net::buffer_copy(
auto const in_begin = net::buffer_sequence_begin(in); net::mutable_buffer(buf, 3),
auto const out_begin = net::buffer_sequence_begin(out); buffers);
BOOST_ASSERT(buffer_bytes(in) == buffer_bytes(out)); if(n >= 1 && buf[0] != 'I')
if(in_pos == in_begin || out_pos == out_begin) return false;
return; if(n >= 2 && buf[1] != 'C')
net::const_buffer cb{*--in_pos}; return false;
net::mutable_buffer mb{*--out_pos}; if(n >= 3 && buf[2] != 'Y')
for(;;) return false;
{ if(n < 3)
if(mb.size() >= cb.size()) return boost::indeterminate;
{ return true;
std::memmove(
static_cast<char*>(
mb.data()) + mb.size() - cb.size(),
cb.data(),
cb.size());
mb = net::mutable_buffer{
mb.data(), mb.size() - cb.size()};
if(in_pos == in_begin)
break;
cb = *--in_pos;
}
else
{
std::memmove(
mb.data(),
static_cast<char const*>(
cb.data()) + cb.size() - mb.size(),
mb.size());
cb = net::const_buffer{
cb.data(), cb.size() - mb.size()};
if(out_pos == out_begin)
break;
mb = *--out_pos;
}
}
} }
template<class FwdIt>
class match_icy
{
bool& match_;
public:
using result_type = std::pair<FwdIt, bool>;
explicit
match_icy(bool& b)
: match_(b)
{
}
result_type
operator()(FwdIt first, FwdIt last) const
{
auto it = first;
if(it == last)
return {first, false};
if(*it != 'I')
return {last, true};
if(++it == last)
return {first, false};
if(*it != 'C')
return {last, true};
if(++it == last)
return {first, false};
if(*it != 'Y')
return {last, true};
match_ = true;
return {last, true};
};
};
} // detail } // detail
template<class NextLayer> template<class NextLayer>
@ -123,35 +55,15 @@ struct icy_stream<NextLayer>::ops
template<class Buffers, class Handler> template<class Buffers, class Handler>
class read_op class read_op
: public beast::stable_async_base<Handler, : public beast::async_base<Handler,
beast::executor_type<icy_stream>> beast::executor_type<icy_stream>>
, public net::coroutine , public net::coroutine
{ {
// VFALCO We need a stable reference to `b` icy_stream& s_;
// to pass to asio's read functions. Buffers b_;
// std::size_t n_ = 0;
// VFALCO Why did I do all this rigamarole? error_code ec_;
// we only need 6 or 8 bytes at most, bool match_ = false;
// this should all just be tucked
// away into the icy_stream. We can
// simulate a dynamic buffer adaptor
// with one or two simple ints.
struct data
{
icy_stream& s;
buffers_adaptor<Buffers> b;
bool match = false;
data(
icy_stream& s_,
Buffers const& b_)
: s(s_)
, b(b_)
{
}
};
data& d_;
public: public:
template<class Handler_> template<class Handler_>
@ -159,140 +71,77 @@ public:
Handler_&& h, Handler_&& h,
icy_stream& s, icy_stream& s,
Buffers const& b) Buffers const& b)
: stable_async_base<Handler, : async_base<Handler,
beast::executor_type<icy_stream>>( beast::executor_type<icy_stream>>(
std::forward<Handler_>(h), s.get_executor()) std::forward<Handler_>(h), s.get_executor())
, d_(beast::allocate_stable<data>(*this, s, b)) , s_(s)
, b_(b)
{ {
(*this)({}, 0); (*this)({}, 0, false);
} }
void void
operator()( operator()(
boost::system::error_code ec, error_code ec,
std::size_t bytes_transferred) std::size_t bytes_transferred,
bool cont = true)
{ {
using iterator = net::buffers_iterator<
typename beast::dynamic_buffer_ref_wrapper<
buffers_adaptor<Buffers>>::const_buffers_type>;
BOOST_ASIO_CORO_REENTER(*this) BOOST_ASIO_CORO_REENTER(*this)
{ {
if(d_.b.max_size() == 0) if(s_.detect_)
{ {
BOOST_ASIO_CORO_YIELD BOOST_ASSERT(s_.n_ == 0);
net::post(d_.s.get_executor(), for(;;)
beast::bind_handler(std::move(*this), ec, 0));
goto upcall;
}
if(! d_.s.detect_)
{
if(d_.s.copy_ > 0)
{
auto const n = net::buffer_copy(
d_.b.prepare(std::min<std::size_t>(
d_.s.copy_, d_.b.max_size())),
net::buffer(d_.s.buf_));
d_.b.commit(n);
d_.s.copy_ = static_cast<unsigned char>(
d_.s.copy_ - n);
if(d_.s.copy_ > 0)
std::memmove(
d_.s.buf_,
&d_.s.buf_[n],
d_.s.copy_);
}
if(d_.b.size() < d_.b.max_size())
{ {
// Try to read the first three characters
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
d_.s.next_layer().async_read_some( s_.next_layer().async_read_some(
d_.b.prepare(d_.b.max_size() - d_.b.size()), net::mutable_buffer(
s_.buf_ + s_.n_, 3 - s_.n_),
std::move(*this)); std::move(*this));
d_.b.commit(bytes_transferred); s_.n_ += static_cast<char>(bytes_transferred);
if(ec)
goto upcall;
auto result = detail::is_icy(
net::const_buffer(s_.buf_, s_.n_));
if(boost::indeterminate(result))
continue;
if(result)
s_.n_ = static_cast<char>(net::buffer_copy(
net::buffer(s_.buf_, sizeof(s_.buf_)),
icy_stream::version()));
break;
} }
bytes_transferred = d_.b.size(); s_.detect_ = false;
goto upcall;
} }
if(s_.n_ > 0)
d_.s.detect_ = false; {
if(d_.b.max_size() < 8) bytes_transferred = net::buffer_copy(
b_, net::const_buffer(s_.buf_, s_.n_));
s_.n_ -= static_cast<char>(bytes_transferred);
std::memmove(
s_.buf_,
s_.buf_ + bytes_transferred,
sizeof(s_.buf_) - bytes_transferred);
}
else
{ {
BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD
net::async_read( s_.next_layer().async_read_some(
d_.s.next_layer(), b_, std::move(*this));
net::buffer(d_.s.buf_, 3),
std::move(*this));
if(ec)
goto upcall;
auto n = bytes_transferred;
BOOST_ASSERT(n == 3);
if(
d_.s.buf_[0] != 'I' ||
d_.s.buf_[1] != 'C' ||
d_.s.buf_[2] != 'Y')
{
net::buffer_copy(
d_.b.value(),
net::buffer(d_.s.buf_, n));
if(d_.b.max_size() < 3)
{
d_.s.copy_ = static_cast<unsigned char>(
3 - d_.b.max_size());
std::memmove(
d_.s.buf_,
&d_.s.buf_[d_.b.max_size()],
d_.s.copy_);
}
bytes_transferred = (std::min)(
n, d_.b.max_size());
goto upcall;
}
d_.s.copy_ = static_cast<unsigned char>(
net::buffer_copy(
net::buffer(d_.s.buf_),
icy_stream::version() + d_.b.max_size()));
bytes_transferred = net::buffer_copy(
d_.b.value(), icy_stream::version());
goto upcall;
}
BOOST_ASIO_CORO_YIELD
net::async_read_until(
d_.s.next_layer(),
beast::dynamic_buffer_ref(d_.b),
detail::match_icy<iterator>(d_.match),
std::move(*this));
if(ec)
goto upcall;
{
auto n = bytes_transferred;
BOOST_ASSERT(n == d_.b.size());
if(! d_.match)
goto upcall;
if(d_.b.size() + 5 > d_.b.max_size())
{
d_.s.copy_ = static_cast<unsigned char>(
n + 5 - d_.b.max_size());
std::copy(
net::buffers_begin(d_.b.value()) + n - d_.s.copy_,
net::buffers_begin(d_.b.value()) + n,
d_.s.buf_);
n = d_.b.max_size() - 5;
}
{
buffers_suffix<beast::detail::buffers_ref<
Buffers>> dest(
boost::in_place_init, d_.b.value());
dest.consume(5);
detail::buffer_shift(
beast::buffers_prefix(n, dest),
beast::buffers_prefix(n, d_.b.value()));
net::buffer_copy(d_.b.value(), icy_stream::version());
n += 5;
bytes_transferred = n;
}
} }
upcall: upcall:
if(! cont)
{
ec_ = ec;
n_ = bytes_transferred;
BOOST_ASIO_CORO_YIELD
s_.next_layer().async_read_some(
net::mutable_buffer{},
std::move(*this));
ec = ec_;
bytes_transferred = n_;
}
this->complete_now(ec, bytes_transferred); this->complete_now(ec, bytes_transferred);
} }
} }
@ -333,6 +182,7 @@ icy_stream<NextLayer>::
icy_stream(Args&&... args) icy_stream(Args&&... args)
: stream_(std::forward<Args>(args)...) : stream_(std::forward<Args>(args)...)
{ {
std::memset(buf_, 0, sizeof(buf_));
} }
template<class NextLayer> template<class NextLayer>
@ -364,109 +214,46 @@ read_some(MutableBufferSequence const& buffers, error_code& ec)
static_assert(net::is_mutable_buffer_sequence< static_assert(net::is_mutable_buffer_sequence<
MutableBufferSequence>::value, MutableBufferSequence>::value,
"MutableBufferSequence type requirements not met"); "MutableBufferSequence type requirements not met");
using iterator = net::buffers_iterator< std::size_t bytes_transferred;
typename beast::dynamic_buffer_ref_wrapper< if(detect_)
buffers_adaptor<MutableBufferSequence>>::const_buffers_type>;
buffers_adaptor<MutableBufferSequence> b(buffers);
if(b.max_size() == 0)
{ {
ec = {}; BOOST_ASSERT(n_ == 0);
return 0; for(;;)
}
if(! detect_)
{
if(copy_ > 0)
{ {
auto const n = net::buffer_copy( // Try to read the first three characters
b.prepare(std::min<std::size_t>( bytes_transferred = next_layer().read_some(
copy_, b.max_size())), net::mutable_buffer(buf_ + n_, 3 - n_), ec);
net::buffer(buf_)); n_ += static_cast<char>(bytes_transferred);
b.commit(n); if(ec)
copy_ = static_cast<unsigned char>( return 0;
copy_ - n); auto result = detail::is_icy(
if(copy_ > 0) net::const_buffer(buf_, n_));
std::memmove( if(boost::indeterminate(result))
buf_, continue;
&buf_[n], if(result)
copy_); n_ = static_cast<char>(net::buffer_copy(
net::buffer(buf_, sizeof(buf_)),
icy_stream::version()));
break;
} }
if(b.size() < b.max_size()) detect_ = false;
b.commit(stream_.read_some(
b.prepare(b.max_size() - b.size()), ec));
return b.size();
} }
if(n_ > 0)
detect_ = false;
if(b.max_size() < 8)
{ {
auto n = net::read( bytes_transferred = net::buffer_copy(
stream_, buffers, net::const_buffer(buf_, n_));
net::buffer(buf_, 3), n_ -= static_cast<char>(bytes_transferred);
ec); std::memmove(
if(ec) buf_,
return 0; buf_ + bytes_transferred,
BOOST_ASSERT(n == 3); sizeof(buf_) - bytes_transferred);
if(
buf_[0] != 'I' ||
buf_[1] != 'C' ||
buf_[2] != 'Y')
{
net::buffer_copy(
buffers,
net::buffer(buf_, n));
if(b.max_size() < 3)
{
copy_ = static_cast<unsigned char>(
3 - b.max_size());
std::memmove(
buf_,
&buf_[b.max_size()],
copy_);
}
return std::min<std::size_t>(
n, b.max_size());
}
copy_ = static_cast<unsigned char>(
net::buffer_copy(
net::buffer(buf_),
version() + b.max_size()));
return net::buffer_copy(
buffers,
version());
} }
else
bool match = false;
auto n = net::read_until(
stream_,
beast::dynamic_buffer_ref(b),
detail::match_icy<iterator>(match),
ec);
if(ec)
return n;
BOOST_ASSERT(n == b.size());
if(! match)
return n;
if(b.size() + 5 > b.max_size())
{ {
copy_ = static_cast<unsigned char>( bytes_transferred =
n + 5 - b.max_size()); next_layer().read_some(buffers, ec);
std::copy(
net::buffers_begin(buffers) + n - copy_,
net::buffers_begin(buffers) + n,
buf_);
n = b.max_size() - 5;
} }
buffers_suffix<beast::detail::buffers_ref< return bytes_transferred;
MutableBufferSequence>> dest(
boost::in_place_init, buffers);
dest.consume(5);
detail::buffer_shift(
buffers_prefix(n, dest),
buffers_prefix(n, buffers));
net::buffer_copy(buffers, version());
n += 5;
return n;
} }
template<class NextLayer> template<class NextLayer>