Files
boost_beast/include/beast/http/parser_v1.hpp
T

339 lines
8.5 KiB
C++
Raw Normal View History

2016-04-19 20:29:16 -04:00
//
// Copyright (c) 2013-2016 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_V1_HPP
#define BEAST_HTTP_PARSER_V1_HPP
2016-04-19 20:29:16 -04:00
2016-05-18 12:30:15 -04:00
#include <beast/http/concepts.hpp>
#include <beast/http/header_parser_v1.hpp>
2016-10-09 06:34:35 -04:00
#include <beast/http/message.hpp>
2016-05-07 14:57:15 -04:00
#include <beast/core/error.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <boost/assert.hpp>
2016-10-15 09:29:14 -04:00
#include <boost/optional.hpp>
2016-04-19 20:29:16 -04:00
#include <functional>
2016-04-25 05:27:34 -04:00
#include <string>
2016-04-19 20:29:16 -04:00
#include <type_traits>
#include <utility>
namespace beast {
namespace http {
2016-06-15 11:52:59 -04:00
/** Skip body option.
The options controls whether or not the parser expects to see a
HTTP body, regardless of the presence or absence of certain fields
such as Content-Length.
Depending on the request, some responses do not carry a body.
For example, a 200 response to a CONNECT request from a tunneling
proxy. In these cases, callers use the @ref skip_body option to
inform the parser that no body is expected. The parser will consider
the message complete after the header has been received.
2016-06-15 11:52:59 -04:00
Example:
@code
parser_v1<true, empty_body, fields> p;
2016-06-15 11:52:59 -04:00
p.set_option(skip_body{true});
@endcode
2016-10-15 21:39:24 -04:00
@note Objects of this type are passed to @ref parser_v1::set_option.
2016-06-15 11:52:59 -04:00
*/
struct skip_body
{
bool value;
explicit
skip_body(bool v)
: value(v)
{
}
};
/** A parser for producing HTTP/1 messages.
This class uses the basic HTTP/1 wire format parser to convert
2016-10-09 06:34:35 -04:00
a series of octets into a `message`.
2016-04-30 10:29:39 -04:00
@note A new instance of the parser is required for each message.
*/
template<bool isRequest, class Body, class Fields>
class parser_v1
: public basic_parser_v1<isRequest,
parser_v1<isRequest, Body, Fields>>
2016-04-25 05:27:34 -04:00
, private std::conditional<isRequest,
2016-10-16 19:28:35 -04:00
detail::request_parser_base,
detail::response_parser_base>::type
2016-04-19 20:29:16 -04:00
{
2016-04-30 10:29:39 -04:00
public:
/// The type of message this parser produces.
2016-04-19 20:29:16 -04:00
using message_type =
message<isRequest, Body, Fields>;
2016-04-19 20:29:16 -04:00
2016-04-30 10:29:39 -04:00
private:
2016-10-15 09:29:14 -04:00
using reader =
typename message_type::body_type::reader;
2016-10-15 13:40:17 -04:00
static_assert(is_Body<Body>::value,
"Body requirements not met");
static_assert(has_reader<Body>::value,
"Body has no reader");
static_assert(is_Reader<reader, message_type>::value,
"Reader requirements not met");
2016-10-15 09:29:14 -04:00
2016-04-25 05:27:34 -04:00
std::string field_;
std::string value_;
2016-04-19 20:29:16 -04:00
message_type m_;
2016-10-15 09:29:14 -04:00
boost::optional<reader> r_;
2016-06-15 11:52:59 -04:00
std::uint8_t skip_body_ = 0;
bool flush_ = false;
2016-04-19 20:29:16 -04:00
public:
2016-10-15 09:29:14 -04:00
/// Default constructor
parser_v1() = default;
2016-10-10 06:37:07 -04:00
/// Move constructor
parser_v1(parser_v1&&) = default;
2016-10-10 06:37:07 -04:00
/// Copy constructor (disallowed)
2016-04-30 10:29:39 -04:00
parser_v1(parser_v1 const&) = delete;
2016-10-10 06:37:07 -04:00
/// Move assignment (disallowed)
2016-04-30 10:29:39 -04:00
parser_v1& operator=(parser_v1&&) = delete;
2016-10-10 06:37:07 -04:00
/// Copy assignment (disallowed)
2016-04-30 10:29:39 -04:00
parser_v1& operator=(parser_v1 const&) = delete;
2016-04-19 20:29:16 -04:00
2016-04-30 10:29:39 -04:00
/** Construct the parser.
2016-10-16 19:28:35 -04:00
@param args Forwarded to the message constructor.
2016-11-09 10:17:56 -05:00
@note This function participates in overload resolution only
if the first argument is not a parser or fields parser.
2016-04-30 10:29:39 -04:00
*/
2016-10-15 21:39:24 -04:00
#if GENERATING_DOCS
template<class... Args>
explicit
parser_v1(Args&&... args);
#else
2016-10-10 06:37:07 -04:00
template<class Arg1, class... ArgN,
2016-11-09 10:17:56 -05:00
class = typename std::enable_if<
! std::is_same<typename
std::decay<Arg1>::type,
header_parser_v1<isRequest, Fields>>::value &&
2016-11-09 10:17:56 -05:00
! std::is_same<typename
std::decay<Arg1>::type, parser_v1>::value
>::type>
2016-04-30 10:29:39 -04:00
explicit
2016-10-10 06:37:07 -04:00
parser_v1(Arg1&& arg1, ArgN&&... argn)
: m_(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...)
2016-04-19 20:29:16 -04:00
{
}
2016-10-15 21:39:24 -04:00
#endif
2016-04-19 20:29:16 -04:00
/** Construct the parser from a fields parser.
2016-10-16 19:28:35 -04:00
@param parser The fields parser to construct from.
2016-10-16 19:28:35 -04:00
@param args Forwarded to the message body constructor.
*/
template<class... Args>
explicit
parser_v1(header_parser_v1<isRequest, Fields>& parser,
2016-10-16 19:28:35 -04:00
Args&&... args)
: m_(parser.release(), std::forward<Args>(args)...)
{
static_cast<basic_parser_v1<
isRequest, parser_v1<
isRequest, Body, Fields>>&>(*this) = parser;
2016-10-16 19:28:35 -04:00
}
/// Set the skip body option.
2016-06-15 11:52:59 -04:00
void
set_option(skip_body const& o)
{
skip_body_ = o.value ? 1 : 0;
}
2016-04-30 10:29:39 -04:00
/** Returns the parsed message.
2016-10-16 19:28:35 -04:00
Only valid if @ref complete would return `true`.
2016-04-30 10:29:39 -04:00
*/
message_type const&
get() const
{
return m_;
}
/** Returns the parsed message.
2016-10-16 19:28:35 -04:00
Only valid if @ref complete would return `true`.
2016-04-30 10:29:39 -04:00
*/
message_type&
get()
{
return m_;
}
2016-10-16 19:28:35 -04:00
/** Returns ownership of the parsed message.
2016-04-30 10:29:39 -04:00
2016-10-16 19:28:35 -04:00
Ownership is transferred to the caller. Only
2016-10-19 16:54:50 -04:00
valid if @ref complete would return `true`.
2016-04-30 10:29:39 -04:00
Requires:
`message<isRequest, Body, Fields>` is @b MoveConstructible
2016-04-30 10:29:39 -04:00
*/
2016-04-19 20:29:16 -04:00
message_type
release()
{
2016-04-30 10:29:39 -04:00
static_assert(std::is_move_constructible<decltype(m_)>::value,
"MoveConstructible requirements not met");
2016-04-19 20:29:16 -04:00
return std::move(m_);
}
private:
friend class basic_parser_v1<isRequest, parser_v1>;
2016-04-19 20:29:16 -04:00
2016-04-25 05:27:34 -04:00
void flush()
2016-04-19 20:29:16 -04:00
{
if(! flush_)
return;
flush_ = false;
BOOST_ASSERT(! field_.empty());
m_.fields.insert(field_, value_);
field_.clear();
value_.clear();
2016-04-19 20:29:16 -04:00
}
2016-04-30 10:29:39 -04:00
void on_start(error_code&)
{
}
2016-04-25 05:27:34 -04:00
void on_method(boost::string_ref const& s, error_code&)
2016-04-19 20:29:16 -04:00
{
2016-04-25 05:27:34 -04:00
this->method_.append(s.data(), s.size());
2016-04-19 20:29:16 -04:00
}
2016-04-25 05:27:34 -04:00
void on_uri(boost::string_ref const& s, error_code&)
2016-04-19 20:29:16 -04:00
{
2016-04-25 05:27:34 -04:00
this->uri_.append(s.data(), s.size());
2016-04-19 20:29:16 -04:00
}
2016-04-25 05:27:34 -04:00
void on_reason(boost::string_ref const& s, error_code&)
2016-04-19 20:29:16 -04:00
{
2016-04-25 05:27:34 -04:00
this->reason_.append(s.data(), s.size());
2016-04-19 20:29:16 -04:00
}
2016-10-16 19:28:35 -04:00
void on_request_or_response(std::true_type)
{
m_.method = std::move(this->method_);
m_.url = std::move(this->uri_);
}
void on_request_or_response(std::false_type)
{
m_.status = this->status_code();
m_.reason = std::move(this->reason_);
}
void on_request(error_code&)
2016-10-16 19:28:35 -04:00
{
on_request_or_response(
std::integral_constant<bool, isRequest>{});
}
void on_response(error_code&)
2016-10-16 19:28:35 -04:00
{
on_request_or_response(
std::integral_constant<bool, isRequest>{});
}
2016-04-25 05:27:34 -04:00
void on_field(boost::string_ref const& s, error_code&)
2016-04-19 20:29:16 -04:00
{
2016-04-25 05:27:34 -04:00
flush();
field_.append(s.data(), s.size());
2016-04-19 20:29:16 -04:00
}
2016-04-25 05:27:34 -04:00
void on_value(boost::string_ref const& s, error_code&)
2016-04-19 20:29:16 -04:00
{
2016-04-25 05:27:34 -04:00
value_.append(s.data(), s.size());
flush_ = true;
2016-04-19 20:29:16 -04:00
}
void
on_header(std::uint64_t, error_code&)
2016-04-19 20:29:16 -04:00
{
2016-04-25 05:27:34 -04:00
flush();
m_.version = 10 * this->http_major() + this->http_minor();
}
body_what
on_body_what(std::uint64_t, error_code& ec)
{
2016-10-10 07:55:39 -04:00
if(skip_body_)
return body_what::skip;
2016-10-15 09:29:14 -04:00
r_.emplace(m_);
r_->init(ec);
2016-10-10 07:55:39 -04:00
return body_what::normal;
2016-04-19 20:29:16 -04:00
}
2016-04-25 05:27:34 -04:00
void on_body(boost::string_ref const& s, error_code& ec)
{
2016-10-15 09:29:14 -04:00
r_->write(s.data(), s.size(), ec);
2016-04-25 05:27:34 -04:00
}
void on_complete(error_code&)
2016-04-19 20:29:16 -04:00
{
}
};
/** Create a new parser from a fields parser.
2016-10-16 19:28:35 -04:00
Associates a Body type with a fields parser, and returns
2016-10-16 19:28:35 -04:00
a new parser which parses a complete message object
containing the original message fields and a new body
2016-10-16 19:28:35 -04:00
of the specified body type.
This function allows HTTP messages to be parsed in two stages.
First, the fields are parsed and control is returned. Then,
2016-10-16 19:28:35 -04:00
the caller can choose at run-time, the type of Body to
associate with the message. And finally, complete the parse
in a second call.
@param parser The fields parser to construct from. Ownership
of the message fields in the fields parser is transferred
as if by call to @ref header_parser_v1::release.
2016-10-16 19:28:35 -04:00
@param args Forwarded to the body constructor of the message
in the new parser.
2016-10-19 16:54:50 -04:00
@return A parser for a message with the specified @b Body type.
2016-10-16 19:28:35 -04:00
@par Example
@code
headers_parser<true, fields> ph;
2016-10-16 19:28:35 -04:00
...
2016-11-09 10:17:56 -05:00
auto p = with_body<string_body>(ph);
2016-10-16 19:28:35 -04:00
...
message<true, string_body, fields> m = p.release();
2016-10-16 19:28:35 -04:00
@endcode
*/
template<class Body,
bool isRequest, class Fields, class... Args>
parser_v1<isRequest, Body, Fields>
with_body(header_parser_v1<isRequest, Fields>& parser,
2016-10-16 19:28:35 -04:00
Args&&... args)
{
return parser_v1<isRequest, Body, Fields>(
2016-11-09 10:17:56 -05:00
parser, std::forward<Args>(args)...);
2016-10-16 19:28:35 -04:00
}
2016-04-19 20:29:16 -04:00
} // http
} // beast
#endif