LCOV - code coverage report
Current view: top level - boost/http_proto/serializer.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 38 38
Test Date: 2024-09-13 19:44:06 Functions: 100.0 % 17 17

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/cppalliance/http_proto
       8              : //
       9              : 
      10              : #ifndef BOOST_HTTP_PROTO_SERIALIZER_HPP
      11              : #define BOOST_HTTP_PROTO_SERIALIZER_HPP
      12              : 
      13              : #include <boost/http_proto/detail/config.hpp>
      14              : #include <boost/http_proto/context.hpp>
      15              : #include <boost/http_proto/source.hpp>
      16              : #include <boost/http_proto/detail/array_of_buffers.hpp>
      17              : #include <boost/http_proto/detail/except.hpp>
      18              : #include <boost/http_proto/detail/header.hpp>
      19              : #include <boost/http_proto/detail/workspace.hpp>
      20              : #include <boost/buffers/circular_buffer.hpp>
      21              : #include <boost/buffers/range.hpp>
      22              : #include <boost/buffers/type_traits.hpp>
      23              : #include <boost/system/result.hpp>
      24              : #include <cstdint>
      25              : #include <memory>
      26              : #include <type_traits>
      27              : #include <utility>
      28              : 
      29              : namespace boost {
      30              : namespace http_proto {
      31              : 
      32              : #ifndef BOOST_HTTP_PROTO_DOCS
      33              : class request;
      34              : class response;
      35              : class request_view;
      36              : class response_view;
      37              : class message_view_base;
      38              : namespace detail {
      39              : class filter;
      40              : } // detail
      41              : #endif
      42              : 
      43              : /** A serializer for HTTP/1 messages
      44              : 
      45              :     This is used to serialize one or more complete
      46              :     HTTP/1 messages. Each message consists of a
      47              :     required header followed by an optional body.
      48              : 
      49              :     Objects of this type operate using an "input area" and an
      50              :     "output area". Callers provide data to the input area
      51              :     using one of the @ref start or @ref start_stream member
      52              :     functions. After input is provided, serialized data
      53              :     becomes available in the serializer's output area in the
      54              :     form of a constant buffer sequence.
      55              : 
      56              :     Callers alternate between filling the input area and
      57              :     consuming the output area until all the input has been
      58              :     provided and all the output data has been consumed, or
      59              :     an error occurs.
      60              : 
      61              :     After calling @ref start, the caller must ensure that the
      62              :     contents of the associated message are not changed or
      63              :     destroyed until @ref is_done returns true, @ref reset is
      64              :     called, or the serializer is destroyed, otherwise the
      65              :     behavior is undefined.
      66              : */
      67              : class BOOST_SYMBOL_VISIBLE
      68              :     serializer
      69              : {
      70              : public:
      71              :     class const_buffers_type;
      72              : 
      73              :     struct stream;
      74              : 
      75              :     /** Destructor
      76              :     */
      77              :     BOOST_HTTP_PROTO_DECL
      78              :     ~serializer();
      79              : 
      80              :     /** Constructor
      81              :     */
      82              :     BOOST_HTTP_PROTO_DECL
      83              :     serializer(
      84              :         serializer&&) noexcept;
      85              : 
      86              :     /** Constructor
      87              : 
      88              :         @param ctx The serializer will access services
      89              :                    registered with this context.
      90              :     */
      91              :     BOOST_HTTP_PROTO_DECL
      92              :     serializer(
      93              :         context& ctx);
      94              : 
      95              :     /** Constructor
      96              :     */
      97              :     BOOST_HTTP_PROTO_DECL
      98              :     serializer(
      99              :         context& ctx,
     100              :         std::size_t buffer_size);
     101              : 
     102              :     //--------------------------------------------
     103              : 
     104              :     /** Prepare the serializer for a new stream
     105              :     */
     106              :     BOOST_HTTP_PROTO_DECL
     107              :     void
     108              :     reset() noexcept;
     109              : 
     110              :     /** Prepare the serializer for a new message
     111              : 
     112              :         The message will not contain a body.
     113              :         Changing the contents of the message
     114              :         after calling this function and before
     115              :         @ref is_done returns `true` results in
     116              :         undefined behavior.
     117              :     */
     118              :     void
     119            4 :     start(
     120              :         message_view_base const& m)
     121              :     {
     122            4 :         start_empty(m);
     123            4 :     }
     124              : 
     125              :     /** Prepare the serializer for a new message
     126              : 
     127              :         Changing the contents of the message
     128              :         after calling this function and before
     129              :         @ref is_done returns `true` results in
     130              :         undefined behavior.
     131              : 
     132              :         @par Constraints
     133              :         @code
     134              :         is_const_buffers< ConstBuffers >::value == true
     135              :         @endcode
     136              :     */
     137              :     template<
     138              :         class ConstBufferSequence
     139              : #ifndef BOOST_HTTP_PROTO_DOCS
     140              :         ,class = typename
     141              :             std::enable_if<
     142              :                 buffers::is_const_buffer_sequence<
     143              :                     ConstBufferSequence>::value
     144              :                         >::type
     145              : #endif
     146              :     >
     147              :     void
     148              :     start(
     149              :         message_view_base const& m,
     150              :         ConstBufferSequence&& body);
     151              : 
     152              :     /** Prepare the serializer for a new message
     153              : 
     154              :         Changing the contents of the message
     155              :         after calling this function and before
     156              :         @ref is_done returns `true` results in
     157              :         undefined behavior.
     158              :     */
     159              :     template<
     160              :         class Source,
     161              :         class... Args
     162              : #ifndef BOOST_HTTP_PROTO_DOCS
     163              :         ,class = typename std::enable_if<
     164              :             is_source<Source>::value>::type
     165              : #endif
     166              :     >
     167              :     Source&
     168              :     start(
     169              :         message_view_base const& m,
     170              :         Args&&... args);
     171              : 
     172              :     //--------------------------------------------
     173              : 
     174              :     /** Return a new stream for this serializer.
     175              : 
     176              :         After the serializer is destroyed, @ref reset is called,
     177              :         or @ref is_done returns true, the only valid operation
     178              :         on the stream is destruction.
     179              : 
     180              :         A stream may be used to invert the flow of control
     181              :         when the caller is supplying body data as a series
     182              :         of buffers.
     183              :      */
     184              :     BOOST_HTTP_PROTO_DECL
     185              :     stream
     186              :     start_stream(
     187              :         message_view_base const& m);
     188              : 
     189              :     //--------------------------------------------
     190              : 
     191              :     /** Return true if serialization is complete.
     192              :     */
     193              :     bool
     194         1685 :     is_done() const noexcept
     195              :     {
     196         1685 :         return is_done_;
     197              :     }
     198              : 
     199              :     /** Return the output area.
     200              : 
     201              :         This function will serialize some or
     202              :         all of the content and return the
     203              :         corresponding output buffers.
     204              : 
     205              :         @par Preconditions
     206              :         @code
     207              :         this->is_done() == false
     208              :         @endcode
     209              :     */
     210              :     BOOST_HTTP_PROTO_DECL
     211              :     auto
     212              :     prepare() ->
     213              :         system::result<
     214              :             const_buffers_type>;
     215              : 
     216              :     /** Consume bytes from the output area.
     217              :     */
     218              :     BOOST_HTTP_PROTO_DECL
     219              :     void
     220              :     consume(std::size_t n);
     221              : 
     222              :     /** Applies deflate compression to the current message
     223              : 
     224              :         After @ref reset is called, compression is not
     225              :         applied to the next message.
     226              : 
     227              :         Must be called before any calls to @ref start.
     228              :     */
     229              :     BOOST_HTTP_PROTO_DECL
     230              :     void
     231              :     use_deflate_encoding();
     232              : 
     233              :     /** Applies gzip compression to the current message
     234              : 
     235              :         After @ref reset is called, compression is not
     236              :         applied to the next message.
     237              : 
     238              :         Must be called before any calls to @ref start.
     239              :     */
     240              :     BOOST_HTTP_PROTO_DECL
     241              :     void
     242              :     use_gzip_encoding();
     243              : 
     244              : private:
     245              :     static void copy(
     246              :         buffers::const_buffer*,
     247              :         buffers::const_buffer const*,
     248              :         std::size_t n) noexcept;
     249              :     auto
     250              :     make_array(std::size_t n) ->
     251              :         detail::array_of_const_buffers;
     252              : 
     253              :     template<
     254              :         class Source,
     255              :         class... Args,
     256              :         typename std::enable_if<
     257              :             std::is_constructible<
     258              :                 Source,
     259              :                 Args...>::value>::type* = nullptr>
     260              :     Source&
     261           24 :     construct_source(Args&&... args)
     262              :     {
     263           24 :         return ws_.emplace<Source>(
     264           24 :             std::forward<Args>(args)...);
     265              :     }
     266              : 
     267              :     template<
     268              :         class Source,
     269              :         class... Args,
     270              :         typename std::enable_if<
     271              :             std::is_constructible<
     272              :                 Source,
     273              :                 buffered_base::allocator&,
     274              :                 Args...>::value>::type* = nullptr>
     275              :     Source&
     276              :     construct_source(Args&&... args)
     277              :     {
     278              :         buffered_base::allocator a(
     279              :             ws_.data(),
     280              :             (ws_.size() - ws_.space_needed<Source>()) / 2,
     281              :             false);
     282              :         auto& src = ws_.emplace<Source>(
     283              :             a, std::forward<Args>(args)...);
     284              :         ws_.reserve_front(a.size_used());
     285              :         return src;
     286              :     }
     287              : 
     288              :     BOOST_HTTP_PROTO_DECL void start_init(message_view_base const&);
     289              :     BOOST_HTTP_PROTO_DECL void start_empty(message_view_base const&);
     290              :     BOOST_HTTP_PROTO_DECL void start_buffers(message_view_base const&);
     291              :     BOOST_HTTP_PROTO_DECL void start_source(message_view_base const&, source*);
     292              : 
     293              :     enum class style
     294              :     {
     295              :         empty,
     296              :         buffers,
     297              :         source,
     298              :         stream
     299              :     };
     300              : 
     301              :     // chunked-body   = *chunk
     302              :     //                  last-chunk
     303              :     //                  trailer-section
     304              :     //                  CRLF
     305              : 
     306              :     static
     307              :     constexpr
     308              :     std::size_t
     309              :     crlf_len_ = 2;
     310              : 
     311              :     // chunk          = chunk-size [ chunk-ext ] CRLF
     312              :     //                  chunk-data CRLF
     313              :     static
     314              :     constexpr
     315              :     std::size_t
     316              :     chunk_header_len_ =
     317              :         16 + // 16 hex digits => 64 bit number
     318              :         crlf_len_;
     319              : 
     320              :     // last-chunk     = 1*("0") [ chunk-ext ] CRLF
     321              :     static
     322              :     constexpr
     323              :     std::size_t
     324              :     last_chunk_len_ =
     325              :         1 + // "0"
     326              :         crlf_len_ +
     327              :         crlf_len_; // chunked-body termination requires an extra CRLF
     328              : 
     329              :     static
     330              :     constexpr
     331              :     std::size_t
     332              :     chunked_overhead_ =
     333              :         chunk_header_len_ +
     334              :         crlf_len_ + // closing chunk data
     335              :         last_chunk_len_;
     336              : 
     337              :     detail::workspace ws_;
     338              :     detail::array_of_const_buffers buf_;
     339              :     detail::filter* filter_ = nullptr;
     340              :     source* src_;
     341              :     context& ctx_;
     342              :     buffers::circular_buffer tmp0_;
     343              :     buffers::circular_buffer tmp1_;
     344              :     detail::array_of_const_buffers prepped_;
     345              : 
     346              :     buffers::mutable_buffer chunk_header_;
     347              :     buffers::mutable_buffer chunk_close_;
     348              :     buffers::mutable_buffer last_chunk_;
     349              : 
     350              :     buffers::circular_buffer* in_ = nullptr;
     351              :     buffers::circular_buffer* out_ = nullptr;
     352              : 
     353              :     buffers::const_buffer* hp_;  // header
     354              : 
     355              :     style st_;
     356              :     bool more_;
     357              :     bool is_done_;
     358              :     bool is_header_done_;
     359              :     bool is_chunked_;
     360              :     bool is_expect_continue_;
     361              :     bool is_compressed_ = false;
     362              :     bool filter_done_ = false;
     363              : };
     364              : 
     365              : //------------------------------------------------
     366              : 
     367              : /** The type used for caller-provided body data during
     368              :     serialization.
     369              : 
     370              :     @code{.cpp}
     371              :     http_proto::serializer sr(128);
     372              : 
     373              :     http_proto::request req;
     374              :     auto stream = sr.start_stream(req);
     375              : 
     376              :     std::string_view msg = "Hello, world!";
     377              :     auto n = buffers::buffer_copy(
     378              :         stream.prepare(),
     379              :         buffers::make_buffer(
     380              :             msg.data(), msg.size()));
     381              : 
     382              :     stream.commit(n);
     383              : 
     384              :     auto cbs = sr.prepare().value();
     385              :     (void)cbs;
     386              :     @endcode
     387              : */
     388              : struct serializer::stream
     389              : {
     390              :     /** Constructor.
     391              : 
     392              :         The only valid operations on default constructed
     393              :         streams are assignment and destruction.
     394              :     */
     395              :     stream() = default;
     396              : 
     397              :     /** Constructor.
     398              : 
     399              :         The constructed stream will share the same
     400              :         serializer as `other`.
     401              :     */
     402              :     stream(stream const& other) = default;
     403              : 
     404              :     /** Assignment.
     405              : 
     406              :         The current stream will share the same serializer
     407              :         as `other`.
     408              :     */
     409              :     stream& operator= (
     410              :         stream const& other) = default;
     411              : 
     412              :     /** A MutableBufferSequence consisting of a buffer pair.
     413              :      */
     414              :     using buffers_type =
     415              :         buffers::mutable_buffer_pair;
     416              : 
     417              :     /** Returns the remaining available capacity.
     418              : 
     419              :         The returned value represents the available free
     420              :         space in the backing fixed-sized buffers used by the
     421              :         serializer associated with this stream.
     422              : 
     423              :         The capacity is absolute and does not do any
     424              :         accounting for any octets required by a chunked
     425              :         transfer encoding.
     426              :     */
     427              :     BOOST_HTTP_PROTO_DECL
     428              :     std::size_t
     429              :     capacity() const noexcept;
     430              : 
     431              :     /** Returns the number of octets serialized by this
     432              :         stream.
     433              : 
     434              :         The associated serializer stores stream output in its
     435              :         internal buffers. The stream returns the size of this
     436              :         output.
     437              :     */
     438              :     BOOST_HTTP_PROTO_DECL
     439              :     std::size_t
     440              :     size() const noexcept;
     441              : 
     442              :     /** Return true if the stream cannot currently hold
     443              :         additional output data.
     444              : 
     445              :         The fixed-sized buffers maintained by the associated
     446              :         serializer can be sufficiently full from previous
     447              :         calls to @ref stream::commit.
     448              : 
     449              :         This function can be called to determine if the caller
     450              :         should drain the serializer via @ref serializer::consume calls
     451              :         before attempting to fill the buffer sequence
     452              :         returned from @ref stream::prepare.
     453              :     */
     454              :     BOOST_HTTP_PROTO_DECL
     455              :     bool
     456              :     is_full() const noexcept;
     457              : 
     458              :     /** Returns a MutableBufferSequence for storing
     459              :         serializer input. If `n` bytes are written to the
     460              :         buffer sequence, @ref stream::commit must be called
     461              :         with `n` to update the backing serializer's buffers.
     462              : 
     463              :         The returned buffer sequence is as wide as is
     464              :         possible.
     465              : 
     466              :         @exception std::length_error Thrown if the stream
     467              :         has insufficient capacity and a chunked transfer
     468              :         encoding is being used
     469              :     */
     470              :     BOOST_HTTP_PROTO_DECL
     471              :     buffers_type
     472              :     prepare() const;
     473              : 
     474              :     /** Make `n` bytes available to the serializer.
     475              : 
     476              :         Once the buffer sequence returned from @ref stream::prepare
     477              :         has been filled, the input can be marked as ready
     478              :         for serialization by using this function.
     479              : 
     480              :         @exception std::logic_error Thrown if `commit` is
     481              :         called with 0.
     482              :     */
     483              :     BOOST_HTTP_PROTO_DECL
     484              :     void
     485              :     commit(std::size_t n) const;
     486              : 
     487              :     /** Indicate that no more data is coming and that the
     488              :         body should be treated as complete.
     489              : 
     490              :         @excpeption std::logic_error Thrown if the stream
     491              :         has been previously closed.
     492              :     */
     493              :     BOOST_HTTP_PROTO_DECL
     494              :     void
     495              :     close() const;
     496              : 
     497              : private:
     498              :     friend class serializer;
     499              : 
     500              :     explicit
     501           22 :     stream(
     502              :         serializer& sr) noexcept
     503           22 :         : sr_(&sr)
     504              :     {
     505           22 :     }
     506              : 
     507              :     serializer* sr_ = nullptr;
     508              : };
     509              : 
     510              : //---------------------------------------------------------
     511              : 
     512              : /** A ConstBufferSequence representing the output
     513              : */
     514              : class serializer::
     515              :     const_buffers_type
     516              : {
     517              :     std::size_t n_ = 0;
     518              :     buffers::const_buffer const* p_ = nullptr;
     519              : 
     520              :     friend class serializer;
     521              : 
     522        12568 :     const_buffers_type(
     523              :         buffers::const_buffer const* p,
     524              :         std::size_t n) noexcept
     525        12568 :         : n_(n)
     526        12568 :         , p_(p)
     527              :     {
     528        12568 :     }
     529              : 
     530              : public:
     531              :     using iterator = buffers::const_buffer const*;
     532              :     using const_iterator = iterator;
     533              :     using value_type = buffers::const_buffer;
     534              :     using reference = buffers::const_buffer;
     535              :     using const_reference = buffers::const_buffer;
     536              :     using size_type = std::size_t;
     537              :     using difference_type = std::ptrdiff_t;
     538              : 
     539              :     const_buffers_type() = default;
     540              :     const_buffers_type(
     541              :         const_buffers_type const&) = default;
     542              :     const_buffers_type& operator=(
     543              :         const_buffers_type const&) = default;
     544              : 
     545              :     iterator
     546        51738 :     begin() const noexcept
     547              :     {
     548        51738 :         return p_;
     549              :     }
     550              : 
     551              :     iterator
     552        51738 :     end() const noexcept
     553              :     {
     554        51738 :         return p_ + n_;
     555              :     }
     556              : };
     557              : 
     558              : //------------------------------------------------
     559              : 
     560              : template<
     561              :     class ConstBufferSequence,
     562              :     class>
     563              : void
     564           23 : serializer::
     565              : start(
     566              :     message_view_base const& m,
     567              :     ConstBufferSequence&& body)
     568              : {
     569           23 :     start_init(m);
     570              :     auto const& bs =
     571           23 :         ws_.emplace<ConstBufferSequence>(
     572              :             std::forward<ConstBufferSequence>(body));
     573              : 
     574           23 :     std::size_t n = std::distance(
     575              :         buffers::begin(bs),
     576              :         buffers::end(bs));
     577              : 
     578           23 :     buf_ = make_array(n);
     579           23 :     auto p = buf_.data();
     580          414 :     for(buffers::const_buffer b : buffers::range(bs))
     581          391 :         *p++ = b;
     582              : 
     583           23 :     start_buffers(m);
     584           23 : }
     585              : 
     586              : template<
     587              :     class Source,
     588              :     class... Args,
     589              :     class>
     590              : Source&
     591           24 : serializer::
     592              : start(
     593              :     message_view_base const& m,
     594              :     Args&&... args)
     595              : {
     596              :     static_assert(
     597              :         !std::is_abstract<Source>::value, "");
     598              :     static_assert(
     599              :         std::is_constructible<Source, Args...>::value ||
     600              :         std::is_constructible<Source, buffered_base::allocator&, Args...>::value,
     601              :         "The Source cannot be constructed with the given arguments");
     602              : 
     603           24 :     start_init(m);
     604           24 :     auto& src = construct_source<Source>(
     605              :         std::forward<Args>(args)...);
     606           24 :     start_source(m, std::addressof(src));
     607           24 :     return src;
     608              : }
     609              : 
     610              : //------------------------------------------------
     611              : 
     612              : inline
     613              : auto
     614           96 : serializer::
     615              : make_array(std::size_t n) ->
     616              :     detail::array_of_const_buffers
     617              : {
     618              :     return {
     619           96 :         ws_.push_array(n,
     620           96 :         buffers::const_buffer{}),
     621          192 :         n };
     622              : }
     623              : 
     624              : } // http_proto
     625              : } // boost
     626              : 
     627              : #endif
        

Generated by: LCOV version 2.1