Better error messages for out of range integral values

* This change passes detailed error messages from the JSON parser
  on the server side, back to the client for inclusion into the
  reply's error message.

* Errors originating from the server's inability to parse are
  reclassified from rpcINTERNAL to rpcINVALID_PARAMS.
This commit is contained in:
Howard Hinnant
2018-01-17 17:48:58 -05:00
committed by seelabs
parent 35cc341544
commit a8481e369d
4 changed files with 34 additions and 3 deletions

View File

@@ -1197,6 +1197,15 @@ std::string JSONRPCRequest (std::string const& strMethod, Json::Value const& par
return to_string (request) + "\n";
}
namespace
{
// Special local exception type thrown when request can't be parsed.
class RequestNotParseable : public std::runtime_error
{
using std::runtime_error::runtime_error; // Inherit constructors
};
};
struct RPCCallImp
{
// VFALCO NOTE Is this a to-do comment or a doc comment?
@@ -1228,7 +1237,8 @@ struct RPCCallImp
// Parse reply
JLOG (j.debug()) << "RPC reply: " << strData << std::endl;
if (strData.find("Unable to parse request") == 0)
Throw<RequestNotParseable> (strData);
Json::Reader reader;
Json::Value jvReply;
if (!reader.parse (strData, jvReply))
@@ -1440,6 +1450,12 @@ rpcClient(std::vector<std::string> const& args,
// YYY We could have a command line flag for single line output for scripts.
// YYY We would intercept output here and simplify it.
}
catch (RequestNotParseable& e)
{
jvOutput = rpcError(rpcINVALID_PARAMS);
jvOutput["error_what"] = e.what();
nRet = rpcINVALID_PARAMS;
}
catch (std::exception& e)
{
jvOutput = rpcError (rpcINTERNAL);

View File

@@ -569,7 +569,8 @@ ServerHandlerImp::processRequest (Port const& port,
! jsonOrig ||
! (jsonOrig.isObject () || jsonOrig.isArray()))
{
HTTPReply (400, "Unable to parse request", output, rpcJ);
HTTPReply (400, "Unable to parse request: " +
reader.getFormatedErrorMessages(), output, rpcJ);
return;
}
}

View File

@@ -121,6 +121,20 @@ class LedgerRPC_test : public beast::unit_test::suite
checkErrorValue(jrr, "invalidParams", "Invalid parameters.");
}
{
// Request a ledger with a very large (double) sequence.
auto const ret = env.rpc (
"json", "ledger", "{ \"ledger_index\" : 2e15 }");
BEAST_EXPECT (RPC::contains_error(ret));
BEAST_EXPECT (ret[jss::error_message] == "Invalid parameters.");
}
{
// Request a ledger with very large (integer) sequence.
auto const ret = env.rpc (
"json", "ledger", "{ \"ledger_index\" : 1000000000000000 }");
checkErrorValue(ret, "invalidParams", "Invalid parameters.");
}
}
void testLedgerCurrent()

View File

@@ -893,7 +893,7 @@ class ServerStatus_test :
boost::beast::http::response<boost::beast::http::string_body> resp;
doHTTPRequest(env, yield, false, resp, ec, "{}");
BEAST_EXPECT(resp.result() == boost::beast::http::status::bad_request);
BEAST_EXPECT(resp.body() == "Unable to parse request\r\n");
BEAST_EXPECT(resp.body() == "Unable to parse request: \r\n");
}
Json::Value jv;