New ostream() returns dynamic buffer output stream (API Change):

This eliminates beast::write output for dynamic buffers and replaces
it with the function ostream() that wraps a caller provided dynamic
buffer and returns the result as a std::ostream derived object.
Callers may now produce formatted output into any object meeting the
requirements of DynamicBuffer using operator<< and the standard stream
modifiers such as std::endl.

This new technique is more efficient, as implementations of operator<<
can now write directly into the output using std::ostream::write and
std::ostream::put.

Example of use:

  beast::streambuf sb;
  beast::ostream(sb) << "Hello, world!" << std::endl;
This commit is contained in:
Vinnie Falco
2017-05-03 15:29:23 -07:00
parent 3f58d81fc4
commit 3add5f293c
16 changed files with 373 additions and 337 deletions

View File

@@ -8,6 +8,7 @@ WebSocket:
API Changes:
* Refactor http::header contents
* New ostream() returns dynamic buffer output stream
--------------------------------------------------------------------------------

View File

@@ -176,11 +176,11 @@
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.bind_handler">bind_handler</link></member>
<member><link linkend="beast.ref.buffer_cat">buffer_cat</link></member>
<member><link linkend="beast.ref.ostream">ostream</link></member>
<member><link linkend="beast.ref.prepare_buffer">prepare_buffer</link></member>
<member><link linkend="beast.ref.prepare_buffers">prepare_buffers</link></member>
<member><link linkend="beast.ref.system_category">system_category</link></member>
<member><link linkend="beast.ref.to_string">to_string</link></member>
<member><link linkend="beast.ref.write">write</link></member>
</simplelist>
</entry>
<entry valign="top">

View File

@@ -16,6 +16,8 @@
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/buffers_adapter.hpp>
#include <beast/core/consuming_buffers.hpp>
#include <beast/core/dynabuf_readstream.hpp>
#include <beast/core/ostream.hpp>
#include <beast/core/error.hpp>
#include <beast/core/flat_streambuf.hpp>
#include <beast/core/handler_alloc.hpp>
@@ -28,8 +30,6 @@
#include <beast/core/static_string.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/core/dynabuf_readstream.hpp>
#include <beast/core/to_string.hpp>
#include <beast/core/write_dynabuf.hpp>
#endif

View File

@@ -0,0 +1,210 @@
//
// Copyright (c) 2013-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)
//
#ifndef BEAST_DETAIL_OSTREAM_HPP
#define BEAST_DETAIL_OSTREAM_HPP
#include <boost/asio/buffer.hpp>
#include <boost/utility/base_from_member.hpp>
#include <memory>
#include <ostream>
#include <streambuf>
#include <type_traits>
#include <utility>
namespace beast {
namespace detail {
template<
class DynamicBuffer,
class CharT,
class Traits
>
class ostream_buffer
: public std::basic_streambuf<CharT, Traits>
{
using int_type = typename
std::basic_streambuf<CharT, Traits>::int_type;
using traits_type = typename
std::basic_streambuf<CharT, Traits>::traits_type;
static std::size_t constexpr max_size = 512;
DynamicBuffer& buf_;
public:
ostream_buffer(ostream_buffer&&) = default;
ostream_buffer(ostream_buffer const&) = delete;
~ostream_buffer() noexcept;
explicit
ostream_buffer(DynamicBuffer& buf);
int_type
overflow(int_type ch) override;
int
sync() override;
private:
void
prepare();
void
flush(int extra = 0);
};
template<class DynamicBuffer, class CharT, class Traits>
ostream_buffer<DynamicBuffer, CharT, Traits>::
~ostream_buffer() noexcept
{
sync();
}
template<class DynamicBuffer, class CharT, class Traits>
ostream_buffer<DynamicBuffer, CharT, Traits>::
ostream_buffer(DynamicBuffer& buf)
: buf_(buf)
{
prepare();
}
template<class DynamicBuffer, class CharT, class Traits>
auto
ostream_buffer<DynamicBuffer, CharT, Traits>::
overflow(int_type ch) ->
int_type
{
if(ch != traits_type::eof())
{
Traits::assign(*this->pptr(), ch);
flush(1);
prepare();
return ch;
}
flush();
return traits_type::eof();
}
template<class DynamicBuffer, class CharT, class Traits>
int
ostream_buffer<DynamicBuffer, CharT, Traits>::
sync()
{
flush();
prepare();
return 0;
}
template<class DynamicBuffer, class CharT, class Traits>
void
ostream_buffer<DynamicBuffer, CharT, Traits>::
prepare()
{
using boost::asio::buffer_cast;
using boost::asio::buffer_size;
auto mbs = buf_.prepare(
read_size_helper(buf_, max_size));
auto const mb = *mbs.begin();
auto const p = buffer_cast<CharT*>(mb);
this->setp(p,
p + buffer_size(mb) / sizeof(CharT) - 1);
}
template<class DynamicBuffer, class CharT, class Traits>
void
ostream_buffer<DynamicBuffer, CharT, Traits>::
flush(int extra)
{
buf_.commit(
(this->pptr() - this->pbase() + extra) *
sizeof(CharT));
}
//------------------------------------------------------------------------------
template<class DynamicBuffer,
class CharT, class Traits, bool isMovable>
class ostream_helper;
template<class DynamicBuffer, class CharT, class Traits>
class ostream_helper<
DynamicBuffer, CharT, Traits, true>
: public std::basic_ostream<CharT, Traits>
{
ostream_buffer<DynamicBuffer, CharT, Traits> osb_;
public:
explicit
ostream_helper(DynamicBuffer& buf);
ostream_helper(ostream_helper&& other);
};
template<class DynamicBuffer, class CharT, class Traits>
ostream_helper<DynamicBuffer, CharT, Traits, true>::
ostream_helper(DynamicBuffer& buf)
: std::basic_ostream<CharT, Traits>(
&this->osb_)
, osb_(buf)
{
}
template<class DynamicBuffer, class CharT, class Traits>
ostream_helper<DynamicBuffer, CharT, Traits, true>::
ostream_helper(
ostream_helper&& other)
: std::basic_ostream<CharT, Traits>(&osb_)
, osb_(std::move(other.osb_))
{
}
// This work-around is for libstdc++ versions that
// don't have a movable std::basic_streambuf
template<class DynamicBuffer, class CharT, class Traits>
struct ostream_helper<
DynamicBuffer, CharT, Traits, false>
: private boost::base_from_member<
std::unique_ptr<ostream_buffer<
DynamicBuffer, CharT, Traits>>>
, std::basic_ostream<CharT, Traits>
{
explicit
ostream_helper(DynamicBuffer& buf);
ostream_helper(ostream_helper&& other);
};
template<class DynamicBuffer, class CharT, class Traits>
ostream_helper<DynamicBuffer, CharT, Traits, false>::
ostream_helper(DynamicBuffer& buf)
: boost::base_from_member<std::unique_ptr<
ostream_buffer<DynamicBuffer, CharT, Traits>>>(
new ostream_buffer<DynamicBuffer, CharT, Traits>(buf))
, std::basic_ostream<CharT, Traits>(
this->member.get())
{
}
template<class DynamicBuffer, class CharT, class Traits>
ostream_helper<DynamicBuffer, CharT, Traits, false>::
ostream_helper(ostream_helper&& other)
: boost::base_from_member<std::unique_ptr<
ostream_buffer<DynamicBuffer, CharT, Traits>>>(
std::move(other.member))
, std::basic_ostream<CharT, Traits>(
this->member.get())
{
}
} // detail
} // beast
#endif

View File

@@ -1,140 +0,0 @@
//
// Copyright (c) 2013-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)
//
#ifndef BEAST_DETAIL_WRITE_DYNABUF_HPP
#define BEAST_DETAIL_WRITE_DYNABUF_HPP
#include <beast/core/buffer_concepts.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/lexical_cast.hpp>
#include <utility>
namespace beast {
namespace detail {
// detects string literals.
template<class T>
struct is_string_literal : std::integral_constant<bool,
! std::is_same<T, typename std::remove_extent<T>::type>::value &&
std::is_same<char, typename std::remove_extent<T>::type>::value>
{
};
// `true` if a call to boost::asio::buffer(T const&) is possible
// note: we exclude string literals because boost::asio::buffer()
// will include the null terminator, which we don't want.
template<class T>
class is_BufferConvertible
{
template<class U, class R = decltype(
boost::asio::buffer(std::declval<U const&>()),
std::true_type{})>
static R check(int);
template<class>
static std::false_type check(...);
using type = decltype(check<T>(0));
public:
static bool const value = type::value &&
! is_string_literal<T>::value;
};
template<class DynamicBuffer>
void
write_dynabuf(DynamicBuffer& dynabuf,
boost::asio::const_buffer const& buffer)
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
dynabuf.commit(buffer_copy(
dynabuf.prepare(buffer_size(buffer)),
buffer));
}
template<class DynamicBuffer>
void
write_dynabuf(DynamicBuffer& dynabuf,
boost::asio::mutable_buffer const& buffer)
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
dynabuf.commit(buffer_copy(
dynabuf.prepare(buffer_size(buffer)),
buffer));
}
template<class DynamicBuffer, class T>
typename std::enable_if<
is_BufferConvertible<T>::value &&
! std::is_convertible<T, boost::asio::const_buffer>::value &&
! std::is_convertible<T, boost::asio::mutable_buffer>::value
>::type
write_dynabuf(DynamicBuffer& dynabuf, T const& t)
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
auto const buffers = boost::asio::buffer(t);
dynabuf.commit(buffer_copy(
dynabuf.prepare(buffer_size(buffers)),
buffers));
}
template<class DynamicBuffer, class Buffers>
typename std::enable_if<
is_ConstBufferSequence<Buffers>::value &&
! is_BufferConvertible<Buffers>::value &&
! std::is_convertible<Buffers, boost::asio::const_buffer>::value &&
! std::is_convertible<Buffers, boost::asio::mutable_buffer>::value
>::type
write_dynabuf(DynamicBuffer& dynabuf, Buffers const& buffers)
{
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
dynabuf.commit(buffer_copy(
dynabuf.prepare(buffer_size(buffers)),
buffers));
}
template<class DynamicBuffer, std::size_t N>
void
write_dynabuf(DynamicBuffer& dynabuf, const char (&s)[N])
{
using boost::asio::buffer_copy;
dynabuf.commit(buffer_copy(
dynabuf.prepare(N - 1),
boost::asio::buffer(s, N - 1)));
}
template<class DynamicBuffer, class T>
typename std::enable_if<
! is_string_literal<T>::value &&
! is_ConstBufferSequence<T>::value &&
! is_BufferConvertible<T>::value &&
! std::is_convertible<T, boost::asio::const_buffer>::value &&
! std::is_convertible<T, boost::asio::mutable_buffer>::value
>::type
write_dynabuf(DynamicBuffer& dynabuf, T const& t)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
auto const s = boost::lexical_cast<std::string>(t);
dynabuf.commit(buffer_copy(
dynabuf.prepare(s.size()), buffer(s)));
}
template<class DynamicBuffer, class T0, class T1, class... TN>
void
write_dynabuf(DynamicBuffer& dynabuf,
T0 const& t0, T1 const& t1, TN const&... tn)
{
write_dynabuf(dynabuf, t0);
write_dynabuf(dynabuf, t1, tn...);
}
} // detail
} // beast
#endif

View File

@@ -9,7 +9,6 @@
#define BEAST_IMPL_STREAMBUF_IPP
#include <beast/core/detail/type_traits.hpp>
#include <beast/core/detail/write_dynabuf.hpp>
#include <boost/assert.hpp>
#include <algorithm>
#include <exception>
@@ -871,14 +870,6 @@ read_size_helper(basic_streambuf<
return (std::min)(max_size, low);
}
template<class Alloc, class T>
basic_streambuf<Alloc>&
operator<<(basic_streambuf<Alloc>& streambuf, T const& t)
{
detail::write_dynabuf(streambuf, t);
return streambuf;
}
} // beast
#endif

View File

@@ -0,0 +1,66 @@
//
// Copyright (c) 2013-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)
//
#ifndef BEAST_WRITE_OSTREAM_HPP
#define BEAST_WRITE_OSTREAM_HPP
#include <beast/config.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/detail/ostream.hpp>
#include <type_traits>
#include <streambuf>
#include <utility>
namespace beast {
/** Return an output stream that formats values into a @b DynamicBuffer.
This function wraps the caller provided @b DynamicBuffer into
a `std::ostream` derived class, to allow `operator<<` stream style
formatting operations.
@par Example
@code
ostream(buffer) << "Hello, world!" << std::endl;
@endcode
@note Calling members of the underlying buffer before the output
stream is destroyed results in undefined behavior.
@param buffer An object meeting the requirements of @b DynamicBuffer
into which the formatted output will be placed.
@return An object derived from `std::ostream` which directs output
into the specified dynamic buffer. Ownership of the dynamic buffer
is not transferred. The caller is responsible for ensuring the
dynamic buffer is not destroyed for the lifetime of the output
stream.
*/
template<class DynamicBuffer>
#if BEAST_DOXYGEN
implementation_defined
#else
detail::ostream_helper<
DynamicBuffer, char, std::char_traits<char>,
std::is_move_constructible<
detail::ostream_buffer<DynamicBuffer,
char, std::char_traits<char>>>::value>
#endif
ostream(DynamicBuffer& buffer)
{
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
return detail::ostream_helper<
DynamicBuffer, char, std::char_traits<char>,
std::is_move_constructible<
detail::ostream_buffer<DynamicBuffer,
char, std::char_traits<char>>>::value>{buffer};
}
} // beast
#endif

View File

@@ -326,18 +326,6 @@ private:
*/
using streambuf = basic_streambuf<std::allocator<char>>;
/** Format output to a @ref basic_streambuf.
@param streambuf The @ref basic_streambuf to write to.
@param t The object to write.
@return A reference to the @ref basic_streambuf.
*/
template<class Allocator, class T>
basic_streambuf<Allocator>&
operator<<(basic_streambuf<Allocator>& streambuf, T const& t);
} // beast
#include <beast/core/impl/streambuf.ipp>

View File

@@ -1,64 +0,0 @@
//
// Copyright (c) 2013-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)
//
#ifndef BEAST_WRITE_DYNABUF_HPP
#define BEAST_WRITE_DYNABUF_HPP
#include <beast/config.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/detail/write_dynabuf.hpp>
#include <type_traits>
#include <utility>
namespace beast {
/** Write to a @b `DynamicBuffer`.
This function appends the serialized representation of each provided
argument into the dynamic buffer. It is capable of converting the
following types of arguments:
@li `boost::asio::const_buffer`
@li `boost::asio::mutable_buffer`
@li A type meeting the requirements of @b `ConvertibleToConstBuffer`
@li A type meeting the requirements of @b `ConstBufferSequence`
@li A type meeting the requirements of @b `MutableBufferSequence`
For all types not listed above, the function will invoke
`boost::lexical_cast` on the argument in an attempt to convert to
a string, which is then appended to the dynamic buffer.
When this function serializes numbers, it converts them to
their text representation as if by a call to `std::to_string`.
@param dynabuf The dynamic buffer to write to.
@param args A list of one or more arguments to write.
@throws unspecified Any exceptions thrown by `boost::lexical_cast`.
@note This function participates in overload resolution only if
the `dynabuf` parameter meets the requirements of @b `DynamicBuffer`.
*/
template<class DynamicBuffer, class... Args>
#if BEAST_DOXYGEN
void
#else
typename std::enable_if<is_DynamicBuffer<DynamicBuffer>::value>::type
#endif
write(DynamicBuffer& dynabuf, Args const&... args)
{
detail::write_dynabuf(dynabuf, args...);
}
} // beast
#endif

View File

@@ -13,11 +13,11 @@
#include <beast/core/buffer_cat.hpp>
#include <beast/core/bind_handler.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/ostream.hpp>
#include <beast/core/handler_helpers.hpp>
#include <beast/core/handler_ptr.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/core/write_dynabuf.hpp>
#include <beast/core/detail/sync_ostream.hpp>
#include <boost/asio/write.hpp>
#include <condition_variable>
@@ -31,53 +31,39 @@ namespace http {
namespace detail {
template<class DynamicBuffer, class Fields>
template<class Fields>
void
write_start_line(DynamicBuffer& dynabuf,
write_start_line(std::ostream& os,
header<true, Fields> const& msg)
{
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
write(dynabuf, msg.method());
write(dynabuf, " ");
write(dynabuf, msg.target());
os << msg.method() << " " << msg.target();
switch(msg.version)
{
case 10:
write(dynabuf, " HTTP/1.0\r\n");
break;
case 11:
write(dynabuf, " HTTP/1.1\r\n");
break;
case 10: os << " HTTP/1.0\r\n"; break;
case 11: os << " HTTP/1.1\r\n"; break;
}
}
template<class DynamicBuffer, class Fields>
template<class Fields>
void
write_start_line(DynamicBuffer& dynabuf,
write_start_line(std::ostream& os,
header<false, Fields> const& msg)
{
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
switch(msg.version)
{
case 10:
write(dynabuf, "HTTP/1.0 ");
break;
case 11:
write(dynabuf, "HTTP/1.1 ");
break;
case 10: os << "HTTP/1.0 "; break;
case 11: os << "HTTP/1.1 "; break;
}
write(dynabuf, msg.status);
write(dynabuf, " ");
write(dynabuf, msg.reason());
write(dynabuf, "\r\n");
os << msg.status << " " << msg.reason() << "\r\n";
}
template<class DynamicBuffer, class FieldSequence>
template<class FieldSequence>
void
write_fields(DynamicBuffer& dynabuf, FieldSequence const& fields)
write_fields(std::ostream& os,
FieldSequence const& fields)
{
static_assert(is_DynamicBuffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
//static_assert(is_FieldSequence<FieldSequence>::value,
// "FieldSequence requirements not met");
for(auto const& field : fields)
@@ -86,10 +72,7 @@ write_fields(DynamicBuffer& dynabuf, FieldSequence const& fields)
BOOST_ASSERT(! name.empty());
if(name[0] == ':')
continue;
write(dynabuf, field.name());
write(dynabuf, ": ");
write(dynabuf, field.value());
write(dynabuf, "\r\n");
os << field.name() << ": " << field.value() << "\r\n";
}
}
@@ -218,9 +201,12 @@ write(SyncWriteStream& stream,
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
streambuf sb;
detail::write_start_line(sb, msg);
detail::write_fields(sb, msg.fields);
beast::write(sb, "\r\n");
{
auto os = ostream(sb);
detail::write_start_line(os, msg);
detail::write_fields(os, msg.fields);
os << "\r\n";
}
boost::asio::write(stream, sb.data(), ec);
}
@@ -238,9 +224,12 @@ async_write(AsyncWriteStream& stream,
beast::async_completion<WriteHandler,
void(error_code)> completion{handler};
streambuf sb;
detail::write_start_line(sb, msg);
detail::write_fields(sb, msg.fields);
beast::write(sb, "\r\n");
{
auto os = ostream(sb);
detail::write_start_line(os, msg);
detail::write_fields(os, msg.fields);
os << "\r\n";
}
detail::write_streambuf_op<AsyncWriteStream,
decltype(completion.handler)>{
completion.handler, stream, std::move(sb)};
@@ -281,9 +270,10 @@ struct write_preparation
if(ec)
return;
write_start_line(sb, msg);
write_fields(sb, msg.fields);
beast::write(sb, "\r\n");
auto os = ostream(sb);
write_start_line(os, msg);
write_fields(os, msg.fields);
os << "\r\n";
}
};

View File

@@ -29,6 +29,7 @@ unit-test core-tests :
core/handler_alloc.cpp
core/handler_concepts.cpp
core/handler_ptr.cpp
core/ostream.cpp
core/placeholders.cpp
core/prepare_buffer.cpp
core/prepare_buffers.cpp
@@ -37,7 +38,6 @@ unit-test core-tests :
core/stream_concepts.cpp
core/streambuf.cpp
core/to_string.cpp
core/write_dynabuf.cpp
core/base64.cpp
core/empty_base_optimization.cpp
core/get_lowest_layer.cpp

View File

@@ -22,6 +22,7 @@ add_executable (core-tests
handler_alloc.cpp
handler_concepts.cpp
handler_ptr.cpp
ostream.cpp
placeholders.cpp
prepare_buffer.cpp
prepare_buffers.cpp
@@ -30,7 +31,6 @@ add_executable (core-tests
stream_concepts.cpp
streambuf.cpp
to_string.cpp
write_dynabuf.cpp
base64.cpp
empty_base_optimization.cpp
get_lowest_layer.cpp

32
test/core/ostream.cpp Normal file
View File

@@ -0,0 +1,32 @@
//
// Copyright (c) 2013-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)
//
// Test that header file is self-contained.
#include <beast/core/ostream.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/unit_test/suite.hpp>
#include <ostream>
#include <beast/core/to_string.hpp>
namespace beast {
class ostream_test : public beast::unit_test::suite
{
public:
void run() override
{
streambuf sb;
ostream(sb) << "Hello, world!\n";
BEAST_EXPECT(to_string(sb.data()) == "Hello, world!\n");
}
};
BEAST_DEFINE_TESTSUITE(ostream,core,beast);
} // beast

View File

@@ -273,13 +273,6 @@ public:
BEAST_EXPECT(test::buffer_count(sb.data()) == 4);
}
void testOutputStream()
{
streambuf sb;
sb << "x";
BEAST_EXPECT(to_string(sb.data()) == "x");
}
void testCapacity()
{
using boost::asio::buffer_size;
@@ -353,7 +346,6 @@ public:
testConsume();
testMatrix();
testIterators();
testOutputStream();
testCapacity();
}
};

View File

@@ -1,36 +0,0 @@
//
// Copyright (c) 2013-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)
//
// Test that header file is self-contained.
#include <beast/core/write_dynabuf.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
class write_dynabuf_test : public beast::unit_test::suite
{
public:
void run() override
{
streambuf sb;
std::string s;
write(sb, boost::asio::const_buffer{"", 0});
write(sb, boost::asio::mutable_buffer{nullptr, 0});
write(sb, boost::asio::null_buffers{});
write(sb, boost::asio::const_buffers_1{"", 0});
write(sb, boost::asio::mutable_buffers_1{nullptr, 0});
write(sb, s);
write(sb, 23);
pass();
}
};
BEAST_DEFINE_TESTSUITE(write_dynabuf,core,beast);
} // beast

View File

@@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
#define BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
#include <beast/core/write_dynabuf.hpp>
#include <beast/core/ostream.hpp>
#include <beast/http/detail/rfc7230.hpp>
#include <cstdint>
#include <random>
@@ -319,7 +319,7 @@ public:
}
std::string
uri()
target()
{
//switch(rand(4))
switch(1)
@@ -348,7 +348,7 @@ public:
#if 0
std::string
uri()
target()
{
static char constexpr alpha[63] =
"0123456789" "ABCDEFGHIJ" "KLMNOPQRST"
@@ -476,13 +476,13 @@ public:
void
fields(DynamicBuffer& db)
{
auto os = ostream(db);
while(rand(6))
{
write(db, field());
write(db, rand(4) ? ": " : ":");
write(db, value());
write(db, "\r\n");
}
os <<
field() <<
(rand(4) ? ": " : ":") <<
value() <<
"\r\n";
}
template<class DynamicBuffer>
@@ -491,13 +491,15 @@ public:
{
if(! rand(4))
{
write(db, "Content-Length: 0\r\n\r\n");
ostream(db) <<
"Content-Length: 0\r\n\r\n";
return;
}
if(rand(2))
{
auto const len = rand(500);
write(db, "Content-Length: ", len, "\r\n\r\n");
ostream(db) <<
"Content-Length: " << len << "\r\n\r\n";
for(auto const& b : db.prepare(len))
{
auto p = boost::asio::buffer_cast<char*>(b);
@@ -510,12 +512,14 @@ public:
else
{
auto len = rand(500);
write(db, "Transfer-Encoding: chunked\r\n\r\n");
ostream(db) <<
"Transfer-Encoding: chunked\r\n\r\n";
while(len > 0)
{
auto n = (std::min)(1 + rand(300), len);
len -= n;
write(db, to_hex(n), "\r\n");
ostream(db) <<
to_hex(n) << "\r\n";
for(auto const& b : db.prepare(n))
{
auto p = boost::asio::buffer_cast<char*>(b);
@@ -524,9 +528,9 @@ public:
*p++ = static_cast<char>(32 + rand(26+26+10+6));
}
db.commit(n);
write(db, "\r\n");
ostream(db) << "\r\n";
}
write(db, "0\r\n\r\n");
ostream(db) << "0\r\n\r\n";
}
}
@@ -534,7 +538,8 @@ public:
void
request(DynamicBuffer& db)
{
write(db, method(), " ", uri(), " HTTP/1.1\r\n");
ostream(db) <<
method() << " " << target() << " HTTP/1.1\r\n";
fields(db);
body(db);
}
@@ -543,14 +548,15 @@ public:
void
response(DynamicBuffer& db)
{
write(db, "HTTP/1.");
write(db, rand(2) ? "0" : "1");
write(db, " ", 100 + rand(401), " ");
write(db, token());
write(db, "\r\n");
ostream(db) <<
"HTTP/1." <<
(rand(2) ? "0" : "1") << " " <<
(100 + rand(401)) << " " <<
token() <<
"\r\n";
fields(db);
body(db);
write(db, "\r\n");
ostream(db) << "\r\n";
}
};