]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/beast/http/impl/write.ipp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / beast / http / impl / write.ipp
1 //
2 // Copyright (c) 2016-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 // Official repository: https://github.com/boostorg/beast
8 //
9
10 #ifndef BOOST_BEAST_HTTP_IMPL_WRITE_IPP
11 #define BOOST_BEAST_HTTP_IMPL_WRITE_IPP
12
13 #include <boost/beast/http/type_traits.hpp>
14 #include <boost/beast/core/bind_handler.hpp>
15 #include <boost/beast/core/ostream.hpp>
16 #include <boost/beast/core/handler_ptr.hpp>
17 #include <boost/beast/core/type_traits.hpp>
18 #include <boost/beast/core/detail/config.hpp>
19 #include <boost/asio/associated_allocator.hpp>
20 #include <boost/asio/associated_executor.hpp>
21 #include <boost/asio/handler_continuation_hook.hpp>
22 #include <boost/asio/post.hpp>
23 #include <boost/asio/write.hpp>
24 #include <boost/optional.hpp>
25 #include <boost/throw_exception.hpp>
26 #include <ostream>
27 #include <sstream>
28
29 namespace boost {
30 namespace beast {
31 namespace http {
32 namespace detail {
33
34 template<
35 class Stream, class Handler,
36 bool isRequest, class Body, class Fields>
37 class write_some_op
38 {
39 Stream& s_;
40 serializer<isRequest,Body, Fields>& sr_;
41 Handler h_;
42
43 class lambda
44 {
45 write_some_op& op_;
46
47 public:
48 bool invoked = false;
49
50 explicit
51 lambda(write_some_op& op)
52 : op_(op)
53 {
54 }
55
56 template<class ConstBufferSequence>
57 void
58 operator()(error_code& ec,
59 ConstBufferSequence const& buffers)
60 {
61 invoked = true;
62 ec.assign(0, ec.category());
63 return op_.s_.async_write_some(
64 buffers, std::move(op_));
65 }
66 };
67
68 public:
69 write_some_op(write_some_op&&) = default;
70 write_some_op(write_some_op const&) = default;
71
72 template<class DeducedHandler>
73 write_some_op(DeducedHandler&& h, Stream& s,
74 serializer<isRequest, Body, Fields>& sr)
75 : s_(s)
76 , sr_(sr)
77 , h_(std::forward<DeducedHandler>(h))
78 {
79 }
80
81 using allocator_type =
82 boost::asio::associated_allocator_t<Handler>;
83
84 allocator_type
85 get_allocator() const noexcept
86 {
87 return boost::asio::get_associated_allocator(h_);
88 }
89
90 using executor_type = boost::asio::associated_executor_t<
91 Handler, decltype(std::declval<Stream&>().get_executor())>;
92
93 executor_type
94 get_executor() const noexcept
95 {
96 return boost::asio::get_associated_executor(
97 h_, s_.get_executor());
98 }
99
100 void
101 operator()();
102
103 void
104 operator()(
105 error_code ec,
106 std::size_t bytes_transferred);
107
108 friend
109 bool asio_handler_is_continuation(write_some_op* op)
110 {
111 using boost::asio::asio_handler_is_continuation;
112 return asio_handler_is_continuation(
113 std::addressof(op->h_));
114 }
115 };
116
117 template<
118 class Stream, class Handler,
119 bool isRequest, class Body, class Fields>
120 void
121 write_some_op<
122 Stream, Handler, isRequest, Body, Fields>::
123 operator()()
124 {
125 error_code ec;
126 if(! sr_.is_done())
127 {
128 lambda f{*this};
129 sr_.next(ec, f);
130 if(ec)
131 {
132 BOOST_ASSERT(! f.invoked);
133 return boost::asio::post(
134 s_.get_executor(),
135 bind_handler(std::move(*this), ec, 0));
136 }
137 if(f.invoked)
138 {
139 // *this has been moved from,
140 // cannot access members here.
141 return;
142 }
143 // What else could it be?
144 BOOST_ASSERT(sr_.is_done());
145 }
146 return boost::asio::post(
147 s_.get_executor(),
148 bind_handler(std::move(*this), ec, 0));
149 }
150
151 template<
152 class Stream, class Handler,
153 bool isRequest, class Body, class Fields>
154 void
155 write_some_op<
156 Stream, Handler, isRequest, Body, Fields>::
157 operator()(
158 error_code ec, std::size_t bytes_transferred)
159 {
160 if(! ec)
161 sr_.consume(bytes_transferred);
162 h_(ec, bytes_transferred);
163 }
164
165 //------------------------------------------------------------------------------
166
167 struct serializer_is_header_done
168 {
169 template<
170 bool isRequest, class Body, class Fields>
171 bool
172 operator()(
173 serializer<isRequest, Body, Fields>& sr) const
174 {
175 return sr.is_header_done();
176 }
177 };
178
179 struct serializer_is_done
180 {
181 template<
182 bool isRequest, class Body, class Fields>
183 bool
184 operator()(
185 serializer<isRequest, Body, Fields>& sr) const
186 {
187 return sr.is_done();
188 }
189 };
190
191 //------------------------------------------------------------------------------
192
193 template<
194 class Stream, class Handler, class Predicate,
195 bool isRequest, class Body, class Fields>
196 class write_op
197 {
198 int state_ = 0;
199 Stream& s_;
200 serializer<isRequest, Body, Fields>& sr_;
201 std::size_t bytes_transferred_ = 0;
202 Handler h_;
203
204 public:
205 write_op(write_op&&) = default;
206 write_op(write_op const&) = default;
207
208 template<class DeducedHandler>
209 write_op(DeducedHandler&& h, Stream& s,
210 serializer<isRequest, Body, Fields>& sr)
211 : s_(s)
212 , sr_(sr)
213 , h_(std::forward<DeducedHandler>(h))
214 {
215 }
216
217 using allocator_type =
218 boost::asio::associated_allocator_t<Handler>;
219
220 allocator_type
221 get_allocator() const noexcept
222 {
223 return boost::asio::get_associated_allocator(h_);
224 }
225
226 using executor_type = boost::asio::associated_executor_t<
227 Handler, decltype(std::declval<Stream&>().get_executor())>;
228
229 executor_type
230 get_executor() const noexcept
231 {
232 return boost::asio::get_associated_executor(
233 h_, s_.get_executor());
234 }
235
236 void
237 operator()(
238 error_code ec = {},
239 std::size_t bytes_transferred = 0);
240
241 friend
242 bool asio_handler_is_continuation(write_op* op)
243 {
244 using boost::asio::asio_handler_is_continuation;
245 return op->state_ >= 3 ||
246 asio_handler_is_continuation(
247 std::addressof(op->h_));
248 }
249 };
250
251 template<
252 class Stream, class Handler, class Predicate,
253 bool isRequest, class Body, class Fields>
254 void
255 write_op<Stream, Handler, Predicate,
256 isRequest, Body, Fields>::
257 operator()(
258 error_code ec, std::size_t bytes_transferred)
259 {
260 if(ec)
261 goto upcall;
262 switch(state_)
263 {
264 case 0:
265 {
266 if(Predicate{}(sr_))
267 {
268 state_ = 1;
269 return boost::asio::post(
270 s_.get_executor(),
271 bind_handler(std::move(*this), ec, 0));
272 }
273 state_ = 2;
274 return beast::http::async_write_some(
275 s_, sr_, std::move(*this));
276 }
277
278 case 1:
279 goto upcall;
280
281 case 2:
282 state_ = 3;
283 BOOST_BEAST_FALLTHROUGH;
284
285 case 3:
286 {
287 bytes_transferred_ += bytes_transferred;
288 if(Predicate{}(sr_))
289 goto upcall;
290 return beast::http::async_write_some(
291 s_, sr_, std::move(*this));
292 }
293 }
294 upcall:
295 h_(ec, bytes_transferred_);
296 }
297
298 //------------------------------------------------------------------------------
299
300 template<class Stream, class Handler,
301 bool isRequest, class Body, class Fields>
302 class write_msg_op
303 {
304 struct data
305 {
306 Stream& s;
307 serializer<isRequest, Body, Fields> sr;
308
309 data(Handler&, Stream& s_, message<
310 isRequest, Body, Fields>& m_)
311 : s(s_)
312 , sr(m_)
313 {
314 }
315 };
316
317 handler_ptr<data, Handler> d_;
318
319 public:
320 write_msg_op(write_msg_op&&) = default;
321 write_msg_op(write_msg_op const&) = default;
322
323 template<class DeducedHandler, class... Args>
324 write_msg_op(DeducedHandler&& h, Stream& s, Args&&... args)
325 : d_(std::forward<DeducedHandler>(h),
326 s, std::forward<Args>(args)...)
327 {
328 }
329
330 using allocator_type =
331 boost::asio::associated_allocator_t<Handler>;
332
333 allocator_type
334 get_allocator() const noexcept
335 {
336 return boost::asio::get_associated_allocator(d_.handler());
337 }
338
339 using executor_type = boost::asio::associated_executor_t<
340 Handler, decltype(std::declval<Stream&>().get_executor())>;
341
342 executor_type
343 get_executor() const noexcept
344 {
345 return boost::asio::get_associated_executor(
346 d_.handler(), d_->s.get_executor());
347 }
348
349 void
350 operator()();
351
352 void
353 operator()(
354 error_code ec, std::size_t bytes_transferred);
355
356 friend
357 bool asio_handler_is_continuation(write_msg_op* op)
358 {
359 using boost::asio::asio_handler_is_continuation;
360 return asio_handler_is_continuation(
361 std::addressof(op->d_.handler()));
362 }
363 };
364
365 template<class Stream, class Handler,
366 bool isRequest, class Body, class Fields>
367 void
368 write_msg_op<
369 Stream, Handler, isRequest, Body, Fields>::
370 operator()()
371 {
372 auto& d = *d_;
373 return async_write(d.s, d.sr, std::move(*this));
374 }
375
376 template<class Stream, class Handler,
377 bool isRequest, class Body, class Fields>
378 void
379 write_msg_op<
380 Stream, Handler, isRequest, Body, Fields>::
381 operator()(error_code ec, std::size_t bytes_transferred)
382 {
383 d_.invoke(ec, bytes_transferred);
384 }
385
386 //------------------------------------------------------------------------------
387
388 template<class Stream>
389 class write_some_lambda
390 {
391 Stream& stream_;
392
393 public:
394 bool invoked = false;
395 std::size_t bytes_transferred = 0;
396
397 explicit
398 write_some_lambda(Stream& stream)
399 : stream_(stream)
400 {
401 }
402
403 template<class ConstBufferSequence>
404 void
405 operator()(error_code& ec,
406 ConstBufferSequence const& buffers)
407 {
408 invoked = true;
409 bytes_transferred =
410 stream_.write_some(buffers, ec);
411 }
412 };
413
414 template<class Stream>
415 class write_lambda
416 {
417 Stream& stream_;
418
419 public:
420 bool invoked = false;
421 std::size_t bytes_transferred = 0;
422
423 explicit
424 write_lambda(Stream& stream)
425 : stream_(stream)
426 {
427 }
428
429 template<class ConstBufferSequence>
430 void
431 operator()(error_code& ec,
432 ConstBufferSequence const& buffers)
433 {
434 invoked = true;
435 bytes_transferred = boost::asio::write(
436 stream_, buffers, ec);
437 }
438 };
439
440 template<
441 class SyncWriteStream,
442 bool isRequest, class Body, class Fields>
443 std::size_t
444 write_some(
445 SyncWriteStream& stream,
446 serializer<isRequest, Body, Fields>& sr,
447 error_code& ec)
448 {
449 if(! sr.is_done())
450 {
451 write_some_lambda<SyncWriteStream> f{stream};
452 sr.next(ec, f);
453 if(ec)
454 return f.bytes_transferred;
455 if(f.invoked)
456 sr.consume(f.bytes_transferred);
457 return f.bytes_transferred;
458 }
459 ec.assign(0, ec.category());
460 return 0;
461 }
462
463 template<
464 class AsyncWriteStream,
465 bool isRequest, class Body, class Fields,
466 class WriteHandler>
467 BOOST_ASIO_INITFN_RESULT_TYPE(
468 WriteHandler, void(error_code, std::size_t))
469 async_write_some(
470 AsyncWriteStream& stream,
471 serializer<isRequest, Body, Fields>& sr,
472 WriteHandler&& handler)
473 {
474 boost::asio::async_completion<
475 WriteHandler,
476 void(error_code, std::size_t)> init{handler};
477 detail::write_some_op<
478 AsyncWriteStream,
479 BOOST_ASIO_HANDLER_TYPE(WriteHandler,
480 void(error_code, std::size_t)),
481 isRequest, Body, Fields>{
482 init.completion_handler, stream, sr}();
483 return init.result.get();
484 }
485
486 } // detail
487
488 //------------------------------------------------------------------------------
489
490 template<
491 class SyncWriteStream,
492 bool isRequest, class Body, class Fields>
493 std::size_t
494 write_some(
495 SyncWriteStream& stream,
496 serializer<isRequest, Body, Fields>& sr)
497 {
498 static_assert(is_sync_write_stream<SyncWriteStream>::value,
499 "SyncWriteStream requirements not met");
500 static_assert(is_body<Body>::value,
501 "Body requirements not met");
502 static_assert(is_body_writer<Body>::value,
503 "BodyWriter requirements not met");
504 error_code ec;
505 auto const bytes_transferred =
506 write_some(stream, sr, ec);
507 if(ec)
508 BOOST_THROW_EXCEPTION(system_error{ec});
509 return bytes_transferred;
510 }
511
512 template<
513 class SyncWriteStream,
514 bool isRequest, class Body, class Fields>
515 std::size_t
516 write_some(
517 SyncWriteStream& stream,
518 serializer<isRequest, Body, Fields>& sr,
519 error_code& ec)
520 {
521 static_assert(is_sync_write_stream<SyncWriteStream>::value,
522 "SyncWriteStream requirements not met");
523 static_assert(is_body<Body>::value,
524 "Body requirements not met");
525 static_assert(is_body_writer<Body>::value,
526 "BodyWriter requirements not met");
527 return detail::write_some(stream, sr, ec);
528 }
529
530 template<
531 class AsyncWriteStream,
532 bool isRequest, class Body, class Fields,
533 class WriteHandler>
534 BOOST_ASIO_INITFN_RESULT_TYPE(
535 WriteHandler, void(error_code, std::size_t))
536 async_write_some(
537 AsyncWriteStream& stream,
538 serializer<isRequest, Body, Fields>& sr,
539 WriteHandler&& handler)
540 {
541 static_assert(is_async_write_stream<
542 AsyncWriteStream>::value,
543 "AsyncWriteStream requirements not met");
544 static_assert(is_body<Body>::value,
545 "Body requirements not met");
546 static_assert(is_body_writer<Body>::value,
547 "BodyWriter requirements not met");
548 return detail::async_write_some(stream, sr,
549 std::forward<WriteHandler>(handler));
550 }
551
552 //------------------------------------------------------------------------------
553
554 template<
555 class SyncWriteStream,
556 bool isRequest, class Body, class Fields>
557 std::size_t
558 write_header(SyncWriteStream& stream,
559 serializer<isRequest, Body, Fields>& sr)
560 {
561 static_assert(is_sync_write_stream<SyncWriteStream>::value,
562 "SyncWriteStream requirements not met");
563 static_assert(is_body<Body>::value,
564 "Body requirements not met");
565 static_assert(is_body_writer<Body>::value,
566 "BodyWriter requirements not met");
567 error_code ec;
568 auto const bytes_transferred =
569 write_header(stream, sr, ec);
570 if(ec)
571 BOOST_THROW_EXCEPTION(system_error{ec});
572 return bytes_transferred;
573 }
574
575 template<
576 class SyncWriteStream,
577 bool isRequest, class Body, class Fields>
578 std::size_t
579 write_header(
580 SyncWriteStream& stream,
581 serializer<isRequest, Body, Fields>& sr,
582 error_code& ec)
583 {
584 static_assert(is_sync_write_stream<SyncWriteStream>::value,
585 "SyncWriteStream requirements not met");
586 static_assert(is_body<Body>::value,
587 "Body requirements not met");
588 static_assert(is_body_writer<Body>::value,
589 "BodyWriter requirements not met");
590 sr.split(true);
591 std::size_t bytes_transferred = 0;
592 if(! sr.is_header_done())
593 {
594 detail::write_lambda<SyncWriteStream> f{stream};
595 do
596 {
597 sr.next(ec, f);
598 bytes_transferred += f.bytes_transferred;
599 if(ec)
600 return bytes_transferred;
601 BOOST_ASSERT(f.invoked);
602 sr.consume(f.bytes_transferred);
603 }
604 while(! sr.is_header_done());
605 }
606 else
607 {
608 ec.assign(0, ec.category());
609 }
610 return bytes_transferred;
611 }
612
613 template<
614 class AsyncWriteStream,
615 bool isRequest, class Body, class Fields,
616 class WriteHandler>
617 BOOST_ASIO_INITFN_RESULT_TYPE(
618 WriteHandler, void(error_code, std::size_t))
619 async_write_header(
620 AsyncWriteStream& stream,
621 serializer<isRequest, Body, Fields>& sr,
622 WriteHandler&& handler)
623 {
624 static_assert(is_async_write_stream<
625 AsyncWriteStream>::value,
626 "AsyncWriteStream requirements not met");
627 static_assert(is_body<Body>::value,
628 "Body requirements not met");
629 static_assert(is_body_writer<Body>::value,
630 "BodyWriter requirements not met");
631 sr.split(true);
632 boost::asio::async_completion<
633 WriteHandler,
634 void(error_code, std::size_t)> init{handler};
635 detail::write_op<
636 AsyncWriteStream,
637 BOOST_ASIO_HANDLER_TYPE(WriteHandler,
638 void(error_code, std::size_t)),
639 detail::serializer_is_header_done,
640 isRequest, Body, Fields>{
641 init.completion_handler, stream, sr}();
642 return init.result.get();
643 }
644
645 //------------------------------------------------------------------------------
646
647 template<
648 class SyncWriteStream,
649 bool isRequest, class Body, class Fields>
650 std::size_t
651 write(
652 SyncWriteStream& stream,
653 serializer<isRequest, Body, Fields>& sr)
654 {
655 static_assert(is_sync_write_stream<SyncWriteStream>::value,
656 "SyncWriteStream requirements not met");
657 error_code ec;
658 auto const bytes_transferred =
659 write(stream, sr, ec);
660 if(ec)
661 BOOST_THROW_EXCEPTION(system_error{ec});
662 return bytes_transferred;
663 }
664
665 template<
666 class SyncWriteStream,
667 bool isRequest, class Body, class Fields>
668 std::size_t
669 write(
670 SyncWriteStream& stream,
671 serializer<isRequest, Body, Fields>& sr,
672 error_code& ec)
673 {
674 static_assert(is_sync_write_stream<SyncWriteStream>::value,
675 "SyncWriteStream requirements not met");
676 std::size_t bytes_transferred = 0;
677 sr.split(false);
678 for(;;)
679 {
680 bytes_transferred +=
681 write_some(stream, sr, ec);
682 if(ec)
683 return bytes_transferred;
684 if(sr.is_done())
685 break;
686 }
687 return bytes_transferred;
688 }
689
690 template<
691 class AsyncWriteStream,
692 bool isRequest, class Body, class Fields,
693 class WriteHandler>
694 BOOST_ASIO_INITFN_RESULT_TYPE(
695 WriteHandler, void(error_code, std::size_t))
696 async_write(
697 AsyncWriteStream& stream,
698 serializer<isRequest, Body, Fields>& sr,
699 WriteHandler&& handler)
700 {
701 static_assert(is_async_write_stream<
702 AsyncWriteStream>::value,
703 "AsyncWriteStream requirements not met");
704 static_assert(is_body<Body>::value,
705 "Body requirements not met");
706 static_assert(is_body_writer<Body>::value,
707 "BodyWriter requirements not met");
708 sr.split(false);
709 boost::asio::async_completion<
710 WriteHandler,
711 void(error_code, std::size_t)> init{handler};
712 detail::write_op<
713 AsyncWriteStream,
714 BOOST_ASIO_HANDLER_TYPE(WriteHandler,
715 void(error_code, std::size_t)),
716 detail::serializer_is_done,
717 isRequest, Body, Fields>{
718 init.completion_handler, stream, sr}();
719 return init.result.get();
720 }
721
722 //------------------------------------------------------------------------------
723
724 template<
725 class SyncWriteStream,
726 bool isRequest, class Body, class Fields>
727 std::size_t
728 write(
729 SyncWriteStream& stream,
730 message<isRequest, Body, Fields> const& msg)
731 {
732 static_assert(is_sync_write_stream<SyncWriteStream>::value,
733 "SyncWriteStream requirements not met");
734 static_assert(is_body<Body>::value,
735 "Body requirements not met");
736 static_assert(is_body_writer<Body>::value,
737 "BodyWriter requirements not met");
738 error_code ec;
739 auto const bytes_transferred =
740 write(stream, msg, ec);
741 if(ec)
742 BOOST_THROW_EXCEPTION(system_error{ec});
743 return bytes_transferred;
744 }
745
746 template<
747 class SyncWriteStream,
748 bool isRequest, class Body, class Fields>
749 std::size_t
750 write(
751 SyncWriteStream& stream,
752 message<isRequest, Body, Fields> const& msg,
753 error_code& ec)
754 {
755 static_assert(is_sync_write_stream<SyncWriteStream>::value,
756 "SyncWriteStream requirements not met");
757 static_assert(is_body<Body>::value,
758 "Body requirements not met");
759 static_assert(is_body_writer<Body>::value,
760 "BodyWriter requirements not met");
761 serializer<isRequest, Body, Fields> sr{msg};
762 return write(stream, sr, ec);
763 }
764
765 template<
766 class AsyncWriteStream,
767 bool isRequest, class Body, class Fields,
768 class WriteHandler>
769 BOOST_ASIO_INITFN_RESULT_TYPE(
770 WriteHandler, void(error_code, std::size_t))
771 async_write(
772 AsyncWriteStream& stream,
773 message<isRequest, Body, Fields>& msg,
774 WriteHandler&& handler)
775 {
776 static_assert(
777 is_async_write_stream<AsyncWriteStream>::value,
778 "AsyncWriteStream requirements not met");
779 static_assert(is_body<Body>::value,
780 "Body requirements not met");
781 static_assert(is_body_writer<Body>::value,
782 "BodyWriter requirements not met");
783 boost::asio::async_completion<
784 WriteHandler,
785 void(error_code, std::size_t)> init{handler};
786 detail::write_msg_op<
787 AsyncWriteStream,
788 BOOST_ASIO_HANDLER_TYPE(WriteHandler,
789 void(error_code, std::size_t)),
790 isRequest, Body, Fields>{
791 init.completion_handler, stream, msg}();
792 return init.result.get();
793 }
794
795 //------------------------------------------------------------------------------
796
797 namespace detail {
798
799 template<class Serializer>
800 class write_ostream_lambda
801 {
802 std::ostream& os_;
803 Serializer& sr_;
804
805 public:
806 write_ostream_lambda(std::ostream& os,
807 Serializer& sr)
808 : os_(os)
809 , sr_(sr)
810 {
811 }
812
813 template<class ConstBufferSequence>
814 void
815 operator()(error_code& ec,
816 ConstBufferSequence const& buffers) const
817 {
818 ec.assign(0, ec.category());
819 if(os_.fail())
820 return;
821 std::size_t bytes_transferred = 0;
822 for(auto b : buffers_range(buffers))
823 {
824 os_.write(reinterpret_cast<char const*>(
825 b.data()), b.size());
826 if(os_.fail())
827 return;
828 bytes_transferred += b.size();
829 }
830 sr_.consume(bytes_transferred);
831 }
832 };
833
834 } // detail
835
836 template<class Fields>
837 std::ostream&
838 operator<<(std::ostream& os,
839 header<true, Fields> const& h)
840 {
841 typename Fields::writer fr{
842 h, h.version(), h.method()};
843 return os << buffers(fr.get());
844 }
845
846 template<class Fields>
847 std::ostream&
848 operator<<(std::ostream& os,
849 header<false, Fields> const& h)
850 {
851 typename Fields::writer fr{
852 h, h.version(), h.result_int()};
853 return os << buffers(fr.get());
854 }
855
856 template<bool isRequest, class Body, class Fields>
857 std::ostream&
858 operator<<(std::ostream& os,
859 message<isRequest, Body, Fields> const& msg)
860 {
861 static_assert(is_body<Body>::value,
862 "Body requirements not met");
863 static_assert(is_body_writer<Body>::value,
864 "BodyWriter requirements not met");
865 serializer<isRequest, Body, Fields> sr{msg};
866 error_code ec;
867 detail::write_ostream_lambda<decltype(sr)> f{os, sr};
868 do
869 {
870 sr.next(ec, f);
871 if(os.fail())
872 break;
873 if(ec)
874 {
875 os.setstate(std::ios::failbit);
876 break;
877 }
878 }
879 while(! sr.is_done());
880 return os;
881 }
882
883 } // http
884 } // beast
885 } // boost
886
887 #endif