forked from boostorg/beast
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:
@@ -8,6 +8,7 @@ WebSocket:
|
|||||||
API Changes:
|
API Changes:
|
||||||
|
|
||||||
* Refactor http::header contents
|
* Refactor http::header contents
|
||||||
|
* New ostream() returns dynamic buffer output stream
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@@ -176,11 +176,11 @@
|
|||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.bind_handler">bind_handler</link></member>
|
<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.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_buffer">prepare_buffer</link></member>
|
||||||
<member><link linkend="beast.ref.prepare_buffers">prepare_buffers</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.system_category">system_category</link></member>
|
||||||
<member><link linkend="beast.ref.to_string">to_string</link></member>
|
<member><link linkend="beast.ref.to_string">to_string</link></member>
|
||||||
<member><link linkend="beast.ref.write">write</link></member>
|
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
<entry valign="top">
|
<entry valign="top">
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
#include <beast/core/buffer_concepts.hpp>
|
#include <beast/core/buffer_concepts.hpp>
|
||||||
#include <beast/core/buffers_adapter.hpp>
|
#include <beast/core/buffers_adapter.hpp>
|
||||||
#include <beast/core/consuming_buffers.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/error.hpp>
|
||||||
#include <beast/core/flat_streambuf.hpp>
|
#include <beast/core/flat_streambuf.hpp>
|
||||||
#include <beast/core/handler_alloc.hpp>
|
#include <beast/core/handler_alloc.hpp>
|
||||||
@@ -28,8 +30,6 @@
|
|||||||
#include <beast/core/static_string.hpp>
|
#include <beast/core/static_string.hpp>
|
||||||
#include <beast/core/stream_concepts.hpp>
|
#include <beast/core/stream_concepts.hpp>
|
||||||
#include <beast/core/streambuf.hpp>
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <beast/core/dynabuf_readstream.hpp>
|
|
||||||
#include <beast/core/to_string.hpp>
|
#include <beast/core/to_string.hpp>
|
||||||
#include <beast/core/write_dynabuf.hpp>
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
210
include/beast/core/detail/ostream.hpp
Normal file
210
include/beast/core/detail/ostream.hpp
Normal 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
|
@@ -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
|
|
@@ -9,7 +9,6 @@
|
|||||||
#define BEAST_IMPL_STREAMBUF_IPP
|
#define BEAST_IMPL_STREAMBUF_IPP
|
||||||
|
|
||||||
#include <beast/core/detail/type_traits.hpp>
|
#include <beast/core/detail/type_traits.hpp>
|
||||||
#include <beast/core/detail/write_dynabuf.hpp>
|
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
@@ -871,14 +870,6 @@ read_size_helper(basic_streambuf<
|
|||||||
return (std::min)(max_size, low);
|
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
|
} // beast
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
66
include/beast/core/ostream.hpp
Normal file
66
include/beast/core/ostream.hpp
Normal 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
|
@@ -326,18 +326,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
using streambuf = basic_streambuf<std::allocator<char>>;
|
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
|
} // beast
|
||||||
|
|
||||||
#include <beast/core/impl/streambuf.ipp>
|
#include <beast/core/impl/streambuf.ipp>
|
||||||
|
@@ -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
|
|
@@ -13,11 +13,11 @@
|
|||||||
#include <beast/core/buffer_cat.hpp>
|
#include <beast/core/buffer_cat.hpp>
|
||||||
#include <beast/core/bind_handler.hpp>
|
#include <beast/core/bind_handler.hpp>
|
||||||
#include <beast/core/buffer_concepts.hpp>
|
#include <beast/core/buffer_concepts.hpp>
|
||||||
|
#include <beast/core/ostream.hpp>
|
||||||
#include <beast/core/handler_helpers.hpp>
|
#include <beast/core/handler_helpers.hpp>
|
||||||
#include <beast/core/handler_ptr.hpp>
|
#include <beast/core/handler_ptr.hpp>
|
||||||
#include <beast/core/stream_concepts.hpp>
|
#include <beast/core/stream_concepts.hpp>
|
||||||
#include <beast/core/streambuf.hpp>
|
#include <beast/core/streambuf.hpp>
|
||||||
#include <beast/core/write_dynabuf.hpp>
|
|
||||||
#include <beast/core/detail/sync_ostream.hpp>
|
#include <beast/core/detail/sync_ostream.hpp>
|
||||||
#include <boost/asio/write.hpp>
|
#include <boost/asio/write.hpp>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
@@ -31,53 +31,39 @@ namespace http {
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<class DynamicBuffer, class Fields>
|
template<class Fields>
|
||||||
void
|
void
|
||||||
write_start_line(DynamicBuffer& dynabuf,
|
write_start_line(std::ostream& os,
|
||||||
header<true, Fields> const& msg)
|
header<true, Fields> const& msg)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
||||||
write(dynabuf, msg.method());
|
os << msg.method() << " " << msg.target();
|
||||||
write(dynabuf, " ");
|
|
||||||
write(dynabuf, msg.target());
|
|
||||||
switch(msg.version)
|
switch(msg.version)
|
||||||
{
|
{
|
||||||
case 10:
|
case 10: os << " HTTP/1.0\r\n"; break;
|
||||||
write(dynabuf, " HTTP/1.0\r\n");
|
case 11: os << " HTTP/1.1\r\n"; break;
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
write(dynabuf, " HTTP/1.1\r\n");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class DynamicBuffer, class Fields>
|
template<class Fields>
|
||||||
void
|
void
|
||||||
write_start_line(DynamicBuffer& dynabuf,
|
write_start_line(std::ostream& os,
|
||||||
header<false, Fields> const& msg)
|
header<false, Fields> const& msg)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
||||||
switch(msg.version)
|
switch(msg.version)
|
||||||
{
|
{
|
||||||
case 10:
|
case 10: os << "HTTP/1.0 "; break;
|
||||||
write(dynabuf, "HTTP/1.0 ");
|
case 11: os << "HTTP/1.1 "; break;
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
write(dynabuf, "HTTP/1.1 ");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
write(dynabuf, msg.status);
|
os << msg.status << " " << msg.reason() << "\r\n";
|
||||||
write(dynabuf, " ");
|
|
||||||
write(dynabuf, msg.reason());
|
|
||||||
write(dynabuf, "\r\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class DynamicBuffer, class FieldSequence>
|
template<class FieldSequence>
|
||||||
void
|
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,
|
//static_assert(is_FieldSequence<FieldSequence>::value,
|
||||||
// "FieldSequence requirements not met");
|
// "FieldSequence requirements not met");
|
||||||
for(auto const& field : fields)
|
for(auto const& field : fields)
|
||||||
@@ -86,10 +72,7 @@ write_fields(DynamicBuffer& dynabuf, FieldSequence const& fields)
|
|||||||
BOOST_ASSERT(! name.empty());
|
BOOST_ASSERT(! name.empty());
|
||||||
if(name[0] == ':')
|
if(name[0] == ':')
|
||||||
continue;
|
continue;
|
||||||
write(dynabuf, field.name());
|
os << field.name() << ": " << field.value() << "\r\n";
|
||||||
write(dynabuf, ": ");
|
|
||||||
write(dynabuf, field.value());
|
|
||||||
write(dynabuf, "\r\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,9 +201,12 @@ write(SyncWriteStream& stream,
|
|||||||
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
|
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
|
||||||
"SyncWriteStream requirements not met");
|
"SyncWriteStream requirements not met");
|
||||||
streambuf sb;
|
streambuf sb;
|
||||||
detail::write_start_line(sb, msg);
|
{
|
||||||
detail::write_fields(sb, msg.fields);
|
auto os = ostream(sb);
|
||||||
beast::write(sb, "\r\n");
|
detail::write_start_line(os, msg);
|
||||||
|
detail::write_fields(os, msg.fields);
|
||||||
|
os << "\r\n";
|
||||||
|
}
|
||||||
boost::asio::write(stream, sb.data(), ec);
|
boost::asio::write(stream, sb.data(), ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,9 +224,12 @@ async_write(AsyncWriteStream& stream,
|
|||||||
beast::async_completion<WriteHandler,
|
beast::async_completion<WriteHandler,
|
||||||
void(error_code)> completion{handler};
|
void(error_code)> completion{handler};
|
||||||
streambuf sb;
|
streambuf sb;
|
||||||
detail::write_start_line(sb, msg);
|
{
|
||||||
detail::write_fields(sb, msg.fields);
|
auto os = ostream(sb);
|
||||||
beast::write(sb, "\r\n");
|
detail::write_start_line(os, msg);
|
||||||
|
detail::write_fields(os, msg.fields);
|
||||||
|
os << "\r\n";
|
||||||
|
}
|
||||||
detail::write_streambuf_op<AsyncWriteStream,
|
detail::write_streambuf_op<AsyncWriteStream,
|
||||||
decltype(completion.handler)>{
|
decltype(completion.handler)>{
|
||||||
completion.handler, stream, std::move(sb)};
|
completion.handler, stream, std::move(sb)};
|
||||||
@@ -281,9 +270,10 @@ struct write_preparation
|
|||||||
if(ec)
|
if(ec)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
write_start_line(sb, msg);
|
auto os = ostream(sb);
|
||||||
write_fields(sb, msg.fields);
|
write_start_line(os, msg);
|
||||||
beast::write(sb, "\r\n");
|
write_fields(os, msg.fields);
|
||||||
|
os << "\r\n";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -29,6 +29,7 @@ unit-test core-tests :
|
|||||||
core/handler_alloc.cpp
|
core/handler_alloc.cpp
|
||||||
core/handler_concepts.cpp
|
core/handler_concepts.cpp
|
||||||
core/handler_ptr.cpp
|
core/handler_ptr.cpp
|
||||||
|
core/ostream.cpp
|
||||||
core/placeholders.cpp
|
core/placeholders.cpp
|
||||||
core/prepare_buffer.cpp
|
core/prepare_buffer.cpp
|
||||||
core/prepare_buffers.cpp
|
core/prepare_buffers.cpp
|
||||||
@@ -37,7 +38,6 @@ unit-test core-tests :
|
|||||||
core/stream_concepts.cpp
|
core/stream_concepts.cpp
|
||||||
core/streambuf.cpp
|
core/streambuf.cpp
|
||||||
core/to_string.cpp
|
core/to_string.cpp
|
||||||
core/write_dynabuf.cpp
|
|
||||||
core/base64.cpp
|
core/base64.cpp
|
||||||
core/empty_base_optimization.cpp
|
core/empty_base_optimization.cpp
|
||||||
core/get_lowest_layer.cpp
|
core/get_lowest_layer.cpp
|
||||||
|
@@ -22,6 +22,7 @@ add_executable (core-tests
|
|||||||
handler_alloc.cpp
|
handler_alloc.cpp
|
||||||
handler_concepts.cpp
|
handler_concepts.cpp
|
||||||
handler_ptr.cpp
|
handler_ptr.cpp
|
||||||
|
ostream.cpp
|
||||||
placeholders.cpp
|
placeholders.cpp
|
||||||
prepare_buffer.cpp
|
prepare_buffer.cpp
|
||||||
prepare_buffers.cpp
|
prepare_buffers.cpp
|
||||||
@@ -30,7 +31,6 @@ add_executable (core-tests
|
|||||||
stream_concepts.cpp
|
stream_concepts.cpp
|
||||||
streambuf.cpp
|
streambuf.cpp
|
||||||
to_string.cpp
|
to_string.cpp
|
||||||
write_dynabuf.cpp
|
|
||||||
base64.cpp
|
base64.cpp
|
||||||
empty_base_optimization.cpp
|
empty_base_optimization.cpp
|
||||||
get_lowest_layer.cpp
|
get_lowest_layer.cpp
|
||||||
|
32
test/core/ostream.cpp
Normal file
32
test/core/ostream.cpp
Normal 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
|
@@ -273,13 +273,6 @@ public:
|
|||||||
BEAST_EXPECT(test::buffer_count(sb.data()) == 4);
|
BEAST_EXPECT(test::buffer_count(sb.data()) == 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testOutputStream()
|
|
||||||
{
|
|
||||||
streambuf sb;
|
|
||||||
sb << "x";
|
|
||||||
BEAST_EXPECT(to_string(sb.data()) == "x");
|
|
||||||
}
|
|
||||||
|
|
||||||
void testCapacity()
|
void testCapacity()
|
||||||
{
|
{
|
||||||
using boost::asio::buffer_size;
|
using boost::asio::buffer_size;
|
||||||
@@ -353,7 +346,6 @@ public:
|
|||||||
testConsume();
|
testConsume();
|
||||||
testMatrix();
|
testMatrix();
|
||||||
testIterators();
|
testIterators();
|
||||||
testOutputStream();
|
|
||||||
testCapacity();
|
testCapacity();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -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
|
|
@@ -8,7 +8,7 @@
|
|||||||
#ifndef BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
|
#ifndef BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
|
||||||
#define 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 <beast/http/detail/rfc7230.hpp>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <random>
|
#include <random>
|
||||||
@@ -319,7 +319,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
uri()
|
target()
|
||||||
{
|
{
|
||||||
//switch(rand(4))
|
//switch(rand(4))
|
||||||
switch(1)
|
switch(1)
|
||||||
@@ -348,7 +348,7 @@ public:
|
|||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
std::string
|
std::string
|
||||||
uri()
|
target()
|
||||||
{
|
{
|
||||||
static char constexpr alpha[63] =
|
static char constexpr alpha[63] =
|
||||||
"0123456789" "ABCDEFGHIJ" "KLMNOPQRST"
|
"0123456789" "ABCDEFGHIJ" "KLMNOPQRST"
|
||||||
@@ -476,13 +476,13 @@ public:
|
|||||||
void
|
void
|
||||||
fields(DynamicBuffer& db)
|
fields(DynamicBuffer& db)
|
||||||
{
|
{
|
||||||
|
auto os = ostream(db);
|
||||||
while(rand(6))
|
while(rand(6))
|
||||||
{
|
os <<
|
||||||
write(db, field());
|
field() <<
|
||||||
write(db, rand(4) ? ": " : ":");
|
(rand(4) ? ": " : ":") <<
|
||||||
write(db, value());
|
value() <<
|
||||||
write(db, "\r\n");
|
"\r\n";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class DynamicBuffer>
|
template<class DynamicBuffer>
|
||||||
@@ -491,13 +491,15 @@ public:
|
|||||||
{
|
{
|
||||||
if(! rand(4))
|
if(! rand(4))
|
||||||
{
|
{
|
||||||
write(db, "Content-Length: 0\r\n\r\n");
|
ostream(db) <<
|
||||||
|
"Content-Length: 0\r\n\r\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(rand(2))
|
if(rand(2))
|
||||||
{
|
{
|
||||||
auto const len = rand(500);
|
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))
|
for(auto const& b : db.prepare(len))
|
||||||
{
|
{
|
||||||
auto p = boost::asio::buffer_cast<char*>(b);
|
auto p = boost::asio::buffer_cast<char*>(b);
|
||||||
@@ -510,12 +512,14 @@ public:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto len = rand(500);
|
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)
|
while(len > 0)
|
||||||
{
|
{
|
||||||
auto n = (std::min)(1 + rand(300), len);
|
auto n = (std::min)(1 + rand(300), len);
|
||||||
len -= n;
|
len -= n;
|
||||||
write(db, to_hex(n), "\r\n");
|
ostream(db) <<
|
||||||
|
to_hex(n) << "\r\n";
|
||||||
for(auto const& b : db.prepare(n))
|
for(auto const& b : db.prepare(n))
|
||||||
{
|
{
|
||||||
auto p = boost::asio::buffer_cast<char*>(b);
|
auto p = boost::asio::buffer_cast<char*>(b);
|
||||||
@@ -524,9 +528,9 @@ public:
|
|||||||
*p++ = static_cast<char>(32 + rand(26+26+10+6));
|
*p++ = static_cast<char>(32 + rand(26+26+10+6));
|
||||||
}
|
}
|
||||||
db.commit(n);
|
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
|
void
|
||||||
request(DynamicBuffer& db)
|
request(DynamicBuffer& db)
|
||||||
{
|
{
|
||||||
write(db, method(), " ", uri(), " HTTP/1.1\r\n");
|
ostream(db) <<
|
||||||
|
method() << " " << target() << " HTTP/1.1\r\n";
|
||||||
fields(db);
|
fields(db);
|
||||||
body(db);
|
body(db);
|
||||||
}
|
}
|
||||||
@@ -543,14 +548,15 @@ public:
|
|||||||
void
|
void
|
||||||
response(DynamicBuffer& db)
|
response(DynamicBuffer& db)
|
||||||
{
|
{
|
||||||
write(db, "HTTP/1.");
|
ostream(db) <<
|
||||||
write(db, rand(2) ? "0" : "1");
|
"HTTP/1." <<
|
||||||
write(db, " ", 100 + rand(401), " ");
|
(rand(2) ? "0" : "1") << " " <<
|
||||||
write(db, token());
|
(100 + rand(401)) << " " <<
|
||||||
write(db, "\r\n");
|
token() <<
|
||||||
|
"\r\n";
|
||||||
fields(db);
|
fields(db);
|
||||||
body(db);
|
body(db);
|
||||||
write(db, "\r\n");
|
ostream(db) << "\r\n";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user