Skip to content

Commit 7e1484e

Browse files
authored
Merge pull request #676 from evoskuil/master
Add post parse rpc validation to rpc::body template.
2 parents c2f044d + 9f6c840 commit 7e1484e

File tree

4 files changed

+61
-8
lines changed

4 files changed

+61
-8
lines changed

include/bitcoin/network/protocols/protocol_http.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class BCT_API protocol_http
7979
/// Senders.
8080
virtual void send_ok(const http::request& request={}) NOEXCEPT;
8181
virtual void send_bad_host(const http::request& request={}) NOEXCEPT;
82+
virtual void send_bad_request(const http::request& request={}) NOEXCEPT;
8283
virtual void send_not_found(const http::request& request={}) NOEXCEPT;
8384
virtual void send_not_acceptable(const http::request& request={}) NOEXCEPT;
8485
virtual void send_forbidden(const http::request& request={}) NOEXCEPT;

src/messages/rpc_body.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include <memory>
2222
#include <utility>
23+
#include <variant>
2324
#include <bitcoin/network/define.hpp>
2425
#include <bitcoin/network/messages/messages.hpp>
2526
#include <bitcoin/network/rpc/rpc.hpp>
@@ -119,6 +120,31 @@ finish(boost_code& ec) NOEXCEPT
119120
// As a catch-all we blame alloc.
120121
ec = to_http_code(http_error_t::bad_alloc);
121122
}
123+
124+
// Post-parse semantic validation.
125+
126+
if (value_.message.jsonrpc == version::undefined)
127+
value_.message.jsonrpc = version::v1;
128+
129+
if (value_.message.method.empty() ||
130+
!value_.message.params.has_value())
131+
{
132+
ec = to_boost_code(boost_error_t::bad_message);
133+
return;
134+
}
135+
136+
if (value_.message.jsonrpc == version::v1)
137+
{
138+
if (!value_.message.id.has_value())
139+
ec = to_boost_code(boost_error_t::bad_message);
140+
else if (!std::holds_alternative<array_t>(
141+
value_.message.params.value()))
142+
ec = to_boost_code(boost_error_t::bad_message);
143+
144+
// TODO: v1 batch is not allowed.
145+
////else if (value_.message.is_batch())
146+
//// ec = to_boost_code(boost_error_t::bad_message);
147+
}
122148
}
123149

124150
template <>

src/protocols/protocol_http.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,19 @@ void protocol_http::send_forbidden(const request& request) NOEXCEPT
245245
SEND(std::move(out), handle_complete, _1, error::forbidden);
246246
}
247247

248+
// Closes channel.
249+
void protocol_http::send_bad_request(const request& request) NOEXCEPT
250+
{
251+
BC_ASSERT(stranded());
252+
const auto code = status::bad_request;
253+
const auto media = to_media_type(request[field::accept]);
254+
response out{ code, request.version() };
255+
add_common_headers(out, request, true);
256+
out.body() = string_status(code, out.reason(), media);
257+
out.prepare_payload();
258+
SEND(std::move(out), handle_complete, _1, error::bad_request);
259+
}
260+
248261
// Closes channel.
249262
void protocol_http::send_bad_host(const request& request) NOEXCEPT
250263
{

src/rpc/model.cpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -299,18 +299,26 @@ DEFINE_JSON_FROM_TAG(response_t)
299299
{
300300
const auto& result = instance.error.value();
301301

302-
object["error"] =
303-
{
304-
{ "code", result.code },
305-
{ "message", result.message }
306-
};
307-
308302
if (result.data.has_value())
309303
{
310-
object["data"] = value_from(result.data.value());
304+
object["error"] =
305+
{
306+
{ "code", result.code },
307+
{ "message", result.message },
308+
{ "data", value_from(result.data.value()) }
309+
};
310+
}
311+
else
312+
{
313+
object["error"] =
314+
{
315+
{ "code", result.code },
316+
{ "message", result.message }
317+
};
311318
}
312319
}
313-
else if (instance.jsonrpc != version::v2)
320+
else if (instance.jsonrpc == version::v1 ||
321+
instance.jsonrpc == version::undefined)
314322
{
315323
object["error"] = boost::json::value{};
316324
}
@@ -319,6 +327,11 @@ DEFINE_JSON_FROM_TAG(response_t)
319327
{
320328
object["result"] = value_from(instance.result.value());
321329
}
330+
else if (instance.jsonrpc == version::v1 ||
331+
instance.jsonrpc == version::undefined)
332+
{
333+
object["result"] = boost::json::value{};
334+
}
322335

323336
value = object;
324337
}

0 commit comments

Comments
 (0)