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:
parent
df6e3756d6
commit
a64a2b77e0
3 changed files with 24 additions and 35 deletions
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
UniValue result = tableRPC.execute(jreq);
|
||||||
|
|
||||||
try {
|
return JSONRPCReplyObj(std::move(result), NullUniValue, jreq.id);
|
||||||
jreq.parse(req);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Reference in a new issue