Skip to content

Commit

Permalink
Add on_body_what parser callback (API Change):
Browse files Browse the repository at this point in the history
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
  • Loading branch information
vinniefalco committed Oct 16, 2016
1 parent 4d968c5 commit 10f8004
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,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

--------------------------------------------------------------------------------

Expand Down
53 changes: 38 additions & 15 deletions include/beast/http/basic_parser_v1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -595,12 +600,22 @@ class basic_parser_v1 : public detail::parser_base
std::declval<error_code&>())
)>> : 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?
template<class C>
class check_on_headers_t
class check_on_body_what_t
{
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<error_code&>())),
body_what>>
Expand All @@ -612,8 +627,8 @@ class basic_parser_v1 : public detail::parser_base
static bool const value = type::value;
};
template<class C>
using check_on_headers =
std::integral_constant<bool, check_on_headers_t<C>::value>;
using check_on_body_what =
std::integral_constant<bool, check_on_body_what_t<C>::value>;

template<class T, class = beast::detail::void_t<>>
struct check_on_body : std::false_type {};
Expand Down Expand Up @@ -780,12 +795,20 @@ class basic_parser_v1 : public detail::parser_base
impl().on_value(s, ec);
}

body_what
void
call_on_headers(error_code& ec)
{
static_assert(check_on_headers<Derived>::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<Derived>::value,
"on_body_what requirements not met");
return impl().on_body_what(content_length_, ec);
}

void call_on_body(error_code& ec,
Expand Down
1 change: 1 addition & 0 deletions include/beast/http/detail/basic_parser_v1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class parser_base
s_chunk_data_cr,
s_chunk_data_lf,

s_body_what,
s_body_identity0,
s_body_identity,
s_body_identity_eof0,
Expand Down
12 changes: 10 additions & 2 deletions include/beast/http/impl/basic_parser_v1.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion include/beast/http/parser_v1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,16 @@ class parser_v1
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_);
Expand Down
9 changes: 8 additions & 1 deletion test/http/basic_parser_v1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class basic_parser_v1_test : public beast::unit_test::suite
bool field = false;
bool value = false;
bool headers = false;
bool _body_what = false;
bool body = false;
bool complete = false;

Expand Down Expand Up @@ -90,10 +91,15 @@ class basic_parser_v1_test : public beast::unit_test::suite
{
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&)
Expand Down Expand Up @@ -130,6 +136,7 @@ class basic_parser_v1_test : public beast::unit_test::suite
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);
}
Expand Down
9 changes: 8 additions & 1 deletion test/http/fail_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,15 @@ class fail_parser
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;
Expand Down

0 comments on commit 10f8004

Please sign in to comment.