1//
2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3//
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)
6//
7// Official repository: https://github.com/boostorg/beast
8//
9
10#ifndef BOOST_BEAST_HTTP_IMPL_MESSAGE_HPP
11#define BOOST_BEAST_HTTP_IMPL_MESSAGE_HPP
12
13#include <boost/beast/core/error.hpp>
14#include <boost/assert.hpp>
15#include <boost/throw_exception.hpp>
16#include <stdexcept>
17
18namespace boost {
19namespace beast {
20namespace http {
21
22template<class Fields>
23template<class Arg1, class... ArgN, class>
24header<true, Fields>::
25header(Arg1&& arg1, ArgN&&... argn)
26 : Fields(std::forward<Arg1>(arg1),
27 std::forward<ArgN>(argn)...)
28{
29}
30
31template<class Fields>
32verb
33header<true, Fields>::
34method() const
35{
36 return method_;
37}
38
39template<class Fields>
40void
41header<true, Fields>::
42method(verb v)
43{
44 if(v == verb::unknown)
45 BOOST_THROW_EXCEPTION(
46 std::invalid_argument{"unknown method"});
47 method_ = v;
48 this->set_method_impl({});
49}
50
51template<class Fields>
52string_view
53header<true, Fields>::
54method_string() const
55{
56 if(method_ != verb::unknown)
57 return to_string(v: method_);
58 return this->get_method_impl();
59}
60
61template<class Fields>
62void
63header<true, Fields>::
64method_string(string_view s)
65{
66 method_ = string_to_verb(v: s);
67 if(method_ != verb::unknown)
68 this->set_method_impl({});
69 else
70 this->set_method_impl(s);
71}
72
73template<class Fields>
74string_view
75header<true, Fields>::
76target() const
77{
78 return this->get_target_impl();
79}
80
81template<class Fields>
82void
83header<true, Fields>::
84target(string_view s)
85{
86 this->set_target_impl(s);
87}
88
89template<class Fields>
90void
91swap(
92 header<true, Fields>& h1,
93 header<true, Fields>& h2)
94{
95 using std::swap;
96 swap(
97 static_cast<Fields&>(h1),
98 static_cast<Fields&>(h2));
99 swap(h1.version_, h2.version_);
100 swap(h1.method_, h2.method_);
101}
102
103//------------------------------------------------------------------------------
104
105template<class Fields>
106template<class Arg1, class... ArgN, class>
107header<false, Fields>::
108header(Arg1&& arg1, ArgN&&... argn)
109 : Fields(std::forward<Arg1>(arg1),
110 std::forward<ArgN>(argn)...)
111{
112}
113
114template<class Fields>
115status
116header<false, Fields>::
117result() const
118{
119 return int_to_status(
120 v: static_cast<int>(result_));
121}
122
123template<class Fields>
124void
125header<false, Fields>::
126result(status v)
127{
128 result_ = v;
129}
130
131template<class Fields>
132void
133header<false, Fields>::
134result(unsigned v)
135{
136 if(v > 999)
137 BOOST_THROW_EXCEPTION(
138 std::invalid_argument{
139 "invalid status-code"});
140 result_ = static_cast<status>(v);
141}
142
143template<class Fields>
144unsigned
145header<false, Fields>::
146result_int() const
147{
148 return static_cast<unsigned>(result_);
149}
150
151template<class Fields>
152string_view
153header<false, Fields>::
154reason() const
155{
156 auto const s = this->get_reason_impl();
157 if(! s.empty())
158 return s;
159 return obsolete_reason(v: result_);
160}
161
162template<class Fields>
163void
164header<false, Fields>::
165reason(string_view s)
166{
167 this->set_reason_impl(s);
168}
169
170template<class Fields>
171void
172swap(
173 header<false, Fields>& h1,
174 header<false, Fields>& h2)
175{
176 using std::swap;
177 swap(
178 static_cast<Fields&>(h1),
179 static_cast<Fields&>(h2));
180 swap(h1.version_, h2.version_);
181 swap(h1.result_, h2.result_);
182}
183
184//------------------------------------------------------------------------------
185
186template<bool isRequest, class Body, class Fields>
187template<class... BodyArgs>
188message<isRequest, Body, Fields>::
189message(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)...)
194{
195}
196
197template<bool isRequest, class Body, class Fields>
198template<class... BodyArgs>
199message<isRequest, Body, Fields>::
200message(header_type const& h, BodyArgs&&... body_args)
201 : header_type(h)
202 , boost::empty_value<
203 typename Body::value_type>(boost::empty_init_t(),
204 std::forward<BodyArgs>(body_args)...)
205{
206}
207
208template<bool isRequest, class Body, class Fields>
209template<class Version, class>
210message<isRequest, Body, Fields>::
211message(verb method, string_view target, Version version)
212 : header_type(method, target, version)
213{
214}
215
216template<bool isRequest, class Body, class Fields>
217template<class Version, class BodyArg, class>
218message<isRequest, Body, Fields>::
219message(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))
225{
226}
227
228template<bool isRequest, class Body, class Fields>
229template<class Version, class BodyArg, class FieldsArg, class>
230message<isRequest, Body, Fields>::
231message(
232 verb method, string_view target, Version version,
233 BodyArg&& body_arg,
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))
240{
241}
242
243template<bool isRequest, class Body, class Fields>
244template<class Version, class>
245message<isRequest, Body, Fields>::
246message(status result, Version version)
247 : header_type(result, version)
248{
249}
250
251template<bool isRequest, class Body, class Fields>
252template<class Version, class BodyArg, class>
253message<isRequest, Body, Fields>::
254message(status result, Version version,
255 BodyArg&& body_arg)
256 : header_type(result, version)
257 , boost::empty_value<
258 typename Body::value_type>(boost::empty_init_t(),
259 std::forward<BodyArg>(body_arg))
260{
261}
262
263template<bool isRequest, class Body, class Fields>
264template<class Version, class BodyArg, class FieldsArg, class>
265message<isRequest, Body, Fields>::
266message(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))
273{
274}
275
276template<bool isRequest, class Body, class Fields>
277message<isRequest, Body, Fields>::
278message(std::piecewise_construct_t)
279{
280}
281
282template<bool isRequest, class Body, class Fields>
283template<class... BodyArgs>
284message<isRequest, Body, Fields>::
285message(std::piecewise_construct_t,
286 std::tuple<BodyArgs...> body_args)
287 : message(std::piecewise_construct,
288 body_args,
289 mp11::make_index_sequence<
290 sizeof...(BodyArgs)>{})
291{
292}
293
294template<bool isRequest, class Body, class Fields>
295template<class... BodyArgs, class... FieldsArgs>
296message<isRequest, Body, Fields>::
297message(std::piecewise_construct_t,
298 std::tuple<BodyArgs...> body_args,
299 std::tuple<FieldsArgs...> fields_args)
300 : message(std::piecewise_construct,
301 body_args,
302 fields_args,
303 mp11::make_index_sequence<
304 sizeof...(BodyArgs)>{},
305 mp11::make_index_sequence<
306 sizeof...(FieldsArgs)>{})
307{
308}
309
310template<bool isRequest, class Body, class Fields>
311void
312message<isRequest, Body, Fields>::
313chunked(bool value)
314{
315 this->set_chunked_impl(value);
316 this->set_content_length_impl(boost::none);
317}
318
319template<bool isRequest, class Body, class Fields>
320void
321message<isRequest, Body, Fields>::
322content_length(
323 boost::optional<std::uint64_t> const& value)
324{
325 this->set_content_length_impl(value);
326 this->set_chunked_impl(false);
327}
328
329template<bool isRequest, class Body, class Fields>
330boost::optional<std::uint64_t>
331message<isRequest, Body, Fields>::
332payload_size() const
333{
334 return payload_size(detail::is_body_sized<Body>{});
335}
336
337template<bool isRequest, class Body, class Fields>
338bool
339message<isRequest, Body, Fields>::
340need_eof(std::false_type) const
341{
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() ||
348 chunked())
349 return ! keep_alive();
350 return true;
351}
352
353template<bool isRequest, class Body, class Fields>
354void
355message<isRequest, Body, Fields>::
356prepare_payload(std::true_type)
357{
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"});
362 if(n)
363 {
364 if(*n > 0 ||
365 this->method() == verb::options ||
366 this->method() == verb::put ||
367 this->method() == verb::post)
368 {
369 this->content_length(value: n);
370 }
371 else
372 {
373 this->chunked(false);
374 }
375 }
376 else if(this->version() == 11)
377 {
378 this->chunked(true);
379 }
380 else
381 {
382 this->chunked(false);
383 }
384}
385
386template<bool isRequest, class Body, class Fields>
387void
388message<isRequest, Body, Fields>::
389prepare_payload(std::false_type)
390{
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)))
396 {
397 // The response body MUST be empty for this case
398 BOOST_THROW_EXCEPTION(std::invalid_argument{
399 "invalid response body"});
400 }
401 if(n)
402 this->content_length(value: n);
403 else if(this->version() == 11)
404 this->chunked(true);
405 else
406 this->chunked(false);
407}
408
409//------------------------------------------------------------------------------
410
411template<bool isRequest, class Body, class Fields>
412void
413swap(
414 message<isRequest, Body, Fields>& m1,
415 message<isRequest, Body, Fields>& m2)
416{
417 using std::swap;
418 swap(
419 static_cast<header<isRequest, Fields>&>(m1),
420 static_cast<header<isRequest, Fields>&>(m2));
421 swap(m1.body(), m2.body());
422}
423
424} // http
425} // beast
426} // boost
427
428#endif
429

source code of boost/libs/beast/include/boost/beast/http/impl/message.hpp