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

Generated by: LCOV version 2.1