• 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_IMPL_SERIALIZER_HPP
11 #define BOOST_BEAST_HTTP_IMPL_SERIALIZER_HPP
12 
13 #include <boost/beast/core/buffer_traits.hpp>
14 #include <boost/beast/core/detail/buffers_ref.hpp>
15 #include <boost/beast/http/error.hpp>
16 #include <boost/beast/http/status.hpp>
17 #include <boost/beast/core/detail/config.hpp>
18 #include <boost/assert.hpp>
19 #include <ostream>
20 
21 namespace boost {
22 namespace beast {
23 namespace http {
24 
25 template<
26     bool isRequest, class Body, class Fields>
27 void
28 serializer<isRequest, Body, Fields>::
fwrinit(std::true_type)29 fwrinit(std::true_type)
30 {
31     fwr_.emplace(m_, m_.version(), m_.method());
32 }
33 
34 template<
35     bool isRequest, class Body, class Fields>
36 void
37 serializer<isRequest, Body, Fields>::
fwrinit(std::false_type)38 fwrinit(std::false_type)
39 {
40     fwr_.emplace(m_, m_.version(), m_.result_int());
41 }
42 
43 template<
44     bool isRequest, class Body, class Fields>
45 template<std::size_t I, class Visit>
46 inline
47 void
48 serializer<isRequest, Body, Fields>::
do_visit(error_code & ec,Visit & visit)49 do_visit(error_code& ec, Visit& visit)
50 {
51     pv_.template emplace<I>(limit_, v_.template get<I>());
52     visit(ec, beast::detail::make_buffers_ref(
53         pv_.template get<I>()));
54 }
55 
56 //------------------------------------------------------------------------------
57 
58 template<
59     bool isRequest, class Body, class Fields>
60 serializer<isRequest, Body, Fields>::
serializer(value_type & m)61 serializer(value_type& m)
62     : m_(m)
63     , wr_(m_.base(), m_.body())
64 {
65 }
66 
67 template<
68     bool isRequest, class Body, class Fields>
69 template<class Visit>
70 void
71 serializer<isRequest, Body, Fields>::
next(error_code & ec,Visit && visit)72 next(error_code& ec, Visit&& visit)
73 {
74     switch(s_)
75     {
76     case do_construct:
77     {
78         fwrinit(std::integral_constant<bool,
79             isRequest>{});
80         if(m_.chunked())
81             goto go_init_c;
82         s_ = do_init;
83         BOOST_FALLTHROUGH;
84     }
85 
86     case do_init:
87     {
88         wr_.init(ec);
89         if(ec)
90             return;
91         if(split_)
92             goto go_header_only;
93         auto result = wr_.get(ec);
94         if(ec == error::need_more)
95             goto go_header_only;
96         if(ec)
97             return;
98         if(! result)
99             goto go_header_only;
100         more_ = result->second;
101         v_.template emplace<2>(
102             boost::in_place_init,
103             fwr_->get(),
104             result->first);
105         s_ = do_header;
106         BOOST_FALLTHROUGH;
107     }
108 
109     case do_header:
110         do_visit<2>(ec, visit);
111         break;
112 
113     go_header_only:
114         v_.template emplace<1>(fwr_->get());
115         s_ = do_header_only;
116         BOOST_FALLTHROUGH;
117     case do_header_only:
118         do_visit<1>(ec, visit);
119         break;
120 
121     case do_body:
122         s_ = do_body + 1;
123         BOOST_FALLTHROUGH;
124 
125     case do_body + 1:
126     {
127         auto result = wr_.get(ec);
128         if(ec)
129             return;
130         if(! result)
131             goto go_complete;
132         more_ = result->second;
133         v_.template emplace<3>(result->first);
134         s_ = do_body + 2;
135         BOOST_FALLTHROUGH;
136     }
137 
138     case do_body + 2:
139         do_visit<3>(ec, visit);
140         break;
141 
142     //----------------------------------------------------------------------
143 
144         go_init_c:
145         s_ = do_init_c;
146         BOOST_FALLTHROUGH;
147     case do_init_c:
148     {
149         wr_.init(ec);
150         if(ec)
151             return;
152         if(split_)
153             goto go_header_only_c;
154         auto result = wr_.get(ec);
155         if(ec == error::need_more)
156             goto go_header_only_c;
157         if(ec)
158             return;
159         if(! result)
160             goto go_header_only_c;
161         more_ = result->second;
162         if(! more_)
163         {
164             // do it all in one buffer
165             v_.template emplace<7>(
166                 boost::in_place_init,
167                 fwr_->get(),
168                 buffer_bytes(result->first),
169                 net::const_buffer{nullptr, 0},
170                 chunk_crlf{},
171                 result->first,
172                 chunk_crlf{},
173                 detail::chunk_last(),
174                 net::const_buffer{nullptr, 0},
175                 chunk_crlf{});
176             goto go_all_c;
177         }
178         v_.template emplace<4>(
179             boost::in_place_init,
180             fwr_->get(),
181             buffer_bytes(result->first),
182             net::const_buffer{nullptr, 0},
183             chunk_crlf{},
184             result->first,
185             chunk_crlf{});
186         s_ = do_header_c;
187         BOOST_FALLTHROUGH;
188     }
189 
190     case do_header_c:
191         do_visit<4>(ec, visit);
192         break;
193 
194     go_header_only_c:
195         v_.template emplace<1>(fwr_->get());
196         s_ = do_header_only_c;
197         BOOST_FALLTHROUGH;
198 
199     case do_header_only_c:
200         do_visit<1>(ec, visit);
201         break;
202 
203     case do_body_c:
204         s_ = do_body_c + 1;
205         BOOST_FALLTHROUGH;
206 
207     case do_body_c + 1:
208     {
209         auto result = wr_.get(ec);
210         if(ec)
211             return;
212         if(! result)
213             goto go_final_c;
214         more_ = result->second;
215         if(! more_)
216         {
217             // do it all in one buffer
218             v_.template emplace<6>(
219                 boost::in_place_init,
220                 buffer_bytes(result->first),
221                 net::const_buffer{nullptr, 0},
222                 chunk_crlf{},
223                 result->first,
224                 chunk_crlf{},
225                 detail::chunk_last(),
226                 net::const_buffer{nullptr, 0},
227                 chunk_crlf{});
228             goto go_body_final_c;
229         }
230         v_.template emplace<5>(
231             boost::in_place_init,
232             buffer_bytes(result->first),
233             net::const_buffer{nullptr, 0},
234             chunk_crlf{},
235             result->first,
236             chunk_crlf{});
237         s_ = do_body_c + 2;
238         BOOST_FALLTHROUGH;
239     }
240 
241     case do_body_c + 2:
242         do_visit<5>(ec, visit);
243         break;
244 
245     go_body_final_c:
246         s_ = do_body_final_c;
247         BOOST_FALLTHROUGH;
248     case do_body_final_c:
249         do_visit<6>(ec, visit);
250         break;
251 
252     go_all_c:
253         s_ = do_all_c;
254         BOOST_FALLTHROUGH;
255     case do_all_c:
256         do_visit<7>(ec, visit);
257         break;
258 
259     go_final_c:
260     case do_final_c:
261         v_.template emplace<8>(
262             boost::in_place_init,
263             detail::chunk_last(),
264             net::const_buffer{nullptr, 0},
265             chunk_crlf{});
266         s_ = do_final_c + 1;
267         BOOST_FALLTHROUGH;
268 
269     case do_final_c + 1:
270         do_visit<8>(ec, visit);
271         break;
272 
273     //----------------------------------------------------------------------
274 
275     default:
276     case do_complete:
277         BOOST_ASSERT(false);
278         break;
279 
280     go_complete:
281         s_ = do_complete;
282         break;
283     }
284 }
285 
286 template<
287     bool isRequest, class Body, class Fields>
288 void
289 serializer<isRequest, Body, Fields>::
consume(std::size_t n)290 consume(std::size_t n)
291 {
292     switch(s_)
293     {
294     case do_header:
295         BOOST_ASSERT(
296             n <= buffer_bytes(v_.template get<2>()));
297         v_.template get<2>().consume(n);
298         if(buffer_bytes(v_.template get<2>()) > 0)
299             break;
300         header_done_ = true;
301         v_.reset();
302         if(! more_)
303             goto go_complete;
304         s_ = do_body + 1;
305         break;
306 
307     case do_header_only:
308         BOOST_ASSERT(
309             n <= buffer_bytes(v_.template get<1>()));
310         v_.template get<1>().consume(n);
311         if(buffer_bytes(v_.template get<1>()) > 0)
312             break;
313         fwr_ = boost::none;
314         header_done_ = true;
315         if(! split_)
316             goto go_complete;
317         s_ = do_body;
318         break;
319 
320     case do_body + 2:
321     {
322         BOOST_ASSERT(
323             n <= buffer_bytes(v_.template get<3>()));
324         v_.template get<3>().consume(n);
325         if(buffer_bytes(v_.template get<3>()) > 0)
326             break;
327         v_.reset();
328         if(! more_)
329             goto go_complete;
330         s_ = do_body + 1;
331         break;
332     }
333 
334     //----------------------------------------------------------------------
335 
336     case do_header_c:
337         BOOST_ASSERT(
338             n <= buffer_bytes(v_.template get<4>()));
339         v_.template get<4>().consume(n);
340         if(buffer_bytes(v_.template get<4>()) > 0)
341             break;
342         header_done_ = true;
343         v_.reset();
344         if(more_)
345             s_ = do_body_c + 1;
346         else
347             s_ = do_final_c;
348         break;
349 
350     case do_header_only_c:
351     {
352         BOOST_ASSERT(
353             n <= buffer_bytes(v_.template get<1>()));
354         v_.template get<1>().consume(n);
355         if(buffer_bytes(v_.template get<1>()) > 0)
356             break;
357         fwr_ = boost::none;
358         header_done_ = true;
359         if(! split_)
360         {
361             s_ = do_final_c;
362             break;
363         }
364         s_ = do_body_c;
365         break;
366     }
367 
368     case do_body_c + 2:
369         BOOST_ASSERT(
370             n <= buffer_bytes(v_.template get<5>()));
371         v_.template get<5>().consume(n);
372         if(buffer_bytes(v_.template get<5>()) > 0)
373             break;
374         v_.reset();
375         if(more_)
376             s_ = do_body_c + 1;
377         else
378             s_ = do_final_c;
379         break;
380 
381     case do_body_final_c:
382     {
383         BOOST_ASSERT(
384             n <= buffer_bytes(v_.template get<6>()));
385         v_.template get<6>().consume(n);
386         if(buffer_bytes(v_.template get<6>()) > 0)
387             break;
388         v_.reset();
389         s_ = do_complete;
390         break;
391     }
392 
393     case do_all_c:
394     {
395         BOOST_ASSERT(
396             n <= buffer_bytes(v_.template get<7>()));
397         v_.template get<7>().consume(n);
398         if(buffer_bytes(v_.template get<7>()) > 0)
399             break;
400         header_done_ = true;
401         v_.reset();
402         s_ = do_complete;
403         break;
404     }
405 
406     case do_final_c + 1:
407         BOOST_ASSERT(buffer_bytes(v_.template get<8>()));
408         v_.template get<8>().consume(n);
409         if(buffer_bytes(v_.template get<8>()) > 0)
410             break;
411         v_.reset();
412         goto go_complete;
413 
414     //----------------------------------------------------------------------
415 
416     default:
417         BOOST_ASSERT(false);
418     case do_complete:
419         break;
420 
421     go_complete:
422         s_ = do_complete;
423         break;
424     }
425 }
426 
427 } // http
428 } // beast
429 } // boost
430 
431 #endif
432