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_IMPL_MESSAGE_IPP
11 #define BOOST_BEAST_HTTP_IMPL_MESSAGE_IPP
13 #include <boost/beast/core/error.hpp>
14 #include <boost/beast/core/detail/type_traits.hpp>
15 #include <boost/assert.hpp>
16 #include <boost/throw_exception.hpp>
23 template<class Fields>
24 template<class Arg1, class... ArgN, class>
25 header<true, Fields>::
26 header(Arg1&& arg1, ArgN&&... argn)
27 : Fields(std::forward<Arg1>(arg1),
28 std::forward<ArgN>(argn)...)
32 template<class Fields>
35 header<true, Fields>::
41 template<class Fields>
43 header<true, Fields>::
46 if(v == verb::unknown)
47 BOOST_THROW_EXCEPTION(
48 std::invalid_argument{"unknown method"});
50 this->set_method_impl({});
53 template<class Fields>
55 header<true, Fields>::
58 if(method_ != verb::unknown)
59 return to_string(method_);
60 return this->get_method_impl();
63 template<class Fields>
65 header<true, Fields>::
66 method_string(string_view s)
68 method_ = string_to_verb(s);
69 if(method_ != verb::unknown)
70 this->set_method_impl({});
72 this->set_method_impl(s);
75 template<class Fields>
78 header<true, Fields>::
81 return this->get_target_impl();
84 template<class Fields>
87 header<true, Fields>::
90 this->set_target_impl(s);
93 template<class Fields>
96 header<true, Fields>& h1,
97 header<true, Fields>& h2)
101 static_cast<Fields&>(h1),
102 static_cast<Fields&>(h2));
103 swap(h1.version_, h2.version_);
104 swap(h1.method_, h2.method_);
107 //------------------------------------------------------------------------------
109 template<class Fields>
110 template<class Arg1, class... ArgN, class>
111 header<false, Fields>::
112 header(Arg1&& arg1, ArgN&&... argn)
113 : Fields(std::forward<Arg1>(arg1),
114 std::forward<ArgN>(argn)...)
118 template<class Fields>
121 header<false, Fields>::
124 return int_to_status(
125 static_cast<int>(result_));
128 template<class Fields>
131 header<false, Fields>::
137 template<class Fields>
140 header<false, Fields>::
144 BOOST_THROW_EXCEPTION(
145 std::invalid_argument{
146 "invalid status-code"});
147 result_ = static_cast<status>(v);
150 template<class Fields>
153 header<false, Fields>::
156 return static_cast<unsigned>(result_);
159 template<class Fields>
161 header<false, Fields>::
164 auto const s = this->get_reason_impl();
167 return obsolete_reason(result_);
170 template<class Fields>
173 header<false, Fields>::
174 reason(string_view s)
176 this->set_reason_impl(s);
179 template<class Fields>
182 header<false, Fields>& h1,
183 header<false, Fields>& h2)
187 static_cast<Fields&>(h1),
188 static_cast<Fields&>(h2));
189 swap(h1.version_, h2.version_);
190 swap(h1.result_, h2.result_);
193 //------------------------------------------------------------------------------
195 template<bool isRequest, class Body, class Fields>
196 template<class... BodyArgs>
197 message<isRequest, Body, Fields>::
198 message(header_type&& h, BodyArgs&&... body_args)
199 : header_type(std::move(h))
200 , beast::detail::empty_base_optimization<
201 typename Body::value_type>(
202 std::forward<BodyArgs>(body_args)...)
206 template<bool isRequest, class Body, class Fields>
207 template<class... BodyArgs>
208 message<isRequest, Body, Fields>::
209 message(header_type const& h, BodyArgs&&... body_args)
211 , beast::detail::empty_base_optimization<
212 typename Body::value_type>(
213 std::forward<BodyArgs>(body_args)...)
217 template<bool isRequest, class Body, class Fields>
218 template<class Version, class>
219 message<isRequest, Body, Fields>::
220 message(verb method, string_view target, Version version)
221 : header_type(method, target, version)
225 template<bool isRequest, class Body, class Fields>
226 template<class Version, class BodyArg, class>
227 message<isRequest, Body, Fields>::
228 message(verb method, string_view target,
229 Version version, BodyArg&& body_arg)
230 : header_type(method, target, version)
231 , beast::detail::empty_base_optimization<
232 typename Body::value_type>(
233 std::forward<BodyArg>(body_arg))
237 template<bool isRequest, class Body, class Fields>
238 template<class Version, class BodyArg, class FieldsArg, class>
239 message<isRequest, Body, Fields>::
241 verb method, string_view target, Version version,
243 FieldsArg&& fields_arg)
244 : header_type(method, target, version,
245 std::forward<FieldsArg>(fields_arg))
246 , beast::detail::empty_base_optimization<
247 typename Body::value_type>(
248 std::forward<BodyArg>(body_arg))
252 template<bool isRequest, class Body, class Fields>
253 template<class Version, class>
254 message<isRequest, Body, Fields>::
255 message(status result, Version version)
256 : header_type(result, version)
260 template<bool isRequest, class Body, class Fields>
261 template<class Version, class BodyArg, class>
262 message<isRequest, Body, Fields>::
263 message(status result, Version version,
265 : header_type(result, version)
266 , beast::detail::empty_base_optimization<
267 typename Body::value_type>(
268 std::forward<BodyArg>(body_arg))
272 template<bool isRequest, class Body, class Fields>
273 template<class Version, class BodyArg, class FieldsArg, class>
274 message<isRequest, Body, Fields>::
275 message(status result, Version version,
276 BodyArg&& body_arg, FieldsArg&& fields_arg)
277 : header_type(result, version,
278 std::forward<FieldsArg>(fields_arg))
279 , beast::detail::empty_base_optimization<
280 typename Body::value_type>(
281 std::forward<BodyArg>(body_arg))
285 template<bool isRequest, class Body, class Fields>
286 message<isRequest, Body, Fields>::
287 message(std::piecewise_construct_t)
291 template<bool isRequest, class Body, class Fields>
292 template<class... BodyArgs>
293 message<isRequest, Body, Fields>::
294 message(std::piecewise_construct_t,
295 std::tuple<BodyArgs...> body_args)
296 : message(std::piecewise_construct,
298 beast::detail::make_index_sequence<
299 sizeof...(BodyArgs)>{})
303 template<bool isRequest, class Body, class Fields>
304 template<class... BodyArgs, class... FieldsArgs>
305 message<isRequest, Body, Fields>::
306 message(std::piecewise_construct_t,
307 std::tuple<BodyArgs...> body_args,
308 std::tuple<FieldsArgs...> fields_args)
309 : message(std::piecewise_construct,
312 beast::detail::make_index_sequence<
313 sizeof...(BodyArgs)>{},
314 beast::detail::make_index_sequence<
315 sizeof...(FieldsArgs)>{})
319 template<bool isRequest, class Body, class Fields>
321 message<isRequest, Body, Fields>::
324 this->set_chunked_impl(value);
325 this->set_content_length_impl(boost::none);
328 template<bool isRequest, class Body, class Fields>
330 message<isRequest, Body, Fields>::
332 boost::optional<std::uint64_t> const& value)
334 this->set_content_length_impl(value);
335 this->set_chunked_impl(false);
338 template<bool isRequest, class Body, class Fields>
339 boost::optional<std::uint64_t>
340 message<isRequest, Body, Fields>::
343 return payload_size(detail::is_body_sized<Body>{});
346 template<bool isRequest, class Body, class Fields>
348 message<isRequest, Body, Fields>::
349 need_eof(std::false_type) const
351 // VFALCO Do we need a way to let the caller say "the body is intentionally skipped"?
352 if( this->result() == status::no_content ||
353 this->result() == status::not_modified ||
354 to_status_class(this->result()) ==
355 status_class::informational ||
356 has_content_length() ||
358 return ! keep_alive();
362 template<bool isRequest, class Body, class Fields>
364 message<isRequest, Body, Fields>::
365 prepare_payload(std::true_type)
367 auto const n = payload_size();
368 if(this->method() == verb::trace && (! n || *n > 0))
369 BOOST_THROW_EXCEPTION(std::invalid_argument{
370 "invalid request body"});
374 this->method() == verb::options ||
375 this->method() == verb::put ||
376 this->method() == verb::post)
378 this->content_length(n);
382 this->chunked(false);
385 else if(this->version() == 11)
391 this->chunked(false);
395 template<bool isRequest, class Body, class Fields>
397 message<isRequest, Body, Fields>::
398 prepare_payload(std::false_type)
400 auto const n = payload_size();
401 if( (! n || *n > 0) && (
402 (status_class(this->result()) == status_class::informational ||
403 this->result() == status::no_content ||
404 this->result() == status::not_modified)))
406 // The response body MUST be empty for this case
407 BOOST_THROW_EXCEPTION(std::invalid_argument{
408 "invalid response body"});
411 this->content_length(n);
412 else if(this->version() == 11)
415 this->chunked(false);
418 //------------------------------------------------------------------------------
420 template<bool isRequest, class Body, class Fields>
423 message<isRequest, Body, Fields>& m1,
424 message<isRequest, Body, Fields>& m2)
428 static_cast<header<isRequest, Fields>&>(m1),
429 static_cast<header<isRequest, Fields>&>(m2));
430 swap(m1.body(), m2.body());