Add on_body_what parser callback (API Change):

These changes support parsing the headers separately from the body.

* on_headers now returns void
* on_body_what is a new required callback which returns body_what
This commit is contained in:
Vinnie Falco
2016-10-16 17:40:21 -04:00
parent ac07d0c3ed
commit 83556937f6
7 changed files with 73 additions and 20 deletions

View File

@@ -23,6 +23,8 @@ API Changes:
- Add has_reader, has_writer, is_Reader, is_Writer - Add has_reader, has_writer, is_Reader, is_Writer
- More friendly compile errors on failed concept checks - More friendly compile errors on failed concept checks
* basic_parser_v1 requires all callbacks present * 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
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -103,17 +103,17 @@ enum class body_what
/** The message represents an UPGRADE request. /** 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. to complete and control to return to the caller.
*/ */
upgrade, upgrade,
/** Suspend parsing before reading the body. /** Suspend parsing before reading the body.
When returned by `on_headers` this causes parsing to When returned by `on_body_prepare` this causes parsing
pause. Control is returned to the caller, and the parser to pause. Control is returned to the caller, and the
state is preserved such that a subsequent call to the parser state is preserved such that a subsequent call
parser will begin reading the message body. to the parser will begin reading the message body.
This could be used by callers to inspect the HTTP This could be used by callers to inspect the HTTP
headers before committing to read the body. For example, 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. // Called when all the headers have been parsed successfully.
// //
body_what void
on_headers(std::uint64_t content_length, error_code&); 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. // Called for each piece of the body.
// //
// If the headers indicate chunk encoding, the chunk // If the headers indicate chunk encoding, the chunk
@@ -203,9 +208,9 @@ static std::uint64_t constexpr no_content_length =
}; };
@endcode @endcode
The return value of `on_headers` is special, it controls whether The return value of `on_body_what` is special, it controls
or not the parser should expect a body. See @ref body_what for whether or not the parser should expect a body. See @ref body_what
choices of the return value. for choices of the return value.
If a callback sets an error, parsing stops at the current octet If a callback sets an error, parsing stops at the current octet
and the error is returned to the caller. Callbacks must not throw and the error is returned to the caller. Callbacks must not throw
@@ -595,12 +600,22 @@ private:
std::declval<error_code&>()) std::declval<error_code&>())
)>> : std::true_type {}; )>> : std::true_type {};
template<class T, class = beast::detail::void_t<>>
struct check_on_headers : std::false_type {};
template<class T>
struct check_on_headers<T, beast::detail::void_t<decltype(
std::declval<T>().on_headers(
std::declval<std::uint64_t>(),
std::declval<error_code&>())
)>> : std::true_type {};
// VFALCO Can we use std::is_detected? Is C++11 capable? // VFALCO Can we use std::is_detected? Is C++11 capable?
template<class C> template<class C>
class check_on_headers_t class check_on_body_what_t
{ {
template<class T, class R = std::is_convertible<decltype( template<class T, class R = std::is_convertible<decltype(
std::declval<T>().on_headers( std::declval<T>().on_body_what(
std::declval<std::uint64_t>(), std::declval<std::uint64_t>(),
std::declval<error_code&>())), std::declval<error_code&>())),
body_what>> body_what>>
@@ -612,8 +627,8 @@ private:
static bool const value = type::value; static bool const value = type::value;
}; };
template<class C> template<class C>
using check_on_headers = using check_on_body_what =
std::integral_constant<bool, check_on_headers_t<C>::value>; std::integral_constant<bool, check_on_body_what_t<C>::value>;
template<class T, class = beast::detail::void_t<>> template<class T, class = beast::detail::void_t<>>
struct check_on_body : std::false_type {}; struct check_on_body : std::false_type {};
@@ -780,12 +795,20 @@ private:
impl().on_value(s, ec); impl().on_value(s, ec);
} }
body_what void
call_on_headers(error_code& ec) call_on_headers(error_code& ec)
{ {
static_assert(check_on_headers<Derived>::value, static_assert(check_on_headers<Derived>::value,
"on_headers requirements not met"); "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<Derived>::value,
"on_body_what requirements not met");
return impl().on_body_what(content_length_, ec);
} }
void call_on_body(error_code& ec, void call_on_body(error_code& ec,

View File

@@ -127,6 +127,7 @@ protected:
s_chunk_data_cr, s_chunk_data_cr,
s_chunk_data_lf, s_chunk_data_lf,
s_body_what,
s_body_identity0, s_body_identity0,
s_body_identity, s_body_identity,
s_body_identity_eof0, s_body_identity_eof0,

View File

@@ -899,7 +899,16 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
return err(parse_error::illegal_content_length); return err(parse_error::illegal_content_length);
upgrade_ = ((flags_ & (parse_flag::upgrade | parse_flag::connection_upgrade)) == upgrade_ = ((flags_ & (parse_flag::upgrade | parse_flag::connection_upgrade)) ==
(parse_flag::upgrade | parse_flag::connection_upgrade)) /*|| method == "connect"*/; (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) if(ec)
return errc(); return errc();
switch(what) switch(what)
@@ -913,7 +922,6 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
flags_ |= parse_flag::skipbody; flags_ |= parse_flag::skipbody;
break; break;
case body_what::pause: case body_what::pause:
s_ = s_headers_done;
return used(); return used();
} }
s_ = s_headers_done; s_ = s_headers_done;

View File

@@ -241,11 +241,16 @@ private:
m_.reason = std::move(this->reason_); m_.reason = std::move(this->reason_);
} }
body_what void
on_headers(std::uint64_t, error_code& ec) on_headers(std::uint64_t, error_code& ec)
{ {
flush(); flush();
m_.version = 10 * this->http_major() + this->http_minor(); m_.version = 10 * this->http_major() + this->http_minor();
}
body_what
on_body_what(std::uint64_t, error_code& ec)
{
if(skip_body_) if(skip_body_)
return body_what::skip; return body_what::skip;
r_.emplace(m_); r_.emplace(m_);

View File

@@ -52,6 +52,7 @@ public:
bool field = false; bool field = false;
bool value = false; bool value = false;
bool headers = false; bool headers = false;
bool _body_what = false;
bool body = false; bool body = false;
bool complete = false; bool complete = false;
@@ -90,10 +91,15 @@ public:
{ {
value = true; value = true;
} }
body_what void
on_headers(std::uint64_t, error_code&) on_headers(std::uint64_t, error_code&)
{ {
headers = true; headers = true;
}
body_what
on_body_what(std::uint64_t, error_code&)
{
_body_what = true;
return body_what::normal; return body_what::normal;
} }
void on_body(boost::string_ref const&, error_code&) void on_body(boost::string_ref const&, error_code&)
@@ -130,6 +136,7 @@ public:
BEAST_EXPECT(p.field); BEAST_EXPECT(p.field);
BEAST_EXPECT(p.value); BEAST_EXPECT(p.value);
BEAST_EXPECT(p.headers); BEAST_EXPECT(p.headers);
BEAST_EXPECT(p._body_what);
BEAST_EXPECT(p.body); BEAST_EXPECT(p.body);
BEAST_EXPECT(p.complete); BEAST_EXPECT(p.complete);
} }

View File

@@ -85,8 +85,15 @@ public:
fc_.fail(ec); fc_.fail(ec);
} }
body_what void
on_headers(std::uint64_t content_length, error_code& ec) 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)) if(fc_.fail(ec))
return body_what::normal; return body_what::normal;