aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@exmulti.com>2012-07-03 20:08:36 -0700
committerJeff Garzik <jgarzik@exmulti.com>2012-07-03 20:08:36 -0700
commitc729dbb6d2b63d9c0b32e3937be0ebf528d4c753 (patch)
tree4ee9314b7d5f8bce126101308142b5784bc7f9a2
parent38986093045f252753e35b3d9d4c3e2ad0c82af3 (diff)
parent613389019e6e3c0e903f78f6186d598c5194c395 (diff)
Merge pull request #1512 from jgarzik/json-batch
Support JSON-RPC 2.0 request batches
-rw-r--r--src/bitcoinrpc.cpp133
1 files changed, 101 insertions, 32 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 51690243bc..109cb92f32 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -2552,7 +2552,7 @@ string JSONRPCRequest(const string& strMethod, const Array& params, const Value&
return write_string(Value(request), false) + "\n";
}
-string JSONRPCReply(const Value& result, const Value& error, const Value& id)
+Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
{
Object reply;
if (error.type() != null_type)
@@ -2561,6 +2561,12 @@ string JSONRPCReply(const Value& result, const Value& error, const Value& id)
reply.push_back(Pair("result", result));
reply.push_back(Pair("error", error));
reply.push_back(Pair("id", id));
+ return reply;
+}
+
+string JSONRPCReply(const Value& result, const Value& error, const Value& id)
+{
+ Object reply = JSONRPCReplyObj(result, error, id);
return write_string(Value(reply), false) + "\n";
}
@@ -2905,6 +2911,80 @@ void ThreadRPCServer2(void* parg)
StopRequests();
}
+class JSONRequest
+{
+public:
+ Value id;
+ string strMethod;
+ Array params;
+
+ JSONRequest() { id = Value::null; }
+ void parse(const Value& valRequest);
+};
+
+void JSONRequest::parse(const Value& valRequest)
+{
+ // Parse request
+ if (valRequest.type() != obj_type)
+ throw JSONRPCError(-32600, "Invalid Request object");
+ const Object& request = valRequest.get_obj();
+
+ // Parse id now so errors from here on will have the id
+ id = find_value(request, "id");
+
+ // Parse method
+ Value valMethod = find_value(request, "method");
+ if (valMethod.type() == null_type)
+ throw JSONRPCError(-32600, "Missing method");
+ if (valMethod.type() != str_type)
+ throw JSONRPCError(-32600, "Method must be a string");
+ strMethod = valMethod.get_str();
+ if (strMethod != "getwork" && strMethod != "getmemorypool")
+ printf("ThreadRPCServer method=%s\n", strMethod.c_str());
+
+ // Parse params
+ Value valParams = find_value(request, "params");
+ if (valParams.type() == array_type)
+ params = valParams.get_array();
+ else if (valParams.type() == null_type)
+ params = Array();
+ else
+ 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)
@@ -2954,52 +3034,41 @@ void ThreadRPCServer3(void* parg)
if (mapHeaders["connection"] == "close")
fRun = false;
- Value id = Value::null;
+ JSONRequest jreq;
try
{
// Parse request
Value valRequest;
- if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
+ if (!read_string(strRequest, valRequest))
throw JSONRPCError(-32700, "Parse error");
- const Object& request = valRequest.get_obj();
-
- // Parse id now so errors from here on will have the id
- id = find_value(request, "id");
-
- // Parse method
- Value valMethod = find_value(request, "method");
- if (valMethod.type() == null_type)
- throw JSONRPCError(-32600, "Missing method");
- if (valMethod.type() != str_type)
- throw JSONRPCError(-32600, "Method must be a string");
- string strMethod = valMethod.get_str();
- if (strMethod != "getwork" && strMethod != "getmemorypool")
- printf("ThreadRPCServer method=%s\n", strMethod.c_str());
-
- // Parse params
- Value valParams = find_value(request, "params");
- Array params;
- if (valParams.type() == array_type)
- params = valParams.get_array();
- else if (valParams.type() == null_type)
- params = Array();
- else
- throw JSONRPCError(-32600, "Params must be an array");
- Value result = tableRPC.execute(strMethod, params);
+ string strReply;
- // Send reply
- string strReply = JSONRPCReply(result, Value::null, id);
+ // singleton request
+ if (valRequest.type() == obj_type) {
+ jreq.parse(valRequest);
+
+ Value result = tableRPC.execute(jreq.strMethod, jreq.params);
+
+ // 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)
{
- ErrorReply(conn->stream(), objError, id);
+ ErrorReply(conn->stream(), objError, jreq.id);
break;
}
catch (std::exception& e)
{
- ErrorReply(conn->stream(), JSONRPCError(-32700, e.what()), id);
+ ErrorReply(conn->stream(), JSONRPCError(-32700, e.what()), jreq.id);
break;
}
}