Reputation: 6441
I'm implementing a client which accesses a REST endpoint and then begins processing an SSE stream and monitoring events as they occur. To this end, I'm using Boost::Beast version 124 with Boost 1.63 and attempting to use async_read_some
to incrementally read the body of the response.
Here's my code thus far:
namespace http = boost::beast::http;
http::response_parser<http::string_body> sse_client::m_parser;
http::response<http::string_body> sse_client::m_response;
boost::beast::flat_buffer m_buffer;
void sse_client::monitor_sse()
{
http::request<http::empty_body> req{http::verb::get, m_target, 11};
req.set(http::field::host, m_host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.set(http::field::accept, "text/event-stream");
http::async_write(m_socket, req,
std::bind(
&sse_client::process_sse,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2));
}
void sse_client::process_sse(boost::system::error_code ec, std::size_t byte_count)
{
http::read_header(m_socket, m_buffer, m_parser);
http::async_read_some(m_socket, m_buffer, m_parser,
std::bind(
&sse_client::read_event,
shared_from_this(),
std::placeholders::_1));
}
void sse_client::read_event(boost::system::error_code ec)
{
// TODO: process event
http::async_read_some(m_socket, m_buffer, m_parser,
std::bind(
&sse_client::read_event,
shared_from_this(),
std::placeholders::_1));
}
My questions are:
response_parser
and response
than http::string_body
?read_event
handler is invoked, how does it access the content retrieved by async_read_some
? Should it be pulled from the buffer?Upvotes: 3
Views: 3321
Reputation: 5353
I'll answer your questions first and then provide explanation.
Yes, you want to read the header and then call read_some (or read, see below) until the parser returns true from is_complete(). However, in your code I notice you are mixing synchronous and asynchronous calls (read_header followed by async_read_some). It would be best to stick to just one model instead of mixing them.
For your purposes you probably want buffer_body instead of string_body. There is an example in the documentation which shows how to do this (http://www.boost.org/doc/libs/1_66_0/libs/beast/doc/html/beast/using_http/parser_stream_operations/incremental_read.html)
The "buffer" you refer to is the dynamic buffer argument passed to the HTTP stream operation. While this buffer will hold the message data, it is not for the application to inspect. This buffer is used to hold additional data past the end of the current message that the stream algorithm can read (this is explained in http://www.boost.org/doc/libs/1_66_0/libs/beast/doc/html/beast/using_http/message_stream_operations.html#beast.using_http.message_stream_operations.reading). You will access the content by inspecting the body of the message when using buffer_body
http::response_parser::get() will provide you with access to the message being read in.
The best solution for you is to use buffer_body as in the example, provide an area of memory to point it to and then call read or async_read in a loop. Every time the buffer is full, the read will return with the error beast::http::error::need_buffer
, indicating that further calls are required.
Hope this helps!
Upvotes: 8