diff --git a/doc/5_02_message.qbk b/doc/5_02_message.qbk
index 89ab4789..3e6d1666 100644
--- a/doc/5_02_message.qbk
+++ b/doc/5_02_message.qbk
@@ -152,8 +152,17 @@ meet the requirements, or use the ones that come with the library:
HTTP algorithms will use the open file for reading and writing,
for streaming and incremental sends and receives.
]]
+[[
+ [link beast.ref.beast__http__span_body `span_body`]
+][
+ A body whose `value_type` is a
+ [link beast.ref.beast__span `span`],
+ a non-owning reference to a single linear buffer of bytes.
+ Messages with this body type may be serialized and parsed.
+]]
[[
[link beast.ref.beast__http__basic_string_body `basic_string_body`]
+
[link beast.ref.beast__http__string_body `string_body`]
][
A body whose `value_type` is `std::basic_string` or `std::string`.
diff --git a/doc/quickref.xml b/doc/quickref.xml
index d49491ba..60ed05f9 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -51,6 +51,7 @@
response_parser
response_serializer
serializer
+ span_body
string_body
string_view_body
vector_body
diff --git a/example/http-server-threaded/http_server_threaded.cpp b/example/http-server-threaded/http_server_threaded.cpp
index 4389549c..e75b3796 100644
--- a/example/http-server-threaded/http_server_threaded.cpp
+++ b/example/http-server-threaded/http_server_threaded.cpp
@@ -56,10 +56,10 @@ public:
private:
// Send a client error response
- http::response
+ http::response>
client_error(http::status result, beast::string_view text)
{
- http::response res{result, 11};
+ http::response> res{result, 11};
res.set(http::field::server, BEAST_VERSION_STRING);
res.set(http::field::content_type, "text/plain");
res.set(http::field::connection, "close");
diff --git a/include/beast/core/span.hpp b/include/beast/core/span.hpp
index d6998ea8..1d465ce4 100644
--- a/include/beast/core/span.hpp
+++ b/include/beast/core/span.hpp
@@ -190,7 +190,7 @@ public:
{
return data_;
}
-
+
/// Returns an iterator to one past the end of the span
const_iterator
end() const
diff --git a/include/beast/http.hpp b/include/beast/http.hpp
index a7e8519e..5c093d2d 100644
--- a/include/beast/http.hpp
+++ b/include/beast/http.hpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/beast/http/span_body.hpp b/include/beast/http/span_body.hpp
new file mode 100644
index 00000000..8e83cde2
--- /dev/null
+++ b/include/beast/http/span_body.hpp
@@ -0,0 +1,167 @@
+//
+// 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_HTTP_SPAN_BODY_HPP
+#define BEAST_HTTP_SPAN_BODY_HPP
+
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace http {
+
+/** A @b Body using @ref span
+
+ This body uses @ref span as a memory-based container for
+ holding message payloads. The container represents a
+ non-owning reference to a continguous area of memory.
+ Messages using this body type may be serialized and
+ parsed.
+
+ Unlike @ref buffer_body, only one buffer may be provided
+ during a parse or serialize operation.
+*/
+template
+struct span_body
+{
+private:
+ static_assert(std::is_pod::value,
+ "POD requirements not met");
+
+public:
+ /** The type of container used for the body
+
+ This determines the type of @ref message::body
+ when this body type is used with a message container.
+ */
+ using value_type = span;
+
+ /** Returns the payload size of the body
+
+ When this body is used with @ref message::prepare_payload,
+ the Content-Length will be set to the payload size, and
+ any chunked Transfer-Encoding will be removed.
+ */
+ static
+ std::uint64_t
+ size(value_type const& body)
+ {
+ return body.size();
+ }
+
+ /** The algorithm for serializing the body
+
+ Meets the requirements of @b BodyReader.
+ */
+#if BEAST_DOXYGEN
+ using reader = implementation_defined;
+#else
+ class reader
+ {
+ value_type const& body_;
+
+ public:
+ using const_buffers_type =
+ boost::asio::const_buffers_1;
+
+ template
+ explicit
+ reader(message const& msg)
+ : body_(msg.body)
+ {
+ }
+
+ void
+ init(error_code& ec)
+ {
+ ec.assign(0, ec.category());
+ }
+
+ boost::optional>
+ get(error_code& ec)
+ {
+ ec.assign(0, ec.category());
+ return {{
+ { body_.data(),
+ body_.size() * sizeof(typename
+ value_type::value_type)},
+ false}};
+ }
+ };
+#endif
+
+ /** The algorithm for parsing the body
+
+ Meets the requirements of @b BodyReader.
+ */
+#if BEAST_DOXYGEN
+ using writer = implementation_defined;
+#else
+ class writer
+ {
+ value_type& body_;
+
+ public:
+ template
+ explicit
+ writer(message& m)
+ : body_(m.body)
+ {
+ }
+
+ void
+ init(boost::optional<
+ std::uint64_t> const& length, error_code& ec)
+ {
+ if(length && *length > body_.size())
+ {
+ ec = error::buffer_overflow;
+ return;
+ }
+ ec.assign(0, ec.category());
+ }
+
+ template
+ std::size_t
+ put(ConstBufferSequence const& buffers,
+ error_code& ec)
+ {
+ using boost::asio::buffer_size;
+ using boost::asio::buffer_copy;
+ auto const n = buffer_size(buffers);
+ auto const len = body_.size();
+ if(n > len)
+ {
+ ec = error::buffer_overflow;
+ return 0;
+ }
+ ec.assign(0, ec.category());
+ buffer_copy(boost::asio::buffer(
+ body_.data(), n), buffers);
+ body_ = value_type{
+ body_.data() + n, body_.size() - n};
+ return n;
+ }
+
+ void
+ finish(error_code& ec)
+ {
+ ec.assign(0, ec.category());
+ }
+ };
+#endif
+};
+
+} // http
+} // beast
+
+#endif
diff --git a/test/core/span.cpp b/test/core/span.cpp
index 32892de3..ec8c7d3e 100644
--- a/test/core/span.cpp
+++ b/test/core/span.cpp
@@ -8,6 +8,7 @@
// Test that header file is self-contained.
#include
+#include
#include
namespace beast {
@@ -15,6 +16,10 @@ namespace beast {
class span_test : public beast::unit_test::suite
{
public:
+ BOOST_STATIC_ASSERT(
+ detail::is_contiguous_container<
+ string_view, char const>::value);
+
struct base {};
struct derived : base {};
diff --git a/test/http/CMakeLists.txt b/test/http/CMakeLists.txt
index 9a5f2284..52e4767c 100644
--- a/test/http/CMakeLists.txt
+++ b/test/http/CMakeLists.txt
@@ -28,6 +28,7 @@ add_executable (http-tests
read.cpp
rfc7230.cpp
serializer.cpp
+ span_body.cpp
status.cpp
string_body.cpp
string_view_body.cpp
diff --git a/test/http/Jamfile b/test/http/Jamfile
index 66a959f2..85b25fda 100644
--- a/test/http/Jamfile
+++ b/test/http/Jamfile
@@ -21,6 +21,7 @@ unit-test http-tests :
read.cpp
rfc7230.cpp
serializer.cpp
+ span_body.cpp
status.cpp
string_body.cpp
string_view_body.cpp
diff --git a/test/http/span_body.cpp b/test/http/span_body.cpp
new file mode 100644
index 00000000..3e9e3b17
--- /dev/null
+++ b/test/http/span_body.cpp
@@ -0,0 +1,76 @@
+//
+// 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
+
+#include
+#include
+
+namespace beast {
+namespace http {
+
+struct span_body_test
+ : public beast::unit_test::suite
+{
+ void
+ testSpanBody()
+ {
+ {
+ using B = span_body;
+ request req;
+
+ BEAST_EXPECT(req.body.size() == 0);
+ BEAST_EXPECT(B::size(req.body) == 0);
+
+ req.body = B::value_type("xyz", 3);
+ BEAST_EXPECT(req.body.size() == 3);
+ BEAST_EXPECT(B::size(req.body) == 3);
+
+ B::reader r{req};
+ error_code ec;
+ r.init(ec);
+ BEAST_EXPECTS(! ec, ec.message());
+ auto const buf = r.get(ec);
+ BEAST_EXPECTS(! ec, ec.message());
+ if(! BEAST_EXPECT(buf != boost::none))
+ return;
+ BEAST_EXPECT(boost::asio::buffer_size(buf->first) == 3);
+ BEAST_EXPECT(! buf->second);
+ }
+ {
+ char buf[5];
+ using B = span_body;
+ request req;
+ req.body = span{buf, sizeof(buf)};
+ B::writer w{req};
+ error_code ec;
+ w.init(boost::none, ec);
+ BEAST_EXPECTS(! ec, ec.message());
+ w.put(boost::asio::const_buffers_1{
+ "123", 3}, ec);
+ BEAST_EXPECTS(! ec, ec.message());
+ BEAST_EXPECT(buf[0] == '1');
+ BEAST_EXPECT(buf[1] == '2');
+ BEAST_EXPECT(buf[2] == '3');
+ w.put(boost::asio::const_buffers_1{
+ "456", 3}, ec);
+ BEAST_EXPECTS(ec == error::buffer_overflow, ec.message());
+ }
+ }
+
+ void
+ run() override
+ {
+ testSpanBody();
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(span_body,http,beast);
+
+} // http
+} // beast