diff options
Diffstat (limited to 'boost/beast/http/serializer.hpp')
-rw-r--r-- | boost/beast/http/serializer.hpp | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/boost/beast/http/serializer.hpp b/boost/beast/http/serializer.hpp new file mode 100644 index 0000000000..50e58185a9 --- /dev/null +++ b/boost/beast/http/serializer.hpp @@ -0,0 +1,370 @@ +// +// Copyright (c) 2016-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) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_HTTP_SERIALIZER_HPP +#define BOOST_BEAST_HTTP_SERIALIZER_HPP + +#include <boost/beast/core/detail/config.hpp> +#include <boost/beast/core/buffers_cat.hpp> +#include <boost/beast/core/buffers_prefix.hpp> +#include <boost/beast/core/buffers_suffix.hpp> +#include <boost/beast/core/string.hpp> +#include <boost/beast/core/type_traits.hpp> +#include <boost/beast/core/detail/variant.hpp> +#include <boost/beast/http/message.hpp> +#include <boost/beast/http/chunk_encode.hpp> +#include <boost/asio/buffer.hpp> +#include <boost/optional.hpp> + +namespace boost { +namespace beast { +namespace http { + +/** Provides buffer oriented HTTP message serialization functionality. + + An object of this type is used to serialize a complete + HTTP message into a sequence of octets. To use this class, + construct an instance with the message to be serialized. + The implementation will automatically perform chunk encoding + if the contents of the message indicate that chunk encoding + is required. + + Chunked output produced by the serializer never contains chunk + extensions or trailers, and the location of chunk boundaries + is not specified. If callers require chunk extensions, trailers, + or control over the exact contents of each chunk they should + use the serializer to write just the message header, and then + assume control over serializing the chunked payload by using + the chunk buffer sequence types @ref chunk_body, @ref chunk_crlf, + @ref chunk_header, and @ref chunk_last. + + @tparam isRequest `true` if the message is a request. + + @tparam Body The body type of the message. + + @tparam Fields The type of fields in the message. +*/ +template< + bool isRequest, + class Body, + class Fields = fields> +class serializer +{ +public: + static_assert(is_body<Body>::value, + "Body requirements not met"); + + static_assert(is_body_writer<Body>::value, + "BodyWriter requirements not met"); + + /** The type of message this serializer uses + + This may be const or non-const depending on the + implementation of the corresponding @b BodyWriter. + */ +#if BOOST_BEAST_DOXYGEN + using value_type = implementation_defined; +#else + using value_type = + typename std::conditional< + std::is_constructible<typename Body::writer, + message<isRequest, Body, Fields>&>::value && + ! std::is_constructible<typename Body::writer, + message<isRequest, Body, Fields> const&>::value, + message<isRequest, Body, Fields>, + message<isRequest, Body, Fields> const>::type; +#endif + +private: + enum + { + do_construct = 0, + + do_init = 10, + do_header_only = 20, + do_header = 30, + do_body = 40, + + do_init_c = 50, + do_header_only_c = 60, + do_header_c = 70, + do_body_c = 80, + do_final_c = 90, + #ifndef BOOST_BEAST_NO_BIG_VARIANTS + do_body_final_c = 100, + do_all_c = 110, + #endif + + do_complete = 120 + }; + + void frdinit(std::true_type); + void frdinit(std::false_type); + + template<std::size_t, class Visit> + void + do_visit(error_code& ec, Visit& visit); + + using writer = typename Body::writer; + + using cb1_t = buffers_suffix<typename + Fields::writer::const_buffers_type>; // header + using pcb1_t = buffers_prefix_view<cb1_t const&>; + + using cb2_t = buffers_suffix<buffers_cat_view< + typename Fields::writer::const_buffers_type,// header + typename writer::const_buffers_type>>; // body + using pcb2_t = buffers_prefix_view<cb2_t const&>; + + using cb3_t = buffers_suffix< + typename writer::const_buffers_type>; // body + using pcb3_t = buffers_prefix_view<cb3_t const&>; + + using cb4_t = buffers_suffix<buffers_cat_view< + typename Fields::writer::const_buffers_type,// header + detail::chunk_size, // chunk-size + boost::asio::const_buffer, // chunk-ext + chunk_crlf, // crlf + typename writer::const_buffers_type, // body + chunk_crlf>>; // crlf + using pcb4_t = buffers_prefix_view<cb4_t const&>; + + using cb5_t = buffers_suffix<buffers_cat_view< + detail::chunk_size, // chunk-header + boost::asio::const_buffer, // chunk-ext + chunk_crlf, // crlf + typename writer::const_buffers_type, // body + chunk_crlf>>; // crlf + using pcb5_t = buffers_prefix_view<cb5_t const&>; + + using cb6_t = buffers_suffix<buffers_cat_view< + detail::chunk_size, // chunk-header + boost::asio::const_buffer, // chunk-size + chunk_crlf, // crlf + typename writer::const_buffers_type, // body + chunk_crlf, // crlf + boost::asio::const_buffer, // chunk-final + boost::asio::const_buffer, // trailers + chunk_crlf>>; // crlf + using pcb6_t = buffers_prefix_view<cb6_t const&>; + + using cb7_t = buffers_suffix<buffers_cat_view< + typename Fields::writer::const_buffers_type,// header + detail::chunk_size, // chunk-size + boost::asio::const_buffer, // chunk-ext + chunk_crlf, // crlf + typename writer::const_buffers_type, // body + chunk_crlf, // crlf + boost::asio::const_buffer, // chunk-final + boost::asio::const_buffer, // trailers + chunk_crlf>>; // crlf + using pcb7_t = buffers_prefix_view<cb7_t const&>; + + using cb8_t = buffers_suffix<buffers_cat_view< + boost::asio::const_buffer, // chunk-final + boost::asio::const_buffer, // trailers + chunk_crlf>>; // crlf + using pcb8_t = buffers_prefix_view<cb8_t const&>; + + value_type& m_; + writer rd_; + boost::optional<typename Fields::writer> frd_; + beast::detail::variant< + cb1_t, cb2_t, cb3_t, cb4_t, + cb5_t ,cb6_t, cb7_t, cb8_t> v_; + beast::detail::variant< + pcb1_t, pcb2_t, pcb3_t, pcb4_t, + pcb5_t ,pcb6_t, pcb7_t, pcb8_t> pv_; + std::size_t limit_ = + (std::numeric_limits<std::size_t>::max)(); + int s_ = do_construct; + bool split_ = false; + bool header_done_ = false; + bool more_; + +public: + /// Constructor + serializer(serializer&&) = default; + + /// Constructor + serializer(serializer const&) = default; + + /// Assignment + serializer& operator=(serializer const&) = delete; + + /** Constructor + + The implementation guarantees that the message passed on + construction will not be accessed until the first call to + @ref next. This allows the message to be lazily created. + For example, if the header is filled in before serialization. + + @param msg A reference to the message to serialize, which must + remain valid for the lifetime of the serializer. Depending on + the type of Body used, this may or may not be a `const` reference. + + @note This function participates in overload resolution only if + Body::writer is constructible from a `const` message reference. + */ + explicit + serializer(value_type& msg); + + /// Returns the message being serialized + value_type& + get() + { + return m_; + } + + /// Returns the serialized buffer size limit + std::size_t + limit() + { + return limit_; + } + + /** Set the serialized buffer size limit + + This function adjusts the limit on the maximum size of the + buffers passed to the visitor. The new size limit takes effect + in the following call to @ref next. + + The default is no buffer size limit. + + @param limit The new buffer size limit. If this number + is zero, the size limit is removed. + */ + void + limit(std::size_t limit) + { + limit_ = limit > 0 ? limit : + (std::numeric_limits<std::size_t>::max)(); + } + + /** Returns `true` if we will pause after writing the complete header. + */ + bool + split() + { + return split_; + } + + /** Set whether the header and body are written separately. + + When the split feature is enabled, the implementation will + write only the octets corresponding to the serialized header + first. If the header has already been written, this function + will have no effect on output. + */ + void + split(bool v) + { + split_ = v; + } + + /** Return `true` if serialization of the header is complete. + + This function indicates whether or not all buffers containing + serialized header octets have been retrieved. + */ + bool + is_header_done() + { + return header_done_; + } + + /** Return `true` if serialization is complete. + + The operation is complete when all octets corresponding + to the serialized representation of the message have been + successfully retrieved. + */ + bool + is_done() + { + return s_ == do_complete; + } + + /** Returns the next set of buffers in the serialization. + + This function will attempt to call the `visit` function + object with a @b ConstBufferSequence of unspecified type + representing the next set of buffers in the serialization + of the message represented by this object. + + If there are no more buffers in the serialization, the + visit function will not be called. In this case, no error + will be indicated, and the function @ref is_done will + return `true`. + + @param ec Set to the error, if any occurred. + + @param visit The function to call. The equivalent function + signature of this object must be: + @code + template<class ConstBufferSequence> + void visit(error_code&, ConstBufferSequence const&); + @endcode + The function is not copied, if no error occurs it will be + invoked before the call to @ref next returns. + + */ + template<class Visit> + void + next(error_code& ec, Visit&& visit); + + /** Consume buffer octets in the serialization. + + This function should be called after one or more octets + contained in the buffers provided in the prior call + to @ref next have been used. + + After a call to @ref consume, callers should check the + return value of @ref is_done to determine if the entire + message has been serialized. + + @param n The number of octets to consume. This number must + be greater than zero and no greater than the number of + octets in the buffers provided in the prior call to @ref next. + */ + void + consume(std::size_t n); + + /** Provides low-level access to the associated @b BodyWriter + + This function provides access to the instance of the writer + associated with the body and created by the serializer + upon construction. The behavior of accessing this object + is defined by the specification of the particular writer + and its associated body. + + @return A reference to the writer. + */ + writer& + reader_impl() + { + return rd_; + } +}; + +/// A serializer for HTTP/1 requests +template<class Body, class Fields = fields> +using request_serializer = serializer<true, Body, Fields>; + +/// A serializer for HTTP/1 responses +template<class Body, class Fields = fields> +using response_serializer = serializer<false, Body, Fields>; + +} // http +} // beast +} // boost + +#include <boost/beast/http/impl/serializer.ipp> + +#endif |