diff --git a/src/protocols/bitcoind/protocol_bitcoind.cpp b/src/protocols/bitcoind/protocol_bitcoind.cpp index f58be993..736550b9 100644 --- a/src/protocols/bitcoind/protocol_bitcoind.cpp +++ b/src/protocols/bitcoind/protocol_bitcoind.cpp @@ -382,8 +382,22 @@ void protocol_bitcoind::send_rpc(response_t&& model, const auto statused = options().error_status && !batched; auto message = to_response(statused ? to_status(model) : status::ok); message.set(field::content_type, json); - message.body() = rpc::response{ {}, std::move(model) }; - message.prepare_payload(); + + // Batch parts are streamed (chunked). A singleton is sized, as bitcoind + // does and as some of its clients (e.g. fulcrum) require. + if (batched) + { + message.body() = rpc::response{ {}, std::move(model) }; + message.prepare_payload(); + } + else + { + auto text = serialize(value_from(model)); + const auto size = text.size(); + message.body() = std::move(text); + message.content_length(size); + } + SEND(std::move(message), handle_complete, _1, close_reason); } diff --git a/src/protocols/protocol_http.cpp b/src/protocols/protocol_http.cpp index 60476a0c..1f3da1b6 100644 --- a/src/protocols/protocol_http.cpp +++ b/src/protocols/protocol_http.cpp @@ -200,7 +200,7 @@ void protocol_http::send_stream(size_t size, wire_writer&& writer, .write = std::move(writer), .size = size }; - message.prepare_payload(); + message.content_length(size); SEND(std::move(message), handle_stream, _1); } diff --git a/test/protocols/bitcoind/bitcoind_rpc.cpp b/test/protocols/bitcoind/bitcoind_rpc.cpp index c931e88b..a9e09e6f 100644 --- a/test/protocols/bitcoind/bitcoind_rpc.cpp +++ b/test/protocols/bitcoind/bitcoind_rpc.cpp @@ -173,6 +173,35 @@ BC_FIXTURE_TEST_SUITE(bitcoind_tests, bitcoind_ten_block_setup_fixture) // blockchain // ---------------------------------------------------------------------------- +BC_AUTO_TEST_CASE(bitcoind_rpc__getblockcount__http_response__content_length) +{ + const auto response = rpc_response("getblockcount"); + BC_REQUIRE(response.result() == status::ok); + BC_REQUIRE(!response.chunked()); + BC_REQUIRE(response.content_length().has_value()); + BC_REQUIRE_EQUAL(response.content_length().value(), response.body().size()); + BC_REQUIRE_EQUAL(test::parse_json(response.body()).at("result").as_int64(), 9); +} + +BC_AUTO_TEST_CASE(bitcoind_rpc__getblock__hex_http_response__content_length) +{ + const auto response = rpc_response("getblock", hash_param(test::block9_hash, "0")); + BC_REQUIRE(response.result() == status::ok); + BC_REQUIRE(!response.chunked()); + BC_REQUIRE(response.content_length().has_value()); + BC_REQUIRE_EQUAL(response.content_length().value(), response.body().size()); + REQUIRE_NO_THROW_TRUE(test::parse_json(response.body()).at("result").is_string()); +} + +BC_AUTO_TEST_CASE(bitcoind_rpc__unknown_method__http_response__content_length) +{ + const auto response = rpc_response("nonsense"); + BC_REQUIRE(!response.chunked()); + BC_REQUIRE(response.content_length().has_value()); + BC_REQUIRE_EQUAL(response.content_length().value(), response.body().size()); + BC_REQUIRE(has_code(test::parse_json(response.body()), -32601)); +} + BC_AUTO_TEST_CASE(bitcoind_rpc__getblockcount__ten_block_store__nine) { const auto response = rpc("getblockcount"); diff --git a/test/protocols/bitcoind/bitcoind_setup_fixture.cpp b/test/protocols/bitcoind/bitcoind_setup_fixture.cpp index 9518cd47..618f3b1a 100644 --- a/test/protocols/bitcoind/bitcoind_setup_fixture.cpp +++ b/test/protocols/bitcoind/bitcoind_setup_fixture.cpp @@ -109,6 +109,13 @@ system::json::value bitcoind_setup_fixture::rpc(std::string_view method, return client_.post(body_of(method, params), "/", true); } +network::http::message +bitcoind_setup_fixture::rpc_response(std::string_view method, + std::string_view params) +{ + return client_.post_response(body_of(method, params)); +} + system::json::value bitcoind_setup_fixture::tcp_rpc(std::string_view method, std::string_view params) { diff --git a/test/protocols/bitcoind/bitcoind_setup_fixture.hpp b/test/protocols/bitcoind/bitcoind_setup_fixture.hpp index 23423d81..9b7124ae 100644 --- a/test/protocols/bitcoind/bitcoind_setup_fixture.hpp +++ b/test/protocols/bitcoind/bitcoind_setup_fixture.hpp @@ -46,6 +46,10 @@ struct bitcoind_setup_fixture // object). Returns the parsed json-rpc response object (with result/error). system::json::value rpc(std::string_view method, std::string_view params="[]"); + // As rpc(), returning the http response (for framing). + network::http::message rpc_response( + std::string_view method, std::string_view params="[]"); + // JSON-RPC over HTTP POST to "/" with a raw body (e.g. a batch). Returns // the parsed json response, or {"dropped":true} if the channel dropped. system::json::value rpc_body(std::string_view body);