diff --git a/include/bitcoin/network/impl/messages/json_body.ipp b/include/bitcoin/network/impl/messages/json_body.ipp index 7d58d7016..f33fcb811 100644 --- a/include/bitcoin/network/impl/messages/json_body.ipp +++ b/include/bitcoin/network/impl/messages/json_body.ipp @@ -89,6 +89,13 @@ size_t CLASS::reader::put(const buffer_type& buffer, boost_code& ec) NOEXCEPT TEMPLATE void CLASS::reader::finish(boost_code& ec) NOEXCEPT { + using namespace network::error; + if (!done()) + { + ec = to_http_code(http_error_t::partial_message); + return; + } + BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT) parser_.finish(ec); BC_POP_WARNING() @@ -107,7 +114,6 @@ void CLASS::reader::finish(boost_code& ec) NOEXCEPT catch (...) { // As a catch-all we blame alloc. - using namespace network::error; ec = to_http_code(http_error_t::bad_alloc); } diff --git a/include/bitcoin/network/messages/rpc/body.hpp b/include/bitcoin/network/messages/rpc/body.hpp index 8199f1133..bfd9c0705 100644 --- a/include/bitcoin/network/messages/rpc/body.hpp +++ b/include/bitcoin/network/messages/rpc/body.hpp @@ -66,6 +66,7 @@ struct BCT_API body size_t put(const buffer_type& buffer, boost_code& ec) NOEXCEPT override; void finish(boost_code& ec) NOEXCEPT override; + bool done() const NOEXCEPT override; private: const bool terminated_{}; diff --git a/src/messages/rpc/body.cpp b/src/messages/rpc/body.cpp index 8d3ba8af7..65578e94a 100644 --- a/src/messages/rpc/body.cpp +++ b/src/messages/rpc/body.cpp @@ -23,7 +23,6 @@ #include #include #include -////#include namespace libbitcoin { namespace network { @@ -65,33 +64,38 @@ put(const buffer_type& buffer, boost_code& ec) NOEXCEPT if (!terminated_) return parsed; - // There is no terminator. + // There is no terminator (terminal). if (is_zero(parsed)) { ec = to_http_code(http_error_t::end_of_stream); return parsed; } - // There are extra characters. - if (size > parsed) - { - ec = to_http_code(http_error_t::unexpected_body); - return parsed; - } - - // boost::json consumes whitespace, so terminator is always last. + // boost::json consumes whitespace, and leaves any subsequent chars + // unparsed, so terminator must be in the parsed segment of the buffer. const auto data = pointer_cast(buffer.data()); - if (data[sub1(parsed)] == '\n') + for (auto index = parsed; !is_zero(index);) { - has_terminator_ = true; - return parsed; + if (data[--index] == '\n') + { + // There may be unparsed characters (ok, next message). + has_terminator_ = true; + return parsed; + } } - // There is no terminator. - ec = to_http_code(http_error_t::end_of_stream); + // There is no terminator (yet). return parsed; } +template <> +bool body::reader:: +done() const NOEXCEPT +{ + // Parser may be done but with terminator still outstanding. + return parser_.done() && (!terminated_ || has_terminator_); +} + template <> void body::reader:: finish(boost_code& ec) NOEXCEPT @@ -99,12 +103,6 @@ finish(boost_code& ec) NOEXCEPT base::reader::finish(ec); if (ec) return; - if (terminated_ && !has_terminator_) - { - ec = to_http_code(http_error_t::end_of_stream); - return; - } - try { value_.message = value_to(value_.model); @@ -162,6 +160,14 @@ finish(boost_code&) NOEXCEPT BC_ASSERT(false); } +template <> +bool body::reader:: +done() const NOEXCEPT +{ + BC_ASSERT(false); + return {}; +} + // rpc::body::writer // ---------------------------------------------------------------------------- diff --git a/src/net/socket.cpp b/src/net/socket.cpp index 122c58c39..f35cbad58 100644 --- a/src/net/socket.cpp +++ b/src/net/socket.cpp @@ -686,18 +686,10 @@ void socket::handle_rpc_read(boost_code ec, size_t size, size_t total, const auto parsed = in->reader.put(data, ec); if (!ec) { - if (parsed < data.size()) - { - handler(error::unexpected_body, total); - return; - } - in->value.buffer->consume(parsed); if (in->reader.done()) { in->reader.finish(ec); - - // Finished. if (!ec) { handler(error::success, total);