Add span_body

This commit is contained in:
Vinnie Falco
2017-07-08 18:47:33 -07:00
parent c9908eada0
commit 37110f2d04
10 changed files with 264 additions and 3 deletions

View File

@@ -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, HTTP algorithms will use the open file for reading and writing,
for streaming and incremental sends and receives. 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__basic_string_body `basic_string_body`]
[link beast.ref.beast__http__string_body `string_body`] [link beast.ref.beast__http__string_body `string_body`]
][ ][
A body whose `value_type` is `std::basic_string` or `std::string`. A body whose `value_type` is `std::basic_string` or `std::string`.

View File

@@ -51,6 +51,7 @@
<member><link linkend="beast.ref.beast__http__response_parser">response_parser</link></member> <member><link linkend="beast.ref.beast__http__response_parser">response_parser</link></member>
<member><link linkend="beast.ref.beast__http__response_serializer">response_serializer</link></member> <member><link linkend="beast.ref.beast__http__response_serializer">response_serializer</link></member>
<member><link linkend="beast.ref.beast__http__serializer">serializer</link></member> <member><link linkend="beast.ref.beast__http__serializer">serializer</link></member>
<member><link linkend="beast.ref.beast__http__span_body">span_body</link></member>
<member><link linkend="beast.ref.beast__http__string_body">string_body</link></member> <member><link linkend="beast.ref.beast__http__string_body">string_body</link></member>
<member><link linkend="beast.ref.beast__http__string_view_body">string_view_body</link></member> <member><link linkend="beast.ref.beast__http__string_view_body">string_view_body</link></member>
<member><link linkend="beast.ref.beast__http__vector_body">vector_body</link></member> <member><link linkend="beast.ref.beast__http__vector_body">vector_body</link></member>

View File

@@ -56,10 +56,10 @@ public:
private: private:
// Send a client error response // Send a client error response
http::response<http::string_view_body> http::response<http::span_body<char const>>
client_error(http::status result, beast::string_view text) client_error(http::status result, beast::string_view text)
{ {
http::response<http::string_view_body> res{result, 11}; http::response<http::span_body<char const>> res{result, 11};
res.set(http::field::server, BEAST_VERSION_STRING); res.set(http::field::server, BEAST_VERSION_STRING);
res.set(http::field::content_type, "text/plain"); res.set(http::field::content_type, "text/plain");
res.set(http::field::connection, "close"); res.set(http::field::connection, "close");

View File

@@ -190,7 +190,7 @@ public:
{ {
return data_; return data_;
} }
/// Returns an iterator to one past the end of the span /// Returns an iterator to one past the end of the span
const_iterator const_iterator
end() const end() const

View File

@@ -23,6 +23,7 @@
#include <beast/http/read.hpp> #include <beast/http/read.hpp>
#include <beast/http/rfc7230.hpp> #include <beast/http/rfc7230.hpp>
#include <beast/http/serializer.hpp> #include <beast/http/serializer.hpp>
#include <beast/http/span_body.hpp>
#include <beast/http/status.hpp> #include <beast/http/status.hpp>
#include <beast/http/string_body.hpp> #include <beast/http/string_body.hpp>
#include <beast/http/string_view_body.hpp> #include <beast/http/string_view_body.hpp>

View File

@@ -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 <beast/config.hpp>
#include <beast/core/span.hpp>
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <boost/optional.hpp>
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<class T>
struct span_body
{
private:
static_assert(std::is_pod<T>::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<T>;
/** 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<bool isRequest, class Fields>
explicit
reader(message<isRequest,
span_body, Fields> const& msg)
: body_(msg.body)
{
}
void
init(error_code& ec)
{
ec.assign(0, ec.category());
}
boost::optional<std::pair<const_buffers_type, bool>>
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<bool isRequest, class Fields>
explicit
writer(message<isRequest,
span_body, Fields>& 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<class ConstBufferSequence>
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

View File

@@ -8,6 +8,7 @@
// Test that header file is self-contained. // Test that header file is self-contained.
#include <beast/core/span.hpp> #include <beast/core/span.hpp>
#include <beast/core/string.hpp>
#include <beast/unit_test/suite.hpp> #include <beast/unit_test/suite.hpp>
namespace beast { namespace beast {
@@ -15,6 +16,10 @@ namespace beast {
class span_test : public beast::unit_test::suite class span_test : public beast::unit_test::suite
{ {
public: public:
BOOST_STATIC_ASSERT(
detail::is_contiguous_container<
string_view, char const>::value);
struct base {}; struct base {};
struct derived : base {}; struct derived : base {};

View File

@@ -28,6 +28,7 @@ add_executable (http-tests
read.cpp read.cpp
rfc7230.cpp rfc7230.cpp
serializer.cpp serializer.cpp
span_body.cpp
status.cpp status.cpp
string_body.cpp string_body.cpp
string_view_body.cpp string_view_body.cpp

View File

@@ -21,6 +21,7 @@ unit-test http-tests :
read.cpp read.cpp
rfc7230.cpp rfc7230.cpp
serializer.cpp serializer.cpp
span_body.cpp
status.cpp status.cpp
string_body.cpp string_body.cpp
string_view_body.cpp string_view_body.cpp

76
test/http/span_body.cpp Normal file
View File

@@ -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 <beast/http/span_body.hpp>
#include <beast/http/message.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
namespace http {
struct span_body_test
: public beast::unit_test::suite
{
void
testSpanBody()
{
{
using B = span_body<char const>;
request<B> 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<char>;
request<B> req;
req.body = span<char>{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