123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- //
- // Copyright (c) 2016-2019 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)
- //
- // Official repository: https://github.com/boostorg/beast
- //
- #ifndef BOOST_BEAST_HTTP_IMPL_MESSAGE_HPP
- #define BOOST_BEAST_HTTP_IMPL_MESSAGE_HPP
- #include <boost/beast/core/error.hpp>
- #include <boost/assert.hpp>
- #include <boost/throw_exception.hpp>
- #include <stdexcept>
- namespace boost {
- namespace beast {
- namespace http {
- template<class Fields>
- template<class Arg1, class... ArgN, class>
- header<true, Fields>::
- header(Arg1&& arg1, ArgN&&... argn)
- : Fields(std::forward<Arg1>(arg1),
- std::forward<ArgN>(argn)...)
- {
- }
- template<class Fields>
- verb
- header<true, Fields>::
- method() const
- {
- return method_;
- }
- template<class Fields>
- void
- header<true, Fields>::
- method(verb v)
- {
- if(v == verb::unknown)
- BOOST_THROW_EXCEPTION(
- std::invalid_argument{"unknown method"});
- method_ = v;
- 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();
- }
- template<class Fields>
- void
- header<true, Fields>::
- method_string(string_view s)
- {
- method_ = string_to_verb(s);
- if(method_ != verb::unknown)
- this->set_method_impl({});
- else
- this->set_method_impl(s);
- }
- template<class Fields>
- string_view
- header<true, Fields>::
- target() const
- {
- return this->get_target_impl();
- }
- template<class Fields>
- 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>
- status
- header<false, Fields>::
- result() const
- {
- return int_to_status(
- static_cast<int>(result_));
- }
- template<class Fields>
- void
- header<false, Fields>::
- result(status v)
- {
- result_ = v;
- }
- template<class Fields>
- void
- header<false, Fields>::
- result(unsigned v)
- {
- if(v > 999)
- BOOST_THROW_EXCEPTION(
- std::invalid_argument{
- "invalid status-code"});
- result_ = static_cast<status>(v);
- }
- template<class Fields>
- unsigned
- header<false, Fields>::
- result_int() const
- {
- return static_cast<unsigned>(result_);
- }
- template<class Fields>
- string_view
- header<false, Fields>::
- reason() const
- {
- auto const s = this->get_reason_impl();
- if(! s.empty())
- return s;
- return obsolete_reason(result_);
- }
- template<class Fields>
- 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_);
- }
- //------------------------------------------------------------------------------
- template<bool isRequest, class Body, class Fields>
- template<class... BodyArgs>
- message<isRequest, Body, Fields>::
- message(header_type&& h, BodyArgs&&... body_args)
- : header_type(std::move(h))
- , boost::empty_value<
- typename Body::value_type>(boost::empty_init_t(),
- std::forward<BodyArgs>(body_args)...)
- {
- }
- template<bool isRequest, class Body, class Fields>
- template<class... BodyArgs>
- message<isRequest, Body, Fields>::
- message(header_type const& h, BodyArgs&&... body_args)
- : header_type(h)
- , boost::empty_value<
- typename Body::value_type>(boost::empty_init_t(),
- std::forward<BodyArgs>(body_args)...)
- {
- }
- template<bool isRequest, class Body, class Fields>
- template<class Version, class>
- message<isRequest, Body, Fields>::
- message(verb method, string_view target, Version version)
- : header_type(method, target, version)
- {
- }
- template<bool isRequest, class Body, class Fields>
- template<class Version, class BodyArg, class>
- message<isRequest, Body, Fields>::
- message(verb method, string_view target,
- Version version, BodyArg&& body_arg)
- : header_type(method, target, version)
- , boost::empty_value<
- typename Body::value_type>(boost::empty_init_t(),
- std::forward<BodyArg>(body_arg))
- {
- }
- template<bool isRequest, class Body, class Fields>
- template<class Version, class BodyArg, class FieldsArg, class>
- message<isRequest, Body, Fields>::
- message(
- verb method, string_view target, Version version,
- BodyArg&& body_arg,
- FieldsArg&& fields_arg)
- : header_type(method, target, version,
- std::forward<FieldsArg>(fields_arg))
- , boost::empty_value<
- typename Body::value_type>(boost::empty_init_t(),
- std::forward<BodyArg>(body_arg))
- {
- }
- template<bool isRequest, class Body, class Fields>
- template<class Version, class>
- message<isRequest, Body, Fields>::
- message(status result, Version version)
- : header_type(result, version)
- {
- }
- template<bool isRequest, class Body, class Fields>
- template<class Version, class BodyArg, class>
- message<isRequest, Body, Fields>::
- message(status result, Version version,
- BodyArg&& body_arg)
- : header_type(result, version)
- , boost::empty_value<
- typename Body::value_type>(boost::empty_init_t(),
- std::forward<BodyArg>(body_arg))
- {
- }
- template<bool isRequest, class Body, class Fields>
- template<class Version, class BodyArg, class FieldsArg, class>
- message<isRequest, Body, Fields>::
- message(status result, Version version,
- BodyArg&& body_arg, FieldsArg&& fields_arg)
- : header_type(result, version,
- std::forward<FieldsArg>(fields_arg))
- , boost::empty_value<
- typename Body::value_type>(boost::empty_init_t(),
- std::forward<BodyArg>(body_arg))
- {
- }
- template<bool isRequest, class Body, class Fields>
- message<isRequest, Body, Fields>::
- message(std::piecewise_construct_t)
- {
- }
- template<bool isRequest, class Body, class Fields>
- template<class... BodyArgs>
- message<isRequest, Body, Fields>::
- message(std::piecewise_construct_t,
- std::tuple<BodyArgs...> body_args)
- : message(std::piecewise_construct,
- body_args,
- mp11::make_index_sequence<
- sizeof...(BodyArgs)>{})
- {
- }
- template<bool isRequest, class Body, class Fields>
- template<class... BodyArgs, class... FieldsArgs>
- message<isRequest, Body, Fields>::
- message(std::piecewise_construct_t,
- std::tuple<BodyArgs...> body_args,
- std::tuple<FieldsArgs...> fields_args)
- : message(std::piecewise_construct,
- body_args,
- fields_args,
- mp11::make_index_sequence<
- sizeof...(BodyArgs)>{},
- mp11::make_index_sequence<
- sizeof...(FieldsArgs)>{})
- {
- }
- template<bool isRequest, class Body, class Fields>
- void
- message<isRequest, Body, Fields>::
- chunked(bool value)
- {
- this->set_chunked_impl(value);
- this->set_content_length_impl(boost::none);
- }
- template<bool isRequest, class Body, class Fields>
- void
- message<isRequest, Body, Fields>::
- content_length(
- boost::optional<std::uint64_t> const& value)
- {
- this->set_content_length_impl(value);
- this->set_chunked_impl(false);
- }
- template<bool isRequest, class Body, class Fields>
- boost::optional<std::uint64_t>
- message<isRequest, Body, Fields>::
- payload_size() const
- {
- return payload_size(detail::is_body_sized<Body>{});
- }
- template<bool isRequest, class Body, class Fields>
- bool
- message<isRequest, Body, Fields>::
- need_eof(std::false_type) const
- {
- // VFALCO Do we need a way to let the caller say "the body is intentionally skipped"?
- if( this->result() == status::no_content ||
- this->result() == status::not_modified ||
- to_status_class(this->result()) ==
- status_class::informational ||
- has_content_length() ||
- chunked())
- return ! keep_alive();
- return true;
- }
- template<bool isRequest, class Body, class Fields>
- void
- message<isRequest, Body, Fields>::
- prepare_payload(std::true_type)
- {
- auto const n = payload_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(n);
- }
- else
- {
- this->chunked(false);
- }
- }
- else if(this->version() == 11)
- {
- this->chunked(true);
- }
- else
- {
- this->chunked(false);
- }
- }
- template<bool isRequest, class Body, class Fields>
- void
- message<isRequest, Body, Fields>::
- prepare_payload(std::false_type)
- {
- auto const n = payload_size();
- if( (! n || *n > 0) && (
- (status_class(this->result()) == status_class::informational ||
- this->result() == status::no_content ||
- this->result() == status::not_modified)))
- {
- // The response body MUST be empty for this case
- BOOST_THROW_EXCEPTION(std::invalid_argument{
- "invalid response body"});
- }
- if(n)
- this->content_length(n);
- else if(this->version() == 11)
- this->chunked(true);
- else
- this->chunked(false);
- }
- //------------------------------------------------------------------------------
- template<bool isRequest, class Body, class Fields>
- void
- swap(
- message<isRequest, Body, Fields>& m1,
- message<isRequest, Body, Fields>& m2)
- {
- using std::swap;
- swap(
- static_cast<header<isRequest, Fields>&>(m1),
- static_cast<header<isRequest, Fields>&>(m2));
- swap(m1.body(), m2.body());
- }
- } // http
- } // beast
- } // boost
- #endif
|