aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/rpc/server.cpp65
-rw-r--r--src/rpc/server.h1
2 files changed, 57 insertions, 9 deletions
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 8a223d8aa8..1b94e10071 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -26,6 +26,7 @@
#include <boost/algorithm/string/case_conv.hpp> // for to_upper()
#include <memory> // for unique_ptr
+#include <unordered_map>
using namespace RPCServer;
using namespace std;
@@ -268,11 +269,11 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
* Call Table
*/
static const CRPCCommand vRPCCommands[] =
-{ // category name actor (function) okSafeMode
- // --------------------- ------------------------ ----------------------- ----------
+{ // category name actor (function) okSafe argNames
+ // --------------------- ------------------------ ----------------------- ------ ----------
/* Overall control/query calls */
- { "control", "help", &help, true },
- { "control", "stop", &stop, true },
+ { "control", "help", &help, true, {"command"} },
+ { "control", "stop", &stop, true, {} },
};
CRPCTable::CRPCTable()
@@ -379,12 +380,12 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
// Parse params
UniValue valParams = find_value(request, "params");
- if (valParams.isArray())
- params = valParams.get_array();
+ if (valParams.isArray() || valParams.isObject())
+ params = valParams;
else if (valParams.isNull())
params = UniValue(UniValue::VARR);
else
- throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
+ throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
}
static UniValue JSONRPCExecOne(const UniValue& req)
@@ -420,6 +421,48 @@ std::string JSONRPCExecBatch(const UniValue& vReq)
return ret.write() + "\n";
}
+/**
+ * Process named arguments into a vector of positional arguments, based on the
+ * passed-in specification for the RPC call's arguments.
+ */
+static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames)
+{
+ JSONRPCRequest out = in;
+ out.params = UniValue(UniValue::VARR);
+ // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if
+ // there is an unknown one.
+ const std::vector<std::string>& keys = in.params.getKeys();
+ const std::vector<UniValue>& values = in.params.getValues();
+ std::unordered_map<std::string, const UniValue*> argsIn;
+ for (size_t i=0; i<keys.size(); ++i) {
+ argsIn[keys[i]] = &values[i];
+ }
+ // Process expected parameters.
+ int hole = 0;
+ for (const std::string &argName: argNames) {
+ auto fr = argsIn.find(argName);
+ if (fr != argsIn.end()) {
+ for (int i = 0; i < hole; ++i) {
+ // Fill hole between specified parameters with JSON nulls,
+ // but not at the end (for backwards compatibility with calls
+ // that act based on number of specified parameters).
+ out.params.push_back(UniValue());
+ }
+ hole = 0;
+ out.params.push_back(*fr->second);
+ argsIn.erase(fr);
+ } else {
+ hole += 1;
+ }
+ }
+ // If there are still arguments in the argsIn map, this is an error.
+ if (!argsIn.empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown named parameter " + argsIn.begin()->first);
+ }
+ // Return request with named arguments transformed to positional arguments
+ return out;
+}
+
UniValue CRPCTable::execute(const JSONRPCRequest &request) const
{
// Return immediately if in warmup
@@ -438,8 +481,12 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
try
{
- // Execute
- return pcmd->actor(request);
+ // Execute, convert arguments to array if necessary
+ if (request.params.isObject()) {
+ return pcmd->actor(transformNamedArguments(request, pcmd->argNames));
+ } else {
+ return pcmd->actor(request);
+ }
}
catch (const std::exception& e)
{
diff --git a/src/rpc/server.h b/src/rpc/server.h
index f3cdf3c602..fed3d8c90f 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -136,6 +136,7 @@ public:
std::string name;
rpcfn_type actor;
bool okSafeMode;
+ std::vector<std::string> argNames;
};
/**