LCOV - code coverage report
Current view: top level - boost/http_proto/parser.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 11 11
Test Date: 2024-12-31 05:34:48 Functions: 100.0 % 4 4

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

Generated by: LCOV version 2.1