diff --git a/doc/quickref.xml b/doc/quickref.xml
index cdb33e20b..460e6d3c4 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -131,6 +131,7 @@
buffer_cat
prepare_buffer
prepare_buffers
+ write
diff --git a/include/beast/detail/write_streambuf.hpp b/include/beast/detail/write_streambuf.hpp
new file mode 100644
index 000000000..ccac4b4ca
--- /dev/null
+++ b/include/beast/detail/write_streambuf.hpp
@@ -0,0 +1,146 @@
+//
+// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BEAST_DETAIL_WRITE_STREAMBUF_HPP
+#define BEAST_DETAIL_WRITE_STREAMBUF_HPP
+
+#include
+#include
+#include
+
+namespace beast {
+namespace detail {
+
+// detects string literals.
+template
+struct is_string_literal : std::integral_constant::type>::value &&
+ std::is_same::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 is_BufferConvertible
+{
+ template()),
+ std::true_type{})>
+ static R check(int);
+ template
+ static std::false_type check(...);
+ using type = decltype(check(0));
+public:
+ static bool const value = type::value &&
+ ! is_string_literal::value;
+};
+
+template
+inline
+void
+write_streambuf(Streambuf&)
+{
+}
+
+template
+void
+write_streambuf(Streambuf& streambuf,
+ boost::asio::const_buffer const& buffer)
+{
+ using boost::asio::buffer_copy;
+ using boost::asio::buffer_size;
+ streambuf.commit(buffer_copy(
+ streambuf.prepare(buffer_size(buffer)),
+ buffer));
+}
+
+template
+void
+write_streambuf(Streambuf& streambuf,
+ boost::asio::mutable_buffer const& buffer)
+{
+ using boost::asio::buffer_copy;
+ using boost::asio::buffer_size;
+ streambuf.commit(buffer_copy(
+ streambuf.prepare(buffer_size(buffer)),
+ buffer));
+}
+
+template
+typename std::enable_if<
+ is_BufferConvertible::value &&
+ ! std::is_convertible::value &&
+ ! std::is_convertible::value
+>::type
+write_streambuf(Streambuf& streambuf, T const& t)
+{
+ using boost::asio::buffer_copy;
+ using boost::asio::buffer_size;
+ auto const buffers = boost::asio::buffer(t);
+ streambuf.commit(buffer_copy(
+ streambuf.prepare(buffer_size(buffers)),
+ buffers));
+}
+
+template
+typename std::enable_if<
+ is_ConstBufferSequence::value &&
+ ! is_BufferConvertible::value &&
+ ! std::is_convertible::value &&
+ ! std::is_convertible::value
+>::type
+write_streambuf(Streambuf& streambuf, Buffers const& buffers)
+{
+ using boost::asio::buffer_copy;
+ using boost::asio::buffer_size;
+ streambuf.commit(buffer_copy(
+ streambuf.prepare(buffer_size(buffers)),
+ buffers));
+}
+
+template
+void
+write_streambuf(Streambuf& streambuf, const char (&s)[N])
+{
+ using boost::asio::buffer_copy;
+ streambuf.commit(buffer_copy(
+ streambuf.prepare(N - 1),
+ boost::asio::buffer(s, N - 1)));
+}
+
+template
+typename std::enable_if<
+ ! is_string_literal::value &&
+ ! is_ConstBufferSequence::value &&
+ ! is_BufferConvertible::value &&
+ ! std::is_convertible::value &&
+ ! std::is_convertible::value
+>::type
+write_streambuf(Streambuf& streambuf, T const& t)
+{
+ using boost::asio::buffer;
+ using boost::asio::buffer_copy;
+ auto const s = boost::lexical_cast(t);
+ streambuf.commit(buffer_copy(
+ streambuf.prepare(s.size()), buffer(s)));
+}
+
+template
+void
+write_streambuf(Streambuf& streambuf, T0&& t0, T1&& t1, TN... tn)
+{
+ write_streambuf(streambuf, std::forward(t0));
+ write_streambuf(streambuf, std::forward(t1));
+ write_streambuf(streambuf, std::forward(tn)...);
+}
+
+} // detail
+} // beast
+
+#endif
diff --git a/include/beast/http/basic_headers.hpp b/include/beast/http/basic_headers.hpp
index 6bbff654d..500d0b611 100644
--- a/include/beast/http/basic_headers.hpp
+++ b/include/beast/http/basic_headers.hpp
@@ -8,7 +8,6 @@
#ifndef BEAST_HTTP_BASIC_HEADERS_HPP
#define BEAST_HTTP_BASIC_HEADERS_HPP
-#include
#include
#include
#include
diff --git a/include/beast/http/detail/write_preparation.hpp b/include/beast/http/detail/write_preparation.hpp
index 937ecafd0..13dd6f13a 100644
--- a/include/beast/http/detail/write_preparation.hpp
+++ b/include/beast/http/detail/write_preparation.hpp
@@ -10,6 +10,7 @@
#include
#include
+#include
namespace beast {
namespace http {
@@ -84,7 +85,7 @@ struct write_preparation
msg.write_firstline(sb);
write_fields(sb, h);
- detail::write(sb, "\r\n");
+ beast::write(sb, "\r\n");
}
private:
diff --git a/include/beast/http/detail/writes.hpp b/include/beast/http/detail/writes.hpp
deleted file mode 100644
index bd68bb2c9..000000000
--- a/include/beast/http/detail/writes.hpp
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-
-#ifndef BEAST_HTTP_DETAIL_WRITES_HPP
-#define BEAST_HTTP_DETAIL_WRITES_HPP
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace beast {
-namespace http {
-namespace detail {
-
-template::value>::type>
-void
-write(Streambuf& streambuf, T&& t)
-{
- using boost::asio::buffer;
- using boost::asio::buffer_copy;
- auto const& s =
- boost::lexical_cast(
- std::forward(t));
- streambuf.commit(buffer_copy(
- streambuf.prepare(s.size()), buffer(s)));
-}
-
-template0) &&
- is_Streambuf::value>::type>
-void
-write(Streambuf& streambuf, char const(&s)[N])
-{
- using boost::asio::buffer;
- using boost::asio::buffer_copy;
- streambuf.commit(buffer_copy(
- streambuf.prepare(N), buffer(s, N-1)));
-}
-
-template::value>::type>
-void
-write(Streambuf& streambuf, boost::string_ref const& s)
-{
- using boost::asio::buffer;
- using boost::asio::buffer_copy;
- streambuf.commit(buffer_copy(
- streambuf.prepare(s.size()),
- buffer(s.data(), s.size())));
-}
-
-} // detail
-} // http
-} // beast
-
-#endif
diff --git a/include/beast/http/impl/basic_headers.ipp b/include/beast/http/impl/basic_headers.ipp
index 45a42322d..8880bd890 100644
--- a/include/beast/http/impl/basic_headers.ipp
+++ b/include/beast/http/impl/basic_headers.ipp
@@ -8,7 +8,6 @@
#ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP
-#include
#include
namespace beast {
diff --git a/include/beast/http/impl/message.ipp b/include/beast/http/impl/message.ipp
index 23d748d93..0f89cc4ad 100644
--- a/include/beast/http/impl/message.ipp
+++ b/include/beast/http/impl/message.ipp
@@ -9,10 +9,11 @@
#define BEAST_HTTP_IMPL_MESSAGE_IPP
#include
-#include
-#include
#include
#include
+#include
+#include
+#include
#include
#include
#include
@@ -54,23 +55,23 @@ message::
write_firstline(Streambuf& streambuf,
std::true_type) const
{
- detail::write(streambuf, to_string(this->method));
- detail::write(streambuf, " ");
- detail::write(streambuf, this->url);
+ write(streambuf, to_string(this->method));
+ write(streambuf, " ");
+ write(streambuf, this->url);
switch(version)
{
case 10:
- detail::write(streambuf, " HTTP/1.0\r\n");
+ write(streambuf, " HTTP/1.0\r\n");
break;
case 11:
- detail::write(streambuf, " HTTP/1.1\r\n");
+ write(streambuf, " HTTP/1.1\r\n");
break;
default:
- detail::write(streambuf, " HTTP/");
- detail::write(streambuf, version / 10);
- detail::write(streambuf, ".");
- detail::write(streambuf, version % 10);
- detail::write(streambuf, "\r\n");
+ write(streambuf, " HTTP/");
+ write(streambuf, version / 10);
+ write(streambuf, ".");
+ write(streambuf, version % 10);
+ write(streambuf, "\r\n");
break;
}
}
@@ -85,23 +86,23 @@ write_firstline(Streambuf& streambuf,
switch(version)
{
case 10:
- detail::write(streambuf, "HTTP/1.0 ");
+ write(streambuf, "HTTP/1.0 ");
break;
case 11:
- detail::write(streambuf, "HTTP/1.1 ");
+ write(streambuf, "HTTP/1.1 ");
break;
default:
- detail::write(streambuf, " HTTP/");
- detail::write(streambuf, version / 10);
- detail::write(streambuf, ".");
- detail::write(streambuf, version % 10);
- detail::write(streambuf, " ");
+ write(streambuf, " HTTP/");
+ write(streambuf, version / 10);
+ write(streambuf, ".");
+ write(streambuf, version % 10);
+ write(streambuf, " ");
break;
}
- detail::write(streambuf, this->status);
- detail::write(streambuf, " ");
- detail::write(streambuf, this->reason);
- detail::write(streambuf, "\r\n");
+ write(streambuf, this->status);
+ write(streambuf, " ");
+ write(streambuf, this->reason);
+ write(streambuf, "\r\n");
}
namespace detail {
@@ -273,10 +274,10 @@ write_fields(Streambuf& streambuf, FieldSequence const& fields)
// "FieldSequence requirements not met");
for(auto const& field : fields)
{
- detail::write(streambuf, field.name());
- detail::write(streambuf, ": ");
- detail::write(streambuf, field.value());
- detail::write(streambuf, "\r\n");
+ write(streambuf, field.name());
+ write(streambuf, ": ");
+ write(streambuf, field.value());
+ write(streambuf, "\r\n");
}
}
diff --git a/include/beast/http/impl/write.ipp b/include/beast/http/impl/write.ipp
index 8e538c999..f1640c028 100644
--- a/include/beast/http/impl/write.ipp
+++ b/include/beast/http/impl/write.ipp
@@ -10,7 +10,6 @@
#include
#include
-#include
#include
#include
#include
diff --git a/include/beast/write_streambuf.hpp b/include/beast/write_streambuf.hpp
new file mode 100644
index 000000000..750a024fa
--- /dev/null
+++ b/include/beast/write_streambuf.hpp
@@ -0,0 +1,59 @@
+//
+// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BEAST_WRITE_STREAMBUF_HPP
+#define BEAST_WRITE_STREAMBUF_HPP
+
+#include
+#include
+#include
+#include
+
+namespace beast {
+
+/** Write to a Streambuf.
+
+ This function appends the serialized representation of each provided
+ argument into the stream buffer. It is capable of converting the
+ following types of arguments:
+
+ * `boost::asio::const_buffer`
+ * `boost::asio::mutable_buffer`
+ * A type for which the call to `boost::asio::buffer()` is defined
+ * A type meeting the requirements of `ConstBufferSequence`
+ * A type meeting the requirements of `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 stream buffer.
+
+ When this function serializes numbers, it converts them to
+ their text representation as if by a call to `std::to_string`.
+
+ @param streambuf The stream buffer to write to.
+
+ @param args A list of one or more arguments to write.
+
+ @throws Any exceptions thrown by `boost::lexical_cast`.
+
+ @note This function participates in overload resolution only if
+ the `streambuf` parameter meets the requirements of Streambuf.
+*/
+template
+#if GENERATING_DOCS
+void
+#else
+typename std::enable_if::value>::type
+#endif
+write(Streambuf& streambuf, Args&&... args)
+{
+ detail::write_streambuf(streambuf, std::forward(args)...);
+}
+
+} // beast
+
+#endif
diff --git a/test/Jamfile b/test/Jamfile
index e384b4416..356cda9af 100644
--- a/test/Jamfile
+++ b/test/Jamfile
@@ -50,7 +50,6 @@ unit-test http_tests :
unit-test websocket_tests :
main.cpp
- ../src/beast_http_nodejs_parser.cpp
websocket/error.cpp
websocket/option.cpp
websocket/rfc6455.cpp
diff --git a/test/write_streambuf.cpp b/test/write_streambuf.cpp
new file mode 100644
index 000000000..68290fbce
--- /dev/null
+++ b/test/write_streambuf.cpp
@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+// Test that header file is self-contained.
+#include
+#include
+#include
+
+namespace beast {
+
+class write_streambuf_test : public beast::detail::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_streambuf,core,beast);
+
+} // beast