From 8cfc71b936bb80eb4b409545b096bb9a1c3a585d Mon Sep 17 00:00:00 2001 From: kannibalox Date: Fri, 6 Dec 2024 21:15:32 -0500 Subject: [PATCH] Fix system.multicall parameter parsing --- src/rpc/xmlrpc_tinyxml2.cc | 39 +++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/rpc/xmlrpc_tinyxml2.cc b/src/rpc/xmlrpc_tinyxml2.cc index 87031b83..593793fe 100644 --- a/src/rpc/xmlrpc_tinyxml2.cc +++ b/src/rpc/xmlrpc_tinyxml2.cc @@ -245,15 +245,28 @@ torrent::Object execute_command(std::string method_name, const tinyxml2::XMLElem torrent::Object::list_type& params = params_raw.as_list(); rpc::target_type target = rpc::make_target(); if (params_element != nullptr) { - // Parse out the target if available - const auto* child = params_element->FirstChildElement("param"); - if (child != nullptr) { - XmlRpc::object_to_target(xml_value_to_object(child->FirstChildElement("value")), cmd_itr->second.m_flags, &target); - child = child->NextSiblingElement("param"); - // Parse out any other params - while (child != nullptr) { - params.push_back(xml_value_to_object(child->FirstChildElement("value"))); + if (std::strncmp(params_element->Name(), "params", sizeof("params")) == 0) { + // Parse out the target if available + const auto* child = params_element->FirstChildElement("param"); + if (child != nullptr) { + XmlRpc::object_to_target(xml_value_to_object(child->FirstChildElement("value")), cmd_itr->second.m_flags, &target); child = child->NextSiblingElement("param"); + // Parse out any other params + while (child != nullptr) { + params.push_back(xml_value_to_object(child->FirstChildElement("value"))); + child = child->NextSiblingElement("param"); + } + } + } else if (params_element->FirstChildElement("data") != nullptr) { + // If it's not a , it's probably a passed in via system.multicall + const auto* child = params_element->FirstChildElement("data")->FirstChildElement("value"); + if (child != nullptr) { + XmlRpc::object_to_target(xml_value_to_object(child), cmd_itr->second.m_flags, &target); + child = child->NextSiblingElement("value"); + while (child != nullptr) { + params.push_back(xml_value_to_object(child)); + child = child->NextSiblingElement("value"); + } } } } @@ -282,7 +295,15 @@ process_document(const tinyxml2::XMLDocument* doc, tinyxml2::XMLPrinter* printer 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 sub_params = element_access(child, {"struct", "member"})->NextSiblingElement("member")->FirstChildElement("value"); + // 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"); + if (sub_params != nullptr) + sub_params = sub_params->FirstChildElement("value"); + if (sub_params != nullptr) + sub_params = sub_params->FirstChildElement("array"); try { auto sub_result = torrent::Object::create_list(); sub_result.as_list().push_back(execute_command(sub_method_name, sub_params));