Skip to content

Commit db45ad8

Browse files
committed
Merge #9329: [Qt] Console: allow empty arguments
390bd14 [Qt] Console: don't allow empty arguments when using the comma-syntax (Jonas Schnelli) 6a32c0f Qt/Test: Check handling of empty arguments in RPC debug console (Luke Dashjr) 89c8d2c [Qt] Console: allow empty arguments (Jonas Schnelli)
2 parents a7f7651 + 390bd14 commit db45ad8

File tree

2 files changed

+72
-21
lines changed

2 files changed

+72
-21
lines changed

src/qt/rpcconsole.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
137137
enum CmdParseState
138138
{
139139
STATE_EATING_SPACES,
140+
STATE_EATING_SPACES_IN_ARG,
141+
STATE_EATING_SPACES_IN_BRACKETS,
140142
STATE_ARGUMENT,
141143
STATE_SINGLEQUOTED,
142144
STATE_DOUBLEQUOTED,
@@ -220,26 +222,29 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
220222
break;
221223
}
222224
case STATE_ARGUMENT: // In or after argument
225+
case STATE_EATING_SPACES_IN_ARG:
226+
case STATE_EATING_SPACES_IN_BRACKETS:
223227
case STATE_EATING_SPACES: // Handle runs of whitespace
224228
switch(ch)
225229
{
226230
case '"': state = STATE_DOUBLEQUOTED; break;
227231
case '\'': state = STATE_SINGLEQUOTED; break;
228232
case '\\': state = STATE_ESCAPE_OUTER; break;
229233
case '(': case ')': case '\n':
234+
if (state == STATE_EATING_SPACES_IN_ARG)
235+
throw std::runtime_error("Invalid Syntax");
230236
if (state == STATE_ARGUMENT)
231237
{
232238
if (ch == '(' && stack.size() && stack.back().size() > 0)
233239
stack.push_back(std::vector<std::string>());
234-
if (curarg.size())
235-
{
236-
// don't allow commands after executed commands on baselevel
237-
if (!stack.size())
238-
throw std::runtime_error("Invalid Syntax");
239-
stack.back().push_back(curarg);
240-
}
240+
241+
// don't allow commands after executed commands on baselevel
242+
if (!stack.size())
243+
throw std::runtime_error("Invalid Syntax");
244+
245+
stack.back().push_back(curarg);
241246
curarg.clear();
242-
state = STATE_EATING_SPACES;
247+
state = STATE_EATING_SPACES_IN_BRACKETS;
243248
}
244249
if ((ch == ')' || ch == '\n') && stack.size() > 0)
245250
{
@@ -256,12 +261,19 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
256261
}
257262
break;
258263
case ' ': case ',': case '\t':
259-
if(state == STATE_ARGUMENT) // Space ends argument
264+
if(state == STATE_EATING_SPACES_IN_ARG && curarg.empty() && ch == ',')
265+
throw std::runtime_error("Invalid Syntax");
266+
267+
else if(state == STATE_ARGUMENT) // Space ends argument
260268
{
261-
if (curarg.size())
262-
stack.back().push_back(curarg);
269+
stack.back().push_back(curarg);
263270
curarg.clear();
264271
}
272+
if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',')
273+
{
274+
state = STATE_EATING_SPACES_IN_ARG;
275+
break;
276+
}
265277
state = STATE_EATING_SPACES;
266278
break;
267279
default: curarg += ch; state = STATE_ARGUMENT;

src/qt/test/rpcnestedtests.cpp

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,23 @@
1515
#include "util.h"
1616

1717
#include <QDir>
18+
#include <QtGlobal>
1819

1920
#include <boost/filesystem.hpp>
2021

22+
static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
23+
{
24+
if (request.fHelp) {
25+
return "help message";
26+
}
27+
return request.params.write(0, 0);
28+
}
29+
30+
static const CRPCCommand vRPCCommands[] =
31+
{
32+
{ "test", "rpcNestedTest", &rpcNestedTest_rpc, true },
33+
};
34+
2135
void RPCNestedTests::rpcNestedTests()
2236
{
2337
UniValue jsonRPCError;
@@ -26,6 +40,7 @@ void RPCNestedTests::rpcNestedTests()
2640
// could be moved to a more generic place when we add more tests on QT level
2741
const CChainParams& chainparams = Params();
2842
RegisterAllCoreRPCCommands(tableRPC);
43+
tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
2944
ClearDatadirCache();
3045
std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
3146
QDir dir(QString::fromStdString(path));
@@ -63,16 +78,6 @@ void RPCNestedTests::rpcNestedTests()
6378
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated
6479
QVERIFY(result.substr(0,1) == "{");
6580

66-
#if QT_VERSION >= 0x050300
67-
// do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
68-
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
69-
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
70-
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
71-
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts
72-
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument
73-
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found
74-
#endif
75-
7681
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child contaning the quotes in the key
7782
QVERIFY(result == "null");
7883

@@ -85,6 +90,40 @@ void RPCNestedTests::rpcNestedTests()
8590
RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]");
8691
QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
8792

93+
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest");
94+
QVERIFY(result == "[]");
95+
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest ''");
96+
QVERIFY(result == "[\"\"]");
97+
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest \"\"");
98+
QVERIFY(result == "[\"\"]");
99+
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest '' abc");
100+
QVERIFY(result == "[\"\",\"abc\"]");
101+
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc '' abc");
102+
QVERIFY(result == "[\"abc\",\"\",\"abc\"]");
103+
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc abc");
104+
QVERIFY(result == "[\"abc\",\"abc\"]");
105+
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc\t\tabc");
106+
QVERIFY(result == "[\"abc\",\"abc\"]");
107+
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc )");
108+
QVERIFY(result == "[\"abc\"]");
109+
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest( abc )");
110+
QVERIFY(result == "[\"abc\"]");
111+
RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest( abc , cba )");
112+
QVERIFY(result == "[\"abc\",\"cba\"]");
113+
114+
#if QT_VERSION >= 0x050300
115+
// do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
116+
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
117+
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
118+
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
119+
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts
120+
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument
121+
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found
122+
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using ,
123+
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
124+
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
125+
#endif
126+
88127
delete pcoinsTip;
89128
delete pcoinsdbview;
90129
delete pblocktree;

0 commit comments

Comments
 (0)