]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // |
2 | // Copyright (c) 2013-2017 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 | ||
8 | #ifndef BEAST_HTTP_MESSAGE_HPP | |
9 | #define BEAST_HTTP_MESSAGE_HPP | |
10 | ||
11 | #include <beast/config.hpp> | |
12 | #include <beast/http/fields.hpp> | |
13 | #include <beast/core/detail/integer_sequence.hpp> | |
14 | #include <memory> | |
15 | #include <string> | |
16 | #include <tuple> | |
17 | #include <utility> | |
18 | ||
19 | namespace beast { | |
20 | namespace http { | |
21 | ||
22 | #if BEAST_DOXYGEN | |
23 | /** A container for a HTTP request or response header. | |
24 | ||
25 | A header includes the Start Line and Fields. | |
26 | ||
27 | Some use-cases: | |
28 | ||
29 | @li When the message has no body, such as a response to a HEAD request. | |
30 | ||
31 | @li When the caller wishes to defer instantiation of the body. | |
32 | ||
33 | @li Invoke algorithms which operate on the header only. | |
34 | */ | |
35 | template<bool isRequest, class Fields> | |
36 | struct header | |
37 | ||
38 | #else | |
39 | template<bool isRequest, class Fields> | |
40 | struct header; | |
41 | ||
42 | template<class Fields> | |
43 | struct header<true, Fields> | |
44 | #endif | |
45 | { | |
46 | /// Indicates if the header is a request or response. | |
47 | #if BEAST_DOXYGEN | |
48 | static bool constexpr is_request = isRequest; | |
49 | ||
50 | #else | |
51 | static bool constexpr is_request = true; | |
52 | #endif | |
53 | ||
54 | /// The type representing the fields. | |
55 | using fields_type = Fields; | |
56 | ||
57 | /** The HTTP version. | |
58 | ||
59 | This holds both the major and minor version numbers, | |
60 | using these formulas: | |
61 | @code | |
62 | major = version / 10; | |
63 | minor = version % 10; | |
64 | @endcode | |
65 | */ | |
66 | int version; | |
67 | ||
68 | /** The Request Method | |
69 | ||
70 | @note This field is present only if `isRequest == true`. | |
71 | */ | |
72 | std::string method; | |
73 | ||
74 | /** The Request URI | |
75 | ||
76 | @note This field is present only if `isRequest == true`. | |
77 | */ | |
78 | std::string url; | |
79 | ||
80 | /// The HTTP field values. | |
81 | fields_type fields; | |
82 | ||
83 | /// Default constructor | |
84 | header() = default; | |
85 | ||
86 | /// Move constructor | |
87 | header(header&&) = default; | |
88 | ||
89 | /// Copy constructor | |
90 | header(header const&) = default; | |
91 | ||
92 | /// Move assignment | |
93 | header& operator=(header&&) = default; | |
94 | ||
95 | /// Copy assignment | |
96 | header& operator=(header const&) = default; | |
97 | ||
98 | /** Construct the header. | |
99 | ||
100 | All arguments are forwarded to the constructor | |
101 | of the `fields` member. | |
102 | ||
103 | @note This constructor participates in overload resolution | |
104 | if and only if the first parameter is not convertible to | |
105 | `header`. | |
106 | */ | |
107 | #if BEAST_DOXYGEN | |
108 | template<class... Args> | |
109 | explicit | |
110 | header(Args&&... args); | |
111 | ||
112 | #else | |
113 | template<class Arg1, class... ArgN, | |
114 | class = typename std::enable_if< | |
115 | (sizeof...(ArgN) > 0) || ! std::is_convertible< | |
116 | typename std::decay<Arg1>::type, | |
117 | header>::value>::type> | |
118 | explicit | |
119 | header(Arg1&& arg1, ArgN&&... argn) | |
120 | : fields(std::forward<Arg1>(arg1), | |
121 | std::forward<ArgN>(argn)...) | |
122 | { | |
123 | } | |
124 | }; | |
125 | ||
126 | /** A container for a HTTP request or response header. | |
127 | ||
128 | A header includes the Start Line and Fields. | |
129 | ||
130 | Some use-cases: | |
131 | ||
132 | @li When the message has no body, such as a response to a HEAD request. | |
133 | ||
134 | @li When the caller wishes to defer instantiation of the body. | |
135 | ||
136 | @li Invoke algorithms which operate on the header only. | |
137 | */ | |
138 | template<class Fields> | |
139 | struct header<false, Fields> | |
140 | { | |
141 | /// Indicates if the header is a request or response. | |
142 | static bool constexpr is_request = false; | |
143 | ||
144 | /// The type representing the fields. | |
145 | using fields_type = Fields; | |
146 | ||
147 | /** The HTTP version. | |
148 | ||
149 | This holds both the major and minor version numbers, | |
150 | using these formulas: | |
151 | @code | |
152 | major = version / 10; | |
153 | minor = version % 10; | |
154 | @endcode | |
155 | */ | |
156 | int version; | |
157 | ||
158 | /// The HTTP field values. | |
159 | fields_type fields; | |
160 | ||
161 | /// Default constructor | |
162 | header() = default; | |
163 | ||
164 | /// Move constructor | |
165 | header(header&&) = default; | |
166 | ||
167 | /// Copy constructor | |
168 | header(header const&) = default; | |
169 | ||
170 | /// Move assignment | |
171 | header& operator=(header&&) = default; | |
172 | ||
173 | /// Copy assignment | |
174 | header& operator=(header const&) = default; | |
175 | ||
176 | /** Construct the header. | |
177 | ||
178 | All arguments are forwarded to the constructor | |
179 | of the `fields` member. | |
180 | ||
181 | @note This constructor participates in overload resolution | |
182 | if and only if the first parameter is not convertible to | |
183 | `header`. | |
184 | */ | |
185 | template<class Arg1, class... ArgN, | |
186 | class = typename std::enable_if< | |
187 | (sizeof...(ArgN) > 0) || ! std::is_convertible< | |
188 | typename std::decay<Arg1>::type, | |
189 | header>::value>::type> | |
190 | explicit | |
191 | header(Arg1&& arg1, ArgN&&... argn) | |
192 | : fields(std::forward<Arg1>(arg1), | |
193 | std::forward<ArgN>(argn)...) | |
194 | { | |
195 | } | |
196 | #endif | |
197 | ||
198 | /** The Response Status-Code. | |
199 | ||
200 | @note This field is present only if `isRequest == false`. | |
201 | */ | |
202 | int status; | |
203 | ||
204 | /** The Response Reason-Phrase. | |
205 | ||
206 | The Reason-Phrase is obsolete as of rfc7230. | |
207 | ||
208 | @note This field is present only if `isRequest == false`. | |
209 | */ | |
210 | std::string reason; | |
211 | }; | |
212 | ||
213 | /** A container for a complete HTTP message. | |
214 | ||
215 | A message can be a request or response, depending on the | |
216 | `isRequest` template argument value. Requests and responses | |
217 | have different types; functions may be overloaded based on | |
218 | the type if desired. | |
219 | ||
220 | The `Body` template argument type determines the model used | |
221 | to read or write the content body of the message. | |
222 | ||
223 | @tparam isRequest `true` if this represents a request, | |
224 | or `false` if this represents a response. Some class data | |
225 | members are conditionally present depending on this value. | |
226 | ||
227 | @tparam Body A type meeting the requirements of Body. | |
228 | ||
229 | @tparam Fields The type of container used to hold the | |
230 | field value pairs. | |
231 | */ | |
232 | template<bool isRequest, class Body, class Fields> | |
233 | struct message : header<isRequest, Fields> | |
234 | { | |
235 | /// The base class used to hold the header portion of the message. | |
236 | using base_type = header<isRequest, Fields>; | |
237 | ||
238 | /** The type providing the body traits. | |
239 | ||
240 | The @ref message::body member will be of type `body_type::value_type`. | |
241 | */ | |
242 | using body_type = Body; | |
243 | ||
244 | /// A value representing the body. | |
245 | typename Body::value_type body; | |
246 | ||
247 | /// Default constructor | |
248 | message() = default; | |
249 | ||
250 | /// Move constructor | |
251 | message(message&&) = default; | |
252 | ||
253 | /// Copy constructor | |
254 | message(message const&) = default; | |
255 | ||
256 | /// Move assignment | |
257 | message& operator=(message&&) = default; | |
258 | ||
259 | /// Copy assignment | |
260 | message& operator=(message const&) = default; | |
261 | ||
262 | /** Construct a message from a header. | |
263 | ||
264 | Additional arguments, if any, are forwarded to | |
265 | the constructor of the body member. | |
266 | */ | |
267 | template<class... Args> | |
268 | explicit | |
269 | message(base_type&& base, Args&&... args) | |
270 | : base_type(std::move(base)) | |
271 | , body(std::forward<Args>(args)...) | |
272 | { | |
273 | } | |
274 | ||
275 | /** Construct a message from a header. | |
276 | ||
277 | Additional arguments, if any, are forwarded to | |
278 | the constructor of the body member. | |
279 | */ | |
280 | template<class... Args> | |
281 | explicit | |
282 | message(base_type const& base, Args&&... args) | |
283 | : base_type(base) | |
284 | , body(std::forward<Args>(args)...) | |
285 | { | |
286 | } | |
287 | ||
288 | /** Construct a message. | |
289 | ||
290 | @param u An argument forwarded to the body constructor. | |
291 | ||
292 | @note This constructor participates in overload resolution | |
293 | only if `u` is not convertible to `base_type`. | |
294 | */ | |
295 | template<class U | |
296 | #if ! BEAST_DOXYGEN | |
297 | , class = typename std::enable_if< | |
298 | ! std::is_convertible<typename | |
299 | std::decay<U>::type, base_type>::value>::type | |
300 | #endif | |
301 | > | |
302 | explicit | |
303 | message(U&& u) | |
304 | : body(std::forward<U>(u)) | |
305 | { | |
306 | } | |
307 | ||
308 | /** Construct a message. | |
309 | ||
310 | @param u An argument forwarded to the body constructor. | |
311 | ||
312 | @param v An argument forwarded to the fields constructor. | |
313 | ||
314 | @note This constructor participates in overload resolution | |
315 | only if `u` is not convertible to `base_type`. | |
316 | */ | |
317 | template<class U, class V | |
318 | #if ! BEAST_DOXYGEN | |
319 | ,class = typename std::enable_if<! std::is_convertible< | |
320 | typename std::decay<U>::type, base_type>::value>::type | |
321 | #endif | |
322 | > | |
323 | message(U&& u, V&& v) | |
324 | : base_type(std::forward<V>(v)) | |
325 | , body(std::forward<U>(u)) | |
326 | { | |
327 | } | |
328 | ||
329 | /** Construct a message. | |
330 | ||
331 | @param un A tuple forwarded as a parameter pack to the body constructor. | |
332 | */ | |
333 | template<class... Un> | |
334 | message(std::piecewise_construct_t, std::tuple<Un...> un) | |
335 | : message(std::piecewise_construct, un, | |
336 | beast::detail::make_index_sequence<sizeof...(Un)>{}) | |
337 | { | |
338 | } | |
339 | ||
340 | /** Construct a message. | |
341 | ||
342 | @param un A tuple forwarded as a parameter pack to the body constructor. | |
343 | ||
344 | @param vn A tuple forwarded as a parameter pack to the fields constructor. | |
345 | */ | |
346 | template<class... Un, class... Vn> | |
347 | message(std::piecewise_construct_t, | |
348 | std::tuple<Un...>&& un, std::tuple<Vn...>&& vn) | |
349 | : message(std::piecewise_construct, un, vn, | |
350 | beast::detail::make_index_sequence<sizeof...(Un)>{}, | |
351 | beast::detail::make_index_sequence<sizeof...(Vn)>{}) | |
352 | { | |
353 | } | |
354 | ||
355 | /// Returns the header portion of the message | |
356 | base_type& | |
357 | base() | |
358 | { | |
359 | return *this; | |
360 | } | |
361 | ||
362 | /// Returns the header portion of the message | |
363 | base_type const& | |
364 | base() const | |
365 | { | |
366 | return *this; | |
367 | } | |
368 | ||
369 | private: | |
370 | template<class... Un, size_t... IUn> | |
371 | message(std::piecewise_construct_t, | |
372 | std::tuple<Un...>& tu, beast::detail::index_sequence<IUn...>) | |
373 | : body(std::forward<Un>(std::get<IUn>(tu))...) | |
374 | { | |
375 | } | |
376 | ||
377 | template<class... Un, class... Vn, | |
378 | std::size_t... IUn, std::size_t... IVn> | |
379 | message(std::piecewise_construct_t, | |
380 | std::tuple<Un...>& tu, std::tuple<Vn...>& tv, | |
381 | beast::detail::index_sequence<IUn...>, | |
382 | beast::detail::index_sequence<IVn...>) | |
383 | : base_type(std::forward<Vn>(std::get<IVn>(tv))...) | |
384 | , body(std::forward<Un>(std::get<IUn>(tu))...) | |
385 | { | |
386 | } | |
387 | }; | |
388 | ||
389 | //------------------------------------------------------------------------------ | |
390 | ||
391 | #if BEAST_DOXYGEN | |
392 | /** Swap two header objects. | |
393 | ||
394 | @par Requirements | |
395 | `Fields` is @b Swappable. | |
396 | */ | |
397 | template<bool isRequest, class Fields> | |
398 | void | |
399 | swap( | |
400 | header<isRequest, Fields>& m1, | |
401 | header<isRequest, Fields>& m2); | |
402 | #endif | |
403 | ||
404 | /** Swap two message objects. | |
405 | ||
406 | @par Requirements: | |
407 | `Body::value_type` and `Fields` are @b Swappable. | |
408 | */ | |
409 | template<bool isRequest, class Body, class Fields> | |
410 | void | |
411 | swap( | |
412 | message<isRequest, Body, Fields>& m1, | |
413 | message<isRequest, Body, Fields>& m2); | |
414 | ||
415 | /// A typical HTTP request header | |
416 | using request_header = header<true, fields>; | |
417 | ||
418 | /// Typical HTTP response header | |
419 | using response_header = header<false, fields>; | |
420 | ||
421 | /// A typical HTTP request | |
422 | template<class Body, class Fields = fields> | |
423 | using request = message<true, Body, Fields>; | |
424 | ||
425 | /// A typical HTTP response | |
426 | template<class Body, class Fields = fields> | |
427 | using response = message<false, Body, Fields>; | |
428 | ||
429 | //------------------------------------------------------------------------------ | |
430 | ||
431 | /** Returns `true` if the HTTP/1 message indicates a keep alive. | |
432 | ||
433 | Undefined behavior if version is greater than 11. | |
434 | */ | |
435 | template<bool isRequest, class Fields> | |
436 | bool | |
437 | is_keep_alive(header<isRequest, Fields> const& msg); | |
438 | ||
439 | /** Returns `true` if the HTTP/1 message indicates an Upgrade request or response. | |
440 | ||
441 | Undefined behavior if version is greater than 11. | |
442 | */ | |
443 | template<bool isRequest, class Fields> | |
444 | bool | |
445 | is_upgrade(header<isRequest, Fields> const& msg); | |
446 | ||
447 | /** HTTP/1 connection prepare options. | |
448 | ||
449 | @note These values are used with @ref prepare. | |
450 | */ | |
451 | enum class connection | |
452 | { | |
453 | /// Specify Connection: close. | |
454 | close, | |
455 | ||
456 | /// Specify Connection: keep-alive where possible. | |
457 | keep_alive, | |
458 | ||
459 | /// Specify Connection: upgrade. | |
460 | upgrade | |
461 | }; | |
462 | ||
463 | /** Prepare a HTTP message. | |
464 | ||
465 | This function will adjust the Content-Length, Transfer-Encoding, | |
466 | and Connection fields of the message based on the properties of | |
467 | the body and the options passed in. | |
468 | ||
469 | @param msg The message to prepare. The fields may be modified. | |
470 | ||
471 | @param options A list of prepare options. | |
472 | */ | |
473 | template< | |
474 | bool isRequest, class Body, class Fields, | |
475 | class... Options> | |
476 | void | |
477 | prepare(message<isRequest, Body, Fields>& msg, | |
478 | Options&&... options); | |
479 | ||
480 | } // http | |
481 | } // beast | |
482 | ||
483 | #include <beast/http/impl/message.ipp> | |
484 | ||
485 | #endif |