2 // Copyright (c) 2016-2019 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_IMPL_MESSAGE_HPP
11 #define BOOST_BEAST_HTTP_IMPL_MESSAGE_HPP
13 #include <boost/beast/core/error.hpp>
14 #include <boost/assert.hpp>
15 #include <boost/throw_exception.hpp>
22 template<class Fields>
23 template<class Arg1, class... ArgN, class>
24 header<true, Fields>::
25 header(Arg1&& arg1, ArgN&&... argn)
26 : Fields(std::forward<Arg1>(arg1),
27 std::forward<ArgN>(argn)...)
31 template<class Fields>
33 header<true, Fields>::
39 template<class Fields>
41 header<true, Fields>::
44 if(v == verb::unknown)
45 BOOST_THROW_EXCEPTION(
46 std::invalid_argument{"unknown method"});
48 this->set_method_impl({});
51 template<class Fields>
53 header<true, Fields>::
56 if(method_ != verb::unknown)
57 return to_string(method_);
58 return this->get_method_impl();
61 template<class Fields>
63 header<true, Fields>::
64 method_string(string_view s)
66 method_ = string_to_verb(s);
67 if(method_ != verb::unknown)
68 this->set_method_impl({});
70 this->set_method_impl(s);
73 template<class Fields>
75 header<true, Fields>::
78 return this->get_target_impl();
81 template<class Fields>
83 header<true, Fields>::
86 this->set_target_impl(s);
89 template<class Fields>
92 header<true, Fields>& h1,
93 header<true, Fields>& h2)
97 static_cast<Fields&>(h1),
98 static_cast<Fields&>(h2));
99 swap(h1.version_, h2.version_);
100 swap(h1.method_, h2.method_);
103 //------------------------------------------------------------------------------
105 template<class Fields>
106 template<class Arg1, class... ArgN, class>
107 header<false, Fields>::
108 header(Arg1&& arg1, ArgN&&... argn)
109 : Fields(std::forward<Arg1>(arg1),
110 std::forward<ArgN>(argn)...)
114 template<class Fields>
116 header<false, Fields>::
119 return int_to_status(
120 static_cast<int>(result_));
123 template<class Fields>
125 header<false, Fields>::
131 template<class Fields>
133 header<false, Fields>::
137 BOOST_THROW_EXCEPTION(
138 std::invalid_argument{
139 "invalid status-code"});
140 result_ = static_cast<status>(v);
143 template<class Fields>
145 header<false, Fields>::
148 return static_cast<unsigned>(result_);
151 template<class Fields>
153 header<false, Fields>::
156 auto const s = this->get_reason_impl();
159 return obsolete_reason(result_);
162 template<class Fields>
164 header<false, Fields>::
165 reason(string_view s)
167 this->set_reason_impl(s);
170 template<class Fields>
173 header<false, Fields>& h1,
174 header<false, Fields>& h2)
178 static_cast<Fields&>(h1),
179 static_cast<Fields&>(h2));
180 swap(h1.version_, h2.version_);
181 swap(h1.result_, h2.result_);
184 //------------------------------------------------------------------------------
186 template<bool isRequest, class Body, class Fields>
187 template<class... BodyArgs>
188 message<isRequest, Body, Fields>::
189 message(header_type&& h, BodyArgs&&... body_args)
190 : header_type(std::move(h))
191 , boost::empty_value<
192 typename Body::value_type>(boost::empty_init_t(),
193 std::forward<BodyArgs>(body_args)...)
197 template<bool isRequest, class Body, class Fields>
198 template<class... BodyArgs>
199 message<isRequest, Body, Fields>::
200 message(header_type const& h, BodyArgs&&... body_args)
202 , boost::empty_value<
203 typename Body::value_type>(boost::empty_init_t(),
204 std::forward<BodyArgs>(body_args)...)
208 template<bool isRequest, class Body, class Fields>
209 template<class Version, class>
210 message<isRequest, Body, Fields>::
211 message(verb method, string_view target, Version version)
212 : header_type(method, target, version)
216 template<bool isRequest, class Body, class Fields>
217 template<class Version, class BodyArg, class>
218 message<isRequest, Body, Fields>::
219 message(verb method, string_view target,
220 Version version, BodyArg&& body_arg)
221 : header_type(method, target, version)
222 , boost::empty_value<
223 typename Body::value_type>(boost::empty_init_t(),
224 std::forward<BodyArg>(body_arg))
228 template<bool isRequest, class Body, class Fields>
229 template<class Version, class BodyArg, class FieldsArg, class>
230 message<isRequest, Body, Fields>::
232 verb method, string_view target, Version version,
234 FieldsArg&& fields_arg)
235 : header_type(method, target, version,
236 std::forward<FieldsArg>(fields_arg))
237 , boost::empty_value<
238 typename Body::value_type>(boost::empty_init_t(),
239 std::forward<BodyArg>(body_arg))
243 template<bool isRequest, class Body, class Fields>
244 template<class Version, class>
245 message<isRequest, Body, Fields>::
246 message(status result, Version version)
247 : header_type(result, version)
251 template<bool isRequest, class Body, class Fields>
252 template<class Version, class BodyArg, class>
253 message<isRequest, Body, Fields>::
254 message(status result, Version version,
256 : header_type(result, version)
257 , boost::empty_value<
258 typename Body::value_type>(boost::empty_init_t(),
259 std::forward<BodyArg>(body_arg))
263 template<bool isRequest, class Body, class Fields>
264 template<class Version, class BodyArg, class FieldsArg, class>
265 message<isRequest, Body, Fields>::
266 message(status result, Version version,
267 BodyArg&& body_arg, FieldsArg&& fields_arg)
268 : header_type(result, version,
269 std::forward<FieldsArg>(fields_arg))
270 , boost::empty_value<
271 typename Body::value_type>(boost::empty_init_t(),
272 std::forward<BodyArg>(body_arg))
276 template<bool isRequest, class Body, class Fields>
277 message<isRequest, Body, Fields>::
278 message(std::piecewise_construct_t)
282 template<bool isRequest, class Body, class Fields>
283 template<class... BodyArgs>
284 message<isRequest, Body, Fields>::
285 message(std::piecewise_construct_t,
286 std::tuple<BodyArgs...> body_args)
287 : message(std::piecewise_construct,
289 mp11::make_index_sequence<
290 sizeof...(BodyArgs)>{})
294 template<bool isRequest, class Body, class Fields>
295 template<class... BodyArgs, class... FieldsArgs>
296 message<isRequest, Body, Fields>::
297 message(std::piecewise_construct_t,
298 std::tuple<BodyArgs...> body_args,
299 std::tuple<FieldsArgs...> fields_args)
300 : message(std::piecewise_construct,
303 mp11::make_index_sequence<
304 sizeof...(BodyArgs)>{},
305 mp11::make_index_sequence<
306 sizeof...(FieldsArgs)>{})
310 template<bool isRequest, class Body, class Fields>
312 message<isRequest, Body, Fields>::
315 this->set_chunked_impl(value);
316 this->set_content_length_impl(boost::none);
319 template<bool isRequest, class Body, class Fields>
321 message<isRequest, Body, Fields>::
323 boost::optional<std::uint64_t> const& value)
325 this->set_content_length_impl(value);
326 this->set_chunked_impl(false);
329 template<bool isRequest, class Body, class Fields>
330 boost::optional<std::uint64_t>
331 message<isRequest, Body, Fields>::
334 return payload_size(detail::is_body_sized<Body>{});
337 template<bool isRequest, class Body, class Fields>
339 message<isRequest, Body, Fields>::
340 need_eof(std::false_type) const
342 // VFALCO Do we need a way to let the caller say "the body is intentionally skipped"?
343 if( this->result() == status::no_content ||
344 this->result() == status::not_modified ||
345 to_status_class(this->result()) ==
346 status_class::informational ||
347 has_content_length() ||
349 return ! keep_alive();
353 template<bool isRequest, class Body, class Fields>
355 message<isRequest, Body, Fields>::
356 prepare_payload(std::true_type)
358 auto const n = payload_size();
359 if(this->method() == verb::trace && (! n || *n > 0))
360 BOOST_THROW_EXCEPTION(std::invalid_argument{
361 "invalid request body"});
365 this->method() == verb::options ||
366 this->method() == verb::put ||
367 this->method() == verb::post)
369 this->content_length(n);
373 this->chunked(false);
376 else if(this->version() == 11)
382 this->chunked(false);
386 template<bool isRequest, class Body, class Fields>
388 message<isRequest, Body, Fields>::
389 prepare_payload(std::false_type)
391 auto const n = payload_size();
392 if( (! n || *n > 0) && (
393 (status_class(this->result()) == status_class::informational ||
394 this->result() == status::no_content ||
395 this->result() == status::not_modified)))
397 // The response body MUST be empty for this case
398 BOOST_THROW_EXCEPTION(std::invalid_argument{
399 "invalid response body"});
402 this->content_length(n);
403 else if(this->version() == 11)
406 this->chunked(false);
409 //------------------------------------------------------------------------------
411 template<bool isRequest, class Body, class Fields>
414 message<isRequest, Body, Fields>& m1,
415 message<isRequest, Body, Fields>& m2)
419 static_cast<header<isRequest, Fields>&>(m1),
420 static_cast<header<isRequest, Fields>&>(m2));
421 swap(m1.body(), m2.body());