]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // |
92f5a8d4 | 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) |
b32b8144 FG |
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_SERIALIZER_HPP | |
11 | #define BOOST_BEAST_HTTP_SERIALIZER_HPP | |
12 | ||
13 | #include <boost/beast/core/detail/config.hpp> | |
14 | #include <boost/beast/core/buffers_cat.hpp> | |
15 | #include <boost/beast/core/buffers_prefix.hpp> | |
16 | #include <boost/beast/core/buffers_suffix.hpp> | |
17 | #include <boost/beast/core/string.hpp> | |
b32b8144 FG |
18 | #include <boost/beast/core/detail/variant.hpp> |
19 | #include <boost/beast/http/message.hpp> | |
20 | #include <boost/beast/http/chunk_encode.hpp> | |
21 | #include <boost/asio/buffer.hpp> | |
22 | #include <boost/optional.hpp> | |
23 | ||
24 | namespace boost { | |
25 | namespace beast { | |
26 | namespace http { | |
27 | ||
28 | /** Provides buffer oriented HTTP message serialization functionality. | |
29 | ||
30 | An object of this type is used to serialize a complete | |
31 | HTTP message into a sequence of octets. To use this class, | |
32 | construct an instance with the message to be serialized. | |
33 | The implementation will automatically perform chunk encoding | |
34 | if the contents of the message indicate that chunk encoding | |
35 | is required. | |
36 | ||
37 | Chunked output produced by the serializer never contains chunk | |
38 | extensions or trailers, and the location of chunk boundaries | |
39 | is not specified. If callers require chunk extensions, trailers, | |
40 | or control over the exact contents of each chunk they should | |
41 | use the serializer to write just the message header, and then | |
42 | assume control over serializing the chunked payload by using | |
43 | the chunk buffer sequence types @ref chunk_body, @ref chunk_crlf, | |
44 | @ref chunk_header, and @ref chunk_last. | |
45 | ||
46 | @tparam isRequest `true` if the message is a request. | |
47 | ||
48 | @tparam Body The body type of the message. | |
49 | ||
50 | @tparam Fields The type of fields in the message. | |
51 | */ | |
52 | template< | |
53 | bool isRequest, | |
54 | class Body, | |
55 | class Fields = fields> | |
56 | class serializer | |
57 | { | |
58 | public: | |
59 | static_assert(is_body<Body>::value, | |
92f5a8d4 | 60 | "Body type requirements not met"); |
b32b8144 FG |
61 | |
62 | static_assert(is_body_writer<Body>::value, | |
92f5a8d4 | 63 | "BodyWriter type requirements not met"); |
b32b8144 FG |
64 | |
65 | /** The type of message this serializer uses | |
66 | ||
67 | This may be const or non-const depending on the | |
92f5a8d4 | 68 | implementation of the corresponding <em>BodyWriter</em>. |
b32b8144 FG |
69 | */ |
70 | #if BOOST_BEAST_DOXYGEN | |
92f5a8d4 | 71 | using value_type = __implementation_defined__; |
b32b8144 | 72 | #else |
11fdf7f2 | 73 | using value_type = typename std::conditional< |
92f5a8d4 | 74 | std::is_constructible<typename Body::writer, |
11fdf7f2 TL |
75 | header<isRequest, Fields>&, |
76 | typename Body::value_type&>::value && | |
77 | ! std::is_constructible<typename Body::writer, | |
78 | header<isRequest, Fields> const&, | |
92f5a8d4 | 79 | typename Body::value_type const&>::value, |
11fdf7f2 TL |
80 | message<isRequest, Body, Fields>, |
81 | message<isRequest, Body, Fields> const>::type; | |
b32b8144 FG |
82 | #endif |
83 | ||
84 | private: | |
85 | enum | |
86 | { | |
87 | do_construct = 0, | |
88 | ||
89 | do_init = 10, | |
90 | do_header_only = 20, | |
91 | do_header = 30, | |
92 | do_body = 40, | |
93 | ||
94 | do_init_c = 50, | |
95 | do_header_only_c = 60, | |
96 | do_header_c = 70, | |
97 | do_body_c = 80, | |
98 | do_final_c = 90, | |
99 | #ifndef BOOST_BEAST_NO_BIG_VARIANTS | |
100 | do_body_final_c = 100, | |
101 | do_all_c = 110, | |
102 | #endif | |
103 | ||
104 | do_complete = 120 | |
105 | }; | |
106 | ||
11fdf7f2 TL |
107 | void fwrinit(std::true_type); |
108 | void fwrinit(std::false_type); | |
b32b8144 FG |
109 | |
110 | template<std::size_t, class Visit> | |
111 | void | |
112 | do_visit(error_code& ec, Visit& visit); | |
113 | ||
114 | using writer = typename Body::writer; | |
115 | ||
116 | using cb1_t = buffers_suffix<typename | |
117 | Fields::writer::const_buffers_type>; // header | |
118 | using pcb1_t = buffers_prefix_view<cb1_t const&>; | |
119 | ||
120 | using cb2_t = buffers_suffix<buffers_cat_view< | |
121 | typename Fields::writer::const_buffers_type,// header | |
122 | typename writer::const_buffers_type>>; // body | |
123 | using pcb2_t = buffers_prefix_view<cb2_t const&>; | |
124 | ||
125 | using cb3_t = buffers_suffix< | |
126 | typename writer::const_buffers_type>; // body | |
127 | using pcb3_t = buffers_prefix_view<cb3_t const&>; | |
128 | ||
129 | using cb4_t = buffers_suffix<buffers_cat_view< | |
130 | typename Fields::writer::const_buffers_type,// header | |
131 | detail::chunk_size, // chunk-size | |
92f5a8d4 | 132 | net::const_buffer, // chunk-ext |
b32b8144 FG |
133 | chunk_crlf, // crlf |
134 | typename writer::const_buffers_type, // body | |
135 | chunk_crlf>>; // crlf | |
136 | using pcb4_t = buffers_prefix_view<cb4_t const&>; | |
137 | ||
138 | using cb5_t = buffers_suffix<buffers_cat_view< | |
139 | detail::chunk_size, // chunk-header | |
92f5a8d4 | 140 | net::const_buffer, // chunk-ext |
b32b8144 FG |
141 | chunk_crlf, // crlf |
142 | typename writer::const_buffers_type, // body | |
143 | chunk_crlf>>; // crlf | |
144 | using pcb5_t = buffers_prefix_view<cb5_t const&>; | |
145 | ||
146 | using cb6_t = buffers_suffix<buffers_cat_view< | |
147 | detail::chunk_size, // chunk-header | |
92f5a8d4 | 148 | net::const_buffer, // chunk-size |
b32b8144 FG |
149 | chunk_crlf, // crlf |
150 | typename writer::const_buffers_type, // body | |
151 | chunk_crlf, // crlf | |
92f5a8d4 TL |
152 | net::const_buffer, // chunk-final |
153 | net::const_buffer, // trailers | |
b32b8144 FG |
154 | chunk_crlf>>; // crlf |
155 | using pcb6_t = buffers_prefix_view<cb6_t const&>; | |
156 | ||
157 | using cb7_t = buffers_suffix<buffers_cat_view< | |
158 | typename Fields::writer::const_buffers_type,// header | |
159 | detail::chunk_size, // chunk-size | |
92f5a8d4 | 160 | net::const_buffer, // chunk-ext |
b32b8144 FG |
161 | chunk_crlf, // crlf |
162 | typename writer::const_buffers_type, // body | |
163 | chunk_crlf, // crlf | |
92f5a8d4 TL |
164 | net::const_buffer, // chunk-final |
165 | net::const_buffer, // trailers | |
b32b8144 FG |
166 | chunk_crlf>>; // crlf |
167 | using pcb7_t = buffers_prefix_view<cb7_t const&>; | |
168 | ||
169 | using cb8_t = buffers_suffix<buffers_cat_view< | |
92f5a8d4 TL |
170 | net::const_buffer, // chunk-final |
171 | net::const_buffer, // trailers | |
b32b8144 FG |
172 | chunk_crlf>>; // crlf |
173 | using pcb8_t = buffers_prefix_view<cb8_t const&>; | |
174 | ||
175 | value_type& m_; | |
11fdf7f2 TL |
176 | writer wr_; |
177 | boost::optional<typename Fields::writer> fwr_; | |
b32b8144 FG |
178 | beast::detail::variant< |
179 | cb1_t, cb2_t, cb3_t, cb4_t, | |
180 | cb5_t ,cb6_t, cb7_t, cb8_t> v_; | |
181 | beast::detail::variant< | |
182 | pcb1_t, pcb2_t, pcb3_t, pcb4_t, | |
183 | pcb5_t ,pcb6_t, pcb7_t, pcb8_t> pv_; | |
184 | std::size_t limit_ = | |
185 | (std::numeric_limits<std::size_t>::max)(); | |
186 | int s_ = do_construct; | |
187 | bool split_ = false; | |
188 | bool header_done_ = false; | |
92f5a8d4 | 189 | bool more_ = false; |
b32b8144 FG |
190 | |
191 | public: | |
192 | /// Constructor | |
193 | serializer(serializer&&) = default; | |
194 | ||
195 | /// Constructor | |
196 | serializer(serializer const&) = default; | |
197 | ||
198 | /// Assignment | |
199 | serializer& operator=(serializer const&) = delete; | |
200 | ||
201 | /** Constructor | |
202 | ||
203 | The implementation guarantees that the message passed on | |
204 | construction will not be accessed until the first call to | |
205 | @ref next. This allows the message to be lazily created. | |
206 | For example, if the header is filled in before serialization. | |
207 | ||
208 | @param msg A reference to the message to serialize, which must | |
209 | remain valid for the lifetime of the serializer. Depending on | |
210 | the type of Body used, this may or may not be a `const` reference. | |
211 | ||
212 | @note This function participates in overload resolution only if | |
213 | Body::writer is constructible from a `const` message reference. | |
214 | */ | |
215 | explicit | |
216 | serializer(value_type& msg); | |
217 | ||
218 | /// Returns the message being serialized | |
219 | value_type& | |
220 | get() | |
221 | { | |
222 | return m_; | |
223 | } | |
224 | ||
225 | /// Returns the serialized buffer size limit | |
226 | std::size_t | |
227 | limit() | |
228 | { | |
229 | return limit_; | |
230 | } | |
231 | ||
232 | /** Set the serialized buffer size limit | |
233 | ||
234 | This function adjusts the limit on the maximum size of the | |
235 | buffers passed to the visitor. The new size limit takes effect | |
236 | in the following call to @ref next. | |
237 | ||
238 | The default is no buffer size limit. | |
239 | ||
240 | @param limit The new buffer size limit. If this number | |
241 | is zero, the size limit is removed. | |
242 | */ | |
243 | void | |
244 | limit(std::size_t limit) | |
245 | { | |
246 | limit_ = limit > 0 ? limit : | |
247 | (std::numeric_limits<std::size_t>::max)(); | |
248 | } | |
249 | ||
250 | /** Returns `true` if we will pause after writing the complete header. | |
251 | */ | |
252 | bool | |
253 | split() | |
254 | { | |
255 | return split_; | |
256 | } | |
257 | ||
258 | /** Set whether the header and body are written separately. | |
259 | ||
260 | When the split feature is enabled, the implementation will | |
261 | write only the octets corresponding to the serialized header | |
262 | first. If the header has already been written, this function | |
263 | will have no effect on output. | |
264 | */ | |
265 | void | |
266 | split(bool v) | |
267 | { | |
268 | split_ = v; | |
269 | } | |
270 | ||
271 | /** Return `true` if serialization of the header is complete. | |
272 | ||
273 | This function indicates whether or not all buffers containing | |
274 | serialized header octets have been retrieved. | |
275 | */ | |
276 | bool | |
277 | is_header_done() | |
278 | { | |
279 | return header_done_; | |
280 | } | |
281 | ||
282 | /** Return `true` if serialization is complete. | |
283 | ||
284 | The operation is complete when all octets corresponding | |
285 | to the serialized representation of the message have been | |
286 | successfully retrieved. | |
287 | */ | |
288 | bool | |
289 | is_done() | |
290 | { | |
291 | return s_ == do_complete; | |
292 | } | |
293 | ||
294 | /** Returns the next set of buffers in the serialization. | |
295 | ||
296 | This function will attempt to call the `visit` function | |
92f5a8d4 | 297 | object with a <em>ConstBufferSequence</em> of unspecified type |
b32b8144 FG |
298 | representing the next set of buffers in the serialization |
299 | of the message represented by this object. | |
300 | ||
301 | If there are no more buffers in the serialization, the | |
302 | visit function will not be called. In this case, no error | |
303 | will be indicated, and the function @ref is_done will | |
304 | return `true`. | |
305 | ||
306 | @param ec Set to the error, if any occurred. | |
307 | ||
308 | @param visit The function to call. The equivalent function | |
309 | signature of this object must be: | |
310 | @code | |
311 | template<class ConstBufferSequence> | |
312 | void visit(error_code&, ConstBufferSequence const&); | |
313 | @endcode | |
314 | The function is not copied, if no error occurs it will be | |
315 | invoked before the call to @ref next returns. | |
316 | ||
317 | */ | |
318 | template<class Visit> | |
319 | void | |
320 | next(error_code& ec, Visit&& visit); | |
321 | ||
322 | /** Consume buffer octets in the serialization. | |
323 | ||
324 | This function should be called after one or more octets | |
325 | contained in the buffers provided in the prior call | |
326 | to @ref next have been used. | |
327 | ||
328 | After a call to @ref consume, callers should check the | |
329 | return value of @ref is_done to determine if the entire | |
330 | message has been serialized. | |
331 | ||
332 | @param n The number of octets to consume. This number must | |
333 | be greater than zero and no greater than the number of | |
334 | octets in the buffers provided in the prior call to @ref next. | |
335 | */ | |
336 | void | |
337 | consume(std::size_t n); | |
338 | ||
92f5a8d4 | 339 | /** Provides low-level access to the associated <em>BodyWriter</em> |
11fdf7f2 TL |
340 | |
341 | This function provides access to the instance of the writer | |
342 | associated with the body and created by the serializer | |
343 | upon construction. The behavior of accessing this object | |
344 | is defined by the specification of the particular writer | |
345 | and its associated body. | |
346 | ||
347 | @return A reference to the writer. | |
348 | */ | |
349 | writer& | |
350 | writer_impl() | |
351 | { | |
352 | return wr_; | |
b32b8144 FG |
353 | } |
354 | }; | |
355 | ||
356 | /// A serializer for HTTP/1 requests | |
357 | template<class Body, class Fields = fields> | |
358 | using request_serializer = serializer<true, Body, Fields>; | |
359 | ||
360 | /// A serializer for HTTP/1 responses | |
361 | template<class Body, class Fields = fields> | |
362 | using response_serializer = serializer<false, Body, Fields>; | |
363 | ||
364 | } // http | |
365 | } // beast | |
366 | } // boost | |
367 | ||
92f5a8d4 | 368 | #include <boost/beast/http/impl/serializer.hpp> |
b32b8144 FG |
369 | |
370 | #endif |