diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index d175db09e..f254da5de 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -121,6 +121,18 @@ CRPCConvertTable::CRPCConvertTable() 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 jVal; + if (!jVal.read(std::string("[")+strVal+std::string("]")) || + !jVal.isArray() || jVal.size()!=1) + throw runtime_error(string("Error parsing JSON:")+strVal); + return jVal[0]; +} + /** Convert strings to command-specific RPC representation */ UniValue RPCConvertValues(const std::string &strMethod, const std::vector &strParams) { @@ -129,28 +141,12 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector 0)) - if(!jVal.setNumStr(strVal) || jVal.isNull()) - throw runtime_error(string("Error parsing JSON:")+strVal); - } - params.push_back(jVal); + } else { + // parse string as JSON, insert bool/number/object/etc. value + params.push_back(ParseNonRFCJSONValue(strVal)); } } diff --git a/src/rpcclient.h b/src/rpcclient.h index 52270aec7..d68b4ed6a 100644 --- a/src/rpcclient.h +++ b/src/rpcclient.h @@ -9,5 +9,9 @@ #include "univalue/univalue.h" UniValue RPCConvertValues(const std::string& strMethod, const std::vector& strParams); +/** 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); #endif // BITCOIN_RPCCLIENT_H diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 576e62a0b..0b33ddb08 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -143,23 +143,20 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values) BOOST_AUTO_TEST_CASE(json_parse_errors) { - UniValue value; // Valid - BOOST_CHECK_EQUAL(value.read(std::string("1.0")), false); - BOOST_CHECK_EQUAL(value.read(std::string("[1.0]")), true); - // Valid, with trailing whitespace - BOOST_CHECK_EQUAL(value.read(std::string("1.0 ")), false); - BOOST_CHECK_EQUAL(value.read(std::string("[1.0 ] ")), true); + BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0); + // 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); // Invalid, initial garbage - BOOST_CHECK_EQUAL(value.read(std::string("[1.0")), false); - BOOST_CHECK_EQUAL(value.read(std::string("[a1.0]")), false); - BOOST_CHECK_EQUAL(value.read(std::string("[\"a1.0\"]")), true); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error); // Invalid, trailing garbage - BOOST_CHECK_EQUAL(value.read(std::string("1.0sds")), false); - BOOST_CHECK_EQUAL(value.read(std::string("1.0]")), false); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error); // BTC addresses should fail parsing - BOOST_CHECK_EQUAL(value.read(std::string("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W")), false); - BOOST_CHECK_EQUAL(value.read(std::string("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL")), false); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error); + BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error); } BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr)