• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_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>
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,
60         "Body type requirements not met");
61 
62     static_assert(is_body_writer<Body>::value,
63         "BodyWriter type requirements not met");
64 
65     /** The type of message this serializer uses
66 
67         This may be const or non-const depending on the
68         implementation of the corresponding <em>BodyWriter</em>.
69     */
70 #if BOOST_BEAST_DOXYGEN
71     using value_type = __implementation_defined__;
72 #else
73     using value_type = typename std::conditional<
74         std::is_constructible<typename Body::writer,
75             header<isRequest, Fields>&,
76             typename Body::value_type&>::value &&
77         ! std::is_constructible<typename Body::writer,
78             header<isRequest, Fields> const&,
79             typename Body::value_type const&>::value,
80         message<isRequest, Body, Fields>,
81         message<isRequest, Body, Fields> const>::type;
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 
107     void fwrinit(std::true_type);
108     void fwrinit(std::false_type);
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
132         net::const_buffer,                          // chunk-ext
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
140         net::const_buffer,                          // chunk-ext
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
148         net::const_buffer,                          // chunk-size
149         chunk_crlf,                                 // crlf
150         typename writer::const_buffers_type,        // body
151         chunk_crlf,                                 // crlf
152         net::const_buffer,                          // chunk-final
153         net::const_buffer,                          // trailers
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
160         net::const_buffer,                          // chunk-ext
161         chunk_crlf,                                 // crlf
162         typename writer::const_buffers_type,        // body
163         chunk_crlf,                                 // crlf
164         net::const_buffer,                          // chunk-final
165         net::const_buffer,                          // trailers
166         chunk_crlf>>;                               // crlf
167     using pcb7_t = buffers_prefix_view<cb7_t const&>;
168 
169     using cb8_t = buffers_suffix<buffers_cat_view<
170         net::const_buffer,                          // chunk-final
171         net::const_buffer,                          // trailers
172         chunk_crlf>>;                               // crlf
173     using pcb8_t = buffers_prefix_view<cb8_t const&>;
174 
175     value_type& m_;
176     writer wr_;
177     boost::optional<typename Fields::writer> fwr_;
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;
189     bool more_ = false;
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&
get()220     get()
221     {
222         return m_;
223     }
224 
225     /// Returns the serialized buffer size limit
226     std::size_t
limit()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
limit(std::size_t limit)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
split()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
split(bool v)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
is_header_done()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
is_done()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
297         object with a <em>ConstBufferSequence</em> of unspecified type
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 
339     /** Provides low-level access to the associated <em>BodyWriter</em>
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&
writer_impl()350     writer_impl()
351     {
352         return wr_;
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 
368 #include <boost/beast/http/impl/serializer.hpp>
369 
370 #endif
371