LCOV - code coverage report
Current view: top level - boost/http_proto - serializer.hpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 37 38 97.4 %
Date: 2024-04-23 10:22:13 Functions: 16 17 94.1 %

          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             : class BOOST_SYMBOL_VISIBLE
      46           0 :     serializer
      47             : {
      48             : public:
      49             :     /** A ConstBuffers representing the output
      50             :     */
      51             :     class const_buffers_type;
      52             : 
      53             :     struct stream;
      54             : 
      55             :     /** Destructor
      56             :     */
      57             :     BOOST_HTTP_PROTO_DECL
      58             :     ~serializer();
      59             : 
      60             :     /** Constructor
      61             :     */
      62             :     BOOST_HTTP_PROTO_DECL
      63             :     serializer();
      64             : 
      65             :     /** Constructor
      66             :     */
      67             :     BOOST_HTTP_PROTO_DECL
      68             :     serializer(
      69             :         serializer&&) noexcept;
      70             : 
      71             :     /** Constructor
      72             :     */
      73             :     BOOST_HTTP_PROTO_DECL
      74             :     explicit
      75             :     serializer(
      76             :         std::size_t buffer_size);
      77             : 
      78             :     //--------------------------------------------
      79             : 
      80             :     /** Prepare the serializer for a new stream
      81             :     */
      82             :     BOOST_HTTP_PROTO_DECL
      83             :     void
      84             :     reset() noexcept;
      85             : 
      86             :     /** Prepare the serializer for a new message
      87             : 
      88             :         The message will not contain a body.
      89             :         Changing the contents of the message
      90             :         after calling this function and before
      91             :         @ref is_done returns `true` results in
      92             :         undefined behavior.
      93             :     */
      94             :     void
      95           4 :     start(
      96             :         message_view_base const& m)
      97             :     {
      98           4 :         start_empty(m);
      99           4 :     }
     100             : 
     101             :     /** Prepare the serializer for a new message
     102             : 
     103             :         Changing the contents of the message
     104             :         after calling this function and before
     105             :         @ref is_done returns `true` results in
     106             :         undefined behavior.
     107             : 
     108             :         @par Constraints
     109             :         @code
     110             :         is_const_buffers< ConstBuffers >::value == true
     111             :         @endcode
     112             :     */
     113             :     template<
     114             :         class ConstBufferSequence
     115             : #ifndef BOOST_HTTP_PROTO_DOCS
     116             :         ,class = typename
     117             :             std::enable_if<
     118             :                 buffers::is_const_buffer_sequence<
     119             :                     ConstBufferSequence>::value
     120             :                         >::type
     121             : #endif
     122             :     >
     123             :     void
     124             :     start(
     125             :         message_view_base const& m,
     126             :         ConstBufferSequence&& body);
     127             : 
     128             :     /** Prepare the serializer for a new message
     129             : 
     130             :         Changing the contents of the message
     131             :         after calling this function and before
     132             :         @ref is_done returns `true` results in
     133             :         undefined behavior.
     134             :     */
     135             :     template<
     136             :         class Source,
     137             :         class... Args
     138             : #ifndef BOOST_HTTP_PROTO_DOCS
     139             :         ,class = typename std::enable_if<
     140             :             is_source<Source>::value>::type
     141             : #endif
     142             :     >
     143             :     Source&
     144             :     start(
     145             :         message_view_base const& m,
     146             :         Args&&... args);
     147             : 
     148             :     //--------------------------------------------
     149             : 
     150             :     BOOST_HTTP_PROTO_DECL
     151             :     stream
     152             :     start_stream(
     153             :         message_view_base const& m);
     154             : 
     155             :     //--------------------------------------------
     156             : 
     157             :     /** Return true if serialization is complete.
     158             :     */
     159             :     bool
     160          78 :     is_done() const noexcept
     161             :     {
     162          78 :         return is_done_;
     163             :     }
     164             : 
     165             :     /** Return the output area.
     166             : 
     167             :         This function will serialize some or
     168             :         all of the content and return the
     169             :         corresponding output buffers.
     170             : 
     171             :         @par Preconditions
     172             :         @code
     173             :         this->is_done() == false
     174             :         @endcode
     175             :     */
     176             :     BOOST_HTTP_PROTO_DECL
     177             :     auto
     178             :     prepare() ->
     179             :         system::result<
     180             :             const_buffers_type>;
     181             : 
     182             :     /** Consume bytes from the output area.
     183             :     */
     184             :     BOOST_HTTP_PROTO_DECL
     185             :     void
     186             :     consume(std::size_t n);
     187             : 
     188             : private:
     189             :     static void copy(
     190             :         buffers::const_buffer*,
     191             :         buffers::const_buffer const*,
     192             :         std::size_t n) noexcept;
     193             :     auto
     194             :     make_array(std::size_t n) ->
     195             :         detail::array_of_const_buffers;
     196             : 
     197             :     template<
     198             :         class Source,
     199             :         class... Args,
     200             :         typename std::enable_if<
     201             :             std::is_constructible<
     202             :                 Source,
     203             :                 Args...>::value>::type* = nullptr>
     204             :     Source&
     205           8 :     construct_source(Args&&... args)
     206             :     {
     207             :         return ws_.emplace<Source>(
     208           8 :             std::forward<Args>(args)...);
     209             :     }
     210             : 
     211             :     template<
     212             :         class Source,
     213             :         class... Args,
     214             :         typename std::enable_if<
     215             :             std::is_constructible<
     216             :                 Source,
     217             :                 buffered_base::allocator&,
     218             :                 Args...>::value>::type* = nullptr>
     219             :     Source&
     220             :     construct_source(Args&&... args)
     221             :     {
     222             :         buffered_base::allocator a(
     223             :             ws_.data(),
     224             :             (ws_.size() - ws_.space_needed<Source>()) / 2,
     225             :             false);
     226             :         auto& src = ws_.emplace<Source>(
     227             :             a, std::forward<Args>(args)...);
     228             :         ws_.reserve_front(a.size_used());
     229             :         return src;
     230             :     }
     231             : 
     232             :     BOOST_HTTP_PROTO_DECL void start_init(message_view_base const&);
     233             :     BOOST_HTTP_PROTO_DECL void start_empty(message_view_base const&);
     234             :     BOOST_HTTP_PROTO_DECL void start_buffers(message_view_base const&);
     235             :     BOOST_HTTP_PROTO_DECL void start_source(message_view_base const&, source*);
     236             : 
     237             :     enum class style
     238             :     {
     239             :         empty,
     240             :         buffers,
     241             :         source,
     242             :         stream
     243             :     };
     244             : 
     245             :     // chunked-body   = *chunk
     246             :     //                  last-chunk
     247             :     //                  trailer-section
     248             :     //                  CRLF
     249             : 
     250             :     static
     251             :     constexpr
     252             :     std::size_t
     253             :     crlf_len_ = 2;
     254             : 
     255             :     // chunk          = chunk-size [ chunk-ext ] CRLF
     256             :     //                  chunk-data CRLF
     257             :     static
     258             :     constexpr
     259             :     std::size_t
     260             :     chunk_header_len_ =
     261             :         16 + // 16 hex digits => 64 bit number
     262             :         crlf_len_;
     263             : 
     264             :     // last-chunk     = 1*("0") [ chunk-ext ] CRLF
     265             :     static
     266             :     constexpr
     267             :     std::size_t
     268             :     last_chunk_len_ =
     269             :         1 + // "0"
     270             :         crlf_len_ +
     271             :         crlf_len_; // chunked-body termination requires an extra CRLF
     272             : 
     273             :     static
     274             :     constexpr
     275             :     std::size_t
     276             :     chunked_overhead_ =
     277             :         chunk_header_len_ +
     278             :         crlf_len_ + // closing chunk data
     279             :         last_chunk_len_;
     280             : 
     281             :     detail::workspace ws_;
     282             :     detail::array_of_const_buffers buf_;
     283             :     source* src_;
     284             : 
     285             :     buffers::circular_buffer tmp0_;
     286             :     buffers::circular_buffer tmp1_;
     287             :     detail::array_of_const_buffers out_;
     288             : 
     289             :     buffers::const_buffer* hp_;  // header
     290             : 
     291             :     style st_;
     292             :     bool more_;
     293             :     bool is_done_;
     294             :     bool is_chunked_;
     295             :     bool is_expect_continue_;
     296             : };
     297             : 
     298             : //------------------------------------------------
     299             : 
     300             : struct serializer::stream
     301             : {
     302             :     /** Constructor.
     303             :     */
     304             :     stream() = default;
     305             : 
     306             :     /** Constructor.
     307             :     */
     308             :     stream(stream const&) = default;
     309             : 
     310             :     /** Constructor.
     311             :     */
     312             :     stream& operator=
     313             :         (stream const&) = default;
     314             : 
     315             :     using buffers_type =
     316             :         buffers::mutable_buffer_pair;
     317             : 
     318             :     BOOST_HTTP_PROTO_DECL
     319             :     std::size_t
     320             :     capacity() const noexcept;
     321             : 
     322             :     BOOST_HTTP_PROTO_DECL
     323             :     std::size_t
     324             :     size() const noexcept;
     325             : 
     326             :     BOOST_HTTP_PROTO_DECL
     327             :     bool
     328             :     is_full() const noexcept;
     329             : 
     330             :     BOOST_HTTP_PROTO_DECL
     331             :     buffers_type
     332             :     prepare() const;
     333             : 
     334             :     BOOST_HTTP_PROTO_DECL
     335             :     void
     336             :     commit(std::size_t n) const;
     337             : 
     338             :     BOOST_HTTP_PROTO_DECL
     339             :     void
     340             :     close() const;
     341             : 
     342             : private:
     343             :     friend class serializer;
     344             : 
     345             :     explicit
     346           7 :     stream(
     347             :         serializer& sr) noexcept
     348           7 :         : sr_(&sr)
     349             :     {
     350           7 :     }
     351             : 
     352             :     serializer* sr_ = nullptr;
     353             : };
     354             : 
     355             : //---------------------------------------------------------
     356             : 
     357             : class serializer::
     358             :     const_buffers_type
     359             : {
     360             :     std::size_t n_ = 0;
     361             :     buffers::const_buffer const* p_ = nullptr;
     362             : 
     363             :     friend class serializer;
     364             : 
     365          63 :     const_buffers_type(
     366             :         buffers::const_buffer const* p,
     367             :         std::size_t n) noexcept
     368          63 :         : n_(n)
     369          63 :         , p_(p)
     370             :     {
     371          63 :     }
     372             : 
     373             : public:
     374             :     using iterator = buffers::const_buffer const*;
     375             :     using const_iterator = iterator;
     376             :     using value_type = buffers::const_buffer;
     377             :     using reference = buffers::const_buffer;
     378             :     using const_reference = buffers::const_buffer;
     379             :     using size_type = std::size_t;
     380             :     using difference_type = std::ptrdiff_t;
     381             : 
     382             :     const_buffers_type() = default;
     383             :     const_buffers_type(
     384             :         const_buffers_type const&) = default;
     385             :     const_buffers_type& operator=(
     386             :         const_buffers_type const&) = default;
     387             : 
     388             :     iterator
     389         126 :     begin() const noexcept
     390             :     {
     391         126 :         return p_;
     392             :     }
     393             : 
     394             :     iterator
     395         126 :     end() const noexcept
     396             :     {
     397         126 :         return p_ + n_;
     398             :     }
     399             : };
     400             : 
     401             : //------------------------------------------------
     402             : 
     403             : template<
     404             :     class ConstBufferSequence,
     405             :     class>
     406             : void
     407           7 : serializer::
     408             : start(
     409             :     message_view_base const& m,
     410             :     ConstBufferSequence&& body)
     411             : {
     412           7 :     start_init(m);
     413           7 :     auto const& bs =
     414             :         ws_.emplace<ConstBufferSequence>(
     415             :             std::forward<ConstBufferSequence>(body));
     416           7 :     std::size_t n = std::distance(
     417             :         buffers::begin(bs),
     418             :         buffers::end(bs));
     419           7 :     buf_ = make_array(n);
     420           7 :     auto p = buf_.data();
     421          14 :     for(buffers::const_buffer b :
     422           7 :             buffers::range(bs))
     423           7 :         *p++ = b;
     424           7 :     start_buffers(m);
     425           7 : }
     426             : 
     427             : template<
     428             :     class Source,
     429             :     class... Args,
     430             :     class>
     431             : Source&
     432           8 : serializer::
     433             : start(
     434             :     message_view_base const& m,
     435             :     Args&&... args)
     436             : {
     437             :     static_assert(
     438             :         std::is_constructible<Source, Args...>::value ||
     439             :         std::is_constructible<Source, buffered_base::allocator&, Args...>::value,
     440             :         "The Source cannot be constructed with the given arguments");
     441             : 
     442           8 :     start_init(m);
     443           8 :     auto& src = construct_source<Source>(
     444             :         std::forward<Args>(args)...);
     445           8 :     start_source(m, std::addressof(src));
     446           8 :     return src;
     447             : }
     448             : 
     449             : //------------------------------------------------
     450             : 
     451             : inline
     452             : auto
     453          33 : serializer::
     454             : make_array(std::size_t n) ->
     455             :     detail::array_of_const_buffers
     456             : {
     457             :     return {
     458             :         ws_.push_array(n,
     459          66 :         buffers::const_buffer{}),
     460          33 :         n };
     461             : }
     462             : 
     463             : } // http_proto
     464             : } // boost
     465             : 
     466             : #endif

Generated by: LCOV version 1.15