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

Generated by: LCOV version 1.15