mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-04 21:29:21 +00:00
rpc: multicall requires methodName as the struct's first member
Faults clearly instead of the confusing positional parse error it replaces.
This commit is contained in:
@@ -326,15 +326,20 @@ process_document(const tinyxml2::XMLDocument* doc, tinyxml2::XMLPrinter* printer
|
||||
auto& result_list = result.as_list();
|
||||
auto parent_elements = element_access(doc->RootElement(), {"params", "param", "value", "array", "data"});
|
||||
for (auto child = parent_elements->FirstChildElement("value"); child; child = child->NextSiblingElement("value")) {
|
||||
auto sub_method_name = element_access(child, {"struct", "member", "value", "string"})->GetText();
|
||||
auto method_name_member = element_access(child, {"struct", "member"});
|
||||
auto member_name = method_name_member->FirstChildElement("name");
|
||||
|
||||
if (member_name == nullptr || member_name->GetText() == nullptr ||
|
||||
std::strncmp(member_name->GetText(), "methodName", sizeof("methodName")) != 0)
|
||||
throw rpc_error(XMLRPC_PARSE_ERROR, "multicall struct's first member must be methodName");
|
||||
|
||||
auto sub_method_name = element_access(method_name_member, {"value", "string"})->GetText();
|
||||
|
||||
if (sub_method_name == nullptr)
|
||||
throw rpc_error(XMLRPC_PARSE_ERROR, "multicall methodName element is empty");
|
||||
// If sub_params ends up a nullptr at the end of this if-chian,
|
||||
// execute_command will turn it into an empty list
|
||||
auto sub_params = element_access(child, {"struct", "member"});
|
||||
if (sub_params != nullptr)
|
||||
sub_params = sub_params->NextSiblingElement("member");
|
||||
auto sub_params = method_name_member->NextSiblingElement("member");
|
||||
if (sub_params != nullptr)
|
||||
sub_params = sub_params->FirstChildElement("value");
|
||||
if (sub_params != nullptr)
|
||||
|
||||
@@ -192,12 +192,54 @@ TestXmlrpc::test_response_size_limit() {
|
||||
CPPUNIT_ASSERT_EQUAL(expected, output);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const std::string multicall_method_name =
|
||||
"<member><name>methodName</name><value><string>xmlrpc_reflect</string></value></member>";
|
||||
const std::string multicall_params =
|
||||
"<member><name>params</name><value><array><data>"
|
||||
"<value><string></string></value><value><string>a</string></value>"
|
||||
"</data></array></value></member>";
|
||||
|
||||
std::string
|
||||
multicall_request(const std::string& members) {
|
||||
return "<?xml version=\"1.0\"?><methodCall><methodName>system.multicall</methodName>"
|
||||
"<params><param><value><array><data><value><struct>" + members +
|
||||
"</struct></value></data></array></value></param></params></methodCall>";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
TestXmlrpc::test_multicall_member_order() {
|
||||
auto call = [this](const std::string& input) {
|
||||
std::string output;
|
||||
m_xmlrpc.process(input.c_str(), input.size(), [&output](const char* c, uint32_t l){ output.append(c, l); return true;});
|
||||
return output;
|
||||
};
|
||||
|
||||
// methodName first is the only order accepted; the positive control proves
|
||||
// the harness drives the real code path rather than a stub.
|
||||
std::string ordered = call(multicall_request(multicall_method_name + multicall_params));
|
||||
CPPUNIT_ASSERT(ordered.find("faultCode") == std::string::npos);
|
||||
|
||||
// params before methodName is rejected with a clear top-level fault,
|
||||
// instead of the "could not find expected element string" of a positional read.
|
||||
std::string expected_fault =
|
||||
"<?xml version=\"1.0\"?><methodResponse><fault><value><struct>"
|
||||
"<member><name>faultCode</name><value><i8>-503</i8></value></member>"
|
||||
"<member><name>faultString</name><value><string>multicall struct's first member must be methodName</string></value></member>"
|
||||
"</struct></value></fault></methodResponse>";
|
||||
CPPUNIT_ASSERT_EQUAL(expected_fault, call(multicall_request(multicall_params + multicall_method_name)));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void TestXmlrpc::test_invalid_utf8() {}
|
||||
void TestXmlrpc::test_basics() {}
|
||||
void TestXmlrpc::test_size_limit() {}
|
||||
void TestXmlrpc::test_response_size_limit() {}
|
||||
void TestXmlrpc::test_multicall_member_order() {}
|
||||
void TestXmlrpc::setUp() {}
|
||||
void TestXmlrpc::tearDown() {}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ class TestXmlrpc : public test_fixture {
|
||||
CPPUNIT_TEST(test_invalid_utf8);
|
||||
CPPUNIT_TEST(test_size_limit);
|
||||
CPPUNIT_TEST(test_response_size_limit);
|
||||
CPPUNIT_TEST(test_multicall_member_order);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
@@ -24,6 +25,7 @@ public:
|
||||
void test_invalid_utf8();
|
||||
void test_size_limit();
|
||||
void test_response_size_limit();
|
||||
void test_multicall_member_order();
|
||||
|
||||
private:
|
||||
std::unique_ptr<TestMainThread> m_test_main_thread;
|
||||
|
||||
Reference in New Issue
Block a user