From e1de01ad1340ff6b0cc1d42be4396f1e60892175 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sat, 8 Jul 2017 15:12:26 -0700 Subject: [PATCH] Add vector_body fix #580 --- CHANGELOG.md | 1 + doc/5_02_message.qbk | 7 ++ doc/quickref.xml | 15 +-- include/beast/http.hpp | 1 + include/beast/http/vector_body.hpp | 182 +++++++++++++++++++++++++++++ test/http/CMakeLists.txt | 1 + test/http/Jamfile | 1 + test/http/vector_body.cpp | 19 +++ 8 files changed, 220 insertions(+), 7 deletions(-) create mode 100644 include/beast/http/vector_body.hpp create mode 100644 test/http/vector_body.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 32d63638..0ed56e67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Version 78: HTTP: * Tidy up basic_string_body +* Add vector_body -------------------------------------------------------------------------------- diff --git a/doc/5_02_message.qbk b/doc/5_02_message.qbk index f6015056..89ab4789 100644 --- a/doc/5_02_message.qbk +++ b/doc/5_02_message.qbk @@ -169,6 +169,13 @@ meet the requirements, or use the ones that come with the library: is responsible for managing the lifetime of the buffer pointed to by the string view. ]] +[[ + [link beast.ref.beast__http__vector_body `vector_body`] +][ + A body whose `value_type` is `std::vector`. Insertion complexity + is amortized constant time, while capacity grows geometrically. + Messages with this body type may be serialized and parsed. +]] ] [heading Usage] diff --git a/doc/quickref.xml b/doc/quickref.xml index 13e5b9ff..7d80de55 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -53,13 +53,7 @@ serializer string_body string_view_body - - rfc7230 - - ext_list - opt_token_list - param_list - token_list + vector_body @@ -86,6 +80,13 @@ write_header write_some + rfc7230 + + ext_list + opt_token_list + param_list + token_list + Constants diff --git a/include/beast/http.hpp b/include/beast/http.hpp index 3d0ae11e..5ebf1b7a 100644 --- a/include/beast/http.hpp +++ b/include/beast/http.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #endif diff --git a/include/beast/http/vector_body.hpp b/include/beast/http/vector_body.hpp new file mode 100644 index 00000000..36a19c42 --- /dev/null +++ b/include/beast/http/vector_body.hpp @@ -0,0 +1,182 @@ +// +// 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_VECTOR_BODY_HPP +#define BEAST_HTTP_VECTOR_BODY_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace http { + +/** A @b Body using `std::vector` + + This body uses `std::vector` as a memory-based container + for holding message payloads. Messages using this body type + may be serialized and parsed. +*/ +template> +struct vector_body +{ +private: + static_assert(sizeof(T) == 1 && + std::is_integral::value, + "T 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 = std::vector; + + /** 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 {{const_buffers_type{ + body_.data(), body_.size()}, 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) + { + if(*length > ( + std::numeric_limits::max)()) + { + ec = error::buffer_overflow; + return; + } + try + { + body_.reserve( + static_cast(*length)); + } + catch(std::exception const&) + { + 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(); + try + { + body_.resize(len + n); + } + catch(std::exception const&) + { + ec = error::buffer_overflow; + return 0; + } + ec.assign(0, ec.category()); + return buffer_copy(boost::asio::buffer( + &body_[0] + len, n), buffers); + } + + void + finish(error_code& ec) + { + ec.assign(0, ec.category()); + } + }; +#endif +}; + +} // http +} // beast + +#endif diff --git a/test/http/CMakeLists.txt b/test/http/CMakeLists.txt index 743b3a48..9a5f2284 100644 --- a/test/http/CMakeLists.txt +++ b/test/http/CMakeLists.txt @@ -32,6 +32,7 @@ add_executable (http-tests string_body.cpp string_view_body.cpp type_traits.cpp + vector_body.cpp verb.cpp write.cpp ) diff --git a/test/http/Jamfile b/test/http/Jamfile index 0c059509..66a959f2 100644 --- a/test/http/Jamfile +++ b/test/http/Jamfile @@ -25,6 +25,7 @@ unit-test http-tests : string_body.cpp string_view_body.cpp type_traits.cpp + vector_body.cpp verb.cpp write.cpp ; diff --git a/test/http/vector_body.cpp b/test/http/vector_body.cpp new file mode 100644 index 00000000..91252137 --- /dev/null +++ b/test/http/vector_body.cpp @@ -0,0 +1,19 @@ +// +// 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 + +namespace beast { +namespace http { + +BOOST_STATIC_ASSERT(is_body>::value); +BOOST_STATIC_ASSERT(is_body_reader>::value); +BOOST_STATIC_ASSERT(is_body_writer>::value); + +} // http +} // beast