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
21namespace boost {
22namespace beast {
23namespace http {
24
25template<
26 bool isRequest, class Body, class Fields>
27void
28serializer<isRequest, Body, Fields>::
29fwrinit(std::true_type)
30{
31 fwr_.emplace(m_, m_.version(), m_.method());
32}
33
34template<
35 bool isRequest, class Body, class Fields>
36void
37serializer<isRequest, Body, Fields>::
38fwrinit(std::false_type)
39{
40 fwr_.emplace(m_, m_.version(), m_.result_int());
41}
42
43template<
44 bool isRequest, class Body, class Fields>
45template<std::size_t I, class Visit>
46inline
47void
48serializer<isRequest, Body, Fields>::
49do_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
58template<
59 bool isRequest, class Body, class Fields>
60serializer<isRequest, Body, Fields>::
61serializer(value_type& m)
62 : m_(m)
63 , wr_(m_.base(), m_.body())
64{
65}
66
67template<
68 bool isRequest, class Body, class Fields>
69template<class Visit>
70void
71serializer<isRequest, Body, Fields>::
72next(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
286template<
287 bool isRequest, class Body, class Fields>
288void
289serializer<isRequest, Body, Fields>::
290consume(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

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