#1111 Remove xmlrpc-epi
parent
9ab2f662f8
commit
2ea5ac0c43
|
|
@ -2670,66 +2670,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>name</key>
|
||||
<string>vlc-bin</string>
|
||||
</map>
|
||||
<key>xmlrpc-epi</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>aa12611374876196b3ebb6bda8d419a697217b8b</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-darwin64-8a05acf.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>ad0c8b41ee4b4de216382bec46ee1c25962a3f12</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-linux64-8a05acf.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>e53fd38c14b8c47c7c84dead8a1b211bb8be170c</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-windows64-8a05acf.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>license</key>
|
||||
<string>xmlrpc-epi</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/xmlrpc-epi.txt</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright: (C) 2000 Epinions, Inc.</string>
|
||||
<key>version</key>
|
||||
<string>0.54.1.8a05acf</string>
|
||||
<key>name</key>
|
||||
<string>xmlrpc-epi</string>
|
||||
<key>description</key>
|
||||
<string>XMLRPC Library</string>
|
||||
</map>
|
||||
<key>vulkan_gltf</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ set(cmake_SOURCE_FILES
|
|||
VisualLeakDetector.cmake
|
||||
LibVLCPlugin.cmake
|
||||
WebRTC.cmake
|
||||
XmlRpcEpi.cmake
|
||||
xxHash.cmake
|
||||
ZLIBNG.cmake
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,5 +6,3 @@ include(EXPAT)
|
|||
include(Tracy)
|
||||
include(xxHash)
|
||||
include(ZLIBNG)
|
||||
|
||||
include(XmlRpcEpi)
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
include_guard()
|
||||
add_library( ll::xmlrpc-epi INTERFACE IMPORTED )
|
||||
|
||||
use_system_binary( xmlrpc-epi )
|
||||
|
||||
use_prebuilt_binary(xmlrpc-epi)
|
||||
target_link_libraries(ll::xmlrpc-epi INTERFACE xmlrpc-epi )
|
||||
target_include_directories( ll::xmlrpc-epi SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
|
||||
|
|
@ -248,6 +248,24 @@ int LLFile::close(LLFILE * file)
|
|||
return ret_value;
|
||||
}
|
||||
|
||||
std::string LLFile::getContents(const std::string& filename)
|
||||
{
|
||||
LLFILE* fp = fopen(filename, "rb"); /* Flawfinder: ignore */
|
||||
if (fp)
|
||||
{
|
||||
fseek(fp, 0, SEEK_END);
|
||||
U32 length = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
std::vector<char> buffer(length);
|
||||
size_t nread = fread(buffer.data(), 1, length, fp);
|
||||
fclose(fp);
|
||||
|
||||
return std::string(buffer.data(), nread);
|
||||
}
|
||||
|
||||
return LLStringUtil::null;
|
||||
}
|
||||
|
||||
int LLFile::remove(const std::string& filename, int supress_error)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ public:
|
|||
|
||||
static int close(LLFILE * file);
|
||||
|
||||
static std::string getContents(const std::string& filename);
|
||||
|
||||
// perms is a permissions mask like 0777 or 0700. In most cases it will
|
||||
// be overridden by the user's umask. It is ignored on Windows.
|
||||
// mkdir() considers "directory already exists" to be SUCCESS.
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "linden_common.h"
|
||||
#include "llsd.h"
|
||||
|
||||
#include "llbase64.h"
|
||||
#include "llerror.h"
|
||||
#include "../llmath/llmath.h"
|
||||
#include "llformat.h"
|
||||
|
|
@ -142,6 +143,8 @@ public:
|
|||
|
||||
virtual const String& asStringRef() const { static const std::string empty; return empty; }
|
||||
|
||||
virtual String asXMLRPCValue() const { return "<nil/>"; }
|
||||
|
||||
virtual bool has(const String&) const { return false; }
|
||||
virtual LLSD get(const String&) const { return LLSD(); }
|
||||
virtual LLSD getKeys() const { return LLSD::emptyArray(); }
|
||||
|
|
@ -222,6 +225,8 @@ namespace
|
|||
virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; }
|
||||
virtual LLSD::Real asReal() const { return mValue ? 1 : 0; }
|
||||
virtual LLSD::String asString() const;
|
||||
|
||||
virtual LLSD::String asXMLRPCValue() const { return mValue ? "<boolean>1</boolean>" : "<boolean>0</boolean>"; }
|
||||
};
|
||||
|
||||
LLSD::String ImplBoolean::asString() const
|
||||
|
|
@ -243,6 +248,8 @@ namespace
|
|||
virtual LLSD::Integer asInteger() const { return mValue; }
|
||||
virtual LLSD::Real asReal() const { return mValue; }
|
||||
virtual LLSD::String asString() const;
|
||||
|
||||
virtual LLSD::String asXMLRPCValue() const { return "<int>" + std::to_string(mValue) + "</int>"; }
|
||||
};
|
||||
|
||||
LLSD::String ImplInteger::asString() const
|
||||
|
|
@ -259,6 +266,8 @@ namespace
|
|||
virtual LLSD::Integer asInteger() const;
|
||||
virtual LLSD::Real asReal() const { return mValue; }
|
||||
virtual LLSD::String asString() const;
|
||||
|
||||
virtual LLSD::String asXMLRPCValue() const { return "<double>" + std::to_string(mValue) + "</double>"; }
|
||||
};
|
||||
|
||||
LLSD::Boolean ImplReal::asBoolean() const
|
||||
|
|
@ -286,6 +295,8 @@ namespace
|
|||
virtual LLSD::URI asURI() const { return LLURI(mValue); }
|
||||
virtual size_t size() const { return mValue.size(); }
|
||||
virtual const LLSD::String& asStringRef() const { return mValue; }
|
||||
|
||||
virtual LLSD::String asXMLRPCValue() const { return "<string>" + LLStringFn::xml_encode(mValue) + "</string>"; }
|
||||
};
|
||||
|
||||
LLSD::Integer ImplString::asInteger() const
|
||||
|
|
@ -323,6 +334,8 @@ namespace
|
|||
|
||||
virtual LLSD::String asString() const{ return mValue.asString(); }
|
||||
virtual LLSD::UUID asUUID() const { return mValue; }
|
||||
|
||||
virtual LLSD::String asXMLRPCValue() const { return "<string>" + mValue.asString() + "</string>"; }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -344,6 +357,8 @@ namespace
|
|||
}
|
||||
virtual LLSD::String asString() const{ return mValue.asString(); }
|
||||
virtual LLSD::Date asDate() const { return mValue; }
|
||||
|
||||
virtual LLSD::String asXMLRPCValue() const { return "<dateTime.iso8601>" + mValue.toHTTPDateString("%FT%T") + "</dateTime.iso8601>"; }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -355,6 +370,8 @@ namespace
|
|||
|
||||
virtual LLSD::String asString() const{ return mValue.asString(); }
|
||||
virtual LLSD::URI asURI() const { return mValue; }
|
||||
|
||||
virtual LLSD::String asXMLRPCValue() const { return "<string>" + LLStringFn::xml_encode(mValue.asString()) + "</string>"; }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -365,6 +382,8 @@ namespace
|
|||
ImplBinary(const LLSD::Binary& v) : Base(v) { }
|
||||
|
||||
virtual const LLSD::Binary& asBinary() const{ return mValue; }
|
||||
|
||||
virtual LLSD::String asXMLRPCValue() const { return "<base64>" + LLBase64::encode(mValue.data(), mValue.size()) + "</base64>"; }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -387,6 +406,19 @@ namespace
|
|||
|
||||
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
|
||||
|
||||
virtual LLSD::String asXMLRPCValue() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "<struct>";
|
||||
for (const auto& it : mData)
|
||||
{
|
||||
os << "<member><name>" << LLStringFn::xml_encode(it.first) << "</name>"
|
||||
<< it.second.asXMLRPCValue() << "</member>";
|
||||
}
|
||||
os << "</struct>";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
virtual bool has(const LLSD::String&) const;
|
||||
|
||||
using LLSD::Impl::get; // Unhiding get(size_t)
|
||||
|
|
@ -527,6 +559,18 @@ namespace
|
|||
|
||||
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
|
||||
|
||||
virtual LLSD::String asXMLRPCValue() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "<array><data>";
|
||||
for (const auto& it : mData)
|
||||
{
|
||||
os << it.asXMLRPCValue();
|
||||
}
|
||||
os << "</data></array>";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
using LLSD::Impl::get; // Unhiding get(LLSD::String)
|
||||
using LLSD::Impl::erase; // Unhiding erase(LLSD::String)
|
||||
using LLSD::Impl::ref; // Unhiding ref(LLSD::String)
|
||||
|
|
@ -872,6 +916,155 @@ const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); }
|
|||
|
||||
const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); }
|
||||
|
||||
LLSD::String LLSD::asXMLRPCValue() const { return "<value>" + safe(impl).asXMLRPCValue() + "</value>"; }
|
||||
|
||||
static bool inline check(bool condition, const char* warning_message)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
LL_WARNS() << warning_message << LL_ENDL;
|
||||
}
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
static bool parseXMLRPCArrayValue(LLSD& target, LLSD::TreeNode* node)
|
||||
{
|
||||
LLSD::TreeNode* data = node->getFirstChild();
|
||||
if (!check(data, "No array inner XML element (<data> expected)") ||
|
||||
!check(data->hasName("data"), "Invalid array inner XML element (<data> expected)") ||
|
||||
!check(!data->getNextSibling(), "Multiple array inner XML elements (single <data> expected)"))
|
||||
return false;
|
||||
|
||||
for (LLSD::TreeNode* item = data->getFirstChild(); item; item = item->getNextSibling())
|
||||
{
|
||||
LLSD value;
|
||||
if (!value.fromXMLRPCValue(item))
|
||||
return false;
|
||||
|
||||
target.append(value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parseXMLRPCStructValue(LLSD& target, LLSD::TreeNode* node)
|
||||
{
|
||||
for (LLSD::TreeNode* item = node->getFirstChild(); item; item = item->getNextSibling())
|
||||
{
|
||||
if (!check(item->hasName("member"), "Invalid struct inner XML element (<member> expected)"))
|
||||
return false;
|
||||
|
||||
std::string name;
|
||||
LLSD value;
|
||||
for (LLSD::TreeNode* subitem = item->getFirstChild(); subitem; subitem = subitem->getNextSibling())
|
||||
{
|
||||
if (subitem->hasName("name"))
|
||||
{
|
||||
name = LLStringFn::xml_decode(subitem->getTextContents());
|
||||
}
|
||||
else if (!value.fromXMLRPCValue(subitem))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!check(!name.empty(), "Empty struct member name"))
|
||||
return false;
|
||||
|
||||
target.insert(name, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLSD::fromXMLRPCValue(TreeNode* node)
|
||||
{
|
||||
clear();
|
||||
|
||||
llassert(node);
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
if (!check(node->hasName("value"), "Invalid XML element (<value> expected)"))
|
||||
return false;
|
||||
|
||||
TreeNode* inner = node->getFirstChild();
|
||||
if (!inner)
|
||||
{
|
||||
check(false, "No inner XML element (value type expected)");
|
||||
// Value with no type qualifier is treated as string
|
||||
assign(LLStringFn::xml_decode(node->getTextContents()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!check(!inner->getNextSibling(), "Multiple inner XML elements (single expected)"))
|
||||
return false;
|
||||
|
||||
if (inner->hasName("string"))
|
||||
{
|
||||
assign(LLStringFn::xml_decode(inner->getTextContents()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inner->hasName("int") || inner->hasName("i4"))
|
||||
{
|
||||
assign(std::stoi(inner->getTextContents()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inner->hasName("double"))
|
||||
{
|
||||
assign(std::stod(inner->getTextContents()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inner->hasName("boolean"))
|
||||
{
|
||||
assign(!!std::stoi(inner->getTextContents()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inner->hasName("dateTime.iso8601"))
|
||||
{
|
||||
assign(Date(inner->getTextContents()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inner->hasName("base64"))
|
||||
{
|
||||
std::string decoded = LLBase64::decodeAsString(inner->getTextContents());
|
||||
Binary binary(decoded.size());
|
||||
memcpy(binary.data(), decoded.data(), decoded.size());
|
||||
assign(binary);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inner->hasName("array"))
|
||||
{
|
||||
if (!parseXMLRPCArrayValue(*this, inner))
|
||||
{
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inner->hasName("struct"))
|
||||
{
|
||||
if (!parseXMLRPCStructValue(*this, inner))
|
||||
{
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
check(false, "Unknown inner XML element (known value type expected)");
|
||||
// Value with unknown type qualifier is treated as string
|
||||
assign(LLStringFn::xml_decode(inner->getTextContents()));
|
||||
return true;
|
||||
}
|
||||
|
||||
// const char * helpers
|
||||
LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
|
||||
void LLSD::assign(const char* v)
|
||||
|
|
|
|||
|
|
@ -264,6 +264,20 @@ public:
|
|||
// asStringRef on any non-string type will return a ref to an empty string.
|
||||
const String& asStringRef() const;
|
||||
|
||||
// Return "<value><((type))>((scalar value or recursive calls))</((type))></value>"
|
||||
// See http://xmlrpc.com/spec.md
|
||||
String asXMLRPCValue() const;
|
||||
|
||||
struct TreeNode
|
||||
{
|
||||
virtual bool hasName(const String& name) const = 0;
|
||||
virtual String getTextContents() const = 0;
|
||||
virtual TreeNode* getFirstChild() const = 0;
|
||||
virtual TreeNode* getNextSibling() const = 0;
|
||||
};
|
||||
|
||||
bool fromXMLRPCValue(TreeNode* node);
|
||||
|
||||
operator Boolean() const { return asBoolean(); }
|
||||
operator Integer() const { return asInteger(); }
|
||||
operator Real() const { return asReal(); }
|
||||
|
|
|
|||
|
|
@ -1208,6 +1208,75 @@ namespace LLStringFn
|
|||
return output;
|
||||
}
|
||||
|
||||
using literals_t = std::map<char, std::string>;
|
||||
static const literals_t xml_elem_literals =
|
||||
{
|
||||
{ '<', "<" },
|
||||
{ '>', ">" },
|
||||
{ '&', "&" }
|
||||
};
|
||||
static const literals_t xml_attr_literals =
|
||||
{
|
||||
{ '"', """ },
|
||||
{ '\'', "'" }
|
||||
};
|
||||
|
||||
static void literals_encode(std::string& text, const literals_t& literals)
|
||||
{
|
||||
for (const std::pair<char, std::string> it : literals)
|
||||
{
|
||||
std::string::size_type pos = 0;
|
||||
while ((pos = text.find(it.first, pos)) != std::string::npos)
|
||||
{
|
||||
text.replace(pos, 1, it.second);
|
||||
pos += it.second.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void literals_decode(std::string& text, const literals_t& literals)
|
||||
{
|
||||
for (const std::pair<char, std::string> it : literals)
|
||||
{
|
||||
std::string::size_type pos = 0;
|
||||
while ((pos = text.find(it.second, pos)) != std::string::npos)
|
||||
{
|
||||
text[pos++] = it.first;
|
||||
text.erase(pos, it.second.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replace all characters that are not allowed in XML 1.0
|
||||
* with corresponding literals: [ < > & ] => [ < > & ]
|
||||
*/
|
||||
std::string xml_encode(const std::string& input, bool for_attribute)
|
||||
{
|
||||
std::string result(input);
|
||||
literals_encode(result, xml_elem_literals);
|
||||
if (for_attribute)
|
||||
{
|
||||
literals_encode(result, xml_attr_literals);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replace some of XML literals that are defined in XML 1.0
|
||||
* with corresponding characters: [ < > & ] => [ < > & ]
|
||||
*/
|
||||
std::string xml_decode(const std::string& input, bool for_attribute)
|
||||
{
|
||||
std::string result(input);
|
||||
literals_decode(result, xml_elem_literals);
|
||||
if (for_attribute)
|
||||
{
|
||||
literals_decode(result, xml_attr_literals);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replace all control characters (c < 0x20) with replacement in
|
||||
* string.
|
||||
|
|
|
|||
|
|
@ -889,6 +889,20 @@ namespace LLStringFn
|
|||
LL_COMMON_API std::string strip_invalid_xml(const std::string& input);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Replace all characters that are not allowed in XML 1.0
|
||||
* with corresponding literals: [ < > & ] => [ < > & ]
|
||||
*/
|
||||
LL_COMMON_API std::string xml_encode(const std::string& input, bool for_attribute = false);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Replace some of XML literals that are defined in XML 1.0
|
||||
* with corresponding characters: [ < > & ] => [ < > & ]
|
||||
*/
|
||||
LL_COMMON_API std::string xml_decode(const std::string& input, bool for_attribute = false);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Replace all control characters (0 <= c < 0x20) with replacement in
|
||||
* string. This is safe for utf-8
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ set(llmessage_SOURCE_FILES
|
|||
lldatapacker.cpp
|
||||
lldispatcher.cpp
|
||||
llexperiencecache.cpp
|
||||
llfiltersd2xmlrpc.cpp
|
||||
llgenericstreamingmessage.cpp
|
||||
llhost.cpp
|
||||
llhttpnode.cpp
|
||||
|
|
@ -111,7 +110,6 @@ set(llmessage_HEADER_FILES
|
|||
lleventflags.h
|
||||
llexperiencecache.h
|
||||
llextendedstatus.h
|
||||
llfiltersd2xmlrpc.h
|
||||
llfollowcamparams.h
|
||||
llgenericstreamingmessage.h
|
||||
llhost.h
|
||||
|
|
@ -193,7 +191,6 @@ target_link_libraries(
|
|||
llfilesystem
|
||||
llmath
|
||||
llcorehttp
|
||||
ll::xmlrpc-epi
|
||||
)
|
||||
target_include_directories( llmessage INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,778 +0,0 @@
|
|||
/**
|
||||
* @file llfiltersd2xmlrpc.cpp
|
||||
* @author Phoenix
|
||||
* @date 2005-04-26
|
||||
*
|
||||
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
/**
|
||||
* xml rpc request:
|
||||
* <code>
|
||||
* <?xml version="1.0"?>
|
||||
* <methodCall><methodName>examples.getStateName</methodName>
|
||||
* <params><param><value><i4>41</i4></value></param></params>
|
||||
* </methodCall>
|
||||
* </code>
|
||||
*
|
||||
* xml rpc response:
|
||||
* <code>
|
||||
* <?xml version="1.0"?>
|
||||
* <methodResponse>
|
||||
* <params><param><value><string>South Dakota</string></value></param></params>
|
||||
* </methodResponse>
|
||||
* </code>
|
||||
*
|
||||
* xml rpc fault:
|
||||
* </code>
|
||||
* <?xml version="1.0"?>
|
||||
* <methodResponse>
|
||||
* <fault><value><struct>
|
||||
* <member><name>faultCode</name><value><int>4</int></value></member>
|
||||
* <member><name>faultString</name><value><string>...</string></value></member>
|
||||
* </struct></value></fault>
|
||||
* </methodResponse>
|
||||
* </code>
|
||||
*
|
||||
* llsd rpc request:
|
||||
* <code>
|
||||
* { 'method':'...', 'parameter':...]}
|
||||
* </code>
|
||||
*
|
||||
* llsd rpc response:
|
||||
* <code>
|
||||
* { 'response':... }
|
||||
* </code>
|
||||
*
|
||||
* llsd rpc fault:
|
||||
* <code>
|
||||
* { 'fault': {'code':i..., 'description':'...'} }
|
||||
* </code>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llfiltersd2xmlrpc.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
|
||||
#ifdef LL_USESYSTEMLIBS
|
||||
#include <xmlrpc.h>
|
||||
#else
|
||||
#include <xmlrpc-epi/xmlrpc.h>
|
||||
#endif
|
||||
|
||||
#include "apr_base64.h"
|
||||
|
||||
#include "llbuffer.h"
|
||||
#include "llbufferstream.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llmemorystream.h"
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "lluuid.h"
|
||||
|
||||
// spammy mode
|
||||
//#define LL_SPEW_STREAM_OUT_DEBUGGING 1
|
||||
|
||||
/**
|
||||
* String constants
|
||||
*/
|
||||
static const char XML_HEADER[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||
static const char XMLRPC_REQUEST_HEADER_1[] = "<methodCall><methodName>";
|
||||
static const char XMLRPC_REQUEST_HEADER_2[] = "</methodName><params>";
|
||||
static const char XMLRPC_REQUEST_FOOTER[] = "</params></methodCall>";
|
||||
static const char XMLRPC_METHOD_RESPONSE_HEADER[] = "<methodResponse>";
|
||||
static const char XMLRPC_METHOD_RESPONSE_FOOTER[] = "</methodResponse>";
|
||||
static const char XMLRPC_RESPONSE_HEADER[] = "<params><param>";
|
||||
static const char XMLRPC_RESPONSE_FOOTER[] = "</param></params>";
|
||||
static const char XMLRPC_FAULT_1[] = "<fault><value><struct><member><name>faultCode</name><value><int>";
|
||||
static const char XMLRPC_FAULT_2[] = "</int></value></member><member><name>faultString</name><value><string>";
|
||||
static const char XMLRPC_FAULT_3[] = "</string></value></member></struct></value></fault>";
|
||||
static const char LLSDRPC_RESPONSE_HEADER[] = "{'response':";
|
||||
static const char LLSDRPC_RESPONSE_FOOTER[] = "}";
|
||||
const char LLSDRPC_REQUEST_HEADER_1[] = "{'method':'";
|
||||
const char LLSDRPC_REQUEST_HEADER_2[] = "', 'parameter': ";
|
||||
const char LLSDRPC_REQUEST_FOOTER[] = "}";
|
||||
static const char LLSDRPC_FAULT_HADER_1[] = "{ 'fault': {'code':i";
|
||||
static const char LLSDRPC_FAULT_HADER_2[] = ", 'description':";
|
||||
static const char LLSDRPC_FAULT_FOOTER[] = "} }";
|
||||
static const S32 DEFAULT_PRECISION = 20;
|
||||
|
||||
/**
|
||||
* LLFilterSD2XMLRPC
|
||||
*/
|
||||
LLFilterSD2XMLRPC::LLFilterSD2XMLRPC()
|
||||
{
|
||||
}
|
||||
|
||||
LLFilterSD2XMLRPC::~LLFilterSD2XMLRPC()
|
||||
{
|
||||
}
|
||||
|
||||
std::string xml_escape_string(const std::string& in)
|
||||
{
|
||||
std::ostringstream out;
|
||||
std::string::const_iterator it = in.begin();
|
||||
std::string::const_iterator end = in.end();
|
||||
for(; it != end; ++it)
|
||||
{
|
||||
switch((*it))
|
||||
{
|
||||
case '<':
|
||||
out << "<";
|
||||
break;
|
||||
case '>':
|
||||
out << ">";
|
||||
break;
|
||||
case '&':
|
||||
out << "&";
|
||||
break;
|
||||
case '\'':
|
||||
out << "'";
|
||||
break;
|
||||
case '"':
|
||||
out << """;
|
||||
break;
|
||||
default:
|
||||
out << (*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd)
|
||||
{
|
||||
ostr << "<value>";
|
||||
switch(sd.type())
|
||||
{
|
||||
case LLSD::TypeMap:
|
||||
{
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(map) BEGIN" << LL_ENDL;
|
||||
#endif
|
||||
ostr << "<struct>";
|
||||
if(ostr.fail())
|
||||
{
|
||||
LL_INFOS() << "STREAM FAILURE writing struct" << LL_ENDL;
|
||||
}
|
||||
LLSD::map_const_iterator it = sd.beginMap();
|
||||
LLSD::map_const_iterator end = sd.endMap();
|
||||
for(; it != end; ++it)
|
||||
{
|
||||
ostr << "<member><name>" << xml_escape_string((*it).first)
|
||||
<< "</name>";
|
||||
streamOut(ostr, (*it).second);
|
||||
if(ostr.fail())
|
||||
{
|
||||
LL_INFOS() << "STREAM FAILURE writing '" << (*it).first
|
||||
<< "' with sd type " << (*it).second.type() << LL_ENDL;
|
||||
}
|
||||
ostr << "</member>";
|
||||
}
|
||||
ostr << "</struct>";
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(map) END" << LL_ENDL;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case LLSD::TypeArray:
|
||||
{
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(array) BEGIN" << LL_ENDL;
|
||||
#endif
|
||||
ostr << "<array><data>";
|
||||
LLSD::array_const_iterator it = sd.beginArray();
|
||||
LLSD::array_const_iterator end = sd.endArray();
|
||||
for(; it != end; ++it)
|
||||
{
|
||||
streamOut(ostr, *it);
|
||||
if(ostr.fail())
|
||||
{
|
||||
LL_INFOS() << "STREAM FAILURE writing array element sd type "
|
||||
<< (*it).type() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(array) END" << LL_ENDL;
|
||||
#endif
|
||||
ostr << "</data></array>";
|
||||
break;
|
||||
}
|
||||
case LLSD::TypeUndefined:
|
||||
// treat undefined as a bool with a false value.
|
||||
case LLSD::TypeBoolean:
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(bool)" << LL_ENDL;
|
||||
#endif
|
||||
ostr << "<boolean>" << (sd.asBoolean() ? "1" : "0") << "</boolean>";
|
||||
break;
|
||||
case LLSD::TypeInteger:
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(int)" << LL_ENDL;
|
||||
#endif
|
||||
ostr << "<i4>" << sd.asInteger() << "</i4>";
|
||||
break;
|
||||
case LLSD::TypeReal:
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(real)" << LL_ENDL;
|
||||
#endif
|
||||
ostr << "<double>" << sd.asReal() << "</double>";
|
||||
break;
|
||||
case LLSD::TypeString:
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(string)" << LL_ENDL;
|
||||
#endif
|
||||
ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>";
|
||||
break;
|
||||
case LLSD::TypeUUID:
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(uuid)" << LL_ENDL;
|
||||
#endif
|
||||
// serialize it as a string
|
||||
ostr << "<string>" << sd.asString() << "</string>";
|
||||
break;
|
||||
case LLSD::TypeURI:
|
||||
{
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(uri)" << LL_ENDL;
|
||||
#endif
|
||||
// serialize it as a string
|
||||
ostr << "<string>" << xml_escape_string(sd.asString()) << "</string>";
|
||||
break;
|
||||
}
|
||||
case LLSD::TypeBinary:
|
||||
{
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(binary)" << LL_ENDL;
|
||||
#endif
|
||||
// this is pretty inefficient, but we'll deal with that
|
||||
// problem when it becomes one.
|
||||
ostr << "<base64>";
|
||||
LLSD::Binary buffer = sd.asBinary();
|
||||
if(!buffer.empty())
|
||||
{
|
||||
// *TODO: convert to LLBase64
|
||||
int b64_buffer_length = apr_base64_encode_len(static_cast<int>(buffer.size()));
|
||||
char* b64_buffer = new char[b64_buffer_length];
|
||||
b64_buffer_length = apr_base64_encode_binary(
|
||||
b64_buffer,
|
||||
&buffer[0],
|
||||
static_cast<int>(buffer.size()));
|
||||
ostr.write(b64_buffer, b64_buffer_length - 1);
|
||||
delete[] b64_buffer;
|
||||
}
|
||||
ostr << "</base64>";
|
||||
break;
|
||||
}
|
||||
case LLSD::TypeDate:
|
||||
#if LL_SPEW_STREAM_OUT_DEBUGGING
|
||||
LL_INFOS() << "streamOut(date)" << LL_ENDL;
|
||||
#endif
|
||||
// no need to escape this since it will be alpha-numeric.
|
||||
ostr << "<dateTime.iso8601>" << sd.asString() << "</dateTime.iso8601>";
|
||||
break;
|
||||
default:
|
||||
// unhandled type
|
||||
LL_WARNS() << "Unhandled structured data type: " << sd.type()
|
||||
<< LL_ENDL;
|
||||
break;
|
||||
}
|
||||
ostr << "</value>";
|
||||
}
|
||||
|
||||
/**
|
||||
* LLFilterSD2XMLRPCResponse
|
||||
*/
|
||||
|
||||
LLFilterSD2XMLRPCResponse::LLFilterSD2XMLRPCResponse()
|
||||
{
|
||||
}
|
||||
|
||||
LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// virtual
|
||||
LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
bool& eos,
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
||||
PUMP_DEBUG;
|
||||
// This pipe does not work if it does not have everyting. This
|
||||
// could be addressed by making a stream parser for llsd which
|
||||
// handled partial information.
|
||||
if(!eos)
|
||||
{
|
||||
return STATUS_BREAK;
|
||||
}
|
||||
|
||||
PUMP_DEBUG;
|
||||
// we have everyting in the buffer, so turn the structure data rpc
|
||||
// response into an xml rpc response.
|
||||
LLBufferStream stream(channels, buffer.get());
|
||||
stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER;
|
||||
LLSD sd;
|
||||
LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in()));
|
||||
|
||||
PUMP_DEBUG;
|
||||
LLIOPipe::EStatus rv = STATUS_ERROR;
|
||||
if(sd.has("response"))
|
||||
{
|
||||
PUMP_DEBUG;
|
||||
// it is a normal response. pack it up and ship it out.
|
||||
stream.precision(DEFAULT_PRECISION);
|
||||
stream << XMLRPC_RESPONSE_HEADER;
|
||||
streamOut(stream, sd["response"]);
|
||||
stream << XMLRPC_RESPONSE_FOOTER << XMLRPC_METHOD_RESPONSE_FOOTER;
|
||||
rv = STATUS_DONE;
|
||||
}
|
||||
else if(sd.has("fault"))
|
||||
{
|
||||
PUMP_DEBUG;
|
||||
// it is a fault.
|
||||
stream << XMLRPC_FAULT_1 << sd["fault"]["code"].asInteger()
|
||||
<< XMLRPC_FAULT_2
|
||||
<< xml_escape_string(sd["fault"]["description"].asString())
|
||||
<< XMLRPC_FAULT_3 << XMLRPC_METHOD_RESPONSE_FOOTER;
|
||||
rv = STATUS_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Unable to determine the type of LLSD response." << LL_ENDL;
|
||||
}
|
||||
PUMP_DEBUG;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* LLFilterSD2XMLRPCRequest
|
||||
*/
|
||||
LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest()
|
||||
{
|
||||
}
|
||||
|
||||
LLFilterSD2XMLRPCRequest::LLFilterSD2XMLRPCRequest(const char* method)
|
||||
{
|
||||
if(method)
|
||||
{
|
||||
mMethod.assign(method);
|
||||
}
|
||||
}
|
||||
|
||||
LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest()
|
||||
{
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
bool& eos,
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
// This pipe does not work if it does not have everyting. This
|
||||
// could be addressed by making a stream parser for llsd which
|
||||
// handled partial information.
|
||||
PUMP_DEBUG;
|
||||
if(!eos)
|
||||
{
|
||||
LL_INFOS() << "!eos" << LL_ENDL;
|
||||
return STATUS_BREAK;
|
||||
}
|
||||
|
||||
// See if we can parse it
|
||||
LLBufferStream stream(channels, buffer.get());
|
||||
LLSD sd;
|
||||
LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in()));
|
||||
if(stream.fail())
|
||||
{
|
||||
LL_INFOS() << "STREAM FAILURE reading structure data." << LL_ENDL;
|
||||
}
|
||||
|
||||
PUMP_DEBUG;
|
||||
// We can get the method and parameters from either the member
|
||||
// function or passed in via the buffer. We prefer the buffer if
|
||||
// we found a parameter and a method, or fall back to using
|
||||
// mMethod and putting everyting in the buffer into the parameter.
|
||||
std::string method;
|
||||
LLSD param_sd;
|
||||
if(sd.has("method") && sd.has("parameter"))
|
||||
{
|
||||
method = sd["method"].asString();
|
||||
param_sd = sd["parameter"];
|
||||
}
|
||||
else
|
||||
{
|
||||
method = mMethod;
|
||||
param_sd = sd;
|
||||
}
|
||||
if(method.empty())
|
||||
{
|
||||
LL_WARNS() << "SD -> XML Request no method found." << LL_ENDL;
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
PUMP_DEBUG;
|
||||
// We have a method, and some kind of parameter, so package it up
|
||||
// and send it out.
|
||||
LLBufferStream ostream(channels, buffer.get());
|
||||
ostream.precision(DEFAULT_PRECISION);
|
||||
if(ostream.fail())
|
||||
{
|
||||
LL_INFOS() << "STREAM FAILURE setting precision" << LL_ENDL;
|
||||
}
|
||||
ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1
|
||||
<< xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2;
|
||||
if(ostream.fail())
|
||||
{
|
||||
LL_INFOS() << "STREAM FAILURE writing method headers" << LL_ENDL;
|
||||
}
|
||||
switch(param_sd.type())
|
||||
{
|
||||
case LLSD::TypeMap:
|
||||
// If the params are a map, then we do not want to iterate
|
||||
// through them since the iterators returned will be map
|
||||
// ordered un-named values, which will lose the names, and
|
||||
// only stream the values, turning it into an array.
|
||||
ostream << "<param>";
|
||||
streamOut(ostream, param_sd);
|
||||
ostream << "</param>";
|
||||
break;
|
||||
case LLSD::TypeArray:
|
||||
{
|
||||
|
||||
LLSD::array_iterator it = param_sd.beginArray();
|
||||
LLSD::array_iterator end = param_sd.endArray();
|
||||
for(; it != end; ++it)
|
||||
{
|
||||
ostream << "<param>";
|
||||
streamOut(ostream, *it);
|
||||
ostream << "</param>";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ostream << "<param>";
|
||||
streamOut(ostream, param_sd);
|
||||
ostream << "</param>";
|
||||
break;
|
||||
}
|
||||
|
||||
stream << XMLRPC_REQUEST_FOOTER;
|
||||
return STATUS_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* LLFilterXMLRPCResponse2LLSD
|
||||
*/
|
||||
// this is a c function here since it's really an implementation
|
||||
// detail that requires a header file just get the definition of the
|
||||
// parameters.
|
||||
LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value)
|
||||
{
|
||||
XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(value);
|
||||
LLIOPipe::EStatus status = LLIOPipe::STATUS_OK;
|
||||
switch(type)
|
||||
{
|
||||
case xmlrpc_type_base64:
|
||||
{
|
||||
S32 len = XMLRPC_GetValueStringLen(value);
|
||||
const char* buf = XMLRPC_GetValueBase64(value);
|
||||
ostr << " b(";
|
||||
if((len > 0) && buf)
|
||||
{
|
||||
ostr << len << ")\"";
|
||||
ostr.write(buf, len);
|
||||
ostr << "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
ostr << "0)\"\"";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_boolean:
|
||||
//LL_DEBUGS() << "stream_out() bool" << LL_ENDL;
|
||||
ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false");
|
||||
break;
|
||||
case xmlrpc_type_datetime:
|
||||
ostr << " d\"" << XMLRPC_GetValueDateTime_ISO8601(value) << "\"";
|
||||
break;
|
||||
case xmlrpc_type_double:
|
||||
ostr << " r" << XMLRPC_GetValueDouble(value);
|
||||
//LL_DEBUGS() << "stream_out() double" << XMLRPC_GetValueDouble(value)
|
||||
// << LL_ENDL;
|
||||
break;
|
||||
case xmlrpc_type_int:
|
||||
ostr << " i" << XMLRPC_GetValueInt(value);
|
||||
//LL_DEBUGS() << "stream_out() integer:" << XMLRPC_GetValueInt(value)
|
||||
// << LL_ENDL;
|
||||
break;
|
||||
case xmlrpc_type_string:
|
||||
//LL_DEBUGS() << "stream_out() string: " << str << LL_ENDL;
|
||||
ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'"
|
||||
<< XMLRPC_GetValueString(value) << "'";
|
||||
break;
|
||||
case xmlrpc_type_array: // vector
|
||||
case xmlrpc_type_mixed: // vector
|
||||
{
|
||||
//LL_DEBUGS() << "stream_out() array" << LL_ENDL;
|
||||
ostr << " [";
|
||||
U32 needs_comma = 0;
|
||||
XMLRPC_VALUE current = XMLRPC_VectorRewind(value);
|
||||
while(current && (LLIOPipe::STATUS_OK == status))
|
||||
{
|
||||
if(needs_comma++) ostr << ",";
|
||||
status = stream_out(ostr, current);
|
||||
current = XMLRPC_VectorNext(value);
|
||||
}
|
||||
ostr << "]";
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_struct: // still vector
|
||||
{
|
||||
//LL_DEBUGS() << "stream_out() struct" << LL_ENDL;
|
||||
ostr << " {";
|
||||
std::string name;
|
||||
U32 needs_comma = 0;
|
||||
XMLRPC_VALUE current = XMLRPC_VectorRewind(value);
|
||||
while(current && (LLIOPipe::STATUS_OK == status))
|
||||
{
|
||||
if(needs_comma++) ostr << ",";
|
||||
name.assign(XMLRPC_GetValueID(current));
|
||||
ostr << "'" << LLSDNotationFormatter::escapeString(name) << "':";
|
||||
status = stream_out(ostr, current);
|
||||
current = XMLRPC_VectorNext(value);
|
||||
}
|
||||
ostr << "}";
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_empty:
|
||||
case xmlrpc_type_none:
|
||||
default:
|
||||
status = LLIOPipe::STATUS_ERROR;
|
||||
LL_WARNS() << "Found an empty xmlrpc type.." << LL_ENDL;
|
||||
// not much we can do here...
|
||||
break;
|
||||
};
|
||||
return status;
|
||||
}
|
||||
|
||||
LLFilterXMLRPCResponse2LLSD::LLFilterXMLRPCResponse2LLSD()
|
||||
{
|
||||
}
|
||||
|
||||
LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD()
|
||||
{
|
||||
}
|
||||
|
||||
LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
bool& eos,
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
||||
PUMP_DEBUG;
|
||||
if(!eos) return STATUS_BREAK;
|
||||
if(!buffer) return STATUS_ERROR;
|
||||
|
||||
PUMP_DEBUG;
|
||||
// *FIX: This technique for reading data is far from optimal. We
|
||||
// need to have some kind of istream interface into the xml
|
||||
// parser...
|
||||
S32 bytes = buffer->countAfter(channels.in(), NULL);
|
||||
if(!bytes) return STATUS_ERROR;
|
||||
char* buf = new char[bytes + 1];
|
||||
buf[bytes] = '\0';
|
||||
buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes);
|
||||
|
||||
//LL_DEBUGS() << "xmlrpc response: " << buf << LL_ENDL;
|
||||
|
||||
PUMP_DEBUG;
|
||||
XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML(
|
||||
buf,
|
||||
bytes,
|
||||
NULL);
|
||||
if(!response)
|
||||
{
|
||||
LL_WARNS() << "XML -> SD Response unable to parse xml." << LL_ENDL;
|
||||
delete[] buf;
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
PUMP_DEBUG;
|
||||
LLBufferStream stream(channels, buffer.get());
|
||||
stream.precision(DEFAULT_PRECISION);
|
||||
if(XMLRPC_ResponseIsFault(response))
|
||||
{
|
||||
PUMP_DEBUG;
|
||||
stream << LLSDRPC_FAULT_HADER_1
|
||||
<< XMLRPC_GetResponseFaultCode(response)
|
||||
<< LLSDRPC_FAULT_HADER_2;
|
||||
const char* fault_str = XMLRPC_GetResponseFaultString(response);
|
||||
std::string fault_string;
|
||||
if(fault_str)
|
||||
{
|
||||
fault_string.assign(fault_str);
|
||||
}
|
||||
stream << "'" << LLSDNotationFormatter::escapeString(fault_string)
|
||||
<< "'" <<LLSDRPC_FAULT_FOOTER;
|
||||
}
|
||||
else
|
||||
{
|
||||
PUMP_DEBUG;
|
||||
stream << LLSDRPC_RESPONSE_HEADER;
|
||||
XMLRPC_VALUE param = XMLRPC_RequestGetData(response);
|
||||
if(param)
|
||||
{
|
||||
stream_out(stream, param);
|
||||
}
|
||||
stream << LLSDRPC_RESPONSE_FOOTER;
|
||||
}
|
||||
PUMP_DEBUG;
|
||||
XMLRPC_RequestFree(response, 1);
|
||||
delete[] buf;
|
||||
PUMP_DEBUG;
|
||||
return STATUS_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* LLFilterXMLRPCRequest2LLSD
|
||||
*/
|
||||
LLFilterXMLRPCRequest2LLSD::LLFilterXMLRPCRequest2LLSD()
|
||||
{
|
||||
}
|
||||
|
||||
LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD()
|
||||
{
|
||||
}
|
||||
|
||||
LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
bool& eos,
|
||||
LLSD& context,
|
||||
LLPumpIO* pump)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
PUMP_DEBUG;
|
||||
if(!eos) return STATUS_BREAK;
|
||||
if(!buffer) return STATUS_ERROR;
|
||||
|
||||
PUMP_DEBUG;
|
||||
// *FIX: This technique for reading data is far from optimal. We
|
||||
// need to have some kind of istream interface into the xml
|
||||
// parser...
|
||||
S32 bytes = buffer->countAfter(channels.in(), NULL);
|
||||
if(!bytes) return STATUS_ERROR;
|
||||
char* buf = new char[bytes + 1];
|
||||
buf[bytes] = '\0';
|
||||
buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes);
|
||||
|
||||
//LL_DEBUGS() << "xmlrpc request: " << buf << LL_ENDL;
|
||||
|
||||
// Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if
|
||||
// values that are less than 0x20 are passed to it, except
|
||||
// 0x09: Horizontal tab; 0x0a: New Line; 0x0d: Carriage
|
||||
U8* cur_pBuf = (U8*)buf;
|
||||
U8 cur_char;
|
||||
for (S32 i=0; i<bytes; i++)
|
||||
{
|
||||
cur_char = *cur_pBuf;
|
||||
if ( cur_char < 0x20
|
||||
&& 0x09 != cur_char
|
||||
&& 0x0a != cur_char
|
||||
&& 0x0d != cur_char )
|
||||
{
|
||||
*cur_pBuf = '?';
|
||||
}
|
||||
++cur_pBuf;
|
||||
}
|
||||
|
||||
PUMP_DEBUG;
|
||||
XMLRPC_REQUEST request = XMLRPC_REQUEST_FromXML(
|
||||
buf,
|
||||
bytes,
|
||||
NULL);
|
||||
if(!request)
|
||||
{
|
||||
LL_WARNS() << "XML -> SD Request process parse error." << LL_ENDL;
|
||||
delete[] buf;
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
PUMP_DEBUG;
|
||||
LLBufferStream stream(channels, buffer.get());
|
||||
stream.precision(DEFAULT_PRECISION);
|
||||
const char* name = XMLRPC_RequestGetMethodName(request);
|
||||
stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "")
|
||||
<< LLSDRPC_REQUEST_HEADER_2;
|
||||
XMLRPC_VALUE param = XMLRPC_RequestGetData(request);
|
||||
if(param)
|
||||
{
|
||||
PUMP_DEBUG;
|
||||
S32 size = XMLRPC_VectorSize(param);
|
||||
if(size > 1)
|
||||
{
|
||||
// if there are multiple parameters, stuff the values into
|
||||
// an array so that the next step in the chain can read them.
|
||||
stream << "[";
|
||||
}
|
||||
XMLRPC_VALUE current = XMLRPC_VectorRewind(param);
|
||||
bool needs_comma = false;
|
||||
while(current)
|
||||
{
|
||||
if(needs_comma)
|
||||
{
|
||||
stream << ",";
|
||||
}
|
||||
needs_comma = true;
|
||||
stream_out(stream, current);
|
||||
current = XMLRPC_VectorNext(param);
|
||||
}
|
||||
if(size > 1)
|
||||
{
|
||||
// close the array
|
||||
stream << "]";
|
||||
}
|
||||
}
|
||||
stream << LLSDRPC_REQUEST_FOOTER;
|
||||
XMLRPC_RequestFree(request, 1);
|
||||
delete[] buf;
|
||||
PUMP_DEBUG;
|
||||
return STATUS_DONE;
|
||||
}
|
||||
|
||||
|
|
@ -1,271 +0,0 @@
|
|||
/**
|
||||
* @file llfiltersd2xmlrpc.h
|
||||
* @author Phoenix
|
||||
* @date 2005-04-26
|
||||
*
|
||||
* $LicenseInfo:firstyear=2005&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFILTERSD2XMLRPC_H
|
||||
#define LL_LLFILTERSD2XMLRPC_H
|
||||
|
||||
/**
|
||||
* These classes implement the necessary pipes for translating between
|
||||
* xmlrpc and llsd rpc. The llsd rpcs mechanism was developed as an
|
||||
* extensible and easy to parse serialization grammer which maintains
|
||||
* a time efficient in-memory representation.
|
||||
*/
|
||||
|
||||
#include <iosfwd>
|
||||
#include "lliopipe.h"
|
||||
|
||||
/**
|
||||
* @class LLFilterSD2XMLRPC
|
||||
* @brief Filter from serialized LLSD to an XMLRPC method call
|
||||
*
|
||||
* This clas provides common functionality for the LLFilterSD2XMLRPRC
|
||||
* request and response classes.
|
||||
*/
|
||||
class LLFilterSD2XMLRPC : public LLIOPipe
|
||||
{
|
||||
public:
|
||||
LLFilterSD2XMLRPC();
|
||||
virtual ~LLFilterSD2XMLRPC();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief helper method
|
||||
*/
|
||||
void streamOut(std::ostream& ostr, const LLSD& sd);
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLFilterSD2XMLRPCResponse
|
||||
* @brief Filter from serialized LLSD to an XMLRPC response
|
||||
*
|
||||
* This class filters a serialized LLSD object to an xmlrpc
|
||||
* repsonse. Since resonses are limited to a single param, the xmlrprc
|
||||
* response only serializes it as one object.
|
||||
* This class correctly handles normal llsd responses as well as llsd
|
||||
* rpc faults.
|
||||
*
|
||||
* For example, if given:
|
||||
* <code>{'response':[ i200, r3.4, {"foo":"bar"} ]}</code>
|
||||
* Would generate:
|
||||
* <code>
|
||||
* <?xml version="1.0"?>
|
||||
* <methodResponse><params><param><array><data>
|
||||
* <value><int>200</int></value>
|
||||
* <value><double>3.4</double></value>
|
||||
* <value><struct><member>
|
||||
* <name>foo</name><value><string>bar</string></value></member>
|
||||
* </struct></value>
|
||||
* </data></array></param></params></methodResponse>
|
||||
* </code>
|
||||
*/
|
||||
class LLFilterSD2XMLRPCResponse : public LLFilterSD2XMLRPC
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
LLFilterSD2XMLRPCResponse();
|
||||
|
||||
// destructor
|
||||
virtual ~LLFilterSD2XMLRPCResponse();
|
||||
|
||||
/* @name LLIOPipe virtual implementations
|
||||
*/
|
||||
//@{
|
||||
protected:
|
||||
/**
|
||||
* @brief Process the data in buffer.
|
||||
*/
|
||||
virtual EStatus process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
bool& eos,
|
||||
LLSD& context,
|
||||
LLPumpIO* pump);
|
||||
//@}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLFilterSD2XMLRPCRequest
|
||||
* @brief Filter from serialized LLSD to an XMLRPC method call
|
||||
*
|
||||
* This class will accept any kind of serialized LLSD object, but you
|
||||
* probably want to have an array on the outer boundary since this
|
||||
* object will interpret each element in the top level LLSD as a
|
||||
* parameter into the xmlrpc spec.
|
||||
*
|
||||
* For example, you would represent 3 params as:
|
||||
* <code>
|
||||
* {'method'='foo', 'parameter':[i200, r3.4, {"foo":"bar"}]}
|
||||
* </code>
|
||||
* To generate:
|
||||
* <code>
|
||||
* <?xml version="1.0"?>
|
||||
* <methodCall><params>
|
||||
* <param><value><int>200</int></value></param>
|
||||
* <param><value><double>3.4</double></value></param>
|
||||
* <param><value><struct><member>
|
||||
* <name>foo</name><value><string>bar</string></value></member>
|
||||
* </struct></value></param>
|
||||
* </params></methodCall>
|
||||
*
|
||||
* This class will accept 2 different kinds of encodings. The first
|
||||
* just an array of params as long as you specify the method in the
|
||||
* constructor. It will also accept a structured data in the form:
|
||||
* {'method':'$method_name', 'parameter':[...] } In the latter form, the
|
||||
* encoded 'method' will be used regardless of the construction of the
|
||||
* object, and the 'parameter' will be used as parameter to the call.
|
||||
*/
|
||||
class LLFilterSD2XMLRPCRequest : public LLFilterSD2XMLRPC
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
LLFilterSD2XMLRPCRequest();
|
||||
|
||||
// constructor
|
||||
LLFilterSD2XMLRPCRequest(const char* method);
|
||||
|
||||
// destructor
|
||||
virtual ~LLFilterSD2XMLRPCRequest();
|
||||
|
||||
/* @name LLIOPipe virtual implementations
|
||||
*/
|
||||
//@{
|
||||
protected:
|
||||
/**
|
||||
* @brief Process the data in buffer.
|
||||
*/
|
||||
virtual EStatus process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
bool& eos,
|
||||
LLSD& context,
|
||||
LLPumpIO* pump);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
// The method name of this request.
|
||||
std::string mMethod;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLFilterXMLRPCResponse2LLSD
|
||||
* @brief Filter from serialized XMLRPC method response to LLSD
|
||||
*
|
||||
* The xmlrpc spec states that responses can only have one element
|
||||
* which can be of any supported type.
|
||||
* This takes in xml of the form:
|
||||
* <code>
|
||||
* <?xml version=\"1.0\"?><methodResponse><params><param>
|
||||
* <value><string>ok</string></value></param></params></methodResponse>
|
||||
* </code>
|
||||
* And processes it into:
|
||||
* <code>'ok'</code>
|
||||
*
|
||||
*/
|
||||
class LLFilterXMLRPCResponse2LLSD : public LLIOPipe
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
LLFilterXMLRPCResponse2LLSD();
|
||||
|
||||
// destructor
|
||||
virtual ~LLFilterXMLRPCResponse2LLSD();
|
||||
|
||||
/* @name LLIOPipe virtual implementations
|
||||
*/
|
||||
//@{
|
||||
protected:
|
||||
/**
|
||||
* @brief Process the data in buffer.
|
||||
*/
|
||||
virtual EStatus process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
bool& eos,
|
||||
LLSD& context,
|
||||
LLPumpIO* pump);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLFilterXMLRPCRequest2LLSD
|
||||
* @brief Filter from serialized XMLRPC method call to LLSD
|
||||
*
|
||||
* This takes in xml of the form:
|
||||
* <code>
|
||||
* <?xml version=\"1.0\"?><methodCall>
|
||||
* <methodName>repeat</methodName>
|
||||
* <params>
|
||||
* <param><value><i4>4</i4></value></param>
|
||||
* <param><value><string>ok</string></value></param>
|
||||
* </params></methodCall>
|
||||
* </code>
|
||||
* And processes it into:
|
||||
* <code>{ 'method':'repeat', 'params':[i4, 'ok'] }</code>
|
||||
*/
|
||||
class LLFilterXMLRPCRequest2LLSD : public LLIOPipe
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
LLFilterXMLRPCRequest2LLSD();
|
||||
|
||||
// destructor
|
||||
virtual ~LLFilterXMLRPCRequest2LLSD();
|
||||
|
||||
/* @name LLIOPipe virtual implementations
|
||||
*/
|
||||
//@{
|
||||
protected:
|
||||
/**
|
||||
* @brief Process the data in buffer.
|
||||
*/
|
||||
virtual EStatus process_impl(
|
||||
const LLChannelDescriptors& channels,
|
||||
buffer_ptr_t& buffer,
|
||||
bool& eos,
|
||||
LLSD& context,
|
||||
LLPumpIO* pump);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This function takes string, and escapes it appropritately
|
||||
* for inclusion as xml data.
|
||||
*/
|
||||
std::string xml_escape_string(const std::string& in);
|
||||
|
||||
/**
|
||||
* @brief Externally available constants
|
||||
*/
|
||||
extern const char LLSDRPC_REQUEST_HEADER_1[];
|
||||
extern const char LLSDRPC_REQUEST_HEADER_2[];
|
||||
extern const char LLSDRPC_REQUEST_FOOTER[];
|
||||
|
||||
#endif // LL_LLFILTERSD2XMLRPC_H
|
||||
|
|
@ -653,32 +653,24 @@ bool LLXMLNode::updateNode(
|
|||
// static
|
||||
bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree)
|
||||
{
|
||||
// Read file
|
||||
LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL;
|
||||
LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
|
||||
if (fp == NULL)
|
||||
std::string xml = LLFile::getContents(filename);
|
||||
if (xml.empty())
|
||||
{
|
||||
node = NULL ;
|
||||
return false;
|
||||
LL_WARNS("XMLNode") << "no XML file: " << filename << LL_ENDL;
|
||||
}
|
||||
else if (parseBuffer(xml.data(), xml.size(), node, defaults_tree))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
fseek(fp, 0, SEEK_END);
|
||||
U32 length = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
U8* buffer = new U8[length+1];
|
||||
size_t nread = fread(buffer, 1, length, fp);
|
||||
buffer[nread] = 0;
|
||||
fclose(fp);
|
||||
|
||||
bool rv = parseBuffer(buffer, static_cast<U32>(nread), node, defaults_tree);
|
||||
delete [] buffer;
|
||||
return rv;
|
||||
node = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLXMLNode::parseBuffer(
|
||||
U8* buffer,
|
||||
U32 length,
|
||||
const char* buffer,
|
||||
U64 length,
|
||||
LLXMLNodePtr& node,
|
||||
LLXMLNode* defaults)
|
||||
{
|
||||
|
|
@ -693,20 +685,25 @@ bool LLXMLNode::parseBuffer(
|
|||
|
||||
file_node->mParser = &my_parser;
|
||||
|
||||
XML_SetUserData(my_parser, (void *)file_node_ptr);
|
||||
XML_SetUserData(my_parser, file_node_ptr);
|
||||
|
||||
// Do the parsing
|
||||
if (XML_Parse(my_parser, (const char *)buffer, length, true) != XML_STATUS_OK)
|
||||
bool success = XML_STATUS_OK == XML_Parse(my_parser, buffer, (int)length, true);
|
||||
if (!success)
|
||||
{
|
||||
LL_WARNS() << "Error parsing xml error code: "
|
||||
<< XML_ErrorString(XML_GetErrorCode(my_parser))
|
||||
<< " on line " << XML_GetCurrentLineNumber(my_parser)
|
||||
<< ", column " << XML_GetCurrentColumnNumber(my_parser)
|
||||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
// Deinit
|
||||
XML_ParserFree(my_parser);
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
if (!file_node->mChildren || file_node->mChildren->map.size() != 1)
|
||||
{
|
||||
LL_WARNS() << "Parse failure - wrong number of top-level nodes xml."
|
||||
|
|
|
|||
|
|
@ -129,20 +129,20 @@ public:
|
|||
void addChild(LLXMLNodePtr& new_child);
|
||||
void setParent(LLXMLNodePtr& new_parent); // reparent if necessary
|
||||
|
||||
// Serialization
|
||||
// Deserialization
|
||||
static bool parseFile(
|
||||
const std::string& filename,
|
||||
LLXMLNodePtr& node,
|
||||
LLXMLNode* defaults_tree);
|
||||
LLXMLNode* defaults = nullptr);
|
||||
static bool parseBuffer(
|
||||
U8* buffer,
|
||||
U32 length,
|
||||
const char* buffer,
|
||||
U64 length,
|
||||
LLXMLNodePtr& node,
|
||||
LLXMLNode* defaults);
|
||||
LLXMLNode* defaults = nullptr);
|
||||
static bool parseStream(
|
||||
std::istream& str,
|
||||
LLXMLNodePtr& node,
|
||||
LLXMLNode* defaults);
|
||||
LLXMLNode* defaults = nullptr);
|
||||
static bool updateNode(
|
||||
LLXMLNodePtr& node,
|
||||
LLXMLNodePtr& update_node);
|
||||
|
|
|
|||
|
|
@ -111,16 +111,17 @@ public:
|
|||
bool hasEstimate() const;
|
||||
std::string getLocalEstimate() const;
|
||||
|
||||
void startTransaction(TransactionType type,
|
||||
const char* method, LLXMLRPCValue params);
|
||||
bool checkTransaction();
|
||||
void startTransaction(TransactionType type, const char* method, const LLSD& params);
|
||||
|
||||
// return true if update needed
|
||||
bool checkTransaction();
|
||||
|
||||
void setError(const std::string& message, const std::string& uri);
|
||||
void clearError();
|
||||
|
||||
bool considerUpdateCurrency();
|
||||
// return true if update needed
|
||||
bool considerUpdateCurrency();
|
||||
|
||||
void currencyKey(S32);
|
||||
static void onCurrencyKey(LLLineEditor* caller, void* data);
|
||||
|
||||
|
|
@ -160,32 +161,29 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo()
|
|||
return;
|
||||
}
|
||||
|
||||
LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
|
||||
keywordArgs.appendString("agentId", gAgent.getID().asString());
|
||||
keywordArgs.appendString(
|
||||
"secureSessionId",
|
||||
gAgent.getSecureSessionID().asString());
|
||||
keywordArgs.appendString("language", LLUI::getLanguage());
|
||||
keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
|
||||
keywordArgs.appendString("viewerChannel", LLVersionInfo::instance().getChannel());
|
||||
keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::instance().getMajor());
|
||||
keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::instance().getMinor());
|
||||
keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::instance().getPatch());
|
||||
// With GitHub builds, the build number is too big to fit in a 32-bit int,
|
||||
// and XMLRPC_VALUE doesn't deal with integers wider than int. Use string.
|
||||
keywordArgs.appendString("viewerBuildVersion", stringize(LLVersionInfo::instance().getBuild()));
|
||||
const LLVersionInfo& vi(LLVersionInfo::instance());
|
||||
|
||||
LLXMLRPCValue params = LLXMLRPCValue::createArray();
|
||||
params.append(keywordArgs);
|
||||
LLSD params = LLSD::emptyMap();
|
||||
params["agentId"] = gAgent.getID().asString();
|
||||
params["secureSessionId"] = gAgent.getSecureSessionID().asString();
|
||||
params["language"] = LLUI::getLanguage();
|
||||
params["currencyBuy"] = mUserCurrencyBuy;
|
||||
params["viewerChannel"] = vi.getChannel();
|
||||
params["viewerMajorVersion"] = vi.getMajor();
|
||||
params["viewerMinorVersion"] = vi.getMinor();
|
||||
params["viewerPatchVersion"] = vi.getPatch();
|
||||
// With GitHub builds, the build number is too big to fit in a 32-bit int,
|
||||
// and XMLRPC value doesn't deal with integers wider than int. Use string.
|
||||
params["viewerBuildVersion"] = std::to_string(vi.getBuild());
|
||||
|
||||
startTransaction(TransactionCurrency, "getCurrencyQuote", params);
|
||||
}
|
||||
|
||||
void LLCurrencyUIManager::Impl::finishCurrencyInfo()
|
||||
{
|
||||
LLXMLRPCValue result = mTransaction->responseValue();
|
||||
const LLSD& result = mTransaction->response();
|
||||
|
||||
bool success = result["success"].asBool();
|
||||
bool success = result["success"].asBoolean();
|
||||
if (!success)
|
||||
{
|
||||
setError(
|
||||
|
|
@ -195,24 +193,24 @@ void LLCurrencyUIManager::Impl::finishCurrencyInfo()
|
|||
return;
|
||||
}
|
||||
|
||||
LLXMLRPCValue currency = result["currency"];
|
||||
const LLSD& currency = result["currency"];
|
||||
|
||||
// old XML-RPC server: estimatedCost = value in US cents
|
||||
mUSDCurrencyEstimated = currency["estimatedCost"].isValid();
|
||||
mUSDCurrencyEstimated = currency.has("estimatedCost");
|
||||
if (mUSDCurrencyEstimated)
|
||||
{
|
||||
mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInt();
|
||||
mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInteger();
|
||||
}
|
||||
|
||||
// newer XML-RPC server: estimatedLocalCost = local currency string
|
||||
mLocalCurrencyEstimated = currency["estimatedLocalCost"].isValid();
|
||||
mLocalCurrencyEstimated = currency.has("estimatedLocalCost");
|
||||
if (mLocalCurrencyEstimated)
|
||||
{
|
||||
mLocalCurrencyEstimatedCost = currency["estimatedLocalCost"].asString();
|
||||
mSupportsInternationalBilling = true;
|
||||
}
|
||||
|
||||
S32 newCurrencyBuy = currency["currencyBuy"].asInt();
|
||||
S32 newCurrencyBuy = currency["currencyBuy"].asInteger();
|
||||
if (newCurrencyBuy != mUserCurrencyBuy)
|
||||
{
|
||||
mUserCurrencyBuy = newCurrencyBuy;
|
||||
|
|
@ -224,36 +222,36 @@ void LLCurrencyUIManager::Impl::finishCurrencyInfo()
|
|||
|
||||
void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
|
||||
{
|
||||
LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
|
||||
keywordArgs.appendString("agentId", gAgent.getID().asString());
|
||||
keywordArgs.appendString(
|
||||
"secureSessionId",
|
||||
gAgent.getSecureSessionID().asString());
|
||||
keywordArgs.appendString("language", LLUI::getLanguage());
|
||||
keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
|
||||
const LLVersionInfo& vi(LLVersionInfo::instance());
|
||||
|
||||
LLSD params = LLSD::emptyMap();
|
||||
params["agentId"] = gAgent.getID().asString();
|
||||
params["secureSessionId"] = gAgent.getSecureSessionID().asString();
|
||||
params["language"] = LLUI::getLanguage();
|
||||
params["currencyBuy"] = mUserCurrencyBuy;
|
||||
params["confirm"] = mSiteConfirm;
|
||||
params["viewerChannel"] = vi.getChannel();
|
||||
params["viewerMajorVersion"] = vi.getMajor();
|
||||
params["viewerMinorVersion"] = vi.getMinor();
|
||||
params["viewerPatchVersion"] = vi.getPatch();
|
||||
// With GitHub builds, the build number is too big to fit in a 32-bit int,
|
||||
// and XMLRPC value doesn't deal with integers wider than int. Use string.
|
||||
params["viewerBuildVersion"] = std::to_string(vi.getBuild());
|
||||
|
||||
if (mUSDCurrencyEstimated)
|
||||
{
|
||||
keywordArgs.appendInt("estimatedCost", mUSDCurrencyEstimatedCost);
|
||||
params["estimatedCost"] = mUSDCurrencyEstimatedCost;
|
||||
}
|
||||
|
||||
if (mLocalCurrencyEstimated)
|
||||
{
|
||||
keywordArgs.appendString("estimatedLocalCost", mLocalCurrencyEstimatedCost);
|
||||
params["estimatedLocalCost"] = mLocalCurrencyEstimatedCost;
|
||||
}
|
||||
keywordArgs.appendString("confirm", mSiteConfirm);
|
||||
|
||||
if (!password.empty())
|
||||
{
|
||||
keywordArgs.appendString("password", password);
|
||||
params["password"] = password;
|
||||
}
|
||||
keywordArgs.appendString("viewerChannel", LLVersionInfo::instance().getChannel());
|
||||
keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::instance().getMajor());
|
||||
keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::instance().getMinor());
|
||||
keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::instance().getPatch());
|
||||
// With GitHub builds, the build number is too big to fit in a 32-bit int,
|
||||
// and XMLRPC_VALUE doesn't deal with integers wider than int. Use string.
|
||||
keywordArgs.appendString("viewerBuildVersion", stringize(LLVersionInfo::instance().getBuild()));
|
||||
|
||||
LLXMLRPCValue params = LLXMLRPCValue::createArray();
|
||||
params.append(keywordArgs);
|
||||
|
||||
startTransaction(TransactionBuy, "buyCurrency", params);
|
||||
|
||||
|
|
@ -263,9 +261,9 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
|
|||
|
||||
void LLCurrencyUIManager::Impl::finishCurrencyBuy()
|
||||
{
|
||||
LLXMLRPCValue result = mTransaction->responseValue();
|
||||
const LLSD& result = mTransaction->response();
|
||||
|
||||
bool success = result["success"].asBool();
|
||||
bool success = result["success"].asBoolean();
|
||||
if (!success)
|
||||
{
|
||||
setError(
|
||||
|
|
@ -282,7 +280,7 @@ void LLCurrencyUIManager::Impl::finishCurrencyBuy()
|
|||
}
|
||||
|
||||
void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
|
||||
const char* method, LLXMLRPCValue params)
|
||||
const char* method, const LLSD& params)
|
||||
{
|
||||
static std::string transactionURI;
|
||||
if (transactionURI.empty())
|
||||
|
|
@ -293,12 +291,7 @@ void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
|
|||
delete mTransaction;
|
||||
|
||||
mTransactionType = type;
|
||||
mTransaction = new LLXMLRPCTransaction(
|
||||
transactionURI,
|
||||
method,
|
||||
params,
|
||||
false /* don't use gzip */
|
||||
);
|
||||
mTransaction = new LLXMLRPCTransaction(transactionURI, method, params);
|
||||
|
||||
clearError();
|
||||
}
|
||||
|
|
@ -352,11 +345,16 @@ bool LLCurrencyUIManager::Impl::checkTransaction()
|
|||
{
|
||||
setError(mTransaction->statusMessage(), mTransaction->statusURI());
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
switch (mTransactionType)
|
||||
{
|
||||
case TransactionCurrency: finishCurrencyInfo(); break;
|
||||
case TransactionBuy: finishCurrencyBuy(); break;
|
||||
case TransactionCurrency:
|
||||
finishCurrencyInfo();
|
||||
break;
|
||||
case TransactionBuy:
|
||||
finishCurrencyBuy();
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
|
@ -385,9 +383,8 @@ void LLCurrencyUIManager::Impl::clearError()
|
|||
|
||||
bool LLCurrencyUIManager::Impl::considerUpdateCurrency()
|
||||
{
|
||||
if (mCurrencyChanged
|
||||
&& !mTransaction
|
||||
&& mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
|
||||
if (mCurrencyChanged && !mTransaction &&
|
||||
mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
|
||||
{
|
||||
updateCurrencyInfo();
|
||||
return true;
|
||||
|
|
@ -408,7 +405,8 @@ void LLCurrencyUIManager::Impl::currencyKey(S32 value)
|
|||
|
||||
mUserCurrencyBuy = value;
|
||||
|
||||
if (hasEstimate()) {
|
||||
if (hasEstimate())
|
||||
{
|
||||
clearEstimate();
|
||||
//cannot just simply refresh the whole UI, as the edit field will
|
||||
// get reset and the cursor will change...
|
||||
|
|
@ -421,8 +419,7 @@ void LLCurrencyUIManager::Impl::currencyKey(S32 value)
|
|||
}
|
||||
|
||||
// static
|
||||
void LLCurrencyUIManager::Impl::onCurrencyKey(
|
||||
LLLineEditor* caller, void* data)
|
||||
void LLCurrencyUIManager::Impl::onCurrencyKey(LLLineEditor* caller, void* data)
|
||||
{
|
||||
S32 value = atoi(caller->getText().c_str());
|
||||
LLCurrencyUIManager::Impl* self = (LLCurrencyUIManager::Impl*)data;
|
||||
|
|
@ -589,14 +586,12 @@ bool LLCurrencyUIManager::inProcess()
|
|||
|
||||
bool LLCurrencyUIManager::canCancel()
|
||||
{
|
||||
return impl.mTransactionType != Impl::TransactionBuy;
|
||||
return !buying();
|
||||
}
|
||||
|
||||
bool LLCurrencyUIManager::canBuy()
|
||||
{
|
||||
return impl.mTransactionType == Impl::TransactionNone
|
||||
&& impl.hasEstimate()
|
||||
&& impl.mUserCurrencyBuy > 0;
|
||||
return !inProcess() && impl.hasEstimate() && impl.mUserCurrencyBuy > 0;
|
||||
}
|
||||
|
||||
bool LLCurrencyUIManager::buying()
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ public:
|
|||
|
||||
void refreshUI();
|
||||
|
||||
void startTransaction(TransactionType type, const LLXMLRPCValue& params);
|
||||
void startTransaction(TransactionType type, const LLSD& params);
|
||||
bool checkTransaction();
|
||||
|
||||
void tellUserError(const std::string& message, const std::string& uri);
|
||||
|
|
@ -399,8 +399,7 @@ void LLFloaterBuyLandUI::updateParcelInfo()
|
|||
if (region)
|
||||
{
|
||||
S32 max_tasks_per_region = (S32)region->getMaxTasks();
|
||||
mParcelSupportedObjects = llmin(
|
||||
mParcelSupportedObjects, max_tasks_per_region);
|
||||
mParcelSupportedObjects = llmin(mParcelSupportedObjects, max_tasks_per_region);
|
||||
}
|
||||
|
||||
mParcelSoldWithObjects = parcel->getSellWithObjects();
|
||||
|
|
@ -492,14 +491,13 @@ void LLFloaterBuyLandUI::updateParcelInfo()
|
|||
void LLFloaterBuyLandUI::updateCovenantInfo()
|
||||
{
|
||||
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
|
||||
if(!region) return;
|
||||
if (!region)
|
||||
return;
|
||||
|
||||
U8 sim_access = region->getSimAccess();
|
||||
std::string rating = LLViewerRegion::accessToString(sim_access);
|
||||
|
||||
LLTextBox* region_name = getChild<LLTextBox>("region_name_text");
|
||||
if (region_name)
|
||||
{
|
||||
std::string region_name_txt = region->getName() + " ("+rating +")";
|
||||
region_name->setText(region_name_txt);
|
||||
|
||||
|
|
@ -523,54 +521,26 @@ void LLFloaterBuyLandUI::updateCovenantInfo()
|
|||
default:
|
||||
rating_icon->setValue(getString("icon_M"));
|
||||
}
|
||||
}
|
||||
|
||||
LLTextBox* region_type = getChild<LLTextBox>("region_type_text");
|
||||
if (region_type)
|
||||
{
|
||||
region_type->setText(region->getLocalizedSimProductName());
|
||||
region_type->setToolTip(region->getLocalizedSimProductName());
|
||||
}
|
||||
|
||||
LLTextBox* resellable_clause = getChild<LLTextBox>("resellable_clause");
|
||||
if (resellable_clause)
|
||||
{
|
||||
if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL))
|
||||
{
|
||||
resellable_clause->setText(getString("can_not_resell"));
|
||||
}
|
||||
else
|
||||
{
|
||||
resellable_clause->setText(getString("can_resell"));
|
||||
}
|
||||
}
|
||||
const char* can_resell = region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL) ? "can_not_resell" : "can_resell";
|
||||
resellable_clause->setText(getString(can_resell));
|
||||
|
||||
LLTextBox* changeable_clause = getChild<LLTextBox>("changeable_clause");
|
||||
if (changeable_clause)
|
||||
{
|
||||
if (region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES))
|
||||
{
|
||||
changeable_clause->setText(getString("can_change"));
|
||||
}
|
||||
else
|
||||
{
|
||||
changeable_clause->setText(getString("can_not_change"));
|
||||
}
|
||||
}
|
||||
const char* can_change = region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES) ? "can_change" : "can_not_change";
|
||||
changeable_clause->setText(getString(can_change));
|
||||
|
||||
LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant");
|
||||
if(check)
|
||||
{
|
||||
check->set(false);
|
||||
check->setEnabled(true);
|
||||
check->setCommitCallback(onChangeAgreeCovenant, this);
|
||||
}
|
||||
|
||||
LLTextBox* box = getChild<LLTextBox>("covenant_text");
|
||||
if(box)
|
||||
{
|
||||
box->setVisible(false);
|
||||
}
|
||||
|
||||
// send EstateCovenantInfo message
|
||||
LLMessageSystem *msg = gMessageSystem;
|
||||
|
|
@ -584,10 +554,9 @@ void LLFloaterBuyLandUI::updateCovenantInfo()
|
|||
// static
|
||||
void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data)
|
||||
{
|
||||
LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)user_data;
|
||||
if(self)
|
||||
if (user_data)
|
||||
{
|
||||
self->refreshUI();
|
||||
((LLFloaterBuyLandUI*)user_data)->refreshUI();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -626,13 +595,13 @@ void LLFloaterBuyLandUI::updateFloaterEstateName(const std::string& name)
|
|||
void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text)
|
||||
{
|
||||
LLTextBox* editor = getChild<LLTextBox>("covenant_timestamp_text");
|
||||
if (editor) editor->setText(text);
|
||||
editor->setText(text);
|
||||
}
|
||||
|
||||
void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name)
|
||||
{
|
||||
LLTextBox* box = getChild<LLTextBox>("estate_owner_text");
|
||||
if (box) box->setText(name);
|
||||
box->setText(name);
|
||||
}
|
||||
|
||||
void LLFloaterBuyLandUI::updateWebSiteInfo()
|
||||
|
|
@ -640,9 +609,10 @@ void LLFloaterBuyLandUI::updateWebSiteInfo()
|
|||
S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea;
|
||||
S32 askCurrencyBuy = mCurrency.getAmount();
|
||||
|
||||
if (mTransaction && mTransactionType == TransactionPreflight
|
||||
&& mPreflightAskBillableArea == askBillableArea
|
||||
&& mPreflightAskCurrencyBuy == askCurrencyBuy)
|
||||
if (mTransaction &&
|
||||
mTransactionType == TransactionPreflight &&
|
||||
mPreflightAskBillableArea == askBillableArea &&
|
||||
mPreflightAskCurrencyBuy == askCurrencyBuy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -664,27 +634,21 @@ void LLFloaterBuyLandUI::updateWebSiteInfo()
|
|||
mSiteCurrencyEstimatedCost = 0;
|
||||
#endif
|
||||
|
||||
LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
|
||||
keywordArgs.appendString("agentId", gAgent.getID().asString());
|
||||
keywordArgs.appendString(
|
||||
"secureSessionId",
|
||||
gAgent.getSecureSessionID().asString());
|
||||
keywordArgs.appendString("language", LLUI::getLanguage());
|
||||
keywordArgs.appendInt("billableArea", mPreflightAskBillableArea);
|
||||
keywordArgs.appendInt("currencyBuy", mPreflightAskCurrencyBuy);
|
||||
|
||||
LLXMLRPCValue params = LLXMLRPCValue::createArray();
|
||||
params.append(keywordArgs);
|
||||
LLSD params = LLSD::emptyMap();
|
||||
params["agentId"] = gAgent.getID().asString();
|
||||
params["secureSessionId"] = gAgent.getSecureSessionID().asString();
|
||||
params["language"] = LLUI::getLanguage();
|
||||
params["billableArea"] = mPreflightAskBillableArea;
|
||||
params["currencyBuy"] = mPreflightAskCurrencyBuy;
|
||||
|
||||
startTransaction(TransactionPreflight, params);
|
||||
}
|
||||
|
||||
void LLFloaterBuyLandUI::finishWebSiteInfo()
|
||||
{
|
||||
const LLSD& result = mTransaction->response();
|
||||
|
||||
LLXMLRPCValue result = mTransaction->responseValue();
|
||||
|
||||
mSiteValid = result["success"].asBool();
|
||||
mSiteValid = result["success"].asBoolean();
|
||||
if (!mSiteValid)
|
||||
{
|
||||
tellUserError(
|
||||
|
|
@ -694,31 +658,30 @@ void LLFloaterBuyLandUI::finishWebSiteInfo()
|
|||
return;
|
||||
}
|
||||
|
||||
LLXMLRPCValue membership = result["membership"];
|
||||
mSiteMembershipUpgrade = membership["upgrade"].asBool();
|
||||
const LLSD& membership = result["membership"];
|
||||
mSiteMembershipUpgrade = membership["upgrade"].asBoolean();
|
||||
mSiteMembershipAction = membership["action"].asString();
|
||||
mSiteMembershipPlanIDs.clear();
|
||||
mSiteMembershipPlanNames.clear();
|
||||
LLXMLRPCValue levels = membership["levels"];
|
||||
for (LLXMLRPCValue level = levels.rewind();
|
||||
level.isValid();
|
||||
level = levels.next())
|
||||
const LLSD& levels = membership["levels"];
|
||||
for (auto it = levels.beginArray(); it != levels.endArray(); ++it)
|
||||
{
|
||||
const LLSD& level = *it;
|
||||
mSiteMembershipPlanIDs.push_back(level["id"].asString());
|
||||
mSiteMembershipPlanNames.push_back(level["description"].asString());
|
||||
}
|
||||
mUserPlanChoice = 0;
|
||||
|
||||
LLXMLRPCValue landUse = result["landUse"];
|
||||
mSiteLandUseUpgrade = landUse["upgrade"].asBool();
|
||||
const LLSD& landUse = result["landUse"];
|
||||
mSiteLandUseUpgrade = landUse["upgrade"].asBoolean();
|
||||
mSiteLandUseAction = landUse["action"].asString();
|
||||
|
||||
LLXMLRPCValue currency = result["currency"];
|
||||
if (currency["estimatedCost"].isValid())
|
||||
const LLSD& currency = result["currency"];
|
||||
if (currency.has("estimatedCost"))
|
||||
{
|
||||
mCurrency.setUSDEstimate(currency["estimatedCost"].asInt());
|
||||
mCurrency.setUSDEstimate(currency["estimatedCost"].asInteger());
|
||||
}
|
||||
if (currency["estimatedLocalCost"].isValid())
|
||||
if (currency.has("estimatedLocalCost"))
|
||||
{
|
||||
mCurrency.setLocalEstimate(currency["estimatedLocalCost"].asString());
|
||||
}
|
||||
|
|
@ -760,35 +723,30 @@ void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password)
|
|||
}
|
||||
}
|
||||
|
||||
LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
|
||||
keywordArgs.appendString("agentId", gAgent.getID().asString());
|
||||
keywordArgs.appendString(
|
||||
"secureSessionId",
|
||||
gAgent.getSecureSessionID().asString());
|
||||
keywordArgs.appendString("language", LLUI::getLanguage());
|
||||
keywordArgs.appendString("levelId", newLevel);
|
||||
keywordArgs.appendInt("billableArea",
|
||||
mIsForGroup ? 0 : mParcelBillableArea);
|
||||
keywordArgs.appendInt("currencyBuy", mCurrency.getAmount());
|
||||
keywordArgs.appendInt("estimatedCost", mCurrency.getUSDEstimate());
|
||||
keywordArgs.appendString("estimatedLocalCost", mCurrency.getLocalEstimate());
|
||||
keywordArgs.appendString("confirm", mSiteConfirm);
|
||||
LLSD params = LLSD::emptyMap();
|
||||
params["agentId"] = gAgent.getID().asString();
|
||||
params["secureSessionId"] = gAgent.getSecureSessionID().asString();
|
||||
params["language"] = LLUI::getLanguage();
|
||||
params["levelId"] = newLevel;
|
||||
params["billableArea"] = mIsForGroup ? 0 : mParcelBillableArea;
|
||||
params["currencyBuy"] = mCurrency.getAmount();
|
||||
params["estimatedCost"] = mCurrency.getUSDEstimate();
|
||||
params["estimatedLocalCost"] = mCurrency.getLocalEstimate();
|
||||
params["confirm"] = mSiteConfirm;
|
||||
|
||||
if (!password.empty())
|
||||
{
|
||||
keywordArgs.appendString("password", password);
|
||||
params["password"] = password;
|
||||
}
|
||||
|
||||
LLXMLRPCValue params = LLXMLRPCValue::createArray();
|
||||
params.append(keywordArgs);
|
||||
|
||||
startTransaction(TransactionBuy, params);
|
||||
}
|
||||
|
||||
void LLFloaterBuyLandUI::finishWebSitePrep()
|
||||
{
|
||||
LLXMLRPCValue result = mTransaction->responseValue();
|
||||
const LLSD& result = mTransaction->response();
|
||||
|
||||
bool success = result["success"].asBool();
|
||||
bool success = result["success"].asBoolean();
|
||||
if (!success)
|
||||
{
|
||||
tellUserError(
|
||||
|
|
@ -850,7 +808,7 @@ void LLFloaterBuyLandUI::updateGroupName(const LLUUID& id,
|
|||
}
|
||||
}
|
||||
|
||||
void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params)
|
||||
void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLSD& params)
|
||||
{
|
||||
delete mTransaction;
|
||||
mTransaction = NULL;
|
||||
|
|
@ -878,12 +836,7 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa
|
|||
return;
|
||||
}
|
||||
|
||||
mTransaction = new LLXMLRPCTransaction(
|
||||
transaction_uri,
|
||||
method,
|
||||
params,
|
||||
false /* don't use gzip */
|
||||
);
|
||||
mTransaction = new LLXMLRPCTransaction(transaction_uri, method, params);
|
||||
}
|
||||
|
||||
bool LLFloaterBuyLandUI::checkTransaction()
|
||||
|
|
|
|||
|
|
@ -33,9 +33,6 @@
|
|||
#include "stringize.h"
|
||||
#include "llsdserialize.h"
|
||||
|
||||
// llmessage (!)
|
||||
#include "llfiltersd2xmlrpc.h" // for xml_escape_string()
|
||||
|
||||
// login
|
||||
#include "lllogin.h"
|
||||
|
||||
|
|
@ -612,7 +609,7 @@ std::string construct_start_string()
|
|||
<< position[VX] << "&"
|
||||
<< position[VY] << "&"
|
||||
<< position[VZ]);
|
||||
start = xml_escape_string(unescaped_start);
|
||||
start = LLStringFn::xml_encode(unescaped_start, true);
|
||||
break;
|
||||
}
|
||||
case LLSLURL::HOME_LOCATION:
|
||||
|
|
|
|||
|
|
@ -32,13 +32,15 @@
|
|||
#include "llpanellogin.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewernetwork.h"
|
||||
#include "llfiltersd2xmlrpc.h"
|
||||
|
||||
#include "curl/curl.h"
|
||||
|
||||
const char* LLSLURL::SLURL_HTTP_SCHEME = "http";
|
||||
const char* LLSLURL::SLURL_HTTPS_SCHEME = "https";
|
||||
const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife";
|
||||
const char* LLSLURL::SLURL_SECONDLIFE_PATH = "secondlife";
|
||||
const char* LLSLURL::SLURL_COM = "slurl.com";
|
||||
|
||||
// For DnD - even though www.slurl.com redirects to slurl.com in a browser, you can copy and drag
|
||||
// text with www.slurl.com or a link explicitly pointing at www.slurl.com so testing for this
|
||||
// version is required also.
|
||||
|
|
@ -437,7 +439,7 @@ std::string LLSLURL::getLoginString() const
|
|||
LL_WARNS("AppInit") << "Unexpected SLURL type (" << (int)mType << ")for login string" << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
return xml_escape_string(unescaped_start.str());
|
||||
return LLStringFn::xml_encode(unescaped_start.str(), true);
|
||||
}
|
||||
|
||||
bool LLSLURL::operator ==(const LLSLURL& rhs)
|
||||
|
|
|
|||
|
|
@ -76,37 +76,37 @@ LLVersionInfo::~LLVersionInfo()
|
|||
{
|
||||
}
|
||||
|
||||
S32 LLVersionInfo::getMajor()
|
||||
S32 LLVersionInfo::getMajor() const
|
||||
{
|
||||
return LL_VIEWER_VERSION_MAJOR;
|
||||
}
|
||||
|
||||
S32 LLVersionInfo::getMinor()
|
||||
S32 LLVersionInfo::getMinor() const
|
||||
{
|
||||
return LL_VIEWER_VERSION_MINOR;
|
||||
}
|
||||
|
||||
S32 LLVersionInfo::getPatch()
|
||||
S32 LLVersionInfo::getPatch() const
|
||||
{
|
||||
return LL_VIEWER_VERSION_PATCH;
|
||||
}
|
||||
|
||||
U64 LLVersionInfo::getBuild()
|
||||
U64 LLVersionInfo::getBuild() const
|
||||
{
|
||||
return LL_VIEWER_VERSION_BUILD;
|
||||
}
|
||||
|
||||
std::string LLVersionInfo::getVersion()
|
||||
std::string LLVersionInfo::getVersion() const
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
std::string LLVersionInfo::getShortVersion()
|
||||
std::string LLVersionInfo::getShortVersion() const
|
||||
{
|
||||
return short_version;
|
||||
}
|
||||
|
||||
std::string LLVersionInfo::getChannelAndVersion()
|
||||
std::string LLVersionInfo::getChannelAndVersion() const
|
||||
{
|
||||
if (mVersionChannel.empty())
|
||||
{
|
||||
|
|
@ -117,7 +117,7 @@ std::string LLVersionInfo::getChannelAndVersion()
|
|||
return mVersionChannel;
|
||||
}
|
||||
|
||||
std::string LLVersionInfo::getChannel()
|
||||
std::string LLVersionInfo::getChannel() const
|
||||
{
|
||||
return mWorkingChannelName;
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ void LLVersionInfo::resetChannel(const std::string& channel)
|
|||
mVersionChannel.clear(); // Reset version and channel string til next use.
|
||||
}
|
||||
|
||||
LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity()
|
||||
LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() const
|
||||
{
|
||||
ViewerMaturity maturity;
|
||||
|
||||
|
|
@ -166,12 +166,12 @@ LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity()
|
|||
}
|
||||
|
||||
|
||||
std::string LLVersionInfo::getBuildConfig()
|
||||
std::string LLVersionInfo::getBuildConfig() const
|
||||
{
|
||||
return build_configuration;
|
||||
}
|
||||
|
||||
std::string LLVersionInfo::getReleaseNotes()
|
||||
std::string LLVersionInfo::getReleaseNotes() const
|
||||
{
|
||||
return mReleaseNotes;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,38 +52,38 @@ public:
|
|||
~LLVersionInfo();
|
||||
|
||||
/// return the major version number as an integer
|
||||
S32 getMajor();
|
||||
S32 getMajor() const;
|
||||
|
||||
/// return the minor version number as an integer
|
||||
S32 getMinor();
|
||||
S32 getMinor() const;
|
||||
|
||||
/// return the patch version number as an integer
|
||||
S32 getPatch();
|
||||
S32 getPatch() const;
|
||||
|
||||
/// return the build number as an integer
|
||||
U64 getBuild();
|
||||
U64 getBuild() const;
|
||||
|
||||
/// return the full viewer version as a string like "2.0.0.200030"
|
||||
std::string getVersion();
|
||||
std::string getVersion() const;
|
||||
|
||||
/// return the viewer version as a string like "2.0.0"
|
||||
std::string getShortVersion();
|
||||
std::string getShortVersion() const;
|
||||
|
||||
/// return the viewer version and channel as a string
|
||||
/// like "Second Life Release 2.0.0.200030"
|
||||
std::string getChannelAndVersion();
|
||||
std::string getChannelAndVersion() const;
|
||||
|
||||
/// return the channel name, e.g. "Second Life"
|
||||
std::string getChannel();
|
||||
std::string getChannel() const;
|
||||
|
||||
/// return the CMake build type
|
||||
std::string getBuildConfig();
|
||||
std::string getBuildConfig() const;
|
||||
|
||||
/// reset the channel name used by the viewer.
|
||||
void resetChannel(const std::string& channel);
|
||||
|
||||
/// return the bit width of an address
|
||||
S32 getAddressSize() { return ADDRESS_SIZE; }
|
||||
S32 getAddressSize() const { return ADDRESS_SIZE; }
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
|
@ -92,11 +92,11 @@ public:
|
|||
BETA_VIEWER,
|
||||
RELEASE_VIEWER
|
||||
} ViewerMaturity;
|
||||
ViewerMaturity getViewerMaturity();
|
||||
ViewerMaturity getViewerMaturity() const;
|
||||
|
||||
/// get the release-notes URL, once it becomes available -- until then,
|
||||
/// return empty string
|
||||
std::string getReleaseNotes();
|
||||
std::string getReleaseNotes() const;
|
||||
|
||||
private:
|
||||
std::string version;
|
||||
|
|
@ -107,7 +107,7 @@ private:
|
|||
std::string mWorkingChannelName;
|
||||
// Storage for the "version and channel" string.
|
||||
// This will get reset too.
|
||||
std::string mVersionChannel;
|
||||
mutable std::string mVersionChannel;
|
||||
std::string build_configuration;
|
||||
std::string mReleaseNotes;
|
||||
// Store unique_ptrs to the next couple things so we don't have to explain
|
||||
|
|
|
|||
|
|
@ -39,12 +39,6 @@
|
|||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/range.hpp> // boost::begin(), boost::end()
|
||||
|
||||
#ifdef LL_USESYSTEMLIBS
|
||||
#include <xmlrpc.h>
|
||||
#else
|
||||
#include <xmlrpc-epi/xmlrpc.h>
|
||||
#endif
|
||||
|
||||
#include "curl/curl.h"
|
||||
|
||||
// other Linden headers
|
||||
|
|
@ -178,13 +172,6 @@ public:
|
|||
|
||||
static const CURLcodeMapper sCURLcodeMapper;
|
||||
|
||||
LLXMLRPCListener::LLXMLRPCListener(const std::string& pumpname):
|
||||
mBoundListener(LLEventPumps::instance().
|
||||
obtain(pumpname).
|
||||
listen("LLXMLRPCListener", boost::bind(&LLXMLRPCListener::process, this, _1)))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture an outstanding LLXMLRPCTransaction and poll it periodically until
|
||||
* done.
|
||||
|
|
@ -213,38 +200,20 @@ public:
|
|||
mMethod(command["method"]),
|
||||
mReplyPump(command["reply"])
|
||||
{
|
||||
// LL_ERRS if any of these are missing
|
||||
const char* required[] = { "uri", "method", "reply" };
|
||||
// optional: "options" (array of string)
|
||||
// Validate the request
|
||||
std::set<std::string> missing;
|
||||
for (const char** ri = boost::begin(required); ri != boost::end(required); ++ri)
|
||||
// LL_ERRS if any of these keys are missing or empty
|
||||
if (mUri.empty() || mMethod.empty() || mReplyPump.empty())
|
||||
{
|
||||
// If the command does not contain this required entry, add it to 'missing'.
|
||||
if (! command.has(*ri))
|
||||
{
|
||||
missing.insert(*ri);
|
||||
}
|
||||
}
|
||||
if (! missing.empty())
|
||||
{
|
||||
LL_ERRS("LLXMLRPCListener") << mMethod << " request missing params: ";
|
||||
const char* separator = "";
|
||||
for (std::set<std::string>::const_iterator mi(missing.begin()), mend(missing.end());
|
||||
mi != mend; ++mi)
|
||||
{
|
||||
LL_CONT << separator << *mi;
|
||||
separator = ", ";
|
||||
}
|
||||
LL_CONT << LL_ENDL;
|
||||
LL_ERRS("LLXMLRPCListener")
|
||||
<< "Some params are missing: "
|
||||
<< "reply: '" << mReplyPump << "', "
|
||||
<< "method: '" << mMethod << "', "
|
||||
<< "uri: '" << mUri << "'"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
// Build the XMLRPC request.
|
||||
XMLRPC_REQUEST request = XMLRPC_RequestNew();
|
||||
XMLRPC_RequestSetMethodName(request, mMethod.c_str());
|
||||
XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
|
||||
XMLRPC_VALUE xparams = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
|
||||
LLSD params(command["params"]);
|
||||
LLSD request_params = LLSD::emptyMap();
|
||||
|
||||
LLSD params = command.get("params");
|
||||
if (params.isMap())
|
||||
{
|
||||
for (LLSD::map_const_iterator pi(params.beginMap()), pend(params.endMap());
|
||||
|
|
@ -252,44 +221,33 @@ public:
|
|||
{
|
||||
std::string name(pi->first);
|
||||
LLSD param(pi->second);
|
||||
if (param.isString())
|
||||
switch (param.type())
|
||||
{
|
||||
XMLRPC_VectorAppendString(xparams, name.c_str(), param.asString().c_str(), 0);
|
||||
}
|
||||
else if (param.isInteger() || param.isBoolean())
|
||||
{
|
||||
XMLRPC_VectorAppendInt(xparams, name.c_str(), param.asInteger());
|
||||
}
|
||||
else if (param.isReal())
|
||||
{
|
||||
XMLRPC_VectorAppendDouble(xparams, name.c_str(), param.asReal());
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("LLXMLRPCListener") << mMethod << " request param "
|
||||
<< name << " has unknown type: " << param << LL_ENDL;
|
||||
case LLSD::TypeString:
|
||||
case LLSD::TypeInteger:
|
||||
case LLSD::TypeReal:
|
||||
request_params.insert(name, param);
|
||||
break;
|
||||
case LLSD::TypeBoolean:
|
||||
request_params.insert(name, param.asInteger());
|
||||
break;
|
||||
default:
|
||||
LL_ERRS("LLXMLRPCListener") << mMethod
|
||||
<< " request param '" << name << "' has unknown type: " << param << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
LLSD options(command["options"]);
|
||||
|
||||
LLSD options = command.get("options");
|
||||
if (options.isArray())
|
||||
{
|
||||
XMLRPC_VALUE xoptions = XMLRPC_CreateVector("options", xmlrpc_vector_array);
|
||||
for (LLSD::array_const_iterator oi(options.beginArray()), oend(options.endArray());
|
||||
oi != oend; ++oi)
|
||||
{
|
||||
XMLRPC_VectorAppendString(xoptions, NULL, oi->asString().c_str(), 0);
|
||||
request_params.insert("options", options);
|
||||
}
|
||||
XMLRPC_AddValueToVector(xparams, xoptions);
|
||||
}
|
||||
XMLRPC_RequestSetData(request, xparams);
|
||||
|
||||
mTransaction.reset(new LLXMLRPCTransaction(mUri, request, true, command.has("http_params")? LLSD(command["http_params"]) : LLSD()));
|
||||
LLSD http_params = command.get("http_params");
|
||||
mTransaction.reset(new LLXMLRPCTransaction(mUri, mMethod, request_params, http_params));
|
||||
mPreviousStatus = mTransaction->status(NULL);
|
||||
|
||||
// Free the XMLRPC_REQUEST object and the attached data values.
|
||||
XMLRPC_RequestFree(request, 1);
|
||||
|
||||
// Now ensure that we get regular callbacks to poll for completion.
|
||||
mBoundListener =
|
||||
LLEventPumps::instance().
|
||||
|
|
@ -367,10 +325,8 @@ public:
|
|||
// Given 'message', need we care?
|
||||
if (status == LLXMLRPCTransaction::StatusComplete)
|
||||
{
|
||||
// Success! Parse data.
|
||||
std::string status_string(data["status"]);
|
||||
data["responses"] = parseResponse(status_string);
|
||||
data["status"] = status_string;
|
||||
// Success! Retrieve response data.
|
||||
data["responses"] = mTransaction->response();
|
||||
}
|
||||
|
||||
// whether successful or not, send reply on requested LLEventPump
|
||||
|
|
@ -388,159 +344,6 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
/// Derived from LLUserAuth::parseResponse() and parseOptionInto()
|
||||
LLSD parseResponse(std::string& status_string)
|
||||
{
|
||||
// Extract every member into data["responses"] (a map of string
|
||||
// values).
|
||||
XMLRPC_REQUEST response = mTransaction->response();
|
||||
if (! response)
|
||||
{
|
||||
LL_DEBUGS("LLXMLRPCListener") << "No response" << LL_ENDL;
|
||||
return LLSD();
|
||||
}
|
||||
|
||||
XMLRPC_VALUE param = XMLRPC_RequestGetData(response);
|
||||
if (! param)
|
||||
{
|
||||
LL_DEBUGS("LLXMLRPCListener") << "Response contains no data" << LL_ENDL;
|
||||
return LLSD();
|
||||
}
|
||||
|
||||
// Now, parse everything
|
||||
return parseValues(status_string, "", param);
|
||||
}
|
||||
|
||||
LLSD parseValue(std::string& status_string, const std::string& key, const std::string& key_pfx, XMLRPC_VALUE param)
|
||||
{
|
||||
LLSD response;
|
||||
|
||||
XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(param);
|
||||
switch (type)
|
||||
{
|
||||
case xmlrpc_type_empty:
|
||||
LL_INFOS("LLXMLRPCListener") << "Empty result for key " << key_pfx << key << LL_ENDL;
|
||||
break;
|
||||
case xmlrpc_type_base64:
|
||||
{
|
||||
S32 len = XMLRPC_GetValueStringLen(param);
|
||||
const char* buf = XMLRPC_GetValueBase64(param);
|
||||
if ((len > 0) && buf)
|
||||
{
|
||||
// During implementation this code was not tested
|
||||
// If you encounter this, please make sure this is correct,
|
||||
// then remove llassert
|
||||
llassert(0);
|
||||
|
||||
LLSD::Binary data;
|
||||
data.resize(len);
|
||||
memcpy((void*)&data[0], (void*)buf, len);
|
||||
response = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("LLXMLRPCListener") << "Potentially malformed xmlrpc_type_base64 for key "
|
||||
<< key_pfx << key << LL_ENDL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_boolean:
|
||||
{
|
||||
response = LLSD::Boolean(XMLRPC_GetValueBoolean(param));
|
||||
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_datetime:
|
||||
{
|
||||
std::string iso8601_date(XMLRPC_GetValueDateTime_ISO8601(param));
|
||||
LL_DEBUGS("LLXMLRPCListener") << "val: " << iso8601_date << LL_ENDL;
|
||||
response = LLSD::Date(iso8601_date);
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_double:
|
||||
{
|
||||
response = LLSD::Real(XMLRPC_GetValueDouble(param));
|
||||
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_int:
|
||||
{
|
||||
response = LLSD::Integer(XMLRPC_GetValueInt(param));
|
||||
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_string:
|
||||
{
|
||||
response = LLSD::String(XMLRPC_GetValueString(param));
|
||||
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_mixed:
|
||||
case xmlrpc_type_array:
|
||||
{
|
||||
// We expect this to be an array of submaps. Walk the array,
|
||||
// recursively parsing each submap and collecting them.
|
||||
LLSD array;
|
||||
int i = 0; // for descriptive purposes
|
||||
for (XMLRPC_VALUE row = XMLRPC_VectorRewind(param); row;
|
||||
row = XMLRPC_VectorNext(param), ++i)
|
||||
{
|
||||
// Recursive call. For the lower-level key_pfx, if 'key'
|
||||
// is "foo", pass "foo[0]:", then "foo[1]:", etc. In the
|
||||
// nested call, a subkey "bar" will then be logged as
|
||||
// "foo[0]:bar", and so forth.
|
||||
// Parse the scalar subkey/value pairs from this array
|
||||
// entry into a temp submap. Collect such submaps in 'array'.
|
||||
|
||||
array.append(parseValue(status_string, "",
|
||||
STRINGIZE(key_pfx << key << '[' << i << "]:"),
|
||||
row));
|
||||
}
|
||||
// Having collected an 'array' of 'submap's, insert that whole
|
||||
// 'array' as the value of this 'key'.
|
||||
response = array;
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_struct:
|
||||
{
|
||||
response = parseValues(status_string,
|
||||
STRINGIZE(key_pfx << key << ':'),
|
||||
param);
|
||||
break;
|
||||
}
|
||||
case xmlrpc_type_none: // Not expected
|
||||
default:
|
||||
// whoops - unrecognized type
|
||||
LL_WARNS("LLXMLRPCListener") << "Unhandled xmlrpc type " << type << " for key "
|
||||
<< key_pfx << key << LL_ENDL;
|
||||
response = STRINGIZE("<bad XMLRPC type " << type << '>');
|
||||
status_string = "BadType";
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse key/value pairs from a given XMLRPC_VALUE into an LLSD map.
|
||||
* @param key_pfx Used to describe a given key in log messages. At top
|
||||
* level, pass "". When parsing an options array, pass the top-level key
|
||||
* name of the array plus the index of the array entry; to this we'll
|
||||
* append the subkey of interest.
|
||||
* @param param XMLRPC_VALUE iterator. At top level, pass
|
||||
* XMLRPC_RequestGetData(XMLRPC_REQUEST).
|
||||
*/
|
||||
LLSD parseValues(std::string& status_string, const std::string& key_pfx, XMLRPC_VALUE param)
|
||||
{
|
||||
LLSD responses;
|
||||
for (XMLRPC_VALUE current = XMLRPC_VectorRewind(param); current;
|
||||
current = XMLRPC_VectorNext(param))
|
||||
{
|
||||
std::string key(XMLRPC_GetValueID(current));
|
||||
LL_DEBUGS("LLXMLRPCListener") << "key: " << key_pfx << key << LL_ENDL;
|
||||
responses.insert(key, parseValue(status_string, key, key_pfx, current));
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
const LLReqID mReqID;
|
||||
const std::string mUri;
|
||||
const std::string mMethod;
|
||||
|
|
@ -550,11 +353,18 @@ private:
|
|||
LLXMLRPCTransaction::EStatus mPreviousStatus; // To detect state changes.
|
||||
};
|
||||
|
||||
bool LLXMLRPCListener::process(const LLSD& command)
|
||||
LLXMLRPCListener::LLXMLRPCListener(const std::string& pumpname)
|
||||
: mBoundListener(LLEventPumps::instance().obtain(pumpname).listen
|
||||
(
|
||||
"LLXMLRPCListener",
|
||||
[&](const LLSD& command) -> bool
|
||||
{
|
||||
// Allocate a new heap Poller, but do not save a pointer to it. Poller
|
||||
// will check its own status and free itself on completion of the request.
|
||||
(new Poller(command));
|
||||
// conventional event listener return
|
||||
// Conventional event listener return
|
||||
return false;
|
||||
}
|
||||
))
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,6 @@ public:
|
|||
/// Specify the pump name on which to listen
|
||||
LLXMLRPCListener(const std::string& pumpname);
|
||||
|
||||
/// Handle request events on the event pump specified at construction time
|
||||
bool process(const LLSD& command);
|
||||
|
||||
private:
|
||||
LLTempBoundListener mBoundListener;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -42,22 +42,11 @@
|
|||
#include "bufferarray.h"
|
||||
#include "llversioninfo.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llxmlnode.h"
|
||||
#include "stringize.h"
|
||||
|
||||
// Have to include these last to avoid queue redefinition!
|
||||
|
||||
#ifdef LL_USESYSTEMLIBS
|
||||
#include <xmlrpc.h>
|
||||
#else
|
||||
#include <xmlrpc-epi/xmlrpc.h>
|
||||
#endif
|
||||
// <xmlrpc-epi/queue.h> contains a harmful #define queue xmlrpc_queue. This
|
||||
// breaks any use of std::queue. Ditch that #define: if any of our code wants
|
||||
// to reference xmlrpc_queue, let it reference it directly.
|
||||
#if defined(queue)
|
||||
#undef queue
|
||||
#endif
|
||||
|
||||
#include "llappviewer.h"
|
||||
#include "lltrans.h"
|
||||
|
||||
|
|
@ -75,111 +64,6 @@ namespace boost
|
|||
// nothing.
|
||||
static LLXMLRPCListener listener("LLXMLRPCTransaction");
|
||||
|
||||
LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const
|
||||
{
|
||||
return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id));
|
||||
}
|
||||
|
||||
std::string LLXMLRPCValue::asString() const
|
||||
{
|
||||
const char* s = XMLRPC_GetValueString(mV);
|
||||
return s ? s : "";
|
||||
}
|
||||
|
||||
int LLXMLRPCValue::asInt() const { return XMLRPC_GetValueInt(mV); }
|
||||
bool LLXMLRPCValue::asBool() const { return XMLRPC_GetValueBoolean(mV) != 0; }
|
||||
double LLXMLRPCValue::asDouble() const { return XMLRPC_GetValueDouble(mV); }
|
||||
|
||||
LLXMLRPCValue LLXMLRPCValue::rewind()
|
||||
{
|
||||
return LLXMLRPCValue(XMLRPC_VectorRewind(mV));
|
||||
}
|
||||
|
||||
LLXMLRPCValue LLXMLRPCValue::next()
|
||||
{
|
||||
return LLXMLRPCValue(XMLRPC_VectorNext(mV));
|
||||
}
|
||||
|
||||
bool LLXMLRPCValue::isValid() const
|
||||
{
|
||||
return mV != NULL;
|
||||
}
|
||||
|
||||
LLXMLRPCValue LLXMLRPCValue::createArray()
|
||||
{
|
||||
return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_array));
|
||||
}
|
||||
|
||||
LLXMLRPCValue LLXMLRPCValue::createStruct()
|
||||
{
|
||||
return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_struct));
|
||||
}
|
||||
|
||||
|
||||
void LLXMLRPCValue::append(LLXMLRPCValue& v)
|
||||
{
|
||||
XMLRPC_AddValueToVector(mV, v.mV);
|
||||
}
|
||||
|
||||
void LLXMLRPCValue::appendString(const std::string& v)
|
||||
{
|
||||
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(NULL, v.c_str(), 0));
|
||||
}
|
||||
|
||||
void LLXMLRPCValue::appendInt(int v)
|
||||
{
|
||||
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(NULL, v));
|
||||
}
|
||||
|
||||
void LLXMLRPCValue::appendBool(bool v)
|
||||
{
|
||||
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(NULL, v));
|
||||
}
|
||||
|
||||
void LLXMLRPCValue::appendDouble(double v)
|
||||
{
|
||||
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(NULL, v));
|
||||
}
|
||||
|
||||
|
||||
void LLXMLRPCValue::append(const char* id, LLXMLRPCValue& v)
|
||||
{
|
||||
XMLRPC_SetValueID(v.mV, id, 0);
|
||||
XMLRPC_AddValueToVector(mV, v.mV);
|
||||
}
|
||||
|
||||
void LLXMLRPCValue::appendString(const char* id, const std::string& v)
|
||||
{
|
||||
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(id, v.c_str(), 0));
|
||||
}
|
||||
|
||||
void LLXMLRPCValue::appendInt(const char* id, int v)
|
||||
{
|
||||
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(id, v));
|
||||
}
|
||||
|
||||
void LLXMLRPCValue::appendBool(const char* id, bool v)
|
||||
{
|
||||
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(id, v));
|
||||
}
|
||||
|
||||
void LLXMLRPCValue::appendDouble(const char* id, double v)
|
||||
{
|
||||
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(id, v));
|
||||
}
|
||||
|
||||
void LLXMLRPCValue::cleanup()
|
||||
{
|
||||
XMLRPC_CleanupValue(mV);
|
||||
mV = NULL;
|
||||
}
|
||||
|
||||
XMLRPC_VALUE LLXMLRPCValue::getValue() const
|
||||
{
|
||||
return mV;
|
||||
}
|
||||
|
||||
|
||||
class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler
|
||||
{
|
||||
public:
|
||||
|
|
@ -192,6 +76,9 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
bool parseResponse(LLXMLNodePtr root);
|
||||
bool parseValue(LLSD& target, LLXMLNodePtr source);
|
||||
|
||||
LLXMLRPCTransaction::Impl *mImpl;
|
||||
LLCore::HttpRequest::ptr_t mRequest;
|
||||
};
|
||||
|
|
@ -213,26 +100,26 @@ public:
|
|||
LLCore::HttpHandle mPostH;
|
||||
|
||||
std::string mURI;
|
||||
|
||||
std::string mProxyAddress;
|
||||
|
||||
std::string mResponseText;
|
||||
XMLRPC_REQUEST mResponse;
|
||||
LLSD mResponseData;
|
||||
|
||||
std::string mCertStore;
|
||||
LLSD mErrorCertData;
|
||||
|
||||
Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams);
|
||||
Impl(const std::string& uri,
|
||||
const std::string& method, LLXMLRPCValue params, bool useGzip);
|
||||
~Impl();
|
||||
Impl
|
||||
(
|
||||
const std::string& uri,
|
||||
const std::string& method,
|
||||
const LLSD& params,
|
||||
const LLSD& httpParams
|
||||
);
|
||||
|
||||
bool process();
|
||||
|
||||
void setStatus(EStatus code, const std::string& message = "", const std::string& uri = "");
|
||||
void setHttpStatus(const LLCore::HttpStatus &status);
|
||||
|
||||
private:
|
||||
void init(XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams);
|
||||
};
|
||||
|
||||
LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request,
|
||||
|
|
@ -275,89 +162,113 @@ void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle,
|
|||
mImpl->setStatus(LLXMLRPCTransaction::StatusComplete);
|
||||
mImpl->mTransferStats = response->getTransferStats();
|
||||
|
||||
// the contents of a buffer array are potentially noncontiguous, so we
|
||||
// The contents of a buffer array are potentially noncontiguous, so we
|
||||
// will need to copy them into an contiguous block of memory for XMLRPC.
|
||||
LLCore::BufferArray *body = response->getBody();
|
||||
char * bodydata = new char[body->size()];
|
||||
mImpl->mResponseText.resize(body->size());
|
||||
|
||||
body->read(0, bodydata, body->size());
|
||||
body->read(0, mImpl->mResponseText.data(), body->size());
|
||||
|
||||
mImpl->mResponse = XMLRPC_REQUEST_FromXML(bodydata, static_cast<int>(body->size()), 0);
|
||||
|
||||
delete[] bodydata;
|
||||
|
||||
bool hasError = false;
|
||||
bool hasFault = false;
|
||||
int faultCode = 0;
|
||||
std::string faultString;
|
||||
|
||||
LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse));
|
||||
if (error.isValid())
|
||||
LLXMLNodePtr root;
|
||||
if (!LLXMLNode::parseBuffer(mImpl->mResponseText.data(), body->size(), root, nullptr))
|
||||
{
|
||||
hasError = true;
|
||||
faultCode = error["faultCode"].asInt();
|
||||
faultString = error["faultString"].asString();
|
||||
}
|
||||
else if (XMLRPC_ResponseIsFault(mImpl->mResponse))
|
||||
{
|
||||
hasFault = true;
|
||||
faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse);
|
||||
faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse);
|
||||
LL_WARNS() << "Failed parsing XML response; request URI: " << mImpl->mURI << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasError || hasFault)
|
||||
{
|
||||
mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
|
||||
if (!parseResponse(root))
|
||||
return;
|
||||
|
||||
LL_WARNS() << "LLXMLRPCTransaction XMLRPC "
|
||||
<< (hasError ? "error " : "fault ")
|
||||
<< faultCode << ": "
|
||||
<< faultString << LL_ENDL;
|
||||
LL_WARNS() << "LLXMLRPCTransaction request URI: "
|
||||
<< mImpl->mURI << LL_ENDL;
|
||||
LL_INFOS() << "XML response parsed successfully; request URI: " << mImpl->mURI << LL_ENDL;
|
||||
}
|
||||
|
||||
struct XMLTreeNode final : public LLSD::TreeNode
|
||||
{
|
||||
XMLTreeNode(const LLXMLNodePtr impl)
|
||||
: mImpl(impl)
|
||||
, mFirstChild(impl ? create(impl->getFirstChild()) : nullptr)
|
||||
, mNextSibling(impl ? create(impl->getNextSibling()) : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
static XMLTreeNode* create(LLXMLNodePtr node) { return node ? new XMLTreeNode(node) : nullptr; }
|
||||
|
||||
virtual bool hasName(const LLSD::String& name) const override { return mImpl && mImpl->hasName(name); }
|
||||
virtual LLSD::String getTextContents() const override { return mImpl ? mImpl->getTextContents() : LLStringUtil::null; }
|
||||
virtual TreeNode* getFirstChild() const override { return mFirstChild.get(); }
|
||||
virtual TreeNode* getNextSibling() const override { return mNextSibling.get(); }
|
||||
|
||||
private:
|
||||
const LLXMLNodePtr mImpl;
|
||||
const std::shared_ptr<XMLTreeNode> mFirstChild;
|
||||
const std::shared_ptr<XMLTreeNode> mNextSibling;
|
||||
};
|
||||
|
||||
bool LLXMLRPCTransaction::Handler::parseResponse(LLXMLNodePtr root)
|
||||
{
|
||||
// We have alreasy checked in LLXMLNode::parseBuffer()
|
||||
// that root contains exactly one child
|
||||
if (!root->hasName("methodResponse"))
|
||||
{
|
||||
LL_WARNS() << "Invalid root element in XML response; request URI: " << mImpl->mURI << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
LLXMLNodePtr first = root->getFirstChild();
|
||||
LLXMLNodePtr second = first->getFirstChild();
|
||||
if (!first->getNextSibling() && second && !second->getNextSibling())
|
||||
{
|
||||
if (first->hasName("fault"))
|
||||
{
|
||||
LLSD fault;
|
||||
if (parseValue(fault, second) &&
|
||||
fault.isMap() && fault.has("faultCode") && fault.has("faultString"))
|
||||
{
|
||||
LL_WARNS() << "Request failed;"
|
||||
<< " faultCode: '" << fault.get("faultCode").asString() << "',"
|
||||
<< " faultString: '" << fault.get("faultString").asString() << "',"
|
||||
<< " request URI: " << mImpl->mURI << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (first->hasName("params") &&
|
||||
second->hasName("param") && !second->getNextSibling())
|
||||
{
|
||||
LLXMLNodePtr third = second->getFirstChild();
|
||||
if (third && !third->getNextSibling() && parseValue(mImpl->mResponseData, third))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LL_WARNS() << "Invalid response format; request URI: " << mImpl->mURI << LL_ENDL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLXMLRPCTransaction::Handler::parseValue(LLSD& target, LLXMLNodePtr source)
|
||||
{
|
||||
XMLTreeNode tn(source);
|
||||
return target.fromXMLRPCValue(&tn);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
|
||||
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
|
||||
XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams)
|
||||
: mHttpRequest(),
|
||||
mStatus(LLXMLRPCTransaction::StatusNotStarted),
|
||||
mURI(uri),
|
||||
mResponse(0)
|
||||
{
|
||||
init(request, useGzip, httpParams);
|
||||
}
|
||||
|
||||
|
||||
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
|
||||
const std::string& method, LLXMLRPCValue params, bool useGzip)
|
||||
: mHttpRequest(),
|
||||
mStatus(LLXMLRPCTransaction::StatusNotStarted),
|
||||
mURI(uri),
|
||||
mResponse(0)
|
||||
{
|
||||
XMLRPC_REQUEST request = XMLRPC_RequestNew();
|
||||
XMLRPC_RequestSetMethodName(request, method.c_str());
|
||||
XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
|
||||
XMLRPC_RequestSetData(request, params.getValue());
|
||||
|
||||
init(request, useGzip, LLSD());
|
||||
// DEV-28398: without this XMLRPC_RequestFree() call, it looks as though
|
||||
// the 'request' object is simply leaked. It's less clear to me whether we
|
||||
// should also ask to free request value data (second param 1), since the
|
||||
// data come from 'params'.
|
||||
XMLRPC_RequestFree(request, 1);
|
||||
}
|
||||
|
||||
void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams)
|
||||
LLXMLRPCTransaction::Impl::Impl
|
||||
(
|
||||
const std::string& uri,
|
||||
const std::string& method,
|
||||
const LLSD& params,
|
||||
const LLSD& http_params
|
||||
)
|
||||
: mHttpRequest()
|
||||
, mStatus(LLXMLRPCTransaction::StatusNotStarted)
|
||||
, mURI(uri)
|
||||
{
|
||||
LLCore::HttpOptions::ptr_t httpOpts;
|
||||
LLCore::HttpHeaders::ptr_t httpHeaders;
|
||||
|
||||
|
||||
if (!mHttpRequest)
|
||||
{
|
||||
mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);
|
||||
|
|
@ -366,18 +277,18 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const
|
|||
// LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
|
||||
httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());
|
||||
|
||||
// delay between repeats will start from 5 sec and grow to 20 sec with each repeat
|
||||
// Delay between repeats will start from 5 sec and grow to 20 sec with each repeat
|
||||
httpOpts->setMinBackoff(5E6L);
|
||||
httpOpts->setMaxBackoff(20E6L);
|
||||
|
||||
httpOpts->setTimeout(httpParams.has("timeout") ? httpParams["timeout"].asInteger() : 40L);
|
||||
if (httpParams.has("retries"))
|
||||
httpOpts->setTimeout(http_params.has("timeout") ? http_params["timeout"].asInteger() : 40L);
|
||||
if (http_params.has("retries"))
|
||||
{
|
||||
httpOpts->setRetries(httpParams["retries"].asInteger());
|
||||
httpOpts->setRetries(http_params["retries"].asInteger());
|
||||
}
|
||||
if (httpParams.has("DNSCacheTimeout"))
|
||||
if (http_params.has("DNSCacheTimeout"))
|
||||
{
|
||||
httpOpts->setDNSCacheTimeout(httpParams["DNSCacheTimeout"].asInteger());
|
||||
httpOpts->setDNSCacheTimeout(http_params["DNSCacheTimeout"].asInteger());
|
||||
}
|
||||
|
||||
bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
|
||||
|
|
@ -391,12 +302,9 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const
|
|||
|
||||
httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
|
||||
|
||||
std::string user_agent = stringize(
|
||||
LLVersionInfo::instance().getChannel(), ' ',
|
||||
LLVersionInfo::instance().getMajor(), '.',
|
||||
LLVersionInfo::instance().getMinor(), '.',
|
||||
LLVersionInfo::instance().getPatch(), " (",
|
||||
LLVersionInfo::instance().getBuild(), ')');
|
||||
const LLVersionInfo& vi(LLVersionInfo::instance());
|
||||
std::string user_agent = vi.getChannel() + llformat(" %d.%d.%d (%llu)",
|
||||
vi.getMajor(), vi.getMinor(), vi.getPatch(), vi.getBuild());
|
||||
|
||||
httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
|
||||
|
||||
|
|
@ -404,31 +312,19 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const
|
|||
//This might help with bug #503 */
|
||||
//httpOpts->setDNSCacheTimeout(-1);
|
||||
|
||||
std::string request =
|
||||
"<?xml version=\"1.0\"?><methodCall><methodName>" + method +
|
||||
"</methodName><params><param>" + params.asXMLRPCValue() +
|
||||
"</param></params></methodCall>";
|
||||
|
||||
LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray());
|
||||
|
||||
// TODO: See if there is a way to serialize to a preallocated buffer I'm
|
||||
// not fond of the copy here.
|
||||
int requestSize(0);
|
||||
char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize);
|
||||
|
||||
body->append(requestText, requestSize);
|
||||
|
||||
XMLRPC_Free(requestText);
|
||||
body->append(request.c_str(), request.size());
|
||||
|
||||
mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler(mHttpRequest, this));
|
||||
|
||||
mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID,
|
||||
mURI, body.get(), httpOpts, httpHeaders, mHandler);
|
||||
|
||||
}
|
||||
|
||||
|
||||
LLXMLRPCTransaction::Impl::~Impl()
|
||||
{
|
||||
if (mResponse)
|
||||
{
|
||||
XMLRPC_RequestFree(mResponse, 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool LLXMLRPCTransaction::Impl::process()
|
||||
|
|
@ -539,18 +435,16 @@ void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status)
|
|||
|
||||
}
|
||||
|
||||
|
||||
LLXMLRPCTransaction::LLXMLRPCTransaction(
|
||||
const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams)
|
||||
: impl(* new Impl(uri, request, useGzip, httpParams))
|
||||
{ }
|
||||
|
||||
|
||||
LLXMLRPCTransaction::LLXMLRPCTransaction(
|
||||
LLXMLRPCTransaction::LLXMLRPCTransaction
|
||||
(
|
||||
const std::string& uri,
|
||||
const std::string& method, LLXMLRPCValue params, bool useGzip)
|
||||
: impl(* new Impl(uri, method, params, useGzip))
|
||||
{ }
|
||||
const std::string& method,
|
||||
const LLSD& params,
|
||||
const LLSD& http_params
|
||||
)
|
||||
: impl(*new Impl(uri, method, params, http_params))
|
||||
{
|
||||
}
|
||||
|
||||
LLXMLRPCTransaction::~LLXMLRPCTransaction()
|
||||
{
|
||||
|
|
@ -590,14 +484,9 @@ std::string LLXMLRPCTransaction::statusURI()
|
|||
return impl.mStatusURI;
|
||||
}
|
||||
|
||||
XMLRPC_REQUEST LLXMLRPCTransaction::response()
|
||||
const LLSD& LLXMLRPCTransaction::response()
|
||||
{
|
||||
return impl.mResponse;
|
||||
}
|
||||
|
||||
LLXMLRPCValue LLXMLRPCTransaction::responseValue()
|
||||
{
|
||||
return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse));
|
||||
return impl.mResponseData;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -29,73 +29,22 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
typedef struct _xmlrpc_request* XMLRPC_REQUEST;
|
||||
typedef struct _xmlrpc_value* XMLRPC_VALUE;
|
||||
// foward decl of types from xmlrpc.h (this usage is type safe)
|
||||
class LLCertificate;
|
||||
|
||||
class LLXMLRPCValue
|
||||
// a c++ wrapper around XMLRPC_VALUE
|
||||
{
|
||||
public:
|
||||
LLXMLRPCValue() : mV(NULL) { }
|
||||
LLXMLRPCValue(XMLRPC_VALUE value) : mV(value) { }
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
std::string asString() const;
|
||||
int asInt() const;
|
||||
bool asBool() const;
|
||||
double asDouble() const;
|
||||
|
||||
LLXMLRPCValue operator[](const char*) const;
|
||||
|
||||
LLXMLRPCValue rewind();
|
||||
LLXMLRPCValue next();
|
||||
|
||||
static LLXMLRPCValue createArray();
|
||||
static LLXMLRPCValue createStruct();
|
||||
|
||||
void append(LLXMLRPCValue&);
|
||||
void appendString(const std::string&);
|
||||
void appendInt(int);
|
||||
void appendBool(bool);
|
||||
void appendDouble(double);
|
||||
void appendValue(LLXMLRPCValue&);
|
||||
|
||||
void append(const char*, LLXMLRPCValue&);
|
||||
void appendString(const char*, const std::string&);
|
||||
void appendInt(const char*, int);
|
||||
void appendBool(const char*, bool);
|
||||
void appendDouble(const char*, double);
|
||||
void appendValue(const char*, LLXMLRPCValue&);
|
||||
|
||||
void cleanup();
|
||||
// only call this on the top level created value
|
||||
|
||||
XMLRPC_VALUE getValue() const;
|
||||
|
||||
private:
|
||||
XMLRPC_VALUE mV;
|
||||
};
|
||||
|
||||
|
||||
/// An asynchronous request and responses via XML-RPC
|
||||
class LLXMLRPCTransaction
|
||||
// an asynchronous request and responses via XML-RPC
|
||||
{
|
||||
public:
|
||||
LLXMLRPCTransaction(const std::string& uri,
|
||||
XMLRPC_REQUEST request, bool useGzip = true, const LLSD& httpParams = LLSD());
|
||||
// does not take ownership of the request object
|
||||
// request can be freed as soon as the transaction is constructed
|
||||
|
||||
LLXMLRPCTransaction(const std::string& uri,
|
||||
const std::string& method, LLXMLRPCValue params, bool useGzip = true);
|
||||
// *does* take control of the request value, you must not free it
|
||||
LLXMLRPCTransaction
|
||||
(
|
||||
const std::string& uri,
|
||||
const std::string& method,
|
||||
const LLSD& params,
|
||||
const LLSD& http_params = LLSD()
|
||||
);
|
||||
|
||||
~LLXMLRPCTransaction();
|
||||
|
||||
typedef enum e_status {
|
||||
typedef enum e_status
|
||||
{
|
||||
StatusNotStarted,
|
||||
StatusStarted,
|
||||
StatusDownloading,
|
||||
|
|
@ -105,26 +54,25 @@ public:
|
|||
StatusOtherError
|
||||
} EStatus;
|
||||
|
||||
/// Run the request a little, returns true when done
|
||||
bool process();
|
||||
// run the request a little, returns true when done
|
||||
|
||||
/// Return a status, and extended CURL code, if code isn't null
|
||||
EStatus status(int* curlCode);
|
||||
// return status, and extended CURL code, if code isn't null
|
||||
|
||||
LLSD getErrorCertData();
|
||||
|
||||
/// Return a message string, suitable for showing the user
|
||||
std::string statusMessage();
|
||||
// return a message string, suitable for showing the user
|
||||
|
||||
/// Return a URI for the user with more information (can be empty)
|
||||
std::string statusURI();
|
||||
// return a URI for the user with more information
|
||||
// can be empty
|
||||
|
||||
XMLRPC_REQUEST response();
|
||||
LLXMLRPCValue responseValue();
|
||||
// only valid if StatusComplete, otherwise NULL
|
||||
// retains ownership of the result object, don't free it
|
||||
/// Only non-empty if StatusComplete, otherwise Undefined
|
||||
const LLSD& response();
|
||||
|
||||
/// Only valid if StsatusComplete, otherwise 0.0
|
||||
F64 transferRate();
|
||||
// only valid if StsatusComplete, otherwise 0.0
|
||||
|
||||
private:
|
||||
class Handler;
|
||||
|
|
@ -133,6 +81,4 @@ private:
|
|||
Impl& impl;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // LLXMLRPCTRANSACTION_H
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ OpenSSL Copyright (C) 1998-2002 The OpenSSL Project.
|
|||
PCRE Copyright (c) 1997-2008 University of Cambridge
|
||||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler.
|
||||
google-perftools Copyright (c) 2005, Google Inc.
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ mit Open-Source-Beiträgen von:</text>
|
|||
PCRE Copyright (c) 1997-2012 University of Cambridge.
|
||||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga.
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com).
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly und Mark Adler.
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,6 @@ Dummy Name replaced at run time
|
|||
PCRE Copyright (c) 1997-2012 University of Cambridge
|
||||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ con contribuciones de código abierto de:</text>
|
|||
PCRE Copyright (c) 1997-2012 University of Cambridge
|
||||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly y Mark Adler.
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ avec les contributions Open Source de :</text>
|
|||
PCRE Copyright (c) 1997-2012 University of Cambridge
|
||||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-Loup Gailly et Mark Adler.
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ con contributi open source da:</text>
|
|||
PCRE Copyright (c) 1997-2012 University of Cambridge
|
||||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly e Mark Adler.
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ OpenSSL Copyright (C) 1998-2008 The OpenSSL Project.
|
|||
PCRE Copyright (c) 1997-2012 University of Cambridge
|
||||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ com contribuições de código aberto de:</text>
|
|||
PCRE Copyright (c) 1997-2012 University of Cambridge
|
||||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
PCRE (c) 1997-2012, Кембриджский университет
|
||||
SDL (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib (C) 1995-2012 Jean-loup Gailly и Mark Adler.
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ açık kaynak kod katkısında bulunanlar şunlardır:</text>
|
|||
PCRE Telif Hakkı (c) 1997-2012 University of Cambridge
|
||||
SDL Telif Hakkı (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Telif Hakkı (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Telif Hakkı (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Telif Hakkı (C) 1995-2012 Jean-loup Gailly ve Mark Adler.
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
PCRE Copyright (c) 1997-2012 University of Cambridge
|
||||
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
|
||||
xxHash Copyright (C) 2012-2020 Yann Collet.
|
||||
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,16 @@ public:
|
|||
LLEventPump& getEventPump() { return mPump; }
|
||||
|
||||
private:
|
||||
LLSD hidePasswd(const LLSD& data)
|
||||
{
|
||||
LLSD result(data);
|
||||
if (result.has("params") && result["params"].has("passwd"))
|
||||
{
|
||||
result["params"]["passwd"] = "*******";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LLSD getProgressEventLLSD(const std::string& state, const std::string& change,
|
||||
const LLSD& data = LLSD())
|
||||
{
|
||||
|
|
@ -83,6 +93,7 @@ private:
|
|||
{
|
||||
status_data["data"] = data;
|
||||
}
|
||||
|
||||
return status_data;
|
||||
}
|
||||
|
||||
|
|
@ -124,12 +135,13 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
|
|||
// Launch a coroutine with our login_() method. Run the coroutine until
|
||||
// its first wait; at that point, return here.
|
||||
std::string coroname =
|
||||
LLCoros::instance().launch("LLLogin::Impl::login_",
|
||||
boost::bind(&Impl::loginCoro, this, uri, login_params));
|
||||
LLCoros::instance().launch("LLLogin::Impl::login_", [&]() { loginCoro(uri, login_params); });
|
||||
|
||||
LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
|
||||
}
|
||||
|
||||
namespace {
|
||||
namespace
|
||||
{
|
||||
// Instantiate this rendezvous point at namespace scope so it's already
|
||||
// present no matter how early the updater might post to it.
|
||||
// Use an LLEventMailDrop, which has future-like semantics: regardless of the
|
||||
|
|
@ -140,12 +152,8 @@ static LLEventMailDrop sSyncPoint("LoginSync");
|
|||
|
||||
void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
|
||||
{
|
||||
LLSD printable_params = login_params;
|
||||
if (printable_params.has("params")
|
||||
&& printable_params["params"].has("passwd"))
|
||||
{
|
||||
printable_params["params"]["passwd"] = "*******";
|
||||
}
|
||||
LLSD printable_params = hidePasswd(login_params);
|
||||
|
||||
try
|
||||
{
|
||||
LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::getName()
|
||||
|
|
@ -171,12 +179,7 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
|
|||
++attempts;
|
||||
LLSD progress_data;
|
||||
progress_data["attempt"] = attempts;
|
||||
progress_data["request"] = request;
|
||||
if (progress_data["request"].has("params")
|
||||
&& progress_data["request"]["params"].has("passwd"))
|
||||
{
|
||||
progress_data["request"]["params"]["passwd"] = "*******";
|
||||
}
|
||||
progress_data["request"] = hidePasswd(request);
|
||||
sendProgressEvent("offline", "authenticating", progress_data);
|
||||
|
||||
// We expect zero or more "Downloading" status events, followed by
|
||||
|
|
|
|||
Loading…
Reference in New Issue