Files
boost_beast/include/beast/http/impl/message.ipp
T

467 lines
9.8 KiB
C++
Raw Normal View History

2016-04-19 20:29:16 -04:00
//
2017-02-06 20:07:03 -05:00
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
2016-04-19 20:29:16 -04:00
//
// 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)
//
2016-03-11 06:40:37 -05:00
2016-10-09 06:34:35 -04:00
#ifndef BEAST_HTTP_IMPL_MESSAGE_IPP
#define BEAST_HTTP_IMPL_MESSAGE_IPP
2016-03-11 06:40:37 -05:00
2016-06-20 09:40:35 -04:00
#include <beast/core/error.hpp>
2016-05-24 06:17:04 -04:00
#include <beast/http/rfc7230.hpp>
2016-09-30 08:44:49 -04:00
#include <beast/core/detail/ci_char_traits.hpp>
#include <beast/core/detail/type_traits.hpp>
2016-10-09 06:34:35 -04:00
#include <boost/assert.hpp>
#include <stdexcept>
2016-03-11 06:40:37 -05:00
namespace beast {
namespace http {
2017-06-04 10:03:36 -07:00
template<class Fields>
2017-06-06 16:20:59 -07:00
template<class Arg1, class... ArgN, class>
2017-06-04 10:03:36 -07:00
header<true, Fields>::
2017-06-06 16:20:59 -07:00
header(Arg1&& arg1, ArgN&&... argn)
: Fields(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...)
2017-06-04 10:03:36 -07:00
{
}
template<class Fields>
2017-06-06 16:20:59 -07:00
inline
verb
header<true, Fields>::
method() const
{
return method_;
}
template<class Fields>
2017-06-04 10:03:36 -07:00
void
header<true, Fields>::
2017-06-06 16:20:59 -07:00
method(verb v)
2017-06-04 10:03:36 -07:00
{
if(v == verb::unknown)
BOOST_THROW_EXCEPTION(
std::invalid_argument{"unknown verb"});
method_ = v;
2017-06-06 16:20:59 -07:00
this->set_method_impl({});
}
template<class Fields>
string_view
header<true, Fields>::
method_string() const
{
if(method_ != verb::unknown)
return to_string(method_);
return this->get_method_impl();
2017-06-04 10:03:36 -07:00
}
template<class Fields>
void
header<true, Fields>::
2017-06-06 17:26:11 -07:00
method_string(string_view s)
2017-06-04 10:03:36 -07:00
{
method_ = string_to_verb(s);
if(method_ != verb::unknown)
2017-06-06 16:20:59 -07:00
this->set_method_impl({});
2017-06-04 10:03:36 -07:00
else
2017-06-06 16:20:59 -07:00
this->set_method_impl(s);
}
template<class Fields>
inline
string_view
header<true, Fields>::
target() const
{
return this->get_target_impl();
}
template<class Fields>
inline
void
header<true, Fields>::
target(string_view s)
{
this->set_target_impl(s);
}
template<class Fields>
void
swap(
header<true, Fields>& h1,
header<true, Fields>& h2)
{
using std::swap;
swap(
static_cast<Fields&>(h1),
static_cast<Fields&>(h2));
swap(h1.version, h2.version);
swap(h1.method_, h2.method_);
}
//------------------------------------------------------------------------------
template<class Fields>
template<class Arg1, class... ArgN, class>
header<false, Fields>::
header(Arg1&& arg1, ArgN&&... argn)
: Fields(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...)
{
}
template<class Fields>
inline
status
header<false, Fields>::
result() const
{
return int_to_status(
static_cast<int>(result_));
}
template<class Fields>
inline
void
header<false, Fields>::
result(status v)
{
result_ = v;
}
template<class Fields>
inline
void
header<false, Fields>::
result(unsigned v)
{
if(v > 999)
BOOST_THROW_EXCEPTION(
std::invalid_argument{
"invalid result-code"});
result_ = static_cast<status>(v);
}
template<class Fields>
inline
unsigned
header<false, Fields>::
result_int() const
{
return static_cast<unsigned>(result_);
}
template<class Fields>
string_view
header<false, Fields>::
2017-06-06 16:20:59 -07:00
reason() const
{
2017-06-06 16:20:59 -07:00
auto const s = this->get_reason_impl();
if(! s.empty())
return s;
return obsolete_reason(result_);
2017-06-04 10:03:36 -07:00
}
2017-06-06 16:20:59 -07:00
template<class Fields>
inline
void
header<false, Fields>::
reason(string_view s)
{
this->set_reason_impl(s);
}
template<class Fields>
void
swap(
header<false, Fields>& h1,
header<false, Fields>& h2)
{
using std::swap;
swap(
static_cast<Fields&>(h1),
static_cast<Fields&>(h2));
swap(h1.version, h2.version);
swap(h1.result_, h2.result_);
}
2017-06-05 21:11:33 -07:00
//------------------------------------------------------------------------------
template<bool isRequest, class Body, class Fields>
2017-06-06 17:26:11 -07:00
template<class... Args>
message<isRequest, Body, Fields>::
message(header_type&& base, Args&&... args)
: header_type(std::move(base))
, body(std::forward<Args>(args)...)
{
}
template<bool isRequest, class Body, class Fields>
template<class... Args>
message<isRequest, Body, Fields>::
message(header_type const& base, Args&&... args)
: header_type(base)
, body(std::forward<Args>(args)...)
{
}
template<bool isRequest, class Body, class Fields>
template<class U, class>
message<isRequest, Body, Fields>::
message(U&& u)
: body(std::forward<U>(u))
{
}
template<bool isRequest, class Body, class Fields>
template<class U, class V, class>
message<isRequest, Body, Fields>::
message(U&& u, V&& v)
: header_type(std::forward<V>(v))
, body(std::forward<U>(u))
{
}
template<bool isRequest, class Body, class Fields>
template<class... Un>
message<isRequest, Body, Fields>::
message(std::piecewise_construct_t, std::tuple<Un...> un)
: message(std::piecewise_construct, un,
beast::detail::make_index_sequence<sizeof...(Un)>{})
{
}
template<bool isRequest, class Body, class Fields>
template<class... Un, class... Vn>
message<isRequest, Body, Fields>::
message(std::piecewise_construct_t,
std::tuple<Un...>&& un, std::tuple<Vn...>&& vn)
: message(std::piecewise_construct, un, vn,
beast::detail::make_index_sequence<sizeof...(Un)>{},
beast::detail::make_index_sequence<sizeof...(Vn)>{})
{
}
template<bool isRequest, class Body, class Fields>
inline
2017-06-05 21:11:33 -07:00
bool
message<isRequest, Body, Fields>::
2017-06-06 17:26:11 -07:00
has_close() const
2017-06-05 21:11:33 -07:00
{
2017-06-06 17:26:11 -07:00
return this->has_close_impl();
}
template<bool isRequest, class Body, class Fields>
inline
bool
message<isRequest, Body, Fields>::
has_chunked() const
{
return this->has_chunked_impl();
}
template<bool isRequest, class Body, class Fields>
inline
bool
message<isRequest, Body, Fields>::
has_content_length() const
{
return this->has_content_length_impl();
2017-06-05 21:11:33 -07:00
}
template<bool isRequest, class Body, class Fields>
boost::optional<std::uint64_t>
message<isRequest, Body, Fields>::
size() const
{
static_assert(is_body_reader<Body>::value,
"BodyReader requirements not met");
return size(detail::is_body_sized<
Body, decltype(*this)>{});
}
2017-06-06 12:49:03 -07:00
template<bool isRequest, class Body, class Fields>
void
message<isRequest, Body, Fields>::
content_length(std::uint64_t n)
{
this->content_length_impl(n);
}
2017-06-05 21:11:33 -07:00
template<bool isRequest, class Body, class Fields>
template<class... Args>
void
message<isRequest, Body, Fields>::
prepare(Args const&... args)
{
static_assert(is_body_reader<Body>::value,
"BodyReader requirements not met");
unsigned f = 0;
prepare_opt(f, args...);
if(f & 1)
{
if(this->version > 10)
this->connection_impl(connection::close);
}
if(f & 2)
{
if(this->version < 11)
this->connection_impl(connection::keep_alive);
}
if(f & 4)
{
if(this->version < 11)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid connection upgrade"});
this->connection_impl(connection::upgrade);
}
prepare_payload(typename header<
isRequest, Fields>::is_request{});
}
template<bool isRequest, class Body, class Fields>
template<class Arg, class... Args>
inline
void
message<isRequest, Body, Fields>::
prepare_opt(unsigned& f,
Arg const& arg, Args const&... args)
{
prepare_opt(f, arg);
prepare_opt(f, args...);
}
template<bool isRequest, class Body, class Fields>
inline
void
message<isRequest, Body, Fields>::
prepare_opt(unsigned& f, close_t)
{
f |= 1;
}
template<bool isRequest, class Body, class Fields>
inline
void
message<isRequest, Body, Fields>::
prepare_opt(unsigned& f, keep_alive_t)
{
f |= 2;
}
template<bool isRequest, class Body, class Fields>
inline
void
message<isRequest, Body, Fields>::
prepare_opt(unsigned& f, upgrade_t)
{
f |= 4;
}
template<bool isRequest, class Body, class Fields>
inline
void
message<isRequest, Body, Fields>::
prepare_payload(std::true_type)
{
auto const n = size();
if(this->method_ == verb::trace &&
(! n || *n > 0))
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid request body"});
if(n)
{
if(*n > 0 ||
this->method_ == verb::options ||
this->method_ == verb::put ||
this->method_ == verb::post
)
{
this->content_length_impl(*n);
}
}
else if(this->version >= 11)
{
2017-06-06 17:26:11 -07:00
this->set_chunked_impl(true);
2017-06-05 21:11:33 -07:00
}
}
template<bool isRequest, class Body, class Fields>
inline
void
message<isRequest, Body, Fields>::
prepare_payload(std::false_type)
{
auto const n = size();
if((status_class(this->result_) ==
status_class::informational ||
this->result_ == status::no_content ||
this->result_ == status::not_modified))
{
if(! n || *n > 0)
// The response body MUST BE empty for this case
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid response body"});
}
if(n)
this->content_length_impl(*n);
else if(this->version >= 11)
2017-06-06 17:26:11 -07:00
this->set_chunked_impl(true);
2017-06-05 21:11:33 -07:00
}
//------------------------------------------------------------------------------
template<bool isRequest, class Body, class Fields>
void
swap(
message<isRequest, Body, Fields>& m1,
message<isRequest, Body, Fields>& m2)
{
using std::swap;
2017-06-05 21:11:33 -07:00
swap(
static_cast<header<isRequest, Fields>&>(m1),
static_cast<header<isRequest, Fields>&>(m2));
swap(m1.body, m2.body);
}
template<bool isRequest, class Fields>
2016-03-11 06:40:37 -05:00
bool
is_keep_alive(header<isRequest, Fields> const& msg)
2016-03-11 06:40:37 -05:00
{
2016-10-09 06:34:35 -04:00
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
if(msg.version == 11)
2016-03-11 06:40:37 -05:00
{
2017-06-05 19:28:17 -07:00
if(token_list{msg["Connection"]}.exists("close"))
2016-03-11 06:40:37 -05:00
return false;
return true;
}
2017-06-05 19:28:17 -07:00
if(token_list{msg["Connection"]}.exists("keep-alive"))
2016-03-11 06:40:37 -05:00
return true;
return false;
}
template<bool isRequest, class Fields>
2016-03-11 06:40:37 -05:00
bool
is_upgrade(header<isRequest, Fields> const& msg)
2016-03-11 06:40:37 -05:00
{
2016-10-09 06:34:35 -04:00
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
if(msg.version == 10)
2016-03-11 06:40:37 -05:00
return false;
2017-06-05 19:28:17 -07:00
if(token_list{msg["Connection"]}.exists("upgrade"))
2016-03-11 06:40:37 -05:00
return true;
return false;
}
} // http
} // beast
#endif