diff options
author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-07-09 01:17:22 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-09 01:17:22 +0300 |
commit | a5a7c7c8f5b529f766147c06cfe834f2f0c5f74c (patch) | |
tree | c24d14ce8c535cca8dbdc576faf9ecc032c36f9a /indra/llxml | |
parent | cd5d35ddab52ae577e286140ee54664202a0091d (diff) | |
parent | db6fdcf2df62d1b2bef2bd0a9019b74663b8568c (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.cpp | 170 | ||||
-rw-r--r-- | indra/llxml/llxmlnode.h | 9 |
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 |