diff options
Diffstat (limited to 'src/rpc/server.cpp')
-rw-r--r-- | src/rpc/server.cpp | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 1d7bd2eb94..f57133f75b 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -401,8 +401,16 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c for (size_t i=0; i<keys.size(); ++i) { argsIn[keys[i]] = &values[i]; } - // Process expected parameters. + // Process expected parameters. If any parameters were left unspecified in + // the request before a parameter that was specified, null values need to be + // inserted at the unspecifed parameter positions, and the "hole" variable + // below tracks the number of null values that need to be inserted. + // The "initial_hole_size" variable stores the size of the initial hole, + // i.e. how many initial positional arguments were left unspecified. This is + // used after the for-loop to add initial positional arguments from the + // "args" parameter, if present. int hole = 0; + int initial_hole_size = 0; for (const std::string &argNamePattern: argNames) { std::vector<std::string> vargNames = SplitString(argNamePattern, '|'); auto fr = argsIn.end(); @@ -424,6 +432,24 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c argsIn.erase(fr); } else { hole += 1; + if (out.params.empty()) initial_hole_size = hole; + } + } + // If leftover "args" param was found, use it as a source of positional + // arguments and add named arguments after. This is a convenience for + // clients that want to pass a combination of named and positional + // arguments as described in doc/JSON-RPC-interface.md#parameter-passing + auto positional_args{argsIn.extract("args")}; + if (positional_args && positional_args.mapped()->isArray()) { + const bool has_named_arguments{initial_hole_size < (int)argNames.size()}; + if (initial_hole_size < (int)positional_args.mapped()->size() && has_named_arguments) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + argNames[initial_hole_size] + " specified twice both as positional and named argument"); + } + // Assign positional_args to out.params and append named_args after. + UniValue named_args{std::move(out.params)}; + out.params = *positional_args.mapped(); + for (size_t i{out.params.size()}; i < named_args.size(); ++i) { + out.params.push_back(named_args[i]); } } // If there are still arguments in the argsIn map, this is an error. |