2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_HTTP_IMPL_WRITE_IPP
11 #define BOOST_BEAST_HTTP_IMPL_WRITE_IPP
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>
35 class Stream, class Handler,
36 bool isRequest, class Body, class Fields>
40 serializer<isRequest,Body, Fields>& sr_;
51 lambda(write_some_op& op)
56 template<class ConstBufferSequence>
58 operator()(error_code& ec,
59 ConstBufferSequence const& buffers)
62 ec.assign(0, ec.category());
63 return op_.s_.async_write_some(
64 buffers, std::move(op_));
69 write_some_op(write_some_op&&) = default;
70 write_some_op(write_some_op const&) = default;
72 template<class DeducedHandler>
73 write_some_op(DeducedHandler&& h, Stream& s,
74 serializer<isRequest, Body, Fields>& sr)
77 , h_(std::forward<DeducedHandler>(h))
81 using allocator_type =
82 boost::asio::associated_allocator_t<Handler>;
85 get_allocator() const noexcept
87 return boost::asio::get_associated_allocator(h_);
90 using executor_type = boost::asio::associated_executor_t<
91 Handler, decltype(std::declval<Stream&>().get_executor())>;
94 get_executor() const noexcept
96 return boost::asio::get_associated_executor(
97 h_, s_.get_executor());
106 std::size_t bytes_transferred);
109 bool asio_handler_is_continuation(write_some_op* op)
111 using boost::asio::asio_handler_is_continuation;
112 return asio_handler_is_continuation(
113 std::addressof(op->h_));
118 class Stream, class Handler,
119 bool isRequest, class Body, class Fields>
122 Stream, Handler, isRequest, Body, Fields>::
132 BOOST_ASSERT(! f.invoked);
133 return boost::asio::post(
135 bind_handler(std::move(*this), ec, 0));
139 // *this has been moved from,
140 // cannot access members here.
143 // What else could it be?
144 BOOST_ASSERT(sr_.is_done());
146 return boost::asio::post(
148 bind_handler(std::move(*this), ec, 0));
152 class Stream, class Handler,
153 bool isRequest, class Body, class Fields>
156 Stream, Handler, isRequest, Body, Fields>::
158 error_code ec, std::size_t bytes_transferred)
161 sr_.consume(bytes_transferred);
162 h_(ec, bytes_transferred);
165 //------------------------------------------------------------------------------
167 struct serializer_is_header_done
170 bool isRequest, class Body, class Fields>
173 serializer<isRequest, Body, Fields>& sr) const
175 return sr.is_header_done();
179 struct serializer_is_done
182 bool isRequest, class Body, class Fields>
185 serializer<isRequest, Body, Fields>& sr) const
191 //------------------------------------------------------------------------------
194 class Stream, class Handler, class Predicate,
195 bool isRequest, class Body, class Fields>
200 serializer<isRequest, Body, Fields>& sr_;
201 std::size_t bytes_transferred_ = 0;
205 write_op(write_op&&) = default;
206 write_op(write_op const&) = default;
208 template<class DeducedHandler>
209 write_op(DeducedHandler&& h, Stream& s,
210 serializer<isRequest, Body, Fields>& sr)
213 , h_(std::forward<DeducedHandler>(h))
217 using allocator_type =
218 boost::asio::associated_allocator_t<Handler>;
221 get_allocator() const noexcept
223 return boost::asio::get_associated_allocator(h_);
226 using executor_type = boost::asio::associated_executor_t<
227 Handler, decltype(std::declval<Stream&>().get_executor())>;
230 get_executor() const noexcept
232 return boost::asio::get_associated_executor(
233 h_, s_.get_executor());
239 std::size_t bytes_transferred = 0);
242 bool asio_handler_is_continuation(write_op* op)
244 using boost::asio::asio_handler_is_continuation;
245 return op->state_ >= 3 ||
246 asio_handler_is_continuation(
247 std::addressof(op->h_));
252 class Stream, class Handler, class Predicate,
253 bool isRequest, class Body, class Fields>
255 write_op<Stream, Handler, Predicate,
256 isRequest, Body, Fields>::
258 error_code ec, std::size_t bytes_transferred)
269 return boost::asio::post(
271 bind_handler(std::move(*this), ec, 0));
274 return beast::http::async_write_some(
275 s_, sr_, std::move(*this));
283 BOOST_BEAST_FALLTHROUGH;
287 bytes_transferred_ += bytes_transferred;
290 return beast::http::async_write_some(
291 s_, sr_, std::move(*this));
295 h_(ec, bytes_transferred_);
298 //------------------------------------------------------------------------------
300 template<class Stream, class Handler,
301 bool isRequest, class Body, class Fields>
307 serializer<isRequest, Body, Fields> sr;
309 data(Handler&, Stream& s_, message<
310 isRequest, Body, Fields>& m_)
317 handler_ptr<data, Handler> d_;
320 write_msg_op(write_msg_op&&) = default;
321 write_msg_op(write_msg_op const&) = default;
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)...)
330 using allocator_type =
331 boost::asio::associated_allocator_t<Handler>;
334 get_allocator() const noexcept
336 return boost::asio::get_associated_allocator(d_.handler());
339 using executor_type = boost::asio::associated_executor_t<
340 Handler, decltype(std::declval<Stream&>().get_executor())>;
343 get_executor() const noexcept
345 return boost::asio::get_associated_executor(
346 d_.handler(), d_->s.get_executor());
354 error_code ec, std::size_t bytes_transferred);
357 bool asio_handler_is_continuation(write_msg_op* op)
359 using boost::asio::asio_handler_is_continuation;
360 return asio_handler_is_continuation(
361 std::addressof(op->d_.handler()));
365 template<class Stream, class Handler,
366 bool isRequest, class Body, class Fields>
369 Stream, Handler, isRequest, Body, Fields>::
373 return async_write(d.s, d.sr, std::move(*this));
376 template<class Stream, class Handler,
377 bool isRequest, class Body, class Fields>
380 Stream, Handler, isRequest, Body, Fields>::
381 operator()(error_code ec, std::size_t bytes_transferred)
383 d_.invoke(ec, bytes_transferred);
386 //------------------------------------------------------------------------------
388 template<class Stream>
389 class write_some_lambda
394 bool invoked = false;
395 std::size_t bytes_transferred = 0;
398 write_some_lambda(Stream& stream)
403 template<class ConstBufferSequence>
405 operator()(error_code& ec,
406 ConstBufferSequence const& buffers)
410 stream_.write_some(buffers, ec);
414 template<class Stream>
420 bool invoked = false;
421 std::size_t bytes_transferred = 0;
424 write_lambda(Stream& stream)
429 template<class ConstBufferSequence>
431 operator()(error_code& ec,
432 ConstBufferSequence const& buffers)
435 bytes_transferred = boost::asio::write(
436 stream_, buffers, ec);
441 class SyncWriteStream,
442 bool isRequest, class Body, class Fields>
445 SyncWriteStream& stream,
446 serializer<isRequest, Body, Fields>& sr,
451 write_some_lambda<SyncWriteStream> f{stream};
454 return f.bytes_transferred;
456 sr.consume(f.bytes_transferred);
457 return f.bytes_transferred;
459 ec.assign(0, ec.category());
464 class AsyncWriteStream,
465 bool isRequest, class Body, class Fields,
467 BOOST_ASIO_INITFN_RESULT_TYPE(
468 WriteHandler, void(error_code, std::size_t))
470 AsyncWriteStream& stream,
471 serializer<isRequest, Body, Fields>& sr,
472 WriteHandler&& handler)
474 boost::asio::async_completion<
476 void(error_code, std::size_t)> init{handler};
477 detail::write_some_op<
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();
488 //------------------------------------------------------------------------------
491 class SyncWriteStream,
492 bool isRequest, class Body, class Fields>
495 SyncWriteStream& stream,
496 serializer<isRequest, Body, Fields>& sr)
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");
505 auto const bytes_transferred =
506 write_some(stream, sr, ec);
508 BOOST_THROW_EXCEPTION(system_error{ec});
509 return bytes_transferred;
513 class SyncWriteStream,
514 bool isRequest, class Body, class Fields>
517 SyncWriteStream& stream,
518 serializer<isRequest, Body, Fields>& sr,
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);
531 class AsyncWriteStream,
532 bool isRequest, class Body, class Fields,
534 BOOST_ASIO_INITFN_RESULT_TYPE(
535 WriteHandler, void(error_code, std::size_t))
537 AsyncWriteStream& stream,
538 serializer<isRequest, Body, Fields>& sr,
539 WriteHandler&& handler)
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));
552 //------------------------------------------------------------------------------
555 class SyncWriteStream,
556 bool isRequest, class Body, class Fields>
558 write_header(SyncWriteStream& stream,
559 serializer<isRequest, Body, Fields>& sr)
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");
568 auto const bytes_transferred =
569 write_header(stream, sr, ec);
571 BOOST_THROW_EXCEPTION(system_error{ec});
572 return bytes_transferred;
576 class SyncWriteStream,
577 bool isRequest, class Body, class Fields>
580 SyncWriteStream& stream,
581 serializer<isRequest, Body, Fields>& sr,
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");
591 std::size_t bytes_transferred = 0;
592 if(! sr.is_header_done())
594 detail::write_lambda<SyncWriteStream> f{stream};
598 bytes_transferred += f.bytes_transferred;
600 return bytes_transferred;
601 BOOST_ASSERT(f.invoked);
602 sr.consume(f.bytes_transferred);
604 while(! sr.is_header_done());
608 ec.assign(0, ec.category());
610 return bytes_transferred;
614 class AsyncWriteStream,
615 bool isRequest, class Body, class Fields,
617 BOOST_ASIO_INITFN_RESULT_TYPE(
618 WriteHandler, void(error_code, std::size_t))
620 AsyncWriteStream& stream,
621 serializer<isRequest, Body, Fields>& sr,
622 WriteHandler&& handler)
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");
632 boost::asio::async_completion<
634 void(error_code, std::size_t)> init{handler};
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();
645 //------------------------------------------------------------------------------
648 class SyncWriteStream,
649 bool isRequest, class Body, class Fields>
652 SyncWriteStream& stream,
653 serializer<isRequest, Body, Fields>& sr)
655 static_assert(is_sync_write_stream<SyncWriteStream>::value,
656 "SyncWriteStream requirements not met");
658 auto const bytes_transferred =
659 write(stream, sr, ec);
661 BOOST_THROW_EXCEPTION(system_error{ec});
662 return bytes_transferred;
666 class SyncWriteStream,
667 bool isRequest, class Body, class Fields>
670 SyncWriteStream& stream,
671 serializer<isRequest, Body, Fields>& sr,
674 static_assert(is_sync_write_stream<SyncWriteStream>::value,
675 "SyncWriteStream requirements not met");
676 std::size_t bytes_transferred = 0;
681 write_some(stream, sr, ec);
683 return bytes_transferred;
687 return bytes_transferred;
691 class AsyncWriteStream,
692 bool isRequest, class Body, class Fields,
694 BOOST_ASIO_INITFN_RESULT_TYPE(
695 WriteHandler, void(error_code, std::size_t))
697 AsyncWriteStream& stream,
698 serializer<isRequest, Body, Fields>& sr,
699 WriteHandler&& handler)
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");
709 boost::asio::async_completion<
711 void(error_code, std::size_t)> init{handler};
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();
722 //------------------------------------------------------------------------------
725 class SyncWriteStream,
726 bool isRequest, class Body, class Fields>
729 SyncWriteStream& stream,
730 message<isRequest, Body, Fields> const& msg)
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");
739 auto const bytes_transferred =
740 write(stream, msg, ec);
742 BOOST_THROW_EXCEPTION(system_error{ec});
743 return bytes_transferred;
747 class SyncWriteStream,
748 bool isRequest, class Body, class Fields>
751 SyncWriteStream& stream,
752 message<isRequest, Body, Fields> const& msg,
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);
766 class AsyncWriteStream,
767 bool isRequest, class Body, class Fields,
769 BOOST_ASIO_INITFN_RESULT_TYPE(
770 WriteHandler, void(error_code, std::size_t))
772 AsyncWriteStream& stream,
773 message<isRequest, Body, Fields>& msg,
774 WriteHandler&& handler)
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<
785 void(error_code, std::size_t)> init{handler};
786 detail::write_msg_op<
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();
795 //------------------------------------------------------------------------------
799 template<class Serializer>
800 class write_ostream_lambda
806 write_ostream_lambda(std::ostream& os,
813 template<class ConstBufferSequence>
815 operator()(error_code& ec,
816 ConstBufferSequence const& buffers) const
818 ec.assign(0, ec.category());
821 std::size_t bytes_transferred = 0;
822 for(auto b : buffers_range(buffers))
824 os_.write(reinterpret_cast<char const*>(
825 b.data()), b.size());
828 bytes_transferred += b.size();
830 sr_.consume(bytes_transferred);
836 template<class Fields>
838 operator<<(std::ostream& os,
839 header<true, Fields> const& h)
841 typename Fields::writer fr{
842 h, h.version(), h.method()};
843 return os << buffers(fr.get());
846 template<class Fields>
848 operator<<(std::ostream& os,
849 header<false, Fields> const& h)
851 typename Fields::writer fr{
852 h, h.version(), h.result_int()};
853 return os << buffers(fr.get());
856 template<bool isRequest, class Body, class Fields>
858 operator<<(std::ostream& os,
859 message<isRequest, Body, Fields> const& msg)
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};
867 detail::write_ostream_lambda<decltype(sr)> f{os, sr};
875 os.setstate(std::ios::failbit);
879 while(! sr.is_done());