abcd
abcd

Reputation: 51

Why does Boost-Beast give me a partial message exception

I´m trying to use the boost beast http library for an HTTP Client. It´s working without any issues when I´m using a simulated server, however when I try connecting to the real server, boost::beast::http::read throws an exception saying "partial message".

I´ve been working on this issue for a couple days now but I can´t figure out why. Until now I´ve been using a different http client library and the server communication has been working without any similar issues.

I´d be grateful for any kind of idea or hint as to why this is happening and why it doesn't seem to be an issue when using a different library.

Upvotes: 4

Views: 1406

Answers (1)

sehe
sehe

Reputation: 393134

boost::beast::http::read throws an exception saying "partial message".

This happens because the message being parsed wasn't complete. A typical reason for it is when the content-length header is wrong, or the sender abandons the connection prematurely. E.g.:

Live On Compiler Explorer

This is what http::[async_]read ends up doing under the hood, but without the network related stuff:

#include <iostream>
#include <iomanip>
#include <string_view>
#include <boost/beast/http.hpp>

int main() {
    using namespace boost::beast::http;
    using boost::asio::buffer;

    for (std::string_view buf : {
            "GET / HTTP/1.1\r\n", // incomplete headers
            "GET / HTTP/1.1\r\nHost: example.com\r\nContent-Length: 0\r\n\r\ntrailing data",
            "GET / HTTP/1.1\r\nHost: example.com\r\nContent-Length: 42\r\n\r\nshort",
        })
    {
        //std::cout << std::quoted(test) << "\n";
        std::cout << "---------------------" << "\n";

        request_parser<string_body> parser;
        boost::system::error_code ec;

        size_t n = parser.put(buffer(buf), ec);
        if (n && !ec && !parser.is_done()) {
            buf.remove_prefix(n);
            n = parser.put(buffer(buf), ec); // body
        }
        if (!ec)
            parser.put_eof(ec);
        buf.remove_prefix(n);

        std::cout
            << (parser.is_header_done()?"headers ok":"incomplete headers")
            << " / " << (parser.is_done()?"done":"not done")
            << " / " << ec.message() << "\n";
        if (parser.is_header_done() && !parser.is_done())
            std::cout << parser.content_length_remaining().value_or(0) << " more content bytes expected\n";

        if (!buf.empty())
            std::cout << "Remaining buffer: " << std::quoted(buf) << "\n";
    }
}

Prints

---------------------
incomplete headers / not done / need more
---------------------
headers ok / done / Success
Remaining buffer: "trailing data"
---------------------
headers ok / not done / partial message
37 more content bytes expected

If you're not passing error_code to your calls they will throw the exception system_error with the same code, which is exactly what you see.

Side Note

If another library doesn't have this "problem" there are two options:

  • the library is sloppy (i.e. bad)
  • you're using it wrong (maybe you're not checking for errors)

Upvotes: 3

Related Questions