LCOV - code coverage report
Current view: top level - http_proto - parser.hpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 11 11 100.0 %
Date: 2023-12-23 23:40:21 Functions: 4 4 100.0 %

          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_PARSER_HPP
      11             : #define BOOST_HTTP_PROTO_PARSER_HPP
      12             : 
      13             : #include <boost/http_proto/detail/config.hpp>
      14             : #include <boost/http_proto/error.hpp>
      15             : #include <boost/http_proto/header_limits.hpp>
      16             : #include <boost/http_proto/sink.hpp>
      17             : #include <boost/http_proto/detail/header.hpp>
      18             : #include <boost/http_proto/detail/type_traits.hpp>
      19             : #include <boost/http_proto/detail/workspace.hpp>
      20             : #include <boost/buffers/circular_buffer.hpp>
      21             : #include <boost/buffers/flat_buffer.hpp>
      22             : #include <boost/buffers/mutable_buffer_pair.hpp>
      23             : #include <boost/buffers/mutable_buffer_span.hpp>
      24             : #include <boost/buffers/type_traits.hpp>
      25             : #include <boost/buffers/any_dynamic_buffer.hpp>
      26             : #include <boost/url/grammar/error.hpp>
      27             : #include <cstddef>
      28             : #include <cstdint>
      29             : #include <functional>
      30             : #include <memory>
      31             : #include <utility>
      32             : 
      33             : namespace boost {
      34             : namespace http_proto {
      35             : 
      36             : #ifndef BOOST_HTTP_PROTO_DOCS
      37             : class parser_service;
      38             : class filter;
      39             : class request_parser;
      40             : class response_parser;
      41             : class context;
      42             : 
      43             : #endif
      44             : 
      45             : /** A parser for HTTP/1 messages.
      46             : 
      47             :     The parser is strict. Any malformed
      48             :     inputs according to the documented
      49             :     HTTP ABNFs is treated as an
      50             :     unrecoverable error.
      51             : */
      52             : class BOOST_SYMBOL_VISIBLE
      53             :     parser
      54             : {
      55             :     BOOST_HTTP_PROTO_DECL
      56             :     parser(context& ctx, detail::kind);
      57             : 
      58             : public:
      59             :     /** Parser configuration settings
      60             : 
      61             :         @see
      62             :             @li <a href="https://stackoverflow.com/questions/686217/maximum-on-http-header-values"
      63             :                 >Maximum on HTTP header values (Stackoverflow)</a>
      64             :     */
      65             :     struct config_base
      66             :     {
      67             :         header_limits headers;
      68             : 
      69             :         /** Largest allowed size for a content body.
      70             : 
      71             :             The size of the body is measured
      72             :             after removing any transfer encodings,
      73             :             including a chunked encoding.
      74             :         */
      75             :         std::uint64_t body_limit = 64 * 1024;
      76             : 
      77             :         /** True if parser can decode deflate transfer and content encodings.
      78             : 
      79             :             The deflate decoder must already be
      80             :             installed thusly, or else an exception
      81             :             is thrown.
      82             : 
      83             :             @par Install Deflate Decoder
      84             :             @code
      85             :             deflate_decoder_service::config cfg;
      86             :             cfg.install( ctx );
      87             :             @endcode
      88             :         */
      89             :         bool apply_deflate_decoder = false;
      90             : 
      91             :         /** Minimum space for payload buffering.
      92             : 
      93             :             This value controls the following
      94             :             settings:
      95             : 
      96             :             @li The smallest allocated size of
      97             :                 the buffers used for reading
      98             :                 and decoding the payload.
      99             : 
     100             :             @li The lowest guaranteed size of
     101             :                 an in-place body.
     102             : 
     103             :             @li The largest size used to reserve
     104             :                 space in dynamic buffer bodies
     105             :                 when the payload size is not
     106             :                 known ahead of time.
     107             : 
     108             :             This cannot be zero, and this cannot
     109             :             be greater than @ref body_limit.
     110             :         */
     111             :         std::size_t min_buffer = 4096;
     112             : 
     113             :         /** Largest permissible output size in prepare.
     114             : 
     115             :             This cannot be zero.
     116             :         */
     117             :         std::size_t max_prepare = std::size_t(-1);
     118             : 
     119             :         /** Space to reserve for type-erasure.
     120             :         */
     121             :         std::size_t max_type_erase = 1024;
     122             :     };
     123             : 
     124             :     using mutable_buffers_type =
     125             :         buffers::mutable_buffer_span;
     126             : 
     127             :     using const_buffers_type =
     128             :         buffers::const_buffer_span;
     129             : 
     130             :     struct stream;
     131             : 
     132             :     //--------------------------------------------
     133             :     //
     134             :     // Special Members
     135             :     //
     136             :     //--------------------------------------------
     137             : 
     138             :     /** Destructor.
     139             :     */
     140             :     BOOST_HTTP_PROTO_DECL
     141             :     ~parser();
     142             : 
     143             :     /** Constructor (deleted)
     144             :     */
     145             :     parser(parser&&) = delete;
     146             : 
     147             :     /** Assignment (deleted)
     148             :     */
     149             :     parser& operator=(parser&&) = delete;
     150             : 
     151             :     //--------------------------------------------
     152             :     //
     153             :     // Observers
     154             :     //
     155             :     //--------------------------------------------
     156             : 
     157             : #if 0
     158             :     /** Return true if any input was committed.
     159             :     */
     160             :     bool
     161             :     got_some() const noexcept
     162             :     {
     163             :         return st_ != state::need_start;
     164             :     }
     165             : #endif
     166             : 
     167             :     /** Return true if the complete header was parsed.
     168             :     */
     169             :     bool
     170        2694 :     got_header() const noexcept
     171             :     {
     172        2694 :         return st_ > state::header;
     173             :     }
     174             : 
     175             :     /** Returns `true` if a complete message has been parsed.
     176             : 
     177             :         Calling @ref reset prepares the parser
     178             :         to process the next message in the stream.
     179             : 
     180             :     */
     181             :     bool
     182        2249 :     is_complete() const noexcept
     183             :     {
     184        2249 :         return st_ == state::complete;
     185             :     }
     186             : 
     187             :     /** Returns `true` if the end of the stream was reached.
     188             : 
     189             :         The end of the stream is encountered
     190             :         when one of the following conditions
     191             :         occurs:
     192             : 
     193             :         @li @ref commit_eof was called and there
     194             :             is no more data left to parse, or
     195             : 
     196             :         @li An unrecoverable error occurred
     197             :             during parsing.
     198             : 
     199             :         When the end of stream is reached, the
     200             :             function @ref reset must be called
     201             :             to start parsing a new stream.
     202             :     */
     203             :     bool
     204         714 :     is_end_of_stream() const noexcept
     205             :     {
     206             :         return
     207        1296 :             st_ == state::reset ||
     208         582 :             (   st_ == state::complete &&
     209        1296 :                 got_eof_);
     210             :     }
     211             : 
     212             :     //--------------------------------------------
     213             :     //
     214             :     // Modifiers
     215             :     //
     216             :     //--------------------------------------------
     217             : 
     218             :     /** Prepare for a new stream.
     219             :     */
     220             :     BOOST_HTTP_PROTO_DECL
     221             :     void
     222             :     reset() noexcept;
     223             : 
     224             :     /** Prepare for the next message on the stream.
     225             :     */
     226             :     void
     227        1488 :     start()
     228             :     {
     229        1488 :         start_impl(false);
     230        1483 :     }
     231             : 
     232             : private:
     233             :     // New message on the current stream
     234             :     BOOST_HTTP_PROTO_DECL void
     235             :         start_impl(bool head_response);
     236             : public:
     237             : 
     238             :     /** Return the input buffer
     239             :     */
     240             :     BOOST_HTTP_PROTO_DECL
     241             :     mutable_buffers_type
     242             :     prepare();
     243             : 
     244             :     /** Commit bytes to the input buffer
     245             :     */
     246             :     BOOST_HTTP_PROTO_DECL
     247             :     void
     248             :     commit(
     249             :         std::size_t n);
     250             : 
     251             :     /** Indicate there will be no more input
     252             : 
     253             :         @par Postconditions
     254             :         All buffer sequences previously obtained
     255             :         by calling @ref prepare are invalidated.
     256             :     */
     257             :     BOOST_HTTP_PROTO_DECL
     258             :     void
     259             :     commit_eof();
     260             : 
     261             :     /** Parse pending input data
     262             :     */
     263             :     // VFALCO return result<void>?
     264             :     BOOST_HTTP_PROTO_DECL
     265             :     void
     266             :     parse(
     267             :         system::error_code& ec);
     268             : 
     269             :     /** Attach a body.
     270             : 
     271             :         This function attaches the specified elastic
     272             :         buffer as the storage for the message body.
     273             :         The parser acquires ownership of the object
     274             :         `eb` and destroys it when:
     275             : 
     276             :         @li @ref is_complete returns `true`, or
     277             :         @li @ref reset is called, or
     278             :         @li an unrecoverable parsing error occurs, or
     279             :         @li the parser is destroyed.
     280             :     */
     281             :     // VFALCO Should this function have
     282             :     //        error_code& ec and call parse?
     283             :     template<class ElasticBuffer>
     284             : #ifndef BOOST_HTTP_PROTO_DOCS
     285             :     typename std::enable_if<
     286             :         ! detail::is_reference_wrapper<
     287             :             ElasticBuffer>::value &&
     288             :         ! is_sink<ElasticBuffer>::value>::type
     289             : #else
     290             :     void
     291             : #endif
     292             :     set_body(ElasticBuffer&& eb);
     293             : 
     294             :     /** Attach a body.
     295             : 
     296             :         This function attaches the specified elastic
     297             :         buffer reference as the storage for the message body.
     298             :         Ownership is not transferred; the caller must
     299             :         ensure that the lifetime of the object
     300             :         reference by `eb` extends until:
     301             : 
     302             :         @li @ref is_complete returns `true`, or
     303             :         @li @ref reset is called, or
     304             :         @li an unrecoverable parsing error occurs, or
     305             :         @li the parser is destroyed.
     306             :     */
     307             :     template<class ElasticBuffer>
     308             :     void set_body(
     309             :         std::reference_wrapper<ElasticBuffer> eb);
     310             : 
     311             :     /** Attach a body
     312             :     */
     313             :     template<class Sink>
     314             : #ifndef BOOST_HTTP_PROTO_DOCS
     315             :     typename std::enable_if<
     316             :             is_sink<Sink>::value,
     317             :         typename std::decay<Sink>::type
     318             :             >::type&
     319             : #else
     320             :     typename std::decay<Sink>::type&
     321             : #endif
     322             :     set_body(Sink&& sink);
     323             : 
     324             :     /** Return the available body data and consume it.
     325             : 
     326             :         The buffer referenced by the string view
     327             :         will be invalidated if any member function
     328             :         of the parser is called.
     329             :     */
     330             :     BOOST_HTTP_PROTO_DECL
     331             :     const_buffers_type
     332             :     pull_some();
     333             : 
     334             :     /** Return the complete body as a contiguous character buffer.
     335             :     */
     336             :     BOOST_HTTP_PROTO_DECL
     337             :     core::string_view
     338             :     body() const noexcept;
     339             : 
     340             :     //--------------------------------------------
     341             : 
     342             :     /** Return any leftover data
     343             : 
     344             :         This is used to forward unconsumed data
     345             :         that could lie past the last message.
     346             :         For example on a CONNECT request there
     347             :         could be additional protocol-dependent
     348             :         data that we want to retrieve.
     349             :     */
     350             :     // VFALCO rename to get_leftovers()?
     351             :     BOOST_HTTP_PROTO_DECL
     352             :     core::string_view
     353             :     release_buffered_data() noexcept;
     354             : 
     355             : private:
     356             :     friend class request_parser;
     357             :     friend class response_parser;
     358             : 
     359             :     detail::header const*
     360             :         safe_get_header() const;
     361             :     bool is_plain() const noexcept;
     362             :     void on_headers(system::error_code&);
     363             :     BOOST_HTTP_PROTO_DECL void on_set_body();
     364             :     void init_dynamic(system::error_code&);
     365             : 
     366             :     static constexpr unsigned buffers_N = 8;
     367             : 
     368             :     enum class state
     369             :     {
     370             :         // order matters
     371             :         reset,
     372             :         start,
     373             :         header,
     374             :         body,
     375             :         set_body,
     376             :         complete
     377             :     };
     378             : 
     379             :     enum class how
     380             :     {
     381             :         in_place,
     382             :         dynamic,
     383             :         sink,
     384             :         pull
     385             :     };
     386             : 
     387             :     context& ctx_;
     388             :     parser_service& svc_;
     389             :     detail::workspace ws_;
     390             :     detail::header h_;
     391             :     std::uint64_t body_avail_;
     392             :     std::uint64_t body_total_;
     393             :     std::uint64_t payload_remain_;
     394             :     std::size_t nprepare_;
     395             : 
     396             :     buffers::flat_buffer fb_;
     397             :     buffers::circular_buffer cb0_;
     398             :     buffers::circular_buffer cb1_;
     399             :     buffers::circular_buffer* body_buf_;
     400             :     buffers::mutable_buffer_pair mbp_;
     401             :     buffers::any_dynamic_buffer* dyn_;
     402             :     filter* filt_;
     403             :     sink* sink_;
     404             : 
     405             :     state st_;
     406             :     how how_;
     407             :     bool got_eof_;
     408             : //    bool need_more_;
     409             :     bool head_response_;
     410             : };
     411             : 
     412             : //------------------------------------------------
     413             : 
     414             : /** Install the parser service.
     415             : */
     416             : BOOST_HTTP_PROTO_DECL
     417             : void
     418             : install_parser_service(
     419             :     context& ctx,
     420             :     parser::config_base const& cfg);
     421             : 
     422             : } // http_proto
     423             : } // boost
     424             : 
     425             : #include <boost/http_proto/impl/parser.hpp>
     426             : 
     427             : #endif

Generated by: LCOV version 1.15