@ -26,6 +26,7 @@
# include <boost/algorithm/string/case_conv.hpp> // for to_upper()
# include <boost/algorithm/string/case_conv.hpp> // for to_upper()
# include <memory> // for unique_ptr
# include <memory> // for unique_ptr
# include <unordered_map>
using namespace RPCServer ;
using namespace RPCServer ;
using namespace std ;
using namespace std ;
@ -268,11 +269,11 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
* Call Table
* Call Table
*/
*/
static const CRPCCommand vRPCCommands [ ] =
static const CRPCCommand vRPCCommands [ ] =
{ // category name actor (function) okSafeMode
{ // category name actor (function) okSafe argNames
// --------------------- ------------------------ ----------------------- ----------
// --------------------- ------------------------ ----------------------- ------ ------ ----
/* Overall control/query calls */
/* Overall control/query calls */
{ " control " , " help " , & help , true } ,
{ " control " , " help " , & help , true , { " command " } } ,
{ " control " , " stop " , & stop , true } ,
{ " control " , " stop " , & stop , true , { } } ,
} ;
} ;
CRPCTable : : CRPCTable ( )
CRPCTable : : CRPCTable ( )
@ -379,12 +380,12 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
// Parse params
// Parse params
UniValue valParams = find_value ( request , " params " ) ;
UniValue valParams = find_value ( request , " params " ) ;
if ( valParams . isArray ( ) )
if ( valParams . isArray ( ) | | valParams . isObject ( ) )
params = valParams . get_array ( ) ;
params = valParams ;
else if ( valParams . isNull ( ) )
else if ( valParams . isNull ( ) )
params = UniValue ( UniValue : : VARR ) ;
params = UniValue ( UniValue : : VARR ) ;
else
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 )
static UniValue JSONRPCExecOne ( const UniValue & req )
@ -420,6 +421,48 @@ std::string JSONRPCExecBatch(const UniValue& vReq)
return ret . write ( ) + " \n " ;
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
UniValue CRPCTable : : execute ( const JSONRPCRequest & request ) const
{
{
// Return immediately if in warmup
// Return immediately if in warmup
@ -438,9 +481,13 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
try
try
{
{
// Execute
// Execute, convert arguments to array if necessary
if ( request . params . isObject ( ) ) {
return pcmd - > actor ( transformNamedArguments ( request , pcmd - > argNames ) ) ;
} else {
return pcmd - > actor ( request ) ;
return pcmd - > actor ( request ) ;
}
}
}
catch ( const std : : exception & e )
catch ( const std : : exception & e )
{
{
throw JSONRPCError ( RPC_MISC_ERROR , e . what ( ) ) ;
throw JSONRPCError ( RPC_MISC_ERROR , e . what ( ) ) ;