0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-02 09:46:52 -05:00

rpc: refactor single/batch requests

Simplify the request handling flow so that errors and results only
come from JSONRPCExec()
This commit is contained in:
Matthew Zipkin 2023-02-27 13:03:45 -05:00 committed by Ryan Ofsky
parent df6e3756d6
commit a64a2b77e0
3 changed files with 24 additions and 35 deletions

View file

@ -185,7 +185,7 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
// Set the URI // Set the URI
jreq.URI = req->GetURI(); jreq.URI = req->GetURI();
std::string strReply; UniValue reply;
bool user_has_whitelist = g_rpc_whitelist.count(jreq.authUser); bool user_has_whitelist = g_rpc_whitelist.count(jreq.authUser);
if (!user_has_whitelist && g_rpc_whitelist_default) { if (!user_has_whitelist && g_rpc_whitelist_default) {
LogPrintf("RPC User %s not allowed to call any methods\n", jreq.authUser); LogPrintf("RPC User %s not allowed to call any methods\n", jreq.authUser);
@ -200,13 +200,12 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
req->WriteReply(HTTP_FORBIDDEN); req->WriteReply(HTTP_FORBIDDEN);
return false; return false;
} }
UniValue result = tableRPC.execute(jreq);
// Send reply reply = JSONRPCExec(jreq);
strReply = JSONRPCReplyObj(std::move(result), NullUniValue, jreq.id).write() + "\n";
// array of requests // array of requests
} else if (valRequest.isArray()) { } else if (valRequest.isArray()) {
// Check authorization for each request's method
if (user_has_whitelist) { if (user_has_whitelist) {
for (unsigned int reqIdx = 0; reqIdx < valRequest.size(); reqIdx++) { for (unsigned int reqIdx = 0; reqIdx < valRequest.size(); reqIdx++) {
if (!valRequest[reqIdx].isObject()) { if (!valRequest[reqIdx].isObject()) {
@ -223,13 +222,26 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
} }
} }
} }
strReply = JSONRPCExecBatch(jreq, valRequest.get_array());
// Execute each request
reply = UniValue::VARR;
for (size_t i{0}; i < valRequest.size(); ++i) {
// Batches include errors in the batch response, they do not throw
try {
jreq.parse(valRequest[i]);
reply.push_back(JSONRPCExec(jreq));
} catch (UniValue& e) {
reply.push_back(JSONRPCReplyObj(NullUniValue, std::move(e), jreq.id));
} catch (const std::exception& e) {
reply.push_back(JSONRPCReplyObj(NullUniValue, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id));
}
}
} }
else else
throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
req->WriteHeader("Content-Type", "application/json"); req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strReply); req->WriteReply(HTTP_OK, reply.write() + "\n");
} catch (UniValue& e) { } catch (UniValue& e) {
JSONErrorReply(req, std::move(e), jreq.id); JSONErrorReply(req, std::move(e), jreq.id);
return false; return false;

View file

@ -358,36 +358,13 @@ bool IsDeprecatedRPCEnabled(const std::string& method)
return find(enabled_methods.begin(), enabled_methods.end(), method) != enabled_methods.end(); return find(enabled_methods.begin(), enabled_methods.end(), method) != enabled_methods.end();
} }
static UniValue JSONRPCExecOne(JSONRPCRequest jreq, const UniValue& req) UniValue JSONRPCExec(const JSONRPCRequest& jreq)
{ {
UniValue rpc_result(UniValue::VOBJ); // Might throw exception. Single requests will throw and send HTTP error codes
// but inside a batch, we just include the error object and return HTTP 200
try {
jreq.parse(req);
UniValue result = tableRPC.execute(jreq); UniValue result = tableRPC.execute(jreq);
rpc_result = JSONRPCReplyObj(std::move(result), NullUniValue, jreq.id);
}
catch (UniValue& e)
{
rpc_result = JSONRPCReplyObj(NullUniValue, std::move(e), jreq.id);
}
catch (const std::exception& e)
{
rpc_result = JSONRPCReplyObj(NullUniValue,
JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
}
return rpc_result; return JSONRPCReplyObj(std::move(result), NullUniValue, jreq.id);
}
std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq)
{
UniValue ret(UniValue::VARR);
for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
ret.push_back(JSONRPCExecOne(jreq, vReq[reqIdx]));
return ret.write() + "\n";
} }
/** /**

View file

@ -181,7 +181,7 @@ extern CRPCTable tableRPC;
void StartRPC(); void StartRPC();
void InterruptRPC(); void InterruptRPC();
void StopRPC(); void StopRPC();
std::string JSONRPCExecBatch(const JSONRPCRequest& jreq, const UniValue& vReq); UniValue JSONRPCExec(const JSONRPCRequest& jreq);
// Drop witness when serializing for RPC? // Drop witness when serializing for RPC?
bool RPCSerializationWithoutWitness(); bool RPCSerializationWithoutWitness();