diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a67adca..afd31bd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ API Changes: - Add has_reader, has_writer, is_Reader, is_Writer - More friendly compile errors on failed concept checks * basic_parser_v1 requires all callbacks present +* on_headers parser callback now returns void +* on_body_what is a new required parser callback returning body_what -------------------------------------------------------------------------------- diff --git a/include/beast/http/basic_parser_v1.hpp b/include/beast/http/basic_parser_v1.hpp index fbd54743..2174f34b 100644 --- a/include/beast/http/basic_parser_v1.hpp +++ b/include/beast/http/basic_parser_v1.hpp @@ -103,17 +103,17 @@ enum class body_what /** The message represents an UPGRADE request. - When returned by `on_headers` this causes parsing + When returned by `on_body_prepare` this causes parsing to complete and control to return to the caller. */ upgrade, /** Suspend parsing before reading the body. - When returned by `on_headers` this causes parsing to - pause. Control is returned to the caller, and the parser - state is preserved such that a subsequent call to the - parser will begin reading the message body. + When returned by `on_body_prepare` this causes parsing + to pause. Control is returned to the caller, and the + parser state is preserved such that a subsequent call + to the parser will begin reading the message body. This could be used by callers to inspect the HTTP headers before committing to read the body. For example, @@ -183,9 +183,14 @@ static std::uint64_t constexpr no_content_length = // Called when all the headers have been parsed successfully. // - body_what + void on_headers(std::uint64_t content_length, error_code&); + // Called after on_headers, before the body is parsed + // + body_what + on_body_what(std::uint64_t content_length, error_code&); + // Called for each piece of the body. // // If the headers indicate chunk encoding, the chunk @@ -203,9 +208,9 @@ static std::uint64_t constexpr no_content_length = }; @endcode - The return value of `on_headers` is special, it controls whether - or not the parser should expect a body. See @ref body_what for - choices of the return value. + The return value of `on_body_what` is special, it controls + whether or not the parser should expect a body. See @ref body_what + for choices of the return value. If a callback sets an error, parsing stops at the current octet and the error is returned to the caller. Callbacks must not throw @@ -595,12 +600,22 @@ private: std::declval()) )>> : std::true_type {}; + template> + struct check_on_headers : std::false_type {}; + + template + struct check_on_headers().on_headers( + std::declval(), + std::declval()) + )>> : std::true_type {}; + // VFALCO Can we use std::is_detected? Is C++11 capable? template - class check_on_headers_t + class check_on_body_what_t { template().on_headers( + std::declval().on_body_what( std::declval(), std::declval())), body_what>> @@ -612,8 +627,8 @@ private: static bool const value = type::value; }; template - using check_on_headers = - std::integral_constant::value>; + using check_on_body_what = + std::integral_constant::value>; template> struct check_on_body : std::false_type {}; @@ -780,12 +795,20 @@ private: impl().on_value(s, ec); } - body_what + void call_on_headers(error_code& ec) { static_assert(check_on_headers::value, "on_headers requirements not met"); - return impl().on_headers(content_length_, ec); + impl().on_headers(content_length_, ec); + } + + body_what + call_on_body_what(error_code& ec) + { + static_assert(check_on_body_what::value, + "on_body_what requirements not met"); + return impl().on_body_what(content_length_, ec); } void call_on_body(error_code& ec, diff --git a/include/beast/http/detail/basic_parser_v1.hpp b/include/beast/http/detail/basic_parser_v1.hpp index b5370099..d6e0f3ae 100644 --- a/include/beast/http/detail/basic_parser_v1.hpp +++ b/include/beast/http/detail/basic_parser_v1.hpp @@ -127,6 +127,7 @@ protected: s_chunk_data_cr, s_chunk_data_lf, + s_body_what, s_body_identity0, s_body_identity, s_body_identity_eof0, diff --git a/include/beast/http/impl/basic_parser_v1.ipp b/include/beast/http/impl/basic_parser_v1.ipp index 982a988e..c2c98e8f 100644 --- a/include/beast/http/impl/basic_parser_v1.ipp +++ b/include/beast/http/impl/basic_parser_v1.ipp @@ -899,7 +899,16 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) return err(parse_error::illegal_content_length); upgrade_ = ((flags_ & (parse_flag::upgrade | parse_flag::connection_upgrade)) == (parse_flag::upgrade | parse_flag::connection_upgrade)) /*|| method == "connect"*/; - auto const what = call_on_headers(ec); + call_on_headers(ec); + if(ec) + return errc(); + s_ = s_body_what; + // fall through + } + + case s_body_what: + { + auto const what = call_on_body_what(ec); if(ec) return errc(); switch(what) @@ -913,7 +922,6 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) flags_ |= parse_flag::skipbody; break; case body_what::pause: - s_ = s_headers_done; return used(); } s_ = s_headers_done; diff --git a/include/beast/http/parser_v1.hpp b/include/beast/http/parser_v1.hpp index b4abf957..7bbbc846 100644 --- a/include/beast/http/parser_v1.hpp +++ b/include/beast/http/parser_v1.hpp @@ -241,11 +241,16 @@ private: m_.reason = std::move(this->reason_); } - body_what + void on_headers(std::uint64_t, error_code& ec) { flush(); m_.version = 10 * this->http_major() + this->http_minor(); + } + + body_what + on_body_what(std::uint64_t, error_code& ec) + { if(skip_body_) return body_what::skip; r_.emplace(m_); diff --git a/test/http/basic_parser_v1.cpp b/test/http/basic_parser_v1.cpp index dc4270d4..54214aba 100644 --- a/test/http/basic_parser_v1.cpp +++ b/test/http/basic_parser_v1.cpp @@ -52,6 +52,7 @@ public: bool field = false; bool value = false; bool headers = false; + bool _body_what = false; bool body = false; bool complete = false; @@ -90,10 +91,15 @@ public: { value = true; } - body_what + void on_headers(std::uint64_t, error_code&) { headers = true; + } + body_what + on_body_what(std::uint64_t, error_code&) + { + _body_what = true; return body_what::normal; } void on_body(boost::string_ref const&, error_code&) @@ -130,6 +136,7 @@ public: BEAST_EXPECT(p.field); BEAST_EXPECT(p.value); BEAST_EXPECT(p.headers); + BEAST_EXPECT(p._body_what); BEAST_EXPECT(p.body); BEAST_EXPECT(p.complete); } diff --git a/test/http/fail_parser.hpp b/test/http/fail_parser.hpp index e55ca1e3..46a228ce 100644 --- a/test/http/fail_parser.hpp +++ b/test/http/fail_parser.hpp @@ -85,8 +85,15 @@ public: fc_.fail(ec); } - body_what + void on_headers(std::uint64_t content_length, error_code& ec) + { + if(fc_.fail(ec)) + return; + } + + body_what + on_body_what(std::uint64_t content_length, error_code& ec) { if(fc_.fail(ec)) return body_what::normal;