I have test the following Boost::Asio minimal HTTP server example: (Minimal HTTP Server based on Boost:Asio)
I'm able to successfully collect the Header information such as Content-Length but the example hangs when I try to read the Body information. Here is the function that attempts to read the Body information:
static void read_body(std::shared_ptr<session> pThis) {
info("read_body");
int nbuffer = pThis->headers.content_length();
std::shared_ptr<std::vector<char>> bufptr = std::make_shared<std::vector<char>>(nbuffer);
asio::async_read(pThis->socket, boost::asio::buffer(*bufptr, nbuffer),
[pThis](const error_code& e, std::size_t s)
{
info("read body complete");
});
}
I have successfully read the same Body information utilizing a solution with libmicrohttpd.
Is there a more correct means to read the Body (JSON) information with Boost:ASIO?
The essence of the problem is twofold:
firstly, there is Undefined Behaviour because you fail to capture
bufptr
in the completion handler, meaning that the vector is already freed by the time that the syscall is writing to it...Secondly, you're "junking" the first part of the body, as you have already received it when reading the headers. You should add code to preserve the part that was already received in
read_next_line
.The real "misguidance" is probably in the use of
as if it will somehow receive exactly a single line. Sockets do not work that way. You'll receive a packet. The TCP stack(s) decide what constitutes a packet. Asio just promises to read "until" the packet >contains< the delimiter. It doesn't say it won't receive more, it just doesn't schedule another receive operation.
So, to really fix it, you might simply read all headers at once:
NOTE Again, it's important not to assume that the end-of-headers coincides with the packet boundary. Therefore, start
read_body()
with draining the available input already received:FIXED UP DEMO
Live On Coliru