summaryrefslogtreecommitdiff
path: root/indra/llxml
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2024-07-09 01:17:22 +0300
committerGitHub <noreply@github.com>2024-07-09 01:17:22 +0300
commita5a7c7c8f5b529f766147c06cfe834f2f0c5f74c (patch)
treec24d14ce8c535cca8dbdc576faf9ecc032c36f9a /indra/llxml
parentcd5d35ddab52ae577e286140ee54664202a0091d (diff)
parentdb6fdcf2df62d1b2bef2bd0a9019b74663b8568c (diff)
Merge pull request #1949 from sldevel/xmlrpc-crash-fix
Fix for crash in XMLRPC reply decoding on login with large inventories
Diffstat (limited to 'indra/llxml')
-rw-r--r--indra/llxml/llxmlnode.cpp170
-rw-r--r--indra/llxml/llxmlnode.h9
2 files changed, 177 insertions, 2 deletions
diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp
index 7f6b8093fc..d6f9a56c9d 100644
--- a/indra/llxml/llxmlnode.cpp
+++ b/indra/llxml/llxmlnode.cpp
@@ -38,7 +38,9 @@
#include "v3math.h"
#include "v3dmath.h"
#include "v4math.h"
+#include "llbase64.h"
#include "llquaternion.h"
+#include "llsd.h"
#include "llstring.h"
#include "lluuid.h"
#include "lldir.h"
@@ -3263,3 +3265,171 @@ S32 LLXMLNode::getLineNumber()
{
return mLineNumber;
}
+
+bool LLXMLNode::parseXmlRpcArrayValue(LLSD& target)
+{
+ LLXMLNode* datap = getFirstChild().get();
+ if (!datap)
+ {
+ LL_WARNS() << "No inner XML element." << LL_ENDL;
+ return false;
+ }
+ if (!datap->hasName("data"))
+ {
+ LL_WARNS() << "No inner XML element (<data> expected, got: "
+ << datap->mName->mString << ")" << LL_ENDL;
+ return false;
+ }
+ if (datap->getNextSibling().get())
+ {
+ LL_WARNS() << "Multiple inner XML elements (single <data> expected)"
+ << LL_ENDL;
+ return false;
+ }
+ for (LLXMLNode* itemp = datap->getFirstChild().get(); itemp;
+ itemp = itemp->getNextSibling().get())
+ {
+ LLSD value;
+ if (!itemp->fromXMLRPCValue(value))
+ {
+ return false;
+ }
+ target.append(value);
+ }
+ return true;
+}
+
+bool LLXMLNode::parseXmlRpcStructValue(LLSD& target)
+{
+ std::string name;
+ LLSD value;
+ for (LLXMLNode* itemp = getFirstChild().get(); itemp;
+ itemp = itemp->getNextSibling().get())
+ {
+ if (!itemp->hasName("member"))
+ {
+ LL_WARNS() << "Invalid inner XML element (<member> expected, got: <"
+ << itemp->mName->mString << ">" << LL_ENDL;
+ return false;
+ }
+ name.clear();
+ value.clear();
+ for (LLXMLNode* chilp = itemp->getFirstChild().get(); chilp;
+ chilp = chilp->getNextSibling().get())
+ {
+ if (chilp->hasName("name"))
+ {
+ name = LLStringFn::xml_decode(chilp->getTextContents());
+ }
+ else if (!chilp->fromXMLRPCValue(value))
+ {
+ return false;
+ }
+ }
+ if (name.empty())
+ {
+ LL_WARNS() << "Empty struct member name" << LL_ENDL;
+ return false;
+ }
+ target.insert(name, value);
+ }
+ return true;
+}
+
+bool LLXMLNode::fromXMLRPCValue(LLSD& target)
+{
+ target.clear();
+
+ if (!hasName("value"))
+ {
+ LL_WARNS() << "Invalid XML element (<value> expected), got: <"
+ << mName->mString << ">" << LL_ENDL;
+ return false;
+ }
+
+ LLXMLNode* childp = getFirstChild().get();
+ if (!childp)
+ {
+ LL_WARNS() << "No inner XML element (value type expected)" << LL_ENDL;
+ // Value with no type qualifier is treated as string
+ target.assign(LLStringFn::xml_decode(getTextContents()));
+ return true;
+ }
+
+ if (childp->getNextSibling())
+ {
+ LL_WARNS() << "Multiple inner XML elements (single expected)"
+ << LL_ENDL;
+ return false;
+ }
+
+ if (childp->hasName("string"))
+ {
+ target.assign(LLStringFn::xml_decode(childp->getTextContents()));
+ return true;
+ }
+
+ if (childp->hasName("int") || childp->hasName("i4"))
+ {
+ target.assign(std::stoi(childp->getTextContents()));
+ return true;
+ }
+
+ if (childp->hasName("double"))
+ {
+ target.assign(std::stod(childp->getTextContents()));
+ return true;
+ }
+
+ if (childp->hasName("boolean"))
+ {
+ target.assign(std::stoi(childp->getTextContents()) != 0);
+ return true;
+ }
+
+ if (childp->hasName("dateTime.iso8601"))
+ {
+ target.assign(LLSD::Date(childp->getTextContents()));
+ return true;
+ }
+
+ if (childp->hasName("base64"))
+ {
+ std::string decoded =
+ LLBase64::decodeAsString(inner->getTextContents());
+ size_t size = decoded.size();
+ LLSD::Binary binary(size);
+ if (size)
+ {
+ memcpy((void*)binary.data(), (void*)decoded.data(), size);
+ }
+ target.assign(binary);
+ return true;
+ }
+
+ if (childp->hasName("array"))
+ {
+ if (!childp->parseXmlRpcArrayValue(target))
+ {
+ target.clear();
+ return false;
+ }
+ return true;
+ }
+
+ if (childp->hasName("struct"))
+ {
+ if (!childp->parseXmlRpcStructValue(target))
+ {
+ target.clear();
+ return false;
+ }
+ return true;
+ }
+
+ LL_WARNS() << "Unknown inner XML element (known value type expected)"
+ << LL_ENDL;
+ // Value with unknown type qualifier is treated as string
+ target.assign(LLStringFn::xml_decode(childp->getTextContents()));
+ return true;
+}
diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h
index b8f9e1ff69..3769ec8293 100644
--- a/indra/llxml/llxmlnode.h
+++ b/indra/llxml/llxmlnode.h
@@ -50,6 +50,7 @@ class LLVector3d;
class LLQuaternion;
class LLColor4;
class LLColor4U;
+class LLSD;
struct CompareAttributes
@@ -284,12 +285,18 @@ public:
void setAttributes(ValueType type, U32 precision, Encoding encoding, U32 length);
// void appendValue(const std::string& value); // Unused
+ bool fromXMLRPCValue(LLSD& target);
+
// Unit Testing
void createUnitTest(S32 max_num_children);
bool performUnitTest(std::string &error_buffer);
protected:
bool removeChild(LLXMLNode* child);
+ bool isFullyDefault();
+
+ bool parseXmlRpcArrayValue(LLSD& target);
+ bool parseXmlRpcStructValue(LLSD& target);
public:
std::string mID; // The ID attribute of this node
@@ -328,8 +335,6 @@ protected:
static const char *skipNonWhitespace(const char *str);
static const char *parseInteger(const char *str, U64 *dest, bool *is_negative, U32 precision, Encoding encoding);
static const char *parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding);
-
- bool isFullyDefault();
};
#endif // LL_LLXMLNODE