Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:32

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