aboutsummaryrefslogtreecommitdiff
path: root/src/httprpc.cpp
diff options
context:
space:
mode:
authorMatthew Zipkin <pinheadmz@gmail.com>2023-07-07 14:41:23 -0400
committerMatthew Zipkin <pinheadmz@gmail.com>2024-05-14 11:15:54 -0400
commitbf1a1f1662427fbf1a43bb951364eface469bdb7 (patch)
tree40c6da6c106ed68bf368cc2e52496f492866c563 /src/httprpc.cpp
parent466b90562f4785de74b548f7c4a256069e2aaf43 (diff)
downloadbitcoin-bf1a1f1662427fbf1a43bb951364eface469bdb7.tar.xz
rpc: Avoid returning HTTP errors for JSON-RPC 2.0 requests
Avoid returning HTTP status errors for non-batch JSON-RPC 2.0 requests if the RPC method failed but the HTTP request was otherwise valid. Batch requests already did not return HTTP errors previously.
Diffstat (limited to 'src/httprpc.cpp')
-rw-r--r--src/httprpc.cpp15
1 files changed, 12 insertions, 3 deletions
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 817c75f3b5..777ad32bbe 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -75,6 +75,9 @@ static bool g_rpc_whitelist_default = false;
static void JSONErrorReply(HTTPRequest* req, UniValue objError, const JSONRPCRequest& jreq)
{
+ // Sending HTTP errors is a legacy JSON-RPC behavior.
+ Assume(jreq.m_json_version != JSONRPCVersion::V2);
+
// Send error reply from json-rpc error object
int nStatus = HTTP_INTERNAL_SERVER_ERROR;
int code = objError.find_value("code").getInt<int>();
@@ -201,7 +204,12 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
return false;
}
- reply = JSONRPCExec(jreq);
+ // Legacy 1.0/1.1 behavior is for failed requests to throw
+ // exceptions which return HTTP errors and RPC errors to the client.
+ // 2.0 behavior is to catch exceptions and return HTTP success with
+ // RPC errors, as long as there is not an actual HTTP server error.
+ const bool catch_errors{jreq.m_json_version == JSONRPCVersion::V2};
+ reply = JSONRPCExec(jreq, catch_errors);
// array of requests
} else if (valRequest.isArray()) {
@@ -226,10 +234,11 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
// 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
+ // Batches never throw HTTP errors, they are always just included
+ // in "HTTP OK" responses.
try {
jreq.parse(valRequest[i]);
- reply.push_back(JSONRPCExec(jreq));
+ reply.push_back(JSONRPCExec(jreq, /*catch_errors=*/true));
} catch (UniValue& e) {
reply.push_back(JSONRPCReplyObj(NullUniValue, std::move(e), jreq.id, jreq.m_json_version));
} catch (const std::exception& e) {