From 1d02e599012721549d4c20b1b37fcc5ee7b961b6 Mon Sep 17 00:00:00 2001 From: stickies-v Date: Wed, 30 Nov 2022 17:42:59 +0000 Subject: [PATCH 1/3] test: add cases to JSON parsing --- src/test/rpc_tests.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index d807c7cda2..791c9ddf31 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -289,6 +289,10 @@ BOOST_AUTO_TEST_CASE(json_parse_errors) { // Valid BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0); + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("true").get_bool(), true); + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("[false]")[0].get_bool(), false); + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("{\"a\": true}")["a"].get_bool(), true); + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("{\"1\": \"true\"}")["1"].get_str(), "true"); // Valid, with leading or trailing whitespace BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0); BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0); @@ -301,6 +305,11 @@ BOOST_AUTO_TEST_CASE(json_parse_errors) // Invalid, trailing garbage BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error); BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error); + // Invalid, keys have to be names + BOOST_CHECK_THROW(ParseNonRFCJSONValue("{1: \"true\"}"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("{true: 1}"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("{[1]: 1}"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("{{\"a\": \"a\"}: 1}"), std::runtime_error); // BTC addresses should fail parsing BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error); BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error); From 7727603e44f8f674e0fc8389e78047e2b56e6052 Mon Sep 17 00:00:00 2001 From: stickies-v Date: Wed, 30 Nov 2022 16:27:13 +0000 Subject: [PATCH 2/3] refactor: reduce unnecessary complexity in ParseNonRFCJSONValue Since https://github.com/jgarzik/univalue/pull/31, UniValue::read() can now parse raw literals directly, so there is no more need to wrap them into an array first. --- src/rpc/client.cpp | 10 ++++------ src/rpc/client.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 5fe914f0a1..a94c7e8c29 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -253,13 +253,11 @@ static CRPCConvertTable rpcCvtTable; /** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) * as well as objects and arrays. */ -UniValue ParseNonRFCJSONValue(const std::string& strVal) +UniValue ParseNonRFCJSONValue(const std::string& raw) { - UniValue jVal; - if (!jVal.read(std::string("[")+strVal+std::string("]")) || - !jVal.isArray() || jVal.size()!=1) - throw std::runtime_error(std::string("Error parsing JSON: ") + strVal); - return jVal[0]; + UniValue parsed; + if (!parsed.read(raw)) throw std::runtime_error(std::string("Error parsing JSON: ") + raw); + return parsed; } UniValue RPCConvertValues(const std::string &strMethod, const std::vector &strParams) diff --git a/src/rpc/client.h b/src/rpc/client.h index b9fee5bbb3..644081ac22 100644 --- a/src/rpc/client.h +++ b/src/rpc/client.h @@ -17,6 +17,6 @@ UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector Date: Wed, 30 Nov 2022 17:16:04 +0000 Subject: [PATCH 3/3] refactor: use string_view for RPC named argument values Minimize copying RPC named argument values when calling .substr() by using std::string_view instead of std::string. --- src/rpc/client.cpp | 25 ++++++++++++++----------- src/rpc/client.h | 5 ++++- src/univalue/include/univalue.h | 5 ++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index a94c7e8c29..2ef79eb501 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -4,10 +4,13 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include +#include +#include class CRPCConvertParam { @@ -228,15 +231,15 @@ public: CRPCConvertTable(); /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */ - UniValue ArgToUniValue(const std::string& arg_value, const std::string& method, int param_idx) + UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx) { - return members.count(std::make_pair(method, param_idx)) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; + return members.count({method, param_idx}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; } /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */ - UniValue ArgToUniValue(const std::string& arg_value, const std::string& method, const std::string& param_name) + UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name) { - return membersByName.count(std::make_pair(method, param_name)) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; + return membersByName.count({method, param_name}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value; } }; @@ -253,10 +256,10 @@ static CRPCConvertTable rpcCvtTable; /** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) * as well as objects and arrays. */ -UniValue ParseNonRFCJSONValue(const std::string& raw) +UniValue ParseNonRFCJSONValue(std::string_view raw) { UniValue parsed; - if (!parsed.read(raw)) throw std::runtime_error(std::string("Error parsing JSON: ") + raw); + if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw)); return parsed; } @@ -265,8 +268,8 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector +#include + #include /** Convert positional arguments to command-specific RPC representation */ @@ -17,6 +20,6 @@ UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector #include #include +#include #include #include @@ -95,9 +96,7 @@ public: bool read(const char *raw, size_t len); bool read(const char *raw) { return read(raw, strlen(raw)); } - bool read(const std::string& rawStr) { - return read(rawStr.data(), rawStr.size()); - } + bool read(std::string_view raw) { return read(raw.data(), raw.size()); } private: UniValue::VType typ;