...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
While the parsers included in the library will handle a broad number of use-cases,
the basic_parser
interface can be subclassed
to implement custom strategies for storing parsed results: the basic parser
processes the incoming octets into elements according to the HTTP/1 protocol
specification, while the derived class decides what to do with those elements.
In particular, users who create exotic containers for Fields
may need to also create their own parser. Custom parsers will work with all
of the stream read operations that work on parsers, as those algorithms use
only the basic parser interface. Some use cases for implementing custom parsers
are:
The basic parser uses the Curiously
Recurring Template Pattern. To declare your user defined parser,
derive it from basic_parser
. The interface to the
parser is event-driven. Member functions of the derived class (termed "callbacks"
in this context) are invoked with parsed elements as they become available,
requiring either the friend
declaration as shown above or that the member functions are declared public
(not recommended). Buffers provided by the parser are non-owning references;
it is the responsibility of the derived class to copy any information it
needs before returning from the callback.
template<bool isRequest> class custom_parser : public basic_parser<isRequest, custom_parser<isRequest>> { private: // The friend declaration is needed, // otherwise the callbacks must be made public. friend class basic_parser<isRequest, custom_parser>; /// Called after receiving the request-line (isRequest == true). void on_request_impl( verb method, // The method verb, verb::unknown if no match string_view method_str, // The method as a string string_view target, // The request-target int version, // The HTTP-version error_code& ec); // The error returned to the caller, if any /// Called after receiving the start-line (isRequest == false). void on_response_impl( int code, // The status-code string_view reason, // The obsolete reason-phrase int version, // The HTTP-version error_code& ec); // The error returned to the caller, if any /// Called after receiving a header field. void on_field_impl( field f, // The known-field enumeration constant string_view name, // The field name string. string_view value, // The field value error_code& ec); // The error returned to the caller, if any /// Called after the complete header is received. void on_header_impl( error_code& ec); // The error returned to the caller, if any /// Called just before processing the body, if a body exists. void on_body_init_impl( boost::optional< std::uint64_t> const& content_length, // Content length if known, else `boost::none` error_code& ec); // The error returned to the caller, if any /// Called for each piece of the body, if a body exists. //! //! This is used when there is no chunked transfer coding. //! //! The function returns the number of bytes consumed from the //! input buffer. Any input octets not consumed will be will be //! presented on subsequent calls. //! std::size_t on_body_impl( string_view s, // A portion of the body error_code& ec); // The error returned to the caller, if any /// Called for each chunk header. void on_chunk_header_impl( std::uint64_t size, // The size of the upcoming chunk, // or zero for the last chunk string_view extension, // The chunk extensions (may be empty) error_code& ec); // The error returned to the caller, if any /// Called to deliver the chunk body. //! //! This is used when there is a chunked transfer coding. The //! implementation will automatically remove the encoding before //! calling this function. //! //! The function returns the number of bytes consumed from the //! input buffer. Any input octets not consumed will be will be //! presented on subsequent calls. //! std::size_t on_chunk_body_impl( std::uint64_t remain, // The number of bytes remaining in the chunk, // including what is being passed here. // or zero for the last chunk string_view body, // The next piece of the chunk body error_code& ec); // The error returned to the caller, if any /// Called when the complete message is parsed. void on_finish_impl(error_code& ec); public: custom_parser() = default; };