2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_HTTP_MESSAGE_HPP
11 #define BOOST_BEAST_HTTP_MESSAGE_HPP
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/beast/http/fields.hpp>
15 #include <boost/beast/http/verb.hpp>
16 #include <boost/beast/http/status.hpp>
17 #include <boost/beast/http/type_traits.hpp>
18 #include <boost/beast/core/string.hpp>
19 #include <boost/beast/core/detail/empty_base_optimization.hpp>
20 #include <boost/beast/core/detail/integer_sequence.hpp>
21 #include <boost/assert.hpp>
22 #include <boost/optional.hpp>
23 #include <boost/throw_exception.hpp>
34 /** A container for an HTTP request or response header.
36 This container is derived from the `Fields` template type.
37 To understand all of the members of this class it is necessary
38 to view the declaration for the `Fields` type. When using
39 the default fields container, those declarations are in
42 Newly constructed header objects have version set to
43 HTTP/1.1. Newly constructed response objects also have
44 result code set to @ref status::ok.
46 A `header` includes the start-line and header-fields.
48 #if BOOST_BEAST_DOXYGEN
49 template<bool isRequest, class Fields = fields>
50 struct header : Fields
53 template<bool isRequest, class Fields = fields>
56 template<class Fields>
57 struct header<true, Fields> : Fields
60 static_assert(is_fields<Fields>::value,
61 "Fields requirements not met");
63 /// Indicates if the header is a request or response.
64 #if BOOST_BEAST_DOXYGEN
65 using is_request = std::integral_constant<bool, isRequest>;
67 using is_request = std::true_type;
70 /// The type representing the fields.
71 using fields_type = Fields;
77 header(header&&) = default;
80 header(header const&) = default;
83 header& operator=(header&&) = default;
86 header& operator=(header const&) = default;
88 /** Return the HTTP-version.
90 This holds both the major and minor version numbers,
93 unsigned major = version / 10;
94 unsigned minor = version % 10;
97 Newly constructed headers will use HTTP/1.1 by default.
99 unsigned version() const noexcept
104 /** Set the HTTP-version.
106 This holds both the major and minor version numbers,
107 using these formulas:
109 unsigned major = version / 10;
110 unsigned minor = version % 10;
113 Newly constructed headers will use HTTP/1.1 by default.
115 @param value The version number to use
117 void version(unsigned value) noexcept
119 BOOST_ASSERT(value > 0 && value < 100);
123 /** Return the request-method verb.
125 If the request-method is not one of the recognized verbs,
126 @ref verb::unknown is returned. Callers may use @ref method_string
127 to retrieve the exact text.
129 @note This function is only available when `isRequest == true`.
131 @see @ref method_string
136 /** Set the request-method.
138 This function will set the method for requests to a known verb.
140 @param v The request method verb to set.
141 This may not be @ref verb::unknown.
143 @throws std::invalid_argument when `v == verb::unknown`.
145 @note This function is only available when `isRequest == true`.
150 /** Return the request-method as a string.
152 @note This function is only available when `isRequest == true`.
157 method_string() const;
159 /** Set the request-method.
161 This function will set the request-method a known verb
162 if the string matches, otherwise it will store a copy of
165 @param s A string representing the request-method.
167 @note This function is only available when `isRequest == true`.
170 method_string(string_view s);
172 /** Returns the request-target string.
174 The request target string returned is the same string which
175 was received from the network or stored. In particular, it will
176 contain url-encoded characters and should follow the syntax
177 rules for URIs used with HTTP.
179 @note This function is only available when `isRequest == true`.
184 /** Set the request-target string.
186 It is the caller's responsibility to ensure that the request
187 target string follows the syntax rules for URIs used with
188 HTTP. In particular, reserved or special characters must be
189 url-encoded. The implementation does not perform syntax checking
190 on the passed string.
192 @param s A string representing the request-target.
194 @note This function is only available when `isRequest == true`.
197 target(string_view s);
199 // VFALCO Don't rearrange these declarations or
200 // ifdefs, or else the documentation will break.
204 @param args Arguments forwarded to the `Fields`
205 base class constructor.
207 @note This constructor participates in overload
208 resolution if and only if the first parameter is
209 not convertible to @ref header, @ref verb, or
212 #if BOOST_BEAST_DOXYGEN
213 template<class... Args>
215 header(Args&&... args);
218 template<class Arg1, class... ArgN,
219 class = typename std::enable_if<
220 ! std::is_convertible<typename
221 std::decay<Arg1>::type, header>::value &&
222 ! std::is_convertible<typename
223 std::decay<Arg1>::type, verb>::value &&
224 ! std::is_convertible<typename
225 std::decay<Arg1>::type, header>::value
228 header(Arg1&& arg1, ArgN&&... argn);
231 template<bool, class, class>
232 friend struct message;
237 swap(header<true, T>& m1, header<true, T>& m2);
239 template<class... FieldsArgs>
243 unsigned version_value,
244 FieldsArgs&&... fields_args)
245 : Fields(std::forward<FieldsArgs>(fields_args)...)
248 version(version_value);
252 unsigned version_ = 11;
253 verb method_ = verb::unknown;
256 /** A container for an HTTP request or response header.
258 A `header` includes the start-line and header-fields.
260 template<class Fields>
261 struct header<false, Fields> : Fields
263 static_assert(is_fields<Fields>::value,
264 "Fields requirements not met");
266 /// Indicates if the header is a request or response.
267 using is_request = std::false_type;
269 /// The type representing the fields.
270 using fields_type = Fields;
276 header(header&&) = default;
279 header(header const&) = default;
282 header& operator=(header&&) = default;
285 header& operator=(header const&) = default;
289 @param args Arguments forwarded to the `Fields`
290 base class constructor.
292 @note This constructor participates in overload
293 resolution if and only if the first parameter is
294 not convertible to @ref header, @ref verb, or
297 template<class Arg1, class... ArgN,
298 class = typename std::enable_if<
299 ! std::is_convertible<typename
300 std::decay<Arg1>::type, status>::value &&
301 ! std::is_convertible<typename
302 std::decay<Arg1>::type, header>::value
305 header(Arg1&& arg1, ArgN&&... argn);
307 /** Return the HTTP-version.
309 This holds both the major and minor version numbers,
310 using these formulas:
312 unsigned major = version / 10;
313 unsigned minor = version % 10;
316 Newly constructed headers will use HTTP/1.1 by default.
318 unsigned version() const noexcept
323 /** Set the HTTP-version.
325 This holds both the major and minor version numbers,
326 using these formulas:
328 unsigned major = version / 10;
329 unsigned minor = version % 10;
332 Newly constructed headers will use HTTP/1.1 by default.
334 @param value The version number to use
336 void version(unsigned value) noexcept
338 BOOST_ASSERT(value > 0 && value < 100);
343 /** The response status-code result.
345 If the actual status code is not a known code, this
346 function returns @ref status::unknown. Use @ref result_int
347 to return the raw status code as a number.
349 @note This member is only available when `isRequest == false`.
354 /** Set the response status-code.
356 @param v The code to set.
358 @note This member is only available when `isRequest == false`.
363 /** Set the response status-code as an integer.
365 This sets the status code to the exact number passed in.
366 If the number does not correspond to one of the known
367 status codes, the function @ref result will return
368 @ref status::unknown. Use @ref result_int to obtain the
369 original raw status-code.
371 @param v The status-code integer to set.
373 @throws std::invalid_argument if `v > 999`.
378 /** The response status-code expressed as an integer.
380 This returns the raw status code as an integer, even
381 when that code is not in the list of known status codes.
383 @note This member is only available when `isRequest == false`.
388 /** Return the response reason-phrase.
390 The reason-phrase is obsolete as of rfc7230.
392 @note This function is only available when `isRequest == false`.
397 /** Set the response reason-phrase (deprecated)
399 This function sets a custom reason-phrase to a copy of
400 the string passed in. Normally it is not necessary to set
401 the reason phrase on an outgoing response object; the
402 implementation will automatically use the standard reason
403 text for the corresponding status code.
405 To clear a previously set custom phrase, pass an empty
406 string. This will restore the default standard reason text
407 based on the status code used when serializing.
409 The reason-phrase is obsolete as of rfc7230.
411 @param s The string to use for the reason-phrase.
413 @note This function is only available when `isRequest == false`.
416 reason(string_view s);
419 #if ! BOOST_BEAST_DOXYGEN
420 template<bool, class, class>
421 friend struct message;
426 swap(header<false, T>& m1, header<false, T>& m2);
428 template<class... FieldsArgs>
431 unsigned version_value,
432 FieldsArgs&&... fields_args)
433 : Fields(std::forward<FieldsArgs>(fields_args)...)
436 version(version_value);
439 unsigned version_ = 11;
440 status result_ = status::ok;
444 /// A typical HTTP request header
445 template<class Fields = fields>
446 using request_header = header<true, Fields>;
448 /// A typical HTTP response header
449 template<class Fields = fields>
450 using response_header = header<false, Fields>;
452 #if defined(BOOST_MSVC)
453 // Workaround for MSVC bug with private base classes
456 using value_type_t = typename T::value_type;
460 /** A container for a complete HTTP message.
462 This container is derived from the `Fields` template type.
463 To understand all of the members of this class it is necessary
464 to view the declaration for the `Fields` type. When using
465 the default fields container, those declarations are in
468 A message can be a request or response, depending on the
469 `isRequest` template argument value. Requests and responses
470 have different types; functions may be overloaded based on
473 The `Body` template argument type determines the model used
474 to read or write the content body of the message.
476 Newly constructed messages objects have version set to
477 HTTP/1.1. Newly constructed response objects also have
478 result code set to @ref status::ok.
480 @tparam isRequest `true` if this represents a request,
481 or `false` if this represents a response. Some class data
482 members are conditionally present depending on this value.
484 @tparam Body A type meeting the requirements of Body.
486 @tparam Fields The type of container used to hold the
489 template<bool isRequest, class Body, class Fields = fields>
491 : header<isRequest, Fields>
492 #if ! BOOST_BEAST_DOXYGEN
493 , beast::detail::empty_base_optimization<
494 typename Body::value_type>
497 /// The base class used to hold the header portion of the message.
498 using header_type = header<isRequest, Fields>;
500 /** The type providing the body traits.
502 The @ref message::body member will be of type `body_type::value_type`.
504 using body_type = Body;
510 message(message&&) = default;
513 message(message const&) = default;
516 message& operator=(message&&) = default;
519 message& operator=(message const&) = default;
523 @param h The header to move construct from.
525 @param body_args Optional arguments forwarded
526 to the `body` constructor.
528 template<class... BodyArgs>
530 message(header_type&& h, BodyArgs&&... body_args);
534 @param h The header to copy construct from.
536 @param body_args Optional arguments forwarded
537 to the `body` constructor.
539 template<class... BodyArgs>
541 message(header_type const& h, BodyArgs&&... body_args);
545 @param method The request-method to use
547 @param target The request-target.
549 @param version The HTTP-version
551 @note This function is only available when `isRequest == true`.
553 #if BOOST_BEAST_DOXYGEN
554 message(verb method, string_view target, unsigned version);
556 template<class Version,
557 class = typename std::enable_if<isRequest &&
558 std::is_convertible<Version, unsigned>::value>::type>
559 message(verb method, string_view target, Version version);
564 @param method The request-method to use
566 @param target The request-target.
568 @param version The HTTP-version
570 @param body_arg An argument forwarded to the `body` constructor.
572 @note This function is only available when `isRequest == true`.
574 #if BOOST_BEAST_DOXYGEN
575 template<class BodyArg>
576 message(verb method, string_view target,
577 unsigned version, BodyArg&& body_arg);
579 template<class Version, class BodyArg,
580 class = typename std::enable_if<isRequest &&
581 std::is_convertible<Version, unsigned>::value>::type>
582 message(verb method, string_view target,
583 Version version, BodyArg&& body_arg);
588 @param method The request-method to use
590 @param target The request-target.
592 @param version The HTTP-version
594 @param body_arg An argument forwarded to the `body` constructor.
596 @param fields_arg An argument forwarded to the `Fields` constructor.
598 @note This function is only available when `isRequest == true`.
600 #if BOOST_BEAST_DOXYGEN
601 template<class BodyArg, class FieldsArg>
602 message(verb method, string_view target, unsigned version,
603 BodyArg&& body_arg, FieldsArg&& fields_arg);
605 template<class Version, class BodyArg, class FieldsArg,
606 class = typename std::enable_if<isRequest &&
607 std::is_convertible<Version, unsigned>::value>::type>
608 message(verb method, string_view target, Version version,
609 BodyArg&& body_arg, FieldsArg&& fields_arg);
614 @param result The status-code for the response
616 @param version The HTTP-version
618 @note This member is only available when `isRequest == false`.
620 #if BOOST_BEAST_DOXYGEN
621 message(status result, unsigned version);
623 template<class Version,
624 class = typename std::enable_if<! isRequest &&
625 std::is_convertible<Version, unsigned>::value>::type>
626 message(status result, Version version);
631 @param result The status-code for the response
633 @param version The HTTP-version
635 @param body_arg An argument forwarded to the `body` constructor.
637 @note This member is only available when `isRequest == false`.
639 #if BOOST_BEAST_DOXYGEN
640 template<class BodyArg>
641 message(status result, unsigned version, BodyArg&& body_arg);
643 template<class Version, class BodyArg,
644 class = typename std::enable_if<! isRequest &&
645 std::is_convertible<Version, unsigned>::value>::type>
646 message(status result, Version version, BodyArg&& body_arg);
651 @param result The status-code for the response
653 @param version The HTTP-version
655 @param body_arg An argument forwarded to the `body` constructor.
657 @param fields_arg An argument forwarded to the `Fields` base class constructor.
659 @note This member is only available when `isRequest == false`.
661 #if BOOST_BEAST_DOXYGEN
662 template<class BodyArg, class FieldsArg>
663 message(status result, unsigned version,
664 BodyArg&& body_arg, FieldsArg&& fields_arg);
666 template<class Version, class BodyArg, class FieldsArg,
667 class = typename std::enable_if<! isRequest &&
668 std::is_convertible<Version, unsigned>::value>::type>
669 message(status result, Version version,
670 BodyArg&& body_arg, FieldsArg&& fields_arg);
675 The header and body are default-constructed.
678 message(std::piecewise_construct_t);
680 /** Construct a message.
682 @param body_args A tuple forwarded as a parameter
683 pack to the body constructor.
685 template<class... BodyArgs>
686 message(std::piecewise_construct_t,
687 std::tuple<BodyArgs...> body_args);
689 /** Construct a message.
691 @param body_args A tuple forwarded as a parameter
692 pack to the body constructor.
694 @param fields_args A tuple forwarded as a parameter
695 pack to the `Fields` constructor.
697 template<class... BodyArgs, class... FieldsArgs>
698 message(std::piecewise_construct_t,
699 std::tuple<BodyArgs...> body_args,
700 std::tuple<FieldsArgs...> fields_args);
702 /// Returns the header portion of the message
709 /// Returns the header portion of the message
716 /// Returns `true` if the chunked Transfer-Encoding is specified
720 return this->get_chunked_impl();
723 /** Set or clear the chunked Transfer-Encoding
725 This function will set or removed the "chunked" transfer
726 encoding as the last item in the list of encodings in the
729 If the result of removing the chunked token results in an
730 empty string, the field is erased.
732 The Content-Length field is erased unconditionally.
737 /** Returns `true` if the Content-Length field is present.
739 This function inspects the fields and returns `true` if
740 the Content-Length field is present. The properties of the
741 body are not checked, this only looks for the field.
744 has_content_length() const
746 return this->has_content_length_impl();
749 /** Set or clear the Content-Length field
751 This function adjusts the Content-Length field as follows:
753 @li If `value` specifies a value, the Content-Length field
754 is set to the value. Otherwise
756 @li The Content-Length field is erased.
758 If "chunked" token appears as the last item in the
759 Transfer-Encoding field it is unconditionally removed.
761 @param value The value to set for Content-Length.
764 content_length(boost::optional<std::uint64_t> const& value);
766 /** Returns `true` if the message semantics indicate keep-alive
768 The value depends on the version in the message, which must
769 be set to the final value before this function is called or
770 else the return value is unreliable.
775 return this->get_keep_alive_impl(this->version());
778 /** Set the keep-alive message semantic option
780 This function adjusts the Connection field to indicate
781 whether or not the connection should be kept open after
782 the corresponding response. The result depends on the
783 version set on the message, which must be set to the
784 final value before making this call.
786 @param value `true` if the connection should persist.
789 keep_alive(bool value)
791 this->set_keep_alive_impl(this->version(), value);
794 /** Returns `true` if the message semantics require an end of file.
796 For HTTP requests, this function returns the logical
797 NOT of a call to @ref keep_alive.
799 For HTTP responses, this function returns the logical NOT
800 of a call to @ref keep_alive if any of the following are true:
802 @li @ref has_content_length would return `true`
804 @li @ref chunked would return `true`
806 @li @ref result returns @ref status::no_content
808 @li @ref result returns @ref status::not_modified
810 @li @ref result returns any informational status class (100 to 199)
812 Otherwise, the function returns `true`.
814 @see https://tools.ietf.org/html/rfc7230#section-3.3
819 return need_eof(typename header_type::is_request{});
822 /** Returns the payload size of the body in octets if possible.
824 This function invokes the @b Body algorithm to measure
825 the number of octets in the serialized body container. If
826 there is no body, this will return zero. Otherwise, if the
827 body exists but is not known ahead of time, `boost::none`
828 is returned (usually indicating that a chunked Transfer-Encoding
831 @note The value of the Content-Length field in the message
834 boost::optional<std::uint64_t>
835 payload_size() const;
837 /** Prepare the message payload fields for the body.
839 This function will adjust the Content-Length and
840 Transfer-Encoding field values based on the properties
845 request<string_body> req{verb::post, "/"};
846 req.set(field::user_agent, "Beast");
847 req.body() = "Hello, world!";
848 req.prepare_payload();
854 prepare_payload(typename header_type::is_request{});
858 #if BOOST_BEAST_DOXYGEN || ! defined(BOOST_MSVC)
859 typename body_type::value_type&
861 detail::value_type_t<Body>&
865 return this->member();
869 #if BOOST_BEAST_DOXYGEN || ! defined(BOOST_MSVC)
870 typename body_type::value_type&&
872 detail::value_type_t<Body>&&
876 return std::move(this->member());
880 #if BOOST_BEAST_DOXYGEN || ! defined(BOOST_MSVC)
881 typename body_type::value_type const&
883 detail::value_type_t<Body> const&
885 body() const& noexcept
887 return this->member();
891 static_assert(is_body<Body>::value,
892 "Body requirements not met");
896 std::size_t... IBodyArgs>
898 std::piecewise_construct_t,
899 std::tuple<BodyArgs...>& body_args,
900 beast::detail::index_sequence<IBodyArgs...>)
901 : beast::detail::empty_base_optimization<
902 typename Body::value_type>(
903 std::forward<BodyArgs>(
904 std::get<IBodyArgs>(body_args))...)
906 boost::ignore_unused(body_args);
912 std::size_t... IBodyArgs,
913 std::size_t... IFieldsArgs>
915 std::piecewise_construct_t,
916 std::tuple<BodyArgs...>& body_args,
917 std::tuple<FieldsArgs...>& fields_args,
918 beast::detail::index_sequence<IBodyArgs...>,
919 beast::detail::index_sequence<IFieldsArgs...>)
920 : header_type(std::forward<FieldsArgs>(
921 std::get<IFieldsArgs>(fields_args))...)
922 , beast::detail::empty_base_optimization<
923 typename Body::value_type>(
924 std::forward<BodyArgs>(
925 std::get<IBodyArgs>(body_args))...)
927 boost::ignore_unused(body_args);
928 boost::ignore_unused(fields_args);
932 need_eof(std::true_type) const
934 return ! keep_alive();
938 need_eof(std::false_type) const;
940 boost::optional<std::uint64_t>
941 payload_size(std::true_type) const
943 return Body::size(this->body());
946 boost::optional<std::uint64_t>
947 payload_size(std::false_type) const
953 prepare_payload(std::true_type);
956 prepare_payload(std::false_type);
959 /// A typical HTTP request
960 template<class Body, class Fields = fields>
961 using request = message<true, Body, Fields>;
963 /// A typical HTTP response
964 template<class Body, class Fields = fields>
965 using response = message<false, Body, Fields>;
967 //------------------------------------------------------------------------------
969 #if BOOST_BEAST_DOXYGEN
970 /** Swap two header objects.
973 `Fields` is @b Swappable.
975 template<bool isRequest, class Fields>
978 header<isRequest, Fields>& m1,
979 header<isRequest, Fields>& m2);
982 /** Swap two message objects.
985 `Body::value_type` and `Fields` are @b Swappable.
987 template<bool isRequest, class Body, class Fields>
990 message<isRequest, Body, Fields>& m1,
991 message<isRequest, Body, Fields>& m2);
997 #include <boost/beast/http/impl/message.ipp>