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

Generated by: LCOV version 2.1