// // 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_MESSAGE_HPP #define BEAST_HTTP_MESSAGE_HPP #include #include #include #include #include #include namespace beast { namespace http { /** A container for HTTP request headers. The container includes the headers, as well as the request method and URL. Objects of this type may be used to represent incoming or outgoing requests for which the body is not yet known or generated. For example, when receiving a request with the header value "Expect: 100-continue". */ template struct request_headers { /// Indicates if the message is a request. using is_request = std::integral_constant; /// The type representing the headers. using headers_type = Headers; /** The HTTP version. This holds both the major and minor version numbers, using these formulas: @code major = version / 10; minor = version % 10; @endcode */ int version; /// The HTTP method. std::string method; /// The request URI. std::string url; /// The HTTP headers. Headers headers; /** Construct HTTP request headers. Arguments, if any, are forwarded to the constructor of the headers member. */ /** @{ */ request_headers() = default; template 0) || ! std::is_convertible< typename std::decay::type, request_headers>::value>::type> explicit request_headers(Arg1&& arg1, ArgN&&... argn) : headers(std::forward(arg1), std::forward(argn)...) { } /** @} */ }; /** Swap two HTTP request headers. Requirements: Headers is Swappable. */ template void swap( request_headers& a, request_headers& b) { using std::swap; swap(a.version, b.version); swap(a.method, b.method); swap(a.url, b.url); swap(a.headers, b.headers); } /** A container for HTTP response headers. The container includes the headers, as well as the response status and reasons. Objects of this type may be used to represent incoming or outgoing responses for which the body is not yet known or generated. For example, when responding to a HEAD request. */ template struct response_headers { /// Indicates if the message is a response. using is_request = std::integral_constant; /// The type representing the headers. using headers_type = Headers; /** The HTTP version. This holds both the major and minor version numbers, using these formulas: @code major = version / 10; minor = version % 10; @endcode */ int version; /// The HTTP response Status-Code. int status; /// The HTTP Reason-Phrase (obsolete). std::string reason; /// The HTTP headers. Headers headers; /** Construct HTTP request headers. Arguments, if any, are forwarded to the constructor of the headers member. */ /** @{ */ response_headers() = default; template 0) || ! std::is_convertible< typename std::decay::type, response_headers>::value>::type> explicit response_headers(Arg1&& arg1, ArgN&&... argn) : headers(std::forward(arg1), std::forward(argn)...) { } /** @} */ }; /** Swap two HTTP response headers. Requirements: Headers is Swappable. */ template void swap( response_headers& a, response_headers& b) { using std::swap; swap(a.version, b.version); swap(a.status, b.status); swap(a.reason, b.reason); swap(a.headers, b.headers); } /** A container for HTTP request or response headers. */ template using message_headers = typename std::conditional, response_headers>::type; /** A complete HTTP message. A message can be a request or response, depending on the `isRequest` template argument value. Requests and responses have different types, so functions may be overloaded on them if desired. The `Body` template argument type determines the model used to read or write the content body of the message. @tparam isRequest `true` if this is a request. @tparam Body A type meeting the requirements of Body. @tparam Headers A type meeting the requirements of Headers. */ template struct message : message_headers { /// The container used to hold the request or response headers using base_type = message_headers; /** The type controlling the body traits. The body member will be of type `body_type::value_type`. */ using body_type = Body; /// A container representing the body. typename Body::value_type body; /// Default constructor message() = default; /** Construct a message from headers. Additional arguments, if any, are forwarded to the constructor of the body member. */ template explicit message(base_type&& base, Args&&... args) : base_type(std::move(base)) , body(std::forward(args)...) { } /** Construct a message from headers. Additional arguments, if any, are forwarded to the constructor of the body member. */ template explicit message(base_type const& base, Args&&... args) : base_type(base) , body(std::forward(args)...) { } /** Construct a message. @param u An argument forwarded to the body constructor. */ template::type, base_type>::value>> explicit message(U&& u) : body(std::forward(u)) { } /** Construct a message. @param u An argument forwarded to the body constructor. @param v An argument forwarded to the headers constructor. */ template::type, base_type>::value>> message(U&& u, V&& v) : base_type(std::forward(v)) , body(std::forward(u)) { } /** Construct a message. @param un A tuple forwarded as a parameter pack to the body constructor. */ template message(std::piecewise_construct_t, std::tuple un) : message(std::piecewise_construct, un, beast::detail::make_index_sequence{}) { } /** Construct a message. @param un A tuple forwarded as a parameter pack to the body constructor. @param vn A tuple forwarded as a parameter pack to the headers constructor. */ template message(std::piecewise_construct_t, std::tuple&& un, std::tuple&& vn) : message(std::piecewise_construct, un, vn, beast::detail::make_index_sequence{}, beast::detail::make_index_sequence{}) { } private: template message(std::piecewise_construct_t, std::tuple& tu, beast::detail::index_sequence) : body(std::forward(std::get(tu))...) { } template message(std::piecewise_construct_t, std::tuple& tu, std::tuple& tv, beast::detail::index_sequence, beast::detail::index_sequence) : base_type(std::forward(std::get(tv))...) , body(std::forward(std::get(tu))...) { } }; /// Swap one message for another message. template void swap( message& a, message& b) { using std::swap; using base_type = typename message< isRequest, Body, Headers>::base_type; swap(static_cast(a), static_cast(b)); swap(a.body, b.body); } /// A typical HTTP request template>> using request = message; /// A typical HTTP response template>> using response = message; /** Returns `true` if a HTTP/1 message indicates a keep alive. Undefined behavior if version is greater than 11. */ template bool is_keep_alive(message const& msg); /** Returns `true` if a HTTP/1 message indicates an Upgrade request or response. Undefined behavior if version is greater than 11. */ template bool is_upgrade(message const& msg); /** HTTP/1 connection prepare options. @note These values are used with @ref prepare. */ enum class connection { /// Specify Connection: close. close, /// Specify Connection: keep-alive where possible. keep_alive, /// Specify Connection: upgrade. upgrade }; /** Prepare a HTTP message. This function will adjust the Content-Length, Transfer-Encoding, and Connection headers of the message based on the properties of the body and the options passed in. @param msg The message to prepare. The headers may be modified. @param options A list of prepare options. */ template< bool isRequest, class Body, class Headers, class... Options> void prepare(message& msg, Options&&... options); } // http } // beast #include #endif