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 % 39 39
Test Date: 2024-06-05 19:28:02 Functions: 100.0 % 16 16

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

Generated by: LCOV version 2.1