Add const_body, mutable_body to examples

This commit is contained in:
octopus-prime
2017-06-26 13:28:55 +02:00
committed by Vinnie Falco
parent 2d6859831c
commit b5b1295d0c
8 changed files with 347 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ Version 68:
* Adjust buffer size in fast server * Adjust buffer size in fast server
* Use string_ref in older Boost versions * Use string_ref in older Boost versions
* Optimize field lookups * Optimize field lookups
* Add const_body, mutable_body to examples
API Changes: API Changes:

View File

@@ -130,9 +130,11 @@ the example described in the Core Foundations document section.
This code is reused between some of the examples. The header files This code is reused between some of the examples. The header files
stand alone can be directly included in your projects. stand alone can be directly included in your projects.
* [repo_file example/common/const_body.hpp]
* [repo_file example/common/detect_ssl.hpp] * [repo_file example/common/detect_ssl.hpp]
* [repo_file example/common/file_body.hpp] * [repo_file example/common/file_body.hpp]
* [repo_file example/common/mime_types.hpp] * [repo_file example/common/mime_types.hpp]
* [repo_file example/common/mutable_body.hpp]
* [repo_file example/common/rfc7231.hpp] * [repo_file example/common/rfc7231.hpp]
* [repo_file example/common/ssl_stream.hpp] * [repo_file example/common/ssl_stream.hpp]
* [repo_file example/common/write_msg.hpp] * [repo_file example/common/write_msg.hpp]

View File

@@ -0,0 +1,89 @@
//
// Copyright (c) 2017 Mike Gresens (mike dot gresens 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_EXAMPLE_COMMON_CONST_BODY_HPP
#define BEAST_EXAMPLE_COMMON_CONST_BODY_HPP
#include <beast/http/message.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/optional.hpp>
namespace detail {
template <typename T>
using is_const_character = std::integral_constant<bool,
std::is_integral<T>::value &&
sizeof(T) == 1
>;
template<class T, class = void>
struct is_const_container : std::false_type { };
template<class T>
struct is_const_container<T, beast::detail::void_t<
decltype( std::declval<typename T::size_type&>() = std::declval<T&>().size() ),
decltype( std::declval<const typename T::value_type*&>() = std::declval<T&>().data() )
> > : std::true_type { };
}
/** An HTTP message body represented by a constant character container.
Meets the requirements of @b Body.
*/
template <typename ConstContainer>
struct const_body
{
static_assert(
detail::is_const_character<typename ConstContainer::value_type>::value &&
detail::is_const_container<ConstContainer>::value,
"ConstContainer requirements not met");
/// The type of the body member when used in a message.
using value_type = ConstContainer;
/// Returns the content length of the body in a message.
static
std::uint64_t
size(value_type const& v)
{
return v.size();
}
#if BEAST_DOXYGEN
/// The algorithm to obtain buffers representing the body
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(beast::http::message<isRequest, const_body,
Fields> const& msg, beast::error_code& ec)
: body_(msg.body)
{
ec.assign(0, ec.category());
}
boost::optional<std::pair<const_buffers_type, bool>>
get(beast::error_code& ec)
{
ec.assign(0, ec.category());
return {{const_buffers_type{
body_.data(), body_.size()}, false}};
}
};
#endif
};
#endif

View File

@@ -0,0 +1,155 @@
//
// Copyright (c) 2017 Mike Gresens (mike dot gresens 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_EXAMPLE_COMMON_MUTABLE_BODY_HPP
#define BEAST_EXAMPLE_COMMON_MUTABLE_BODY_HPP
#include <beast/http/message.hpp>
#include <beast/http/error.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/optional.hpp>
namespace detail {
template <typename T>
using is_mutable_character = std::integral_constant<bool,
std::is_integral<T>::value &&
sizeof(T) == 1
>;
template<class T, class = void>
struct is_mutable_container : std::false_type { };
template< class T >
struct is_mutable_container<T, beast::detail::void_t<
decltype( std::declval<typename T::size_type&>() = std::declval<T&>().size() ),
decltype( std::declval<const typename T::value_type*&>() = std::declval<T&>().data() ),
decltype( std::declval<T&>().reserve(0) ),
decltype( std::declval<T&>().resize(0) )
> > : std::true_type { };
}
/** An HTTP message body represented by a mutable character container.
Meets the requirements of @b Body.
*/
template <typename MutableContainer>
struct mutable_body
{
static_assert(
detail::is_mutable_character<typename MutableContainer::value_type>::value &&
detail::is_mutable_container<MutableContainer>::value,
"MutableContainer requirements not met");
/// The type of the body member when used in a message.
using value_type = MutableContainer;
/// Returns the content length of the body in a message.
static
std::uint64_t
size(value_type const& v)
{
return v.size();
}
#if BEAST_DOXYGEN
/// The algorithm to obtain buffers representing the body
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(beast::http::message<isRequest, mutable_body,
Fields> const& msg, beast::error_code& ec)
: body_(msg.body)
{
ec.assign(0, ec.category());
}
boost::optional<std::pair<const_buffers_type, bool>>
get(beast::error_code& ec)
{
ec.assign(0, ec.category());
return {{const_buffers_type{
body_.data(), body_.size()}, false}};
}
};
#endif
#if BEAST_DOXYGEN
/// The algorithm used store buffers in this body
using writer = implementation_defined;
#else
class writer
{
value_type& body_;
public:
template<bool isRequest, class Fields>
explicit
writer(beast::http::message<isRequest, mutable_body, Fields>& m,
boost::optional<std::uint64_t> const& content_length,
beast::error_code& ec)
: body_(m.body)
{
if(content_length)
{
if(*content_length > (std::numeric_limits<
std::size_t>::max)())
{
ec = boost::system::errc::make_error_code(
boost::system::errc::not_enough_memory);
return;
}
ec.assign(0, ec.category());
body_.reserve(static_cast<
std::size_t>(*content_length));
}
}
template<class ConstBufferSequence>
void
put(ConstBufferSequence const& buffers,
beast::error_code& ec)
{
using boost::asio::buffer_size;
using boost::asio::buffer_copy;
auto const n = buffer_size(buffers);
auto const len = body_.size();
try
{
body_.resize(len + n);
}
catch(std::length_error const&)
{
ec = beast::http::error::buffer_overflow;
return;
}
ec.assign(0, ec.category());
buffer_copy(boost::asio::buffer(
&body_[0] + len, n), buffers);
}
void
finish(beast::error_code& ec)
{
ec.assign(0, ec.category());
}
};
#endif
};
#endif

View File

@@ -10,6 +10,8 @@ add_executable (common-test
${COMMON_INCLUDES} ${COMMON_INCLUDES}
detect_ssl.cpp detect_ssl.cpp
file_body.cpp file_body.cpp
const_body.cpp
mutable_body.cpp
mime_types.cpp mime_types.cpp
rfc7231.cpp rfc7231.cpp
ssl_stream.cpp ssl_stream.cpp

View File

@@ -0,0 +1,10 @@
//
// Copyright (c) 2017 Mike Gresens (mike dot gresens 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 "../../example/common/const_body.hpp"

View File

@@ -0,0 +1,10 @@
//
// Copyright (c) 2017 Mike Gresens (mike dot gresens 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 "../../example/common/mutable_body.hpp"

View File

@@ -7,6 +7,8 @@
#include "example/doc/http_examples.hpp" #include "example/doc/http_examples.hpp"
#include "example/common/file_body.hpp" #include "example/common/file_body.hpp"
#include "example/common/const_body.hpp"
#include "example/common/mutable_body.hpp"
#include <beast/core/read_size.hpp> #include <beast/core/read_size.hpp>
#include <beast/core/detail/clamp.hpp> #include <beast/core/detail/clamp.hpp>
@@ -16,10 +18,37 @@
#include <beast/test/yield_to.hpp> #include <beast/test/yield_to.hpp>
#include <beast/unit_test/suite.hpp> #include <beast/unit_test/suite.hpp>
#include <sstream> #include <sstream>
#include <array>
#include <vector>
#include <list>
namespace beast { namespace beast {
namespace http { namespace http {
struct Thing {
char value;
};
BOOST_STATIC_ASSERT(::detail::is_const_character<char>::value == true);
BOOST_STATIC_ASSERT(::detail::is_const_character<unsigned char>::value == true);
BOOST_STATIC_ASSERT(::detail::is_const_character<char32_t>::value == false);
BOOST_STATIC_ASSERT(::detail::is_const_character<Thing>::value == false);
BOOST_STATIC_ASSERT(::detail::is_const_container<std::string>::value == true);
BOOST_STATIC_ASSERT(::detail::is_const_container<string_view>::value == true);
BOOST_STATIC_ASSERT(::detail::is_const_container<std::vector<char>>::value == true);
BOOST_STATIC_ASSERT(::detail::is_const_container<std::list<char>>::value == false);
BOOST_STATIC_ASSERT(::detail::is_mutable_character<char>::value == true);
BOOST_STATIC_ASSERT(::detail::is_mutable_character<unsigned char>::value == true);
BOOST_STATIC_ASSERT(::detail::is_mutable_character<char32_t>::value == false);
BOOST_STATIC_ASSERT(::detail::is_mutable_character<Thing>::value == false);
BOOST_STATIC_ASSERT(::detail::is_mutable_container<std::string>::value == true);
BOOST_STATIC_ASSERT(::detail::is_mutable_container<string_view>::value == false);
BOOST_STATIC_ASSERT(::detail::is_mutable_container<std::vector<char>>::value == true);
BOOST_STATIC_ASSERT(::detail::is_mutable_container<std::list<char>>::value == false);
class doc_http_samples_test class doc_http_samples_test
: public beast::unit_test::suite : public beast::unit_test::suite
, public beast::test::enable_yield_to , public beast::test::enable_yield_to
@@ -307,6 +336,54 @@ public:
BEAST_EXPECTS(! ec, ec.message()); BEAST_EXPECTS(! ec, ec.message());
} }
void
doConstAndMutableBody()
{
test::pipe c{ios_};
// people using std::array need to be careful
// because the entire array will be written out
// no matter how big the string is!
std::array<char, 15> const body {{"Hello, world!\n"}};
{
request<const_body<std::array<char, 15>>> req;
req.version = 11;
req.method(verb::put);
req.target("/");
req.body = body;
req.prepare_payload();
write(c.client, req);
}
{
flat_buffer b;
request_parser<empty_body> p0;
read_header(c.server, b, p0);
BEAST_EXPECTS(p0.get().method() == verb::put,
p0.get().method_string());
{
request_parser<mutable_body<std::vector<char>>> p{std::move(p0)};
p.get().body = std::vector<char>(body.begin(), body.end());
read(c.server, b, p);
}
}
{
response<const_body<std::array<char, 15>>> res;
res.version = 11;
res.result(status::ok);
res.insert(field::server, "test");
res.body = body;
res.prepare_payload();
write(c.server, res);
}
{
flat_buffer b;
response<mutable_body<std::vector<char>>> res;
read(c.client, b, res);
BEAST_EXPECTS(res.body == std::vector<char>(body.begin(), body.end()),
std::string(body.begin(), body.end()));
}
}
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
void void
@@ -321,6 +398,7 @@ public:
doHEAD(); doHEAD();
doDeferredBody(); doDeferredBody();
doFileBody(); doFileBody();
doConstAndMutableBody();
} }
}; };