Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 29 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ if (BOOST_HTTP_IO_IS_ROOT)
endif ()
option(BOOST_HTTP_IO_BUILD_TESTS "Build boost::http_io tests" ${BUILD_TESTING})
option(BOOST_HTTP_IO_BUILD_EXAMPLES "Build boost::http_io examples" ${BOOST_HTTP_IO_IS_ROOT})
option(BOOST_HTTP_IO_MRDOCS_BUILD "Build the target for MrDocs: see mrdocs.yml" OFF)


# Check if environment variable BOOST_SRC_DIR is set
Expand Down Expand Up @@ -138,23 +139,36 @@ source_group("" FILES "include/boost/http_io.hpp" "build/Jamfile")
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/include/boost/http_io PREFIX "include" FILES ${BOOST_HTTP_IO_HEADERS})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/src PREFIX "src" FILES ${BOOST_HTTP_IO_SOURCES})


function(boost_http_io_setup_properties target)
target_compile_features(${target} PUBLIC cxx_constexpr)
target_include_directories(${target} PUBLIC "${PROJECT_SOURCE_DIR}/include")
target_link_libraries(${target} PUBLIC ${BOOST_HTTP_IO_DEPENDENCIES})
find_package(Threads REQUIRED)
target_link_libraries(${target} PUBLIC Threads::Threads)
if (MINGW)
target_link_libraries(${target} PUBLIC ws2_32 wsock32)
endif()
target_compile_definitions(${target} PUBLIC BOOST_HTTP_IO_NO_LIB)
target_compile_definitions(${target} PRIVATE BOOST_HTTP_IO_SOURCE)
if (BUILD_SHARED_LIBS)
target_compile_definitions(${target} PUBLIC BOOST_HTTP_IO_DYN_LINK)
else ()
target_compile_definitions(${target} PUBLIC BOOST_HTTP_IO_STATIC_LINK)
endif ()
endfunction()

if (BOOST_HTTP_IO_MRDOCS_BUILD)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/mrdocs.cpp" "#include <boost/http_io.hpp>\n")
add_library(boost_http_io_mrdocs "${CMAKE_CURRENT_BINARY_DIR}/mrdocs.cpp")
boost_http_io_setup_properties(boost_http_io_mrdocs)
boost_http_io_setup_properties(boost_http_io_mrdocs PUBLIC BOOST_HTTP_IO_MRDOCS)
return()
endif()

add_library(boost_http_io include/boost/http_io.hpp build/Jamfile ${BOOST_HTTP_IO_HEADERS} ${BOOST_HTTP_IO_SOURCES})
add_library(Boost::http_io ALIAS boost_http_io)
target_compile_features(boost_http_io PUBLIC cxx_constexpr)
target_include_directories(boost_http_io PUBLIC "${PROJECT_SOURCE_DIR}/include")
target_link_libraries(boost_http_io PUBLIC ${BOOST_HTTP_IO_DEPENDENCIES})
find_package(Threads REQUIRED)
target_link_libraries(boost_http_io PUBLIC Threads::Threads)
if (MINGW)
target_link_libraries(boost_http_io PUBLIC ws2_32 wsock32)
endif()
target_compile_definitions(boost_http_io PUBLIC BOOST_HTTP_IO_NO_LIB)
target_compile_definitions(boost_http_io PRIVATE BOOST_HTTP_IO_SOURCE)
if (BUILD_SHARED_LIBS)
target_compile_definitions(boost_http_io PUBLIC BOOST_HTTP_IO_DYN_LINK)
else ()
target_compile_definitions(boost_http_io PUBLIC BOOST_HTTP_IO_STATIC_LINK)
endif ()
boost_http_io_setup_properties(boost_http_io)

#-------------------------------------------------
#
Expand Down
2 changes: 1 addition & 1 deletion doc/mrdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ multipage: true
use-system-libc: true
use-system-stdlib: true

cmake: '-DCMAKE_CXX_STANDARD=20 -DBOOST_HTTP_IO_BUILD_TESTS=OFF -DBOOST_HTTP_IO_BUILD_EXAMPLES=OFF'
cmake: '-DCMAKE_CXX_STANDARD=20 -DBOOST_HTTP_IO_MRDOCS_BUILD=ON -DBOOST_HTTP_IO_BUILD_TESTS=OFF -DBOOST_HTTP_IO_BUILD_EXAMPLES=OFF'
183 changes: 51 additions & 132 deletions include/boost/http_io/impl/read.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,22 @@ namespace http_io {
namespace detail {

template<class AsyncStream>
class read_header_op
class read_until_op
: public asio::coroutine
{
AsyncStream& stream_;
http_proto::parser& pr_;
std::size_t total_bytes_ = 0;
bool (&condition_)(http_proto::parser&);

public:
read_header_op(
read_until_op(
AsyncStream& s,
http_proto::parser& pr) noexcept
http_proto::parser& pr,
bool (&condition)(http_proto::parser&)) noexcept
: stream_(s)
, pr_(pr)
, condition_(condition)
{
}

Expand All @@ -50,20 +53,34 @@ class read_header_op
{
BOOST_ASIO_CORO_REENTER(*this)
{
if(pr_.got_header())
self.reset_cancellation_state(
asio::enable_total_cancellation());

for(;;)
{
BOOST_ASIO_CORO_YIELD
for(;;)
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"immediate"));
asio::async_immediate(
self.get_io_executor(), std::move(self));
pr_.parse(ec);
if(ec == http_proto::condition::need_more_input)
break;
if(ec.failed() || condition_(pr_))
{
if(total_bytes_ == 0)
{
BOOST_ASIO_CORO_YIELD
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"immediate"));
auto io_ex = self.get_io_executor();
asio::async_immediate(
io_ex,
asio::append(std::move(self), ec));
}
}
goto upcall;
}
}
goto upcall;
}
for(;;)
{
BOOST_ASIO_CORO_YIELD
{
BOOST_ASIO_HANDLER_LOCATION((
Expand All @@ -86,14 +103,6 @@ class read_header_op
{
goto upcall;
}
pr_.parse(ec);
if(ec != http_proto::condition::need_more_input)
break;
if(pr_.got_header())
{
ec = {}; // override possible need_more_input
break;
}
}

upcall:
Expand All @@ -102,97 +111,19 @@ class read_header_op
}
};

//------------------------------------------------

template<class AsyncStream>
class read_body_op
: public asio::coroutine
inline
bool
got_header_condition(http_proto::parser& pr)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or just got_header

{
AsyncStream& stream_;
http_proto::parser& pr_;
std::size_t total_bytes_ = 0;
bool some_;

public:
read_body_op(
AsyncStream& s,
http_proto::parser& pr,
bool some)
: stream_(s)
, pr_(pr)
, some_(some)
{
}

template<class Self>
void
operator()(
Self& self,
system::error_code ec = {},
std::size_t bytes_transferred = 0)
{
BOOST_ASIO_CORO_REENTER(*this)
{
pr_.parse(ec);
if(ec != http_proto::condition::need_more_input)
{
BOOST_ASIO_CORO_YIELD
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"immediate"));
auto io_ex = self.get_io_executor();
asio::async_immediate(
io_ex,
asio::append(std::move(self), ec));
}
goto upcall;
}
for(;;)
{
BOOST_ASIO_CORO_YIELD
{
BOOST_ASIO_HANDLER_LOCATION((
__FILE__, __LINE__,
"async_read_some"));
stream_.async_read_some(
pr_.prepare(),
std::move(self));
}
pr_.commit(bytes_transferred);
total_bytes_ += bytes_transferred;
if(ec == asio::error::eof)
{
BOOST_ASSERT(
bytes_transferred == 0);
pr_.commit_eof();
ec = {};
}
else if(ec.failed())
{
goto upcall;
}
pr_.parse(ec);
if(! ec.failed())
{
BOOST_ASSERT(
pr_.is_complete());
break;
}
if(ec != http_proto::condition::need_more_input)
break;
if(some_)
{
ec = {};
break;
}
}
return pr.got_header();
}

upcall:
self.complete(ec, total_bytes_);
}
}
};
inline
bool
is_complete_condition(http_proto::parser& pr)
{
return pr.is_complete();
}

} // detail

Expand All @@ -204,16 +135,16 @@ template<
void(system::error_code, std::size_t)) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
void (system::error_code, std::size_t))
async_read_header(
async_read_some(
AsyncReadStream& s,
http_proto::parser& pr,
CompletionToken&& token)
{
return asio::async_compose<
CompletionToken,
void(system::error_code, std::size_t)>(
detail::read_header_op<
AsyncReadStream>{s, pr},
detail::read_until_op<AsyncReadStream>
{s, pr, detail::got_header_condition},
token,
s);
}
Expand All @@ -224,22 +155,14 @@ template<
void(system::error_code, std::size_t)) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
void (system::error_code, std::size_t))
async_read_some(
async_read_header(
AsyncReadStream& s,
http_proto::parser& pr,
CompletionToken&& token)
{
// header must be read first!
if(! pr.got_header())
detail::throw_logic_error();

return asio::async_compose<
CompletionToken,
void(system::error_code, std::size_t)>(
detail::read_body_op<
AsyncReadStream>{s, pr, true},
token,
s);
// TODO: async_read_header should not perform a read
// operation if `parser::got_header() == true`.
return async_read_some(s, pr, std::move(token));
}

template<
Expand All @@ -253,15 +176,11 @@ async_read(
http_proto::parser& pr,
CompletionToken&& token)
{
// header must be read first!
if(! pr.got_header())
detail::throw_logic_error();

return asio::async_compose<
CompletionToken,
void(system::error_code, std::size_t)>(
detail::read_body_op<
AsyncReadStream>{s, pr, false},
detail::read_until_op<AsyncReadStream>
{s, pr, detail::is_complete_condition},
token,
s);
}
Expand Down
Loading
Loading