123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- //
- // Copyright (c) 2016-2019 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/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.
- @note
- Moving or copying the serializer after the first call to
- @ref serializer::next results in undefined behavior. Try to heap-allocate
- the serializer object if you need to move the serializer between multiple
- async operations (for example, between a call to `async_write_header` and
- `async_write`).
- @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 type requirements not met");
- static_assert(is_body_writer<Body>::value,
- "BodyWriter type requirements not met");
- /** The type of message this serializer uses
- This may be const or non-const depending on the
- implementation of the corresponding <em>BodyWriter</em>.
- */
- #if BOOST_BEAST_DOXYGEN
- using value_type = __implementation_defined__;
- #else
- using value_type = typename std::conditional<
- std::is_constructible<typename Body::writer,
- header<isRequest, Fields>&,
- typename Body::value_type&>::value &&
- ! std::is_constructible<typename Body::writer,
- header<isRequest, Fields> const&,
- typename Body::value_type 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 fwrinit(std::true_type);
- void fwrinit(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
- net::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
- net::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
- net::const_buffer, // chunk-size
- chunk_crlf, // crlf
- typename writer::const_buffers_type, // body
- chunk_crlf, // crlf
- net::const_buffer, // chunk-final
- net::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
- net::const_buffer, // chunk-ext
- chunk_crlf, // crlf
- typename writer::const_buffers_type, // body
- chunk_crlf, // crlf
- net::const_buffer, // chunk-final
- net::const_buffer, // trailers
- chunk_crlf>>; // crlf
- using pcb7_t = buffers_prefix_view<cb7_t const&>;
- using cb8_t = buffers_suffix<buffers_cat_view<
- net::const_buffer, // chunk-final
- net::const_buffer, // trailers
- chunk_crlf>>; // crlf
- using pcb8_t = buffers_prefix_view<cb8_t const&>;
- value_type& m_;
- writer wr_;
- boost::optional<typename Fields::writer> fwr_;
- 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_ = false;
- public:
- /** Move Constructor
- @note
- Moving or copying the serializer after the first call to
- @ref serializer::next results in undefined behavior. Try to heap-allocate
- the serializer object if you need to move the serializer between multiple
- async operations (for example, between a call to `async_write_header` and
- `async_write`).
- */
- serializer(serializer&&) = default;
- /** Copy Constructor
- @note
- Moving or copying the serializer after the first call to
- @ref serializer::next results in undefined behavior. Try to heap-allocate
- the serializer object if you need to move the serializer between multiple
- async operations (for example, between a call to `async_write_header` and
- `async_write`).
- */
- 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() const
- {
- 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 <em>ConstBufferSequence</em> 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 <em>BodyWriter</em>
- 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&
- writer_impl()
- {
- return wr_;
- }
- };
- /// 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.hpp>
- #endif
|