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-09-20 16:11:51 Functions: 100.0 % 4 4

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

Generated by: LCOV version 2.1