aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Zipkin <pinheadmz@gmail.com>2023-07-07 14:31:18 -0400
committerMatthew Zipkin <pinheadmz@gmail.com>2024-05-14 10:32:43 -0400
commit2ca1460ae3a7217eaa8c5972515bf622bedadfce (patch)
tree5812d18bb8eb28d68d666ae26cc1232cd8f00d3a
parenta64a2b77e09bff784a2635ba19ff4aa6582bb5a5 (diff)
downloadbitcoin-2ca1460ae3a7217eaa8c5972515bf622bedadfce.tar.xz
rpc: identify JSON-RPC 2.0 requests
-rw-r--r--src/rpc/request.cpp19
-rw-r--r--src/rpc/request.h6
-rwxr-xr-xtest/functional/interface_rpc.py14
3 files changed, 33 insertions, 6 deletions
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index 12726ecc88..08e0658561 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -167,6 +167,25 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
// Parse id now so errors from here on will have the id
id = request.find_value("id");
+ // Check for JSON-RPC 2.0 (default 1.1)
+ m_json_version = JSONRPCVersion::V1_LEGACY;
+ const UniValue& jsonrpc_version = request.find_value("jsonrpc");
+ if (!jsonrpc_version.isNull()) {
+ if (!jsonrpc_version.isStr()) {
+ throw JSONRPCError(RPC_INVALID_REQUEST, "jsonrpc field must be a string");
+ }
+ // The "jsonrpc" key was added in the 2.0 spec, but some older documentation
+ // incorrectly included {"jsonrpc":"1.0"} in a request object, so we
+ // maintain that for backwards compatibility.
+ if (jsonrpc_version.get_str() == "1.0") {
+ m_json_version = JSONRPCVersion::V1_LEGACY;
+ } else if (jsonrpc_version.get_str() == "2.0") {
+ m_json_version = JSONRPCVersion::V2;
+ } else {
+ throw JSONRPCError(RPC_INVALID_REQUEST, "JSON-RPC version not supported");
+ }
+ }
+
// Parse method
const UniValue& valMethod{request.find_value("method")};
if (valMethod.isNull())
diff --git a/src/rpc/request.h b/src/rpc/request.h
index 116ebb8aac..8b72172695 100644
--- a/src/rpc/request.h
+++ b/src/rpc/request.h
@@ -11,6 +11,11 @@
#include <univalue.h>
+enum class JSONRPCVersion {
+ V1_LEGACY,
+ V2
+};
+
UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id);
UniValue JSONRPCReplyObj(UniValue result, UniValue error, UniValue id);
UniValue JSONRPCError(int code, const std::string& message);
@@ -35,6 +40,7 @@ public:
std::string authUser;
std::string peerAddr;
std::any context;
+ JSONRPCVersion m_json_version = JSONRPCVersion::V1_LEGACY;
void parse(const UniValue& valRequest);
};
diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py
index 748d83858a..075dd1c2bc 100755
--- a/test/functional/interface_rpc.py
+++ b/test/functional/interface_rpc.py
@@ -161,8 +161,10 @@ class RPCInterfaceTest(BitcoinTestFramework):
self.log.info("Testing nonstandard jsonrpc 1.0 version number is accepted...")
self.test_batch_request(lambda idx: BatchOptions(request_fields={"jsonrpc": "1.0"}))
- self.log.info("Testing unrecognized jsonrpc version number is accepted...")
- self.test_batch_request(lambda idx: BatchOptions(request_fields={"jsonrpc": "2.1"}))
+ self.log.info("Testing unrecognized jsonrpc version number is rejected...")
+ self.test_batch_request(lambda idx: BatchOptions(
+ request_fields={"jsonrpc": "2.1"},
+ response_fields={"result": None, "error": {"code": RPC_INVALID_REQUEST, "message": "JSON-RPC version not supported"}}))
def test_http_status_codes(self):
self.log.info("Testing HTTP status codes for JSON-RPC 1.1 requests...")
@@ -188,11 +190,11 @@ class RPCInterfaceTest(BitcoinTestFramework):
expect_http_rpc_status(500, RPC_INVALID_PARAMETER, self.nodes[0], "getblockhash", [42], 2, False)
# force-send invalidly formatted requests
response, status = send_json_rpc(self.nodes[0], {"jsonrpc": 2, "method": "getblockcount"})
- assert_equal(response, {"error": None, "id": None, "result": 0})
- assert_equal(status, 200)
+ assert_equal(response, {"id": None, "result": None, "error": {"code": RPC_INVALID_REQUEST, "message": "jsonrpc field must be a string"}})
+ assert_equal(status, 400)
response, status = send_json_rpc(self.nodes[0], {"jsonrpc": "3.0", "method": "getblockcount"})
- assert_equal(response, {"error": None, "id": None, "result": 0})
- assert_equal(status, 200)
+ assert_equal(response, {"id": None, "result": None, "error": {"code": RPC_INVALID_REQUEST, "message": "JSON-RPC version not supported"}})
+ assert_equal(status, 400)
self.log.info("Testing HTTP status codes for JSON-RPC 2.0 notifications...")
# Not notification: id exists