diff options
author | Jeff Garzik <jgarzik@exmulti.com> | 2012-06-24 02:01:28 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2012-07-03 22:53:57 -0400 |
commit | 613389019e6e3c0e903f78f6186d598c5194c395 (patch) | |
tree | 4ee9314b7d5f8bce126101308142b5784bc7f9a2 | |
parent | c6494d82fa31913eb075b222293e87ae40c9f9b2 (diff) |
RPC: add support for JSON-RPC 2.0-style request batching
If the top-level object is an array, it is assumed to be an array of
JSON-RPC requests. An array is returned, containing one response (error or
not) per request, in the order submitted.
In a slight change in semantics, batched requests -always- return
an HTTP 200 OK status, even ones full of invalid or incorrect requests.
-rw-r--r-- | src/bitcoinrpc.cpp | 54 |
1 files changed, 49 insertions, 5 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 134c3be93f..109cb92f32 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -2952,6 +2952,39 @@ void JSONRequest::parse(const Value& valRequest) throw JSONRPCError(-32600, "Params must be an array"); } +static Object JSONRPCExecOne(const Value& req) +{ + Object rpc_result; + + JSONRequest jreq; + try { + jreq.parse(req); + + Value result = tableRPC.execute(jreq.strMethod, jreq.params); + rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id); + } + catch (Object& objError) + { + rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id); + } + catch (std::exception& e) + { + rpc_result = JSONRPCReplyObj(Value::null, + JSONRPCError(-32700, e.what()), jreq.id); + } + + return rpc_result; +} + +static string JSONRPCExecBatch(const Array& vReq) +{ + Array ret; + for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++) + ret.push_back(JSONRPCExecOne(vReq[reqIdx])); + + return write_string(Value(ret), false) + "\n"; +} + static CCriticalSection cs_THREAD_RPCHANDLER; void ThreadRPCServer3(void* parg) @@ -3006,15 +3039,26 @@ void ThreadRPCServer3(void* parg) { // Parse request Value valRequest; - if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type) + if (!read_string(strRequest, valRequest)) throw JSONRPCError(-32700, "Parse error"); - jreq.parse(valRequest); + string strReply; + + // singleton request + if (valRequest.type() == obj_type) { + jreq.parse(valRequest); - Value result = tableRPC.execute(jreq.strMethod, jreq.params); + Value result = tableRPC.execute(jreq.strMethod, jreq.params); - // Send reply - string strReply = JSONRPCReply(result, Value::null, jreq.id); + // Send reply + strReply = JSONRPCReply(result, Value::null, jreq.id); + + // array of requests + } else if (valRequest.type() == array_type) + strReply = JSONRPCExecBatch(valRequest.get_array()); + else + throw JSONRPCError(-32700, "Top-level object parse error"); + conn->stream() << HTTPReply(200, strReply, fRun) << std::flush; } catch (Object& objError) |