// // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BEAST_HTTP_PARSER_HPP #define BEAST_HTTP_PARSER_HPP #include #include #include #include #include #include #include #include namespace beast { namespace http { /** An HTTP/1 parser for producing a header. This class uses the basic HTTP/1 wire format parser to convert a series of octets into a @ref header. @note A new instance of the parser is required for each message. @tparam isRequest Indicates whether a request or response will be parsed. @tparam Fields The type of container used to represent the fields. */ template class header_parser : public basic_parser> { header h_; string_view body_; public: /// The type of @ref header this object produces. using value_type = header; /// Default constructor. header_parser() = default; /// Copy constructor. header_parser(header_parser const&) = default; /// Copy assignment. header_parser& operator=(header_parser const&) = default; /** Move constructor. After the move, the only valid operation on the moved-from object is destruction. */ header_parser(header_parser&&) = default; /** Move assignment After the move, the only valid operation on the moved-from object is destruction. */ header_parser& operator=(header_parser&&) = default; /** Constructor @param args Optional arguments forwarded forwarded to the @ref http::header constructor. */ #if BEAST_DOXYGEN template explicit header_parser(Args&&... args); #else template::type, header_parser>::value>> explicit header_parser(Arg0&& arg0, ArgN&&... argn); #endif /** Returns parsed body octets. This function will return the most recent buffer of octets corresponding to the parsed body. This buffer will become invalidated on any subsequent call to @ref put or @ref put_eof */ string_view body() const { return body_; } /** Returns the parsed header @note The return value is undefined unless @ref is_header_done would return `true`. */ value_type const& get() const { return h_; } /** Returns the parsed header. @note The return value is undefined unless @ref is_header_done would return `true`. */ value_type& get() { return h_; } /** Returns ownership of the parsed header. Ownership is transferred to the caller. @note The return value is undefined unless @ref is_header_done would return `true`. Requires: @ref value_type is @b MoveConstructible */ value_type release() { static_assert( std::is_move_constructible::value, "MoveConstructible requirements not met"); return std::move(h_); } private: friend class basic_parser; void on_request(string_view method, string_view path, int version, error_code&) { h_.target(path); h_.method(method); h_.version = version; } void on_response(int code, string_view reason, int version, error_code&) { h_.result(code); h_.version = version; h_.reason(reason); } void on_field(string_view name, string_view value, error_code&) { h_.fields.insert(name, value); } void on_header(error_code&) { } void on_body(boost::optional const&, error_code&) { } void on_data(string_view s, error_code&) { body_ = s; } void on_chunk(std::uint64_t, string_view, error_code&) { body_ = {}; } void on_complete(error_code&) { body_ = {}; } }; template< bool isRequest,class Body, class Fields = fields> class parser; namespace detail { template struct is_parser : std::false_type {}; template struct is_parser> : std::true_type {}; } // detail /** An HTTP/1 parser for producing a message. This class uses the basic HTTP/1 wire format parser to convert a series of octets into a @ref message. @tparam isRequest Indicates whether a request or response will be parsed. @tparam Body The type used to represent the body. @tparam Fields The type of container used to represent the fields. @note A new instance of the parser is required for each message. */ template class parser : public basic_parser> { static_assert(is_body::value, "Body requirements not met"); static_assert(is_body_writer::value, "BodyWriter requirements not met"); template friend class parser; using base_type = basic_parser>; message m_; boost::optional wr_; public: /// The type of message returned by the parser using value_type = message; /// Constructor (default) parser() = default; /// Copy constructor (disallowed) parser(parser const&) = delete; /// Copy assignment (disallowed) parser& operator=(parser const&) = delete; /** Move constructor. After the move, the only valid operation on the moved-from object is destruction. */ parser(parser&& other); /** Constructor @param args Optional arguments forwarded to the @ref http::header constructor. @note This function participates in overload resolution only if the first argument is not a @ref parser. */ #if BEAST_DOXYGEN template explicit msesage_parser(Args&&... args); #else template::type>::value>::type> explicit parser(Arg1&& arg1, ArgN&&... argn); #endif /** Construct a parser from another parser, changing the Body type. This constructs a new parser by move constructing the header from another parser with a different body type. The constructed-from parser must not have any parsed body octets or initialized @b BodyWriter, otherwise an exception is generated. @par Example @code // Deferred body type commitment request_parser req0; ... request_parser req{std::move(req0)}; @endcode If an exception is thrown, the state of the constructed-from parser is undefined. @param parser The other parser to construct from. After this call returns, the constructed-from parser may only be destroyed. @param args Optional arguments forwarded to the message constructor. @throws std::invalid_argument Thrown when the constructed-from parser has already initialized a body writer. */ #if BEAST_DOXYGEN template #else template #endif explicit parser(parser&& parser, Args&&... args); /** Construct a parser from a @ref header_parser. @param parser The header parser to construct from. @param args Optional arguments forwarded to the message constructor. */ template explicit parser(header_parser< isRequest, Fields>&& parser, Args&&... args); /** Returns the parsed message. Depending on the progress of the parser, portions of this object may be incomplete. */ value_type const& get() const { return m_; } /** Returns the parsed message. Depending on the progress of the parser, portions of this object may be incomplete. */ value_type& get() { return m_; } /** Returns ownership of the parsed message. Ownership is transferred to the caller. Depending on the progress of the parser, portions of this object may be incomplete. @par Requires @ref value_type is @b MoveConstructible */ value_type release() { static_assert(std::is_move_constructible::value, "MoveConstructible requirements not met"); return std::move(m_); } private: friend class basic_parser; void on_request( string_view method, string_view target, int version, error_code&) { m_.target(target); m_.method(method); m_.version = version; } void on_response(int code, string_view reason, int version, error_code&) { m_.result(code); m_.version = version; m_.reason(reason); } void on_field(string_view name, string_view value, error_code&) { m_.fields.insert(name, value); } void on_header(error_code& ec) { } void on_body(boost::optional< std::uint64_t> const& content_length, error_code& ec) { wr_.emplace(m_); wr_->init(content_length, ec); } void on_data(string_view s, error_code& ec) { wr_->put(boost::asio::buffer( s.data(), s.size()), ec); } void on_chunk( std::uint64_t, string_view, error_code&) { } void on_complete(error_code& ec) { if(wr_) wr_->finish(ec); } }; /// An HTTP/1 parser for producing a request message. template using request_parser = parser; /// An HTTP/1 parser for producing a response message. template using response_parser = parser; } // http } // beast #include #endif