|
9 | 9 |
|
10 | 10 | #include <boost/beast2/body_read_stream.hpp> |
11 | 11 | #include <boost/beast2/body_write_stream.hpp> |
| 12 | +#include <boost/beast2/detail/config.hpp> |
| 13 | +#include <boost/beast2/wrap_executor.hpp> |
12 | 14 |
|
13 | 15 | #include <boost/asio/bind_cancellation_slot.hpp> |
| 16 | +#include <boost/asio/deferred.hpp> |
14 | 17 | #include <boost/asio/read.hpp> |
15 | 18 | #include <boost/asio/write.hpp> |
16 | 19 | #include <boost/buffers/make_buffer.hpp> |
| 20 | +#include <boost/capy/async_op.hpp> |
17 | 21 | #include <boost/capy/polystore.hpp> |
| 22 | +#include <boost/capy/task.hpp> |
18 | 23 | #include <boost/http_proto/response.hpp> |
19 | 24 | #include <boost/http_proto/request.hpp> |
20 | 25 |
|
@@ -531,6 +536,113 @@ struct single_tester : public ctx_base |
531 | 536 | } |
532 | 537 | }; |
533 | 538 |
|
| 539 | +#ifdef BOOST_BEAST2_HAS_CORO |
| 540 | + |
| 541 | +// Result type for async write operations |
| 542 | +struct write_result |
| 543 | +{ |
| 544 | + system::error_code ec; |
| 545 | + std::size_t bytes_transferred; |
| 546 | +}; |
| 547 | + |
| 548 | +// Helper to wrap async_write_some for coroutines |
| 549 | +template<class Stream, class ConstBufferSequence> |
| 550 | +capy::async_op<write_result> |
| 551 | +coro_write_some( |
| 552 | + body_write_stream<Stream>& bws, |
| 553 | + ConstBufferSequence const& buffers) |
| 554 | +{ |
| 555 | + return capy::make_async_op<write_result>( |
| 556 | + bws.async_write_some(buffers, asio::deferred)); |
| 557 | +} |
| 558 | + |
| 559 | +// Helper to wrap async_close for coroutines |
| 560 | +template<class Stream> |
| 561 | +capy::async_op<system::error_code> |
| 562 | +coro_close(body_write_stream<Stream>& bws) |
| 563 | +{ |
| 564 | + return capy::make_async_op<system::error_code>( |
| 565 | + bws.async_close(asio::deferred)); |
| 566 | +} |
| 567 | + |
| 568 | +capy::task<void> |
| 569 | +do_coro_write( |
| 570 | + test::stream& wts, |
| 571 | + test::stream& rts, |
| 572 | + http_proto::serializer& sr, |
| 573 | + http_proto::serializer::stream& srs, |
| 574 | + std::string const& body, |
| 575 | + std::string const& expected_msg) |
| 576 | +{ |
| 577 | + body_write_stream<test::stream> bws(wts, sr, srs); |
| 578 | + |
| 579 | + // Write body data using co_await |
| 580 | + buffers::const_buffer cb(body.data(), body.size()); |
| 581 | + std::size_t total_written = 0; |
| 582 | + |
| 583 | + while(cb.size() > 0) |
| 584 | + { |
| 585 | + auto result = co_await coro_write_some(bws, cb); |
| 586 | + BOOST_TEST(!result.ec.failed()); |
| 587 | + BOOST_TEST_GT(result.bytes_transferred, 0u); |
| 588 | + total_written += result.bytes_transferred; |
| 589 | + cb += result.bytes_transferred; |
| 590 | + } |
| 591 | + |
| 592 | + BOOST_TEST_EQ(total_written, body.size()); |
| 593 | + BOOST_TEST(!sr.is_done()); |
| 594 | + |
| 595 | + // Close the stream |
| 596 | + auto ec = co_await coro_close(bws); |
| 597 | + BOOST_TEST(!ec.failed()); |
| 598 | + |
| 599 | + BOOST_TEST(sr.is_done()); |
| 600 | + BOOST_TEST_EQ(rts.str(), expected_msg); |
| 601 | + |
| 602 | + co_return; |
| 603 | +} |
| 604 | + |
| 605 | +void |
| 606 | +test_coroutine() |
| 607 | +{ |
| 608 | + // Set up context with parser and serializer services |
| 609 | + capy::polystore capy_ctx; |
| 610 | + http_proto::install_parser_service(capy_ctx, {}); |
| 611 | + http_proto::install_serializer_service(capy_ctx, {}); |
| 612 | + |
| 613 | + std::string body = "Hello World!"; |
| 614 | + std::string header = |
| 615 | + "HTTP/1.1 200 OK\r\n" |
| 616 | + "Content-Length: 12\r\n" |
| 617 | + "\r\n"; |
| 618 | + std::string expected_msg = header + body; |
| 619 | + |
| 620 | + asio::io_context ioc; |
| 621 | + |
| 622 | + test::stream wts(ioc); |
| 623 | + test::stream rts(ioc); |
| 624 | + wts.connect(rts); |
| 625 | + |
| 626 | + http_proto::serializer sr(capy_ctx); |
| 627 | + sr.reset(); |
| 628 | + |
| 629 | + http_proto::response res(header); |
| 630 | + auto srs = sr.start_stream(res); |
| 631 | + |
| 632 | + capy::spawn( |
| 633 | + wrap_executor(ioc.get_executor()), |
| 634 | + do_coro_write(wts, rts, sr, srs, body, expected_msg), |
| 635 | + [](system::result<void, std::exception_ptr> result) |
| 636 | + { |
| 637 | + if(result.has_error()) |
| 638 | + std::rethrow_exception(result.error()); |
| 639 | + }); |
| 640 | + |
| 641 | + ioc.run(); |
| 642 | +} |
| 643 | + |
| 644 | +#endif // BOOST_BEAST2_HAS_CORO |
| 645 | + |
534 | 646 | } // anonymous namespace. |
535 | 647 |
|
536 | 648 | struct body_write_stream_test |
@@ -594,6 +706,13 @@ struct body_write_stream_test |
594 | 706 | { |
595 | 707 | single_tester().test_close_errors(); |
596 | 708 | } |
| 709 | + |
| 710 | +#ifdef BOOST_BEAST2_HAS_CORO |
| 711 | + // Test C++20 coroutine compatibility |
| 712 | + { |
| 713 | + test_coroutine(); |
| 714 | + } |
| 715 | +#endif |
597 | 716 | } |
598 | 717 | }; |
599 | 718 |
|
|
0 commit comments