Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-31 08:34:26

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
0008 //
0009 
0010 #ifndef BOOST_BEAST_HTTP_PARSER_HPP
0011 #define BOOST_BEAST_HTTP_PARSER_HPP
0012 
0013 #include <boost/beast/http/parser_fwd.hpp>
0014 
0015 #include <boost/beast/core/detail/config.hpp>
0016 #include <boost/beast/http/basic_parser.hpp>
0017 #include <boost/beast/http/message.hpp>
0018 #include <boost/beast/http/type_traits.hpp>
0019 #include <boost/optional.hpp>
0020 #include <boost/throw_exception.hpp>
0021 #include <cstdint>
0022 #include <functional>
0023 #include <memory>
0024 #include <type_traits>
0025 #include <utility>
0026 
0027 namespace boost {
0028 namespace beast {
0029 namespace http {
0030 
0031 /** An HTTP/1 parser for producing a message.
0032 
0033     This class uses the basic HTTP/1 wire format parser to convert
0034     a series of octets into a @ref message using the @ref basic_fields
0035     container to represent the fields.
0036 
0037     @tparam isRequest Indicates whether a request or response
0038     will be parsed.
0039 
0040     @tparam Body The type used to represent the body. This must
0041     meet the requirements of <em>Body</em>.
0042 
0043     @tparam Allocator The type of allocator used with the
0044     @ref basic_fields container.
0045 
0046     @note A new instance of the parser is required for each message.
0047 */
0048 #if BOOST_BEAST_DOXYGEN
0049 template<
0050     bool isRequest,
0051     class Body,
0052     class Allocator = std::allocator<char>>
0053 #else
0054 template<
0055     bool isRequest,
0056     class Body,
0057     class Allocator>
0058 #endif
0059 class parser
0060     : public basic_parser<isRequest>
0061 {
0062     static_assert(is_body<Body>::value,
0063         "Body type requirements not met");
0064 
0065     static_assert(is_body_reader<Body>::value,
0066         "BodyReader type requirements not met");
0067 
0068     template<bool, class, class>
0069     friend class parser;
0070 
0071     message<isRequest, Body, basic_fields<Allocator>> m_;
0072     typename Body::reader rd_;
0073     bool rd_inited_ = false;
0074     bool used_ = false;
0075 
0076     std::function<void(
0077         std::uint64_t,
0078         string_view,
0079         error_code&)> cb_h_;
0080 
0081     std::function<std::size_t(
0082         std::uint64_t,
0083         string_view,
0084         error_code&)> cb_b_;
0085 
0086 public:
0087     /// The type of message returned by the parser
0088     using value_type =
0089         message<isRequest, Body, basic_fields<Allocator>>;
0090 
0091     /// Destructor
0092     ~parser() = default;
0093 
0094     /// Constructor (disallowed)
0095     parser(parser const&) = delete;
0096 
0097     /// Assignment (disallowed)
0098     parser& operator=(parser const&) = delete;
0099 
0100     /// Constructor (disallowed)
0101     parser(parser&& other) = delete;
0102 
0103     /// Constructor
0104     parser();
0105 
0106     /** Constructor
0107 
0108         @param args Optional arguments forwarded to the 
0109         @ref http::message constructor.
0110 
0111         @note This function participates in overload
0112         resolution only if the first argument is not a
0113         @ref parser.
0114     */
0115 #if BOOST_BEAST_DOXYGEN
0116     template<class... Args>
0117     explicit
0118     parser(Args&&... args);
0119 #else
0120     template<class Arg1, class... ArgN,
0121         class = typename std::enable_if<
0122             ! detail::is_parser<typename
0123                 std::decay<Arg1>::type>::value>::type>
0124     explicit
0125     parser(Arg1&& arg1, ArgN&&... argn);
0126 #endif
0127 
0128     /** Construct a parser from another parser, changing the Body type.
0129 
0130         This constructs a new parser by move constructing the
0131         header from another parser with a different body type. The
0132         constructed-from parser must not have any parsed body octets or
0133         initialized <em>BodyReader</em>, otherwise an exception is generated.
0134 
0135         @par Example
0136         @code
0137         // Deferred body type commitment
0138         request_parser<empty_body> req0;
0139         ...
0140         request_parser<string_body> req{std::move(req0)};
0141         @endcode
0142 
0143         If an exception is thrown, the state of the constructed-from
0144         parser is undefined.
0145 
0146         @param parser The other parser to construct from. After
0147         this call returns, the constructed-from parser may only
0148         be destroyed.
0149 
0150         @param args Optional arguments forwarded to the message
0151         constructor.
0152 
0153         @throws std::invalid_argument Thrown when the constructed-from
0154         parser has already initialized a body reader.
0155 
0156         @note This function participates in overload resolution only
0157         if the other parser uses a different body type.
0158     */
0159 #if BOOST_BEAST_DOXYGEN
0160     template<class OtherBody, class... Args>
0161 #else
0162     template<class OtherBody, class... Args,
0163         class = typename std::enable_if<
0164             ! std::is_same<Body, OtherBody>::value>::type>
0165 #endif
0166     explicit
0167     parser(parser<isRequest, OtherBody,
0168         Allocator>&& parser, Args&&... args);
0169 
0170     /** Returns the parsed message.
0171 
0172         Depending on the parser's progress,
0173         parts of this object may be incomplete.
0174     */
0175     value_type const&
0176     get() const
0177     {
0178         return m_;
0179     }
0180 
0181     /** Returns the parsed message.
0182 
0183         Depending on the parser's progress,
0184         parts of this object may be incomplete.
0185     */
0186     value_type&
0187     get()
0188     {
0189         return m_;
0190     }
0191 
0192     /** Returns ownership of the parsed message.
0193 
0194         Ownership is transferred to the caller.
0195         Depending on the parser's progress,
0196         parts of this object may be incomplete.
0197 
0198         @par Requires
0199 
0200         @ref value_type is @b MoveConstructible
0201     */
0202     value_type
0203     release()
0204     {
0205         static_assert(std::is_move_constructible<decltype(m_)>::value,
0206             "MoveConstructible requirements not met");
0207         return std::move(m_);
0208     }
0209 
0210     /** Set a callback to be invoked on each chunk header.
0211 
0212         The callback will be invoked once for every chunk in the message
0213         payload, as well as once for the last chunk. The invocation 
0214         happens after the chunk header is available but before any body
0215         octets have been parsed.
0216 
0217         The extensions are provided in raw, validated form, use
0218         @ref chunk_extensions::parse to parse the extensions into a
0219         structured container for easier access.
0220         The implementation type-erases the callback without requiring
0221         a dynamic allocation. For this reason, the callback object is
0222         passed by a non-constant reference.
0223 
0224         @par Example
0225         @code
0226         auto callback =
0227             [](std::uint64_t size, string_view extensions, error_code& ec)
0228             {
0229                 //...
0230             };
0231         parser.on_chunk_header(callback);
0232         @endcode
0233 
0234         @param cb The function to set, which must be invocable with
0235         this equivalent signature:
0236         @code
0237         void
0238         on_chunk_header(
0239             std::uint64_t size,         // Size of the chunk, zero for the last chunk
0240             string_view extensions,     // The chunk-extensions in raw form
0241             error_code& ec);            // May be set by the callback to indicate an error
0242         @endcode
0243     */
0244     template<class Callback>
0245     void
0246     on_chunk_header(Callback& cb)
0247     {
0248         // Callback may not be constant, caller is responsible for
0249         // managing the lifetime of the callback. Copies are not made.
0250         BOOST_STATIC_ASSERT(! std::is_const<Callback>::value);
0251 
0252         // Can't set the callback after receiving any chunk data!
0253         BOOST_ASSERT(! rd_inited_);
0254 
0255         cb_h_ = std::ref(cb);
0256     }
0257 
0258     /** Set a callback to be invoked on chunk body data
0259 
0260         The provided function object will be invoked one or more times
0261         to provide buffers corresponding to the chunk body for the current
0262         chunk. The callback receives the number of octets remaining in this
0263         chunk body including the octets in the buffer provided.
0264 
0265         The callback must return the number of octets actually consumed.
0266         Any octets not consumed will be presented again in a subsequent
0267         invocation of the callback.
0268         The implementation type-erases the callback without requiring
0269         a dynamic allocation. For this reason, the callback object is
0270         passed by a non-constant reference.
0271 
0272         @par Example
0273         @code
0274         auto callback =
0275             [](std::uint64_t remain, string_view body, error_code& ec)
0276             {
0277                 //...
0278             };
0279         parser.on_chunk_body(callback);
0280         @endcode
0281 
0282         @param cb The function to set, which must be invocable with
0283         this equivalent signature:
0284         @code
0285         std::size_t
0286         on_chunk_header(
0287             std::uint64_t remain,       // Octets remaining in this chunk, includes `body`
0288             string_view body,           // A buffer holding some or all of the remainder of the chunk body
0289             error_code& ec);            // May be set by the callback to indicate an error
0290         @endcode
0291         */
0292     template<class Callback>
0293     void
0294     on_chunk_body(Callback& cb)
0295     {
0296         // Callback may not be constant, caller is responsible for
0297         // managing the lifetime of the callback. Copies are not made.
0298         BOOST_STATIC_ASSERT(! std::is_const<Callback>::value);
0299 
0300         // Can't set the callback after receiving any chunk data!
0301         BOOST_ASSERT(! rd_inited_);
0302 
0303         cb_b_ = std::ref(cb);
0304     }
0305 
0306 private:
0307     parser(std::true_type);
0308     parser(std::false_type);
0309 
0310     template<class OtherBody, class... Args,
0311         class = typename std::enable_if<
0312             ! std::is_same<Body, OtherBody>::value>::type>
0313     parser(
0314         std::true_type,
0315         parser<isRequest, OtherBody, Allocator>&& parser,
0316         Args&&... args);
0317 
0318     template<class OtherBody, class... Args,
0319         class = typename std::enable_if<
0320             ! std::is_same<Body, OtherBody>::value>::type>
0321     parser(
0322         std::false_type,
0323         parser<isRequest, OtherBody, Allocator>&& parser,
0324         Args&&... args);
0325 
0326     template<class Arg1, class... ArgN,
0327         class = typename std::enable_if<
0328             ! detail::is_parser<typename
0329                 std::decay<Arg1>::type>::value>::type>
0330     explicit
0331     parser(Arg1&& arg1, std::true_type, ArgN&&... argn);
0332 
0333     template<class Arg1, class... ArgN,
0334         class = typename std::enable_if<
0335             ! detail::is_parser<typename
0336                 std::decay<Arg1>::type>::value>::type>
0337     explicit
0338     parser(Arg1&& arg1, std::false_type, ArgN&&... argn);
0339 
0340     void
0341     on_request_impl(
0342         verb method,
0343         string_view method_str,
0344         string_view target,
0345         int version,
0346         error_code& ec,
0347         std::true_type)
0348     {
0349         // If this assert goes off, it means you tried to re-use a
0350         // parser after it was done reading a message. This is not
0351         // allowed, you need to create a new parser for each message.
0352         // The easiest way to do that is to store the parser in
0353         // an optional object.
0354 
0355         BOOST_ASSERT(! used_);
0356         if(used_)
0357         {
0358             BOOST_BEAST_ASSIGN_EC(ec, error::stale_parser);
0359             return;
0360         }
0361         used_ = true;
0362 
0363         m_.target(target);
0364         if(method != verb::unknown)
0365             m_.method(method);
0366         else
0367             m_.method_string(method_str);
0368         m_.version(version);
0369     }
0370 
0371     void
0372     on_request_impl(
0373         verb, string_view, string_view,
0374         int, error_code&, std::false_type)
0375     {
0376     }
0377 
0378     void
0379     on_request_impl(
0380         verb method,
0381         string_view method_str,
0382         string_view target,
0383         int version,
0384         error_code& ec) override
0385     {
0386         this->on_request_impl(
0387             method, method_str, target, version, ec,
0388             std::integral_constant<bool, isRequest>{});
0389     }
0390 
0391     void
0392     on_response_impl(
0393         int code,
0394         string_view reason,
0395         int version,
0396         error_code& ec,
0397         std::true_type)
0398     {
0399         // If this assert goes off, it means you tried to re-use a
0400         // parser after it was done reading a message. This is not
0401         // allowed, you need to create a new parser for each message.
0402         // The easiest way to do that is to store the parser in
0403         // an optional object.
0404 
0405         BOOST_ASSERT(! used_);
0406         if(used_)
0407         {
0408             BOOST_BEAST_ASSIGN_EC(ec, error::stale_parser);
0409             return;
0410         }
0411         used_ = true;
0412 
0413         m_.result(code);
0414         m_.version(version);
0415         m_.reason(reason);
0416     }
0417 
0418     void
0419     on_response_impl(
0420         int, string_view, int,
0421         error_code&, std::false_type)
0422     {
0423     }
0424 
0425     void
0426     on_response_impl(
0427         int code,
0428         string_view reason,
0429         int version,
0430         error_code& ec) override
0431     {
0432         this->on_response_impl(
0433             code, reason, version, ec,
0434             std::integral_constant<bool, ! isRequest>{});
0435     }
0436 
0437     void
0438     on_field_impl(
0439         field name,
0440         string_view name_string,
0441         string_view value,
0442         error_code& ec) override
0443     {
0444         m_.insert(name, name_string, value, ec);
0445     }
0446 
0447     void
0448     on_header_impl(error_code& ec) override
0449     {
0450         ec = {};
0451     }
0452 
0453     void
0454     on_body_init_impl(
0455         boost::optional<std::uint64_t> const& content_length,
0456         error_code& ec) override
0457     {
0458         rd_.init(content_length, ec);
0459         rd_inited_ = true;
0460     }
0461 
0462     std::size_t
0463     on_body_impl(
0464         string_view body,
0465         error_code& ec) override
0466     {
0467         return rd_.put(net::buffer(
0468             body.data(), body.size()), ec);
0469     }
0470 
0471     void
0472     on_chunk_header_impl(
0473         std::uint64_t size,
0474         string_view extensions,
0475         error_code& ec) override
0476     {
0477         if(cb_h_)
0478             return cb_h_(size, extensions, ec);
0479     }
0480 
0481     std::size_t
0482     on_chunk_body_impl(
0483         std::uint64_t remain,
0484         string_view body,
0485         error_code& ec) override
0486     {
0487         if(cb_b_)
0488             return cb_b_(remain, body, ec);
0489         return rd_.put(net::buffer(
0490             body.data(), body.size()), ec);
0491     }
0492 
0493     void
0494     on_finish_impl(
0495         error_code& ec) override
0496     {
0497         rd_.finish(ec);
0498     }
0499 };
0500 
0501 #if BOOST_BEAST_DOXYGEN
0502 /// An HTTP/1 parser for producing a request message.
0503 template<class Body, class Allocator = std::allocator<char>>
0504 using request_parser = parser<true, Body, Allocator>;
0505 
0506 /// An HTTP/1 parser for producing a response message.
0507 template<class Body, class Allocator = std::allocator<char>>
0508 using response_parser = parser<false, Body, Allocator>;
0509 #endif
0510 
0511 } // http
0512 } // beast
0513 } // boost
0514 
0515 #include <boost/beast/http/impl/parser.hpp>
0516 
0517 #endif