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-04 20:17:10 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          88 :     is_done() const noexcept
     161             :     {
     162          88 :         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             :     // chunk          = chunk-size [ chunk-ext ] CRLF
     251             :     //                  chunk-data CRLF
     252             :     static
     253             :     constexpr
     254             :     std::size_t
     255             :     chunk_header_len_ = 16 + 2; // chunk-size + CRLF
     256             : 
     257             :     // last-chunk     = 1*("0") [ chunk-ext ] CRLF
     258             :     static
     259             :     constexpr
     260             :     std::size_t
     261             :     last_chunk_len_ = 1 + 2 + 2; // chunked-body termination requires an extra CRLF
     262             : 
     263             :     static
     264             :     constexpr
     265             :     std::size_t
     266             :     chunked_overhead_ =
     267             :         chunk_header_len_ +
     268             :         2 + // CRLF
     269             :         last_chunk_len_;
     270             : 
     271             :     detail::workspace ws_;
     272             :     detail::array_of_const_buffers buf_;
     273             :     source* src_;
     274             : 
     275             :     buffers::circular_buffer tmp0_;
     276             :     buffers::circular_buffer tmp1_;
     277             :     detail::array_of_const_buffers out_;
     278             : 
     279             :     buffers::const_buffer* hp_;  // header
     280             : 
     281             :     style st_;
     282             :     bool more_;
     283             :     bool is_done_;
     284             :     bool is_chunked_;
     285             :     bool is_expect_continue_;
     286             : };
     287             : 
     288             : //------------------------------------------------
     289             : 
     290             : struct serializer::stream
     291             : {
     292             :     /** Constructor.
     293             :     */
     294             :     stream() = default;
     295             : 
     296             :     /** Constructor.
     297             :     */
     298             :     stream(stream const&) = default;
     299             : 
     300             :     /** Constructor.
     301             :     */
     302             :     stream& operator=
     303             :         (stream const&) = default;
     304             : 
     305             :     using buffers_type =
     306             :         buffers::mutable_buffer_pair;
     307             : 
     308             :     BOOST_HTTP_PROTO_DECL
     309             :     std::size_t
     310             :     capacity() const;
     311             : 
     312             :     BOOST_HTTP_PROTO_DECL
     313             :     std::size_t
     314             :     size() const;
     315             : 
     316             :     BOOST_HTTP_PROTO_DECL
     317             :     buffers_type
     318             :     prepare(std::size_t n) const;
     319             : 
     320             :     BOOST_HTTP_PROTO_DECL
     321             :     void
     322             :     commit(std::size_t n) const;
     323             : 
     324             :     BOOST_HTTP_PROTO_DECL
     325             :     void
     326             :     close() const;
     327             : 
     328             : private:
     329             :     friend class serializer;
     330             : 
     331             :     explicit
     332           6 :     stream(
     333             :         serializer& sr) noexcept
     334           6 :         : sr_(&sr)
     335             :     {
     336           6 :     }
     337             : 
     338             :     serializer* sr_ = nullptr;
     339             : };
     340             : 
     341             : //---------------------------------------------------------
     342             : 
     343             : class serializer::
     344             :     const_buffers_type
     345             : {
     346             :     std::size_t n_ = 0;
     347             :     buffers::const_buffer const* p_ = nullptr;
     348             : 
     349             :     friend class serializer;
     350             : 
     351          74 :     const_buffers_type(
     352             :         buffers::const_buffer const* p,
     353             :         std::size_t n) noexcept
     354          74 :         : n_(n)
     355          74 :         , p_(p)
     356             :     {
     357          74 :     }
     358             : 
     359             : public:
     360             :     using iterator = buffers::const_buffer const*;
     361             :     using const_iterator = iterator;
     362             :     using value_type = buffers::const_buffer;
     363             :     using reference = buffers::const_buffer;
     364             :     using const_reference = buffers::const_buffer;
     365             :     using size_type = std::size_t;
     366             :     using difference_type = std::ptrdiff_t;
     367             : 
     368             :     const_buffers_type() = default;
     369             :     const_buffers_type(
     370             :         const_buffers_type const&) = default;
     371             :     const_buffers_type& operator=(
     372             :         const_buffers_type const&) = default;
     373             : 
     374             :     iterator
     375         148 :     begin() const noexcept
     376             :     {
     377         148 :         return p_;
     378             :     }
     379             : 
     380             :     iterator
     381         148 :     end() const noexcept
     382             :     {
     383         148 :         return p_ + n_;
     384             :     }
     385             : };
     386             : 
     387             : //------------------------------------------------
     388             : 
     389             : template<
     390             :     class ConstBufferSequence,
     391             :     class>
     392             : void
     393           7 : serializer::
     394             : start(
     395             :     message_view_base const& m,
     396             :     ConstBufferSequence&& body)
     397             : {
     398           7 :     start_init(m);
     399           7 :     auto const& bs =
     400             :         ws_.emplace<ConstBufferSequence>(
     401             :             std::forward<ConstBufferSequence>(body));
     402           7 :     std::size_t n = std::distance(
     403             :         buffers::begin(bs),
     404             :         buffers::end(bs));
     405           7 :     buf_ = make_array(n);
     406           7 :     auto p = buf_.data();
     407          14 :     for(buffers::const_buffer b :
     408           7 :             buffers::range(bs))
     409           7 :         *p++ = b;
     410           7 :     start_buffers(m);
     411           7 : }
     412             : 
     413             : template<
     414             :     class Source,
     415             :     class... Args,
     416             :     class>
     417             : Source&
     418           8 : serializer::
     419             : start(
     420             :     message_view_base const& m,
     421             :     Args&&... args)
     422             : {
     423             :     static_assert(
     424             :         std::is_constructible<Source, Args...>::value ||
     425             :         std::is_constructible<Source, buffered_base::allocator&, Args...>::value,
     426             :         "The Source cannot be constructed with the given arguments");
     427             : 
     428           8 :     start_init(m);
     429           8 :     auto& src = construct_source<Source>(
     430             :         std::forward<Args>(args)...);
     431           8 :     start_source(m, std::addressof(src));
     432           8 :     return src;
     433             : }
     434             : 
     435             : //------------------------------------------------
     436             : 
     437             : inline
     438             : auto
     439          32 : serializer::
     440             : make_array(std::size_t n) ->
     441             :     detail::array_of_const_buffers
     442             : {
     443             :     return {
     444             :         ws_.push_array(n,
     445          64 :         buffers::const_buffer{}),
     446          32 :         n };
     447             : }
     448             : 
     449             : } // http_proto
     450             : } // boost
     451             : 
     452             : #endif

Generated by: LCOV version 1.15