Skip to content

Commit fff771e

Browse files
committed
Handle query string when parsing data format
URLs may contain a query string (prefixed with '?') and this should be ignored when parsing the data format. To facilitate testing this functionality, ParseDataFormat has been made non-static.
1 parent c1aad1b commit fff771e

File tree

4 files changed

+71
-10
lines changed

4 files changed

+71
-10
lines changed

Diff for: src/Makefile.test.include

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ BITCOIN_TESTS =\
116116
test/prevector_tests.cpp \
117117
test/raii_event_tests.cpp \
118118
test/random_tests.cpp \
119+
test/rest_tests.cpp \
119120
test/reverselock_tests.cpp \
120121
test/rpc_tests.cpp \
121122
test/sanity_tests.cpp \

Diff for: src/rest.cpp

+13-10
Original file line numberDiff line numberDiff line change
@@ -135,23 +135,26 @@ static ChainstateManager* GetChainman(const std::any& context, HTTPRequest* req)
135135

136136
RESTResponseFormat ParseDataFormat(std::string& param, const std::string& strReq)
137137
{
138-
const std::string::size_type pos = strReq.rfind('.');
139-
if (pos == std::string::npos)
140-
{
141-
param = strReq;
138+
// Remove query string (if any, separated with '?') as it should not interfere with
139+
// parsing param and data format
140+
param = strReq.substr(0, strReq.rfind('?'));
141+
const std::string::size_type pos_format{param.rfind('.')};
142+
143+
// No format string is found
144+
if (pos_format == std::string::npos) {
142145
return rf_names[0].rf;
143146
}
144147

145-
param = strReq.substr(0, pos);
146-
const std::string suff(strReq, pos + 1);
147-
148+
// Match format string to available formats
149+
const std::string suffix(param, pos_format + 1);
148150
for (const auto& rf_name : rf_names) {
149-
if (suff == rf_name.name)
151+
if (suffix == rf_name.name) {
152+
param.erase(pos_format);
150153
return rf_name.rf;
154+
}
151155
}
152156

153-
/* If no suffix is found, return original string. */
154-
param = strReq;
157+
// If no suffix is found, return RESTResponseFormat::UNDEF and original string without query string
155158
return rf_names[0].rf;
156159
}
157160

Diff for: src/rest.h

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ enum class RESTResponseFormat {
1414
JSON,
1515
};
1616

17+
/**
18+
* Parse a URI to get the data format and URI without data format
19+
* and query string.
20+
*
21+
* @param[out] param The strReq without the data format string and
22+
* without the query string (if any).
23+
* @param[in] strReq The URI to be parsed.
24+
* @return RESTResponseFormat that was parsed from the URI.
25+
*/
1726
RESTResponseFormat ParseDataFormat(std::string& param, const std::string& strReq);
1827

1928
#endif // BITCOIN_REST_H

Diff for: src/test/rest_tests.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) 2012-2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <rest.h>
6+
#include <test/util/setup_common.h>
7+
8+
#include <boost/test/unit_test.hpp>
9+
10+
#include <string>
11+
12+
BOOST_FIXTURE_TEST_SUITE(rest_tests, BasicTestingSetup)
13+
14+
BOOST_AUTO_TEST_CASE(test_query_string)
15+
{
16+
std::string param;
17+
RESTResponseFormat rf;
18+
// No query string
19+
rf = ParseDataFormat(param, "/rest/endpoint/someresource.json");
20+
BOOST_CHECK_EQUAL(param, "/rest/endpoint/someresource");
21+
BOOST_CHECK_EQUAL(rf, RESTResponseFormat::JSON);
22+
23+
// Query string with single parameter
24+
rf = ParseDataFormat(param, "/rest/endpoint/someresource.bin?p1=v1");
25+
BOOST_CHECK_EQUAL(param, "/rest/endpoint/someresource");
26+
BOOST_CHECK_EQUAL(rf, RESTResponseFormat::BINARY);
27+
28+
// Query string with multiple parameters
29+
rf = ParseDataFormat(param, "/rest/endpoint/someresource.hex?p1=v1&p2=v2");
30+
BOOST_CHECK_EQUAL(param, "/rest/endpoint/someresource");
31+
BOOST_CHECK_EQUAL(rf, RESTResponseFormat::HEX);
32+
33+
// Incorrectly formed query string will not be handled
34+
rf = ParseDataFormat(param, "/rest/endpoint/someresource.json&p1=v1");
35+
BOOST_CHECK_EQUAL(param, "/rest/endpoint/someresource.json&p1=v1");
36+
BOOST_CHECK_EQUAL(rf, RESTResponseFormat::UNDEF);
37+
38+
// Omitted data format with query string should return UNDEF and hide query string
39+
rf = ParseDataFormat(param, "/rest/endpoint/someresource?p1=v1");
40+
BOOST_CHECK_EQUAL(param, "/rest/endpoint/someresource");
41+
BOOST_CHECK_EQUAL(rf, RESTResponseFormat::UNDEF);
42+
43+
// Data format specified after query string
44+
rf = ParseDataFormat(param, "/rest/endpoint/someresource?p1=v1.json");
45+
BOOST_CHECK_EQUAL(param, "/rest/endpoint/someresource");
46+
BOOST_CHECK_EQUAL(rf, RESTResponseFormat::UNDEF);
47+
}
48+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)