#1111 Remove xmlrpc-epi

master
Alexander Gavriliuk 2024-07-01 13:34:50 +02:00 committed by Guru
parent 9ab2f662f8
commit 2ea5ac0c43
37 changed files with 732 additions and 1970 deletions

View File

@ -2670,66 +2670,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>name</key> <key>name</key>
<string>vlc-bin</string> <string>vlc-bin</string>
</map> </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> <key>vulkan_gltf</key>
<map> <map>
<key>platforms</key> <key>platforms</key>

View File

@ -63,7 +63,6 @@ set(cmake_SOURCE_FILES
VisualLeakDetector.cmake VisualLeakDetector.cmake
LibVLCPlugin.cmake LibVLCPlugin.cmake
WebRTC.cmake WebRTC.cmake
XmlRpcEpi.cmake
xxHash.cmake xxHash.cmake
ZLIBNG.cmake ZLIBNG.cmake
) )

View File

@ -6,5 +6,3 @@ include(EXPAT)
include(Tracy) include(Tracy)
include(xxHash) include(xxHash)
include(ZLIBNG) include(ZLIBNG)
include(XmlRpcEpi)

View File

@ -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)

View File

@ -248,6 +248,24 @@ int LLFile::close(LLFILE * file)
return ret_value; 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) int LLFile::remove(const std::string& filename, int supress_error)
{ {

View File

@ -67,6 +67,8 @@ public:
static int close(LLFILE * file); 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 // 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. // be overridden by the user's umask. It is ignored on Windows.
// mkdir() considers "directory already exists" to be SUCCESS. // mkdir() considers "directory already exists" to be SUCCESS.

View File

@ -30,6 +30,7 @@
#include "linden_common.h" #include "linden_common.h"
#include "llsd.h" #include "llsd.h"
#include "llbase64.h"
#include "llerror.h" #include "llerror.h"
#include "../llmath/llmath.h" #include "../llmath/llmath.h"
#include "llformat.h" #include "llformat.h"
@ -142,6 +143,8 @@ public:
virtual const String& asStringRef() const { static const std::string empty; return empty; } 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 bool has(const String&) const { return false; }
virtual LLSD get(const String&) const { return LLSD(); } virtual LLSD get(const String&) const { return LLSD(); }
virtual LLSD getKeys() const { return LLSD::emptyArray(); } virtual LLSD getKeys() const { return LLSD::emptyArray(); }
@ -222,6 +225,8 @@ namespace
virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; } virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; }
virtual LLSD::Real asReal() const { return mValue ? 1 : 0; } virtual LLSD::Real asReal() const { return mValue ? 1 : 0; }
virtual LLSD::String asString() const; virtual LLSD::String asString() const;
virtual LLSD::String asXMLRPCValue() const { return mValue ? "<boolean>1</boolean>" : "<boolean>0</boolean>"; }
}; };
LLSD::String ImplBoolean::asString() const LLSD::String ImplBoolean::asString() const
@ -243,6 +248,8 @@ namespace
virtual LLSD::Integer asInteger() const { return mValue; } virtual LLSD::Integer asInteger() const { return mValue; }
virtual LLSD::Real asReal() const { return mValue; } virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const; virtual LLSD::String asString() const;
virtual LLSD::String asXMLRPCValue() const { return "<int>" + std::to_string(mValue) + "</int>"; }
}; };
LLSD::String ImplInteger::asString() const LLSD::String ImplInteger::asString() const
@ -259,6 +266,8 @@ namespace
virtual LLSD::Integer asInteger() const; virtual LLSD::Integer asInteger() const;
virtual LLSD::Real asReal() const { return mValue; } virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const; virtual LLSD::String asString() const;
virtual LLSD::String asXMLRPCValue() const { return "<double>" + std::to_string(mValue) + "</double>"; }
}; };
LLSD::Boolean ImplReal::asBoolean() const LLSD::Boolean ImplReal::asBoolean() const
@ -286,6 +295,8 @@ namespace
virtual LLSD::URI asURI() const { return LLURI(mValue); } virtual LLSD::URI asURI() const { return LLURI(mValue); }
virtual size_t size() const { return mValue.size(); } virtual size_t size() const { return mValue.size(); }
virtual const LLSD::String& asStringRef() const { return mValue; } 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 LLSD::Integer ImplString::asInteger() const
@ -323,6 +334,8 @@ namespace
virtual LLSD::String asString() const{ return mValue.asString(); } virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::UUID asUUID() const { return mValue; } 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::String asString() const{ return mValue.asString(); }
virtual LLSD::Date asDate() const { return mValue; } 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::String asString() const{ return mValue.asString(); }
virtual LLSD::URI asURI() const { return mValue; } 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) { } ImplBinary(const LLSD::Binary& v) : Base(v) { }
virtual const LLSD::Binary& asBinary() const{ return mValue; } 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::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; virtual bool has(const LLSD::String&) const;
using LLSD::Impl::get; // Unhiding get(size_t) using LLSD::Impl::get; // Unhiding get(size_t)
@ -527,6 +559,18 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } 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::get; // Unhiding get(LLSD::String)
using LLSD::Impl::erase; // Unhiding erase(LLSD::String) using LLSD::Impl::erase; // Unhiding erase(LLSD::String)
using LLSD::Impl::ref; // Unhiding ref(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(); } 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 // const char * helpers
LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
void LLSD::assign(const char* v) void LLSD::assign(const char* v)

View File

@ -264,6 +264,20 @@ public:
// asStringRef on any non-string type will return a ref to an empty string. // asStringRef on any non-string type will return a ref to an empty string.
const String& asStringRef() const; 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 Boolean() const { return asBoolean(); }
operator Integer() const { return asInteger(); } operator Integer() const { return asInteger(); }
operator Real() const { return asReal(); } operator Real() const { return asReal(); }

View File

@ -1208,6 +1208,75 @@ namespace LLStringFn
return output; return output;
} }
using literals_t = std::map<char, std::string>;
static const literals_t xml_elem_literals =
{
{ '<', "&lt;" },
{ '>', "&gt;" },
{ '&', "&amp;" }
};
static const literals_t xml_attr_literals =
{
{ '"', "&quot;" },
{ '\'', "&apos;" }
};
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: [ < > & ] => [ &lt; &gt; &amp; ]
*/
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: [ &lt; &gt; &amp; ] => [ < > & ]
*/
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 * @brief Replace all control characters (c < 0x20) with replacement in
* string. * string.

View File

@ -889,6 +889,20 @@ namespace LLStringFn
LL_COMMON_API std::string strip_invalid_xml(const std::string& input); 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: [ < > & ] => [ &lt; &gt; &amp; ]
*/
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: [ &lt; &gt; &amp; ] => [ < > & ]
*/
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 * @brief Replace all control characters (0 <= c < 0x20) with replacement in
* string. This is safe for utf-8 * string. This is safe for utf-8

View File

@ -27,7 +27,6 @@ set(llmessage_SOURCE_FILES
lldatapacker.cpp lldatapacker.cpp
lldispatcher.cpp lldispatcher.cpp
llexperiencecache.cpp llexperiencecache.cpp
llfiltersd2xmlrpc.cpp
llgenericstreamingmessage.cpp llgenericstreamingmessage.cpp
llhost.cpp llhost.cpp
llhttpnode.cpp llhttpnode.cpp
@ -111,7 +110,6 @@ set(llmessage_HEADER_FILES
lleventflags.h lleventflags.h
llexperiencecache.h llexperiencecache.h
llextendedstatus.h llextendedstatus.h
llfiltersd2xmlrpc.h
llfollowcamparams.h llfollowcamparams.h
llgenericstreamingmessage.h llgenericstreamingmessage.h
llhost.h llhost.h
@ -193,7 +191,6 @@ target_link_libraries(
llfilesystem llfilesystem
llmath llmath
llcorehttp llcorehttp
ll::xmlrpc-epi
) )
target_include_directories( llmessage INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories( llmessage INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -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 << "&lt;";
break;
case '>':
out << "&gt;";
break;
case '&':
out << "&amp;";
break;
case '\'':
out << "&apos;";
break;
case '"':
out << "&quot;";
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;
}

View File

@ -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

View File

@ -653,32 +653,24 @@ bool LLXMLNode::updateNode(
// static // static
bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree) bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXMLNode* defaults_tree)
{ {
// Read file std::string xml = LLFile::getContents(filename);
LL_DEBUGS("XMLNode") << "parsing XML file: " << filename << LL_ENDL; if (xml.empty())
LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
if (fp == NULL)
{ {
node = NULL ; LL_WARNS("XMLNode") << "no XML file: " << filename << LL_ENDL;
return false; }
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]; node = nullptr;
size_t nread = fread(buffer, 1, length, fp); return false;
buffer[nread] = 0;
fclose(fp);
bool rv = parseBuffer(buffer, static_cast<U32>(nread), node, defaults_tree);
delete [] buffer;
return rv;
} }
// static // static
bool LLXMLNode::parseBuffer( bool LLXMLNode::parseBuffer(
U8* buffer, const char* buffer,
U32 length, U64 length,
LLXMLNodePtr& node, LLXMLNodePtr& node,
LLXMLNode* defaults) LLXMLNode* defaults)
{ {
@ -693,20 +685,25 @@ bool LLXMLNode::parseBuffer(
file_node->mParser = &my_parser; file_node->mParser = &my_parser;
XML_SetUserData(my_parser, (void *)file_node_ptr); XML_SetUserData(my_parser, file_node_ptr);
// Do the parsing // 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: " LL_WARNS() << "Error parsing xml error code: "
<< XML_ErrorString(XML_GetErrorCode(my_parser)) << XML_ErrorString(XML_GetErrorCode(my_parser))
<< " on line " << XML_GetCurrentLineNumber(my_parser) << " on line " << XML_GetCurrentLineNumber(my_parser)
<< ", column " << XML_GetCurrentColumnNumber(my_parser)
<< LL_ENDL; << LL_ENDL;
} }
// Deinit // Deinit
XML_ParserFree(my_parser); XML_ParserFree(my_parser);
if (!success)
return false;
if (!file_node->mChildren || file_node->mChildren->map.size() != 1) if (!file_node->mChildren || file_node->mChildren->map.size() != 1)
{ {
LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." LL_WARNS() << "Parse failure - wrong number of top-level nodes xml."

View File

@ -129,20 +129,20 @@ public:
void addChild(LLXMLNodePtr& new_child); void addChild(LLXMLNodePtr& new_child);
void setParent(LLXMLNodePtr& new_parent); // reparent if necessary void setParent(LLXMLNodePtr& new_parent); // reparent if necessary
// Serialization // Deserialization
static bool parseFile( static bool parseFile(
const std::string& filename, const std::string& filename,
LLXMLNodePtr& node, LLXMLNodePtr& node,
LLXMLNode* defaults_tree); LLXMLNode* defaults = nullptr);
static bool parseBuffer( static bool parseBuffer(
U8* buffer, const char* buffer,
U32 length, U64 length,
LLXMLNodePtr& node, LLXMLNodePtr& node,
LLXMLNode* defaults); LLXMLNode* defaults = nullptr);
static bool parseStream( static bool parseStream(
std::istream& str, std::istream& str,
LLXMLNodePtr& node, LLXMLNodePtr& node,
LLXMLNode* defaults); LLXMLNode* defaults = nullptr);
static bool updateNode( static bool updateNode(
LLXMLNodePtr& node, LLXMLNodePtr& node,
LLXMLNodePtr& update_node); LLXMLNodePtr& update_node);

View File

@ -111,16 +111,17 @@ public:
bool hasEstimate() const; bool hasEstimate() const;
std::string getLocalEstimate() const; std::string getLocalEstimate() const;
void startTransaction(TransactionType type, void startTransaction(TransactionType type, const char* method, const LLSD& params);
const char* method, LLXMLRPCValue params);
bool checkTransaction();
// return true if update needed // return true if update needed
bool checkTransaction();
void setError(const std::string& message, const std::string& uri); void setError(const std::string& message, const std::string& uri);
void clearError(); void clearError();
bool considerUpdateCurrency();
// return true if update needed // return true if update needed
bool considerUpdateCurrency();
void currencyKey(S32); void currencyKey(S32);
static void onCurrencyKey(LLLineEditor* caller, void* data); static void onCurrencyKey(LLLineEditor* caller, void* data);
@ -160,32 +161,29 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo()
return; return;
} }
LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct(); const LLVersionInfo& vi(LLVersionInfo::instance());
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()));
LLXMLRPCValue params = LLXMLRPCValue::createArray(); LLSD params = LLSD::emptyMap();
params.append(keywordArgs); 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); startTransaction(TransactionCurrency, "getCurrencyQuote", params);
} }
void LLCurrencyUIManager::Impl::finishCurrencyInfo() 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) if (!success)
{ {
setError( setError(
@ -195,24 +193,24 @@ void LLCurrencyUIManager::Impl::finishCurrencyInfo()
return; return;
} }
LLXMLRPCValue currency = result["currency"]; const LLSD& currency = result["currency"];
// old XML-RPC server: estimatedCost = value in US cents // old XML-RPC server: estimatedCost = value in US cents
mUSDCurrencyEstimated = currency["estimatedCost"].isValid(); mUSDCurrencyEstimated = currency.has("estimatedCost");
if (mUSDCurrencyEstimated) if (mUSDCurrencyEstimated)
{ {
mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInt(); mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInteger();
} }
// newer XML-RPC server: estimatedLocalCost = local currency string // newer XML-RPC server: estimatedLocalCost = local currency string
mLocalCurrencyEstimated = currency["estimatedLocalCost"].isValid(); mLocalCurrencyEstimated = currency.has("estimatedLocalCost");
if (mLocalCurrencyEstimated) if (mLocalCurrencyEstimated)
{ {
mLocalCurrencyEstimatedCost = currency["estimatedLocalCost"].asString(); mLocalCurrencyEstimatedCost = currency["estimatedLocalCost"].asString();
mSupportsInternationalBilling = true; mSupportsInternationalBilling = true;
} }
S32 newCurrencyBuy = currency["currencyBuy"].asInt(); S32 newCurrencyBuy = currency["currencyBuy"].asInteger();
if (newCurrencyBuy != mUserCurrencyBuy) if (newCurrencyBuy != mUserCurrencyBuy)
{ {
mUserCurrencyBuy = newCurrencyBuy; mUserCurrencyBuy = newCurrencyBuy;
@ -224,36 +222,36 @@ void LLCurrencyUIManager::Impl::finishCurrencyInfo()
void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password) void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
{ {
LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct(); const LLVersionInfo& vi(LLVersionInfo::instance());
keywordArgs.appendString("agentId", gAgent.getID().asString());
keywordArgs.appendString( LLSD params = LLSD::emptyMap();
"secureSessionId", params["agentId"] = gAgent.getID().asString();
gAgent.getSecureSessionID().asString()); params["secureSessionId"] = gAgent.getSecureSessionID().asString();
keywordArgs.appendString("language", LLUI::getLanguage()); params["language"] = LLUI::getLanguage();
keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy); 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) if (mUSDCurrencyEstimated)
{ {
keywordArgs.appendInt("estimatedCost", mUSDCurrencyEstimatedCost); params["estimatedCost"] = mUSDCurrencyEstimatedCost;
} }
if (mLocalCurrencyEstimated) if (mLocalCurrencyEstimated)
{ {
keywordArgs.appendString("estimatedLocalCost", mLocalCurrencyEstimatedCost); params["estimatedLocalCost"] = mLocalCurrencyEstimatedCost;
} }
keywordArgs.appendString("confirm", mSiteConfirm);
if (!password.empty()) 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); startTransaction(TransactionBuy, "buyCurrency", params);
@ -263,9 +261,9 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
void LLCurrencyUIManager::Impl::finishCurrencyBuy() 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) if (!success)
{ {
setError( setError(
@ -282,7 +280,7 @@ void LLCurrencyUIManager::Impl::finishCurrencyBuy()
} }
void LLCurrencyUIManager::Impl::startTransaction(TransactionType type, void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
const char* method, LLXMLRPCValue params) const char* method, const LLSD& params)
{ {
static std::string transactionURI; static std::string transactionURI;
if (transactionURI.empty()) if (transactionURI.empty())
@ -293,12 +291,7 @@ void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
delete mTransaction; delete mTransaction;
mTransactionType = type; mTransactionType = type;
mTransaction = new LLXMLRPCTransaction( mTransaction = new LLXMLRPCTransaction(transactionURI, method, params);
transactionURI,
method,
params,
false /* don't use gzip */
);
clearError(); clearError();
} }
@ -352,11 +345,16 @@ bool LLCurrencyUIManager::Impl::checkTransaction()
{ {
setError(mTransaction->statusMessage(), mTransaction->statusURI()); setError(mTransaction->statusMessage(), mTransaction->statusURI());
} }
else { else
{
switch (mTransactionType) switch (mTransactionType)
{ {
case TransactionCurrency: finishCurrencyInfo(); break; case TransactionCurrency:
case TransactionBuy: finishCurrencyBuy(); break; finishCurrencyInfo();
break;
case TransactionBuy:
finishCurrencyBuy();
break;
default:; default:;
} }
} }
@ -385,9 +383,8 @@ void LLCurrencyUIManager::Impl::clearError()
bool LLCurrencyUIManager::Impl::considerUpdateCurrency() bool LLCurrencyUIManager::Impl::considerUpdateCurrency()
{ {
if (mCurrencyChanged if (mCurrencyChanged && !mTransaction &&
&& !mTransaction mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
&& mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
{ {
updateCurrencyInfo(); updateCurrencyInfo();
return true; return true;
@ -408,7 +405,8 @@ void LLCurrencyUIManager::Impl::currencyKey(S32 value)
mUserCurrencyBuy = value; mUserCurrencyBuy = value;
if (hasEstimate()) { if (hasEstimate())
{
clearEstimate(); clearEstimate();
//cannot just simply refresh the whole UI, as the edit field will //cannot just simply refresh the whole UI, as the edit field will
// get reset and the cursor will change... // get reset and the cursor will change...
@ -421,8 +419,7 @@ void LLCurrencyUIManager::Impl::currencyKey(S32 value)
} }
// static // static
void LLCurrencyUIManager::Impl::onCurrencyKey( void LLCurrencyUIManager::Impl::onCurrencyKey(LLLineEditor* caller, void* data)
LLLineEditor* caller, void* data)
{ {
S32 value = atoi(caller->getText().c_str()); S32 value = atoi(caller->getText().c_str());
LLCurrencyUIManager::Impl* self = (LLCurrencyUIManager::Impl*)data; LLCurrencyUIManager::Impl* self = (LLCurrencyUIManager::Impl*)data;
@ -589,14 +586,12 @@ bool LLCurrencyUIManager::inProcess()
bool LLCurrencyUIManager::canCancel() bool LLCurrencyUIManager::canCancel()
{ {
return impl.mTransactionType != Impl::TransactionBuy; return !buying();
} }
bool LLCurrencyUIManager::canBuy() bool LLCurrencyUIManager::canBuy()
{ {
return impl.mTransactionType == Impl::TransactionNone return !inProcess() && impl.hasEstimate() && impl.mUserCurrencyBuy > 0;
&& impl.hasEstimate()
&& impl.mUserCurrencyBuy > 0;
} }
bool LLCurrencyUIManager::buying() bool LLCurrencyUIManager::buying()

View File

@ -182,7 +182,7 @@ public:
void refreshUI(); void refreshUI();
void startTransaction(TransactionType type, const LLXMLRPCValue& params); void startTransaction(TransactionType type, const LLSD& params);
bool checkTransaction(); bool checkTransaction();
void tellUserError(const std::string& message, const std::string& uri); void tellUserError(const std::string& message, const std::string& uri);
@ -399,8 +399,7 @@ void LLFloaterBuyLandUI::updateParcelInfo()
if (region) if (region)
{ {
S32 max_tasks_per_region = (S32)region->getMaxTasks(); S32 max_tasks_per_region = (S32)region->getMaxTasks();
mParcelSupportedObjects = llmin( mParcelSupportedObjects = llmin(mParcelSupportedObjects, max_tasks_per_region);
mParcelSupportedObjects, max_tasks_per_region);
} }
mParcelSoldWithObjects = parcel->getSellWithObjects(); mParcelSoldWithObjects = parcel->getSellWithObjects();
@ -492,14 +491,13 @@ void LLFloaterBuyLandUI::updateParcelInfo()
void LLFloaterBuyLandUI::updateCovenantInfo() void LLFloaterBuyLandUI::updateCovenantInfo()
{ {
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
if(!region) return; if (!region)
return;
U8 sim_access = region->getSimAccess(); U8 sim_access = region->getSimAccess();
std::string rating = LLViewerRegion::accessToString(sim_access); std::string rating = LLViewerRegion::accessToString(sim_access);
LLTextBox* region_name = getChild<LLTextBox>("region_name_text"); LLTextBox* region_name = getChild<LLTextBox>("region_name_text");
if (region_name)
{
std::string region_name_txt = region->getName() + " ("+rating +")"; std::string region_name_txt = region->getName() + " ("+rating +")";
region_name->setText(region_name_txt); region_name->setText(region_name_txt);
@ -523,54 +521,26 @@ void LLFloaterBuyLandUI::updateCovenantInfo()
default: default:
rating_icon->setValue(getString("icon_M")); rating_icon->setValue(getString("icon_M"));
} }
}
LLTextBox* region_type = getChild<LLTextBox>("region_type_text"); LLTextBox* region_type = getChild<LLTextBox>("region_type_text");
if (region_type)
{
region_type->setText(region->getLocalizedSimProductName()); region_type->setText(region->getLocalizedSimProductName());
region_type->setToolTip(region->getLocalizedSimProductName()); region_type->setToolTip(region->getLocalizedSimProductName());
}
LLTextBox* resellable_clause = getChild<LLTextBox>("resellable_clause"); LLTextBox* resellable_clause = getChild<LLTextBox>("resellable_clause");
if (resellable_clause) const char* can_resell = region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL) ? "can_not_resell" : "can_resell";
{ resellable_clause->setText(getString(can_resell));
if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL))
{
resellable_clause->setText(getString("can_not_resell"));
}
else
{
resellable_clause->setText(getString("can_resell"));
}
}
LLTextBox* changeable_clause = getChild<LLTextBox>("changeable_clause"); LLTextBox* changeable_clause = getChild<LLTextBox>("changeable_clause");
if (changeable_clause) const char* can_change = region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES) ? "can_change" : "can_not_change";
{ changeable_clause->setText(getString(can_change));
if (region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES))
{
changeable_clause->setText(getString("can_change"));
}
else
{
changeable_clause->setText(getString("can_not_change"));
}
}
LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant"); LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant");
if(check)
{
check->set(false); check->set(false);
check->setEnabled(true); check->setEnabled(true);
check->setCommitCallback(onChangeAgreeCovenant, this); check->setCommitCallback(onChangeAgreeCovenant, this);
}
LLTextBox* box = getChild<LLTextBox>("covenant_text"); LLTextBox* box = getChild<LLTextBox>("covenant_text");
if(box)
{
box->setVisible(false); box->setVisible(false);
}
// send EstateCovenantInfo message // send EstateCovenantInfo message
LLMessageSystem *msg = gMessageSystem; LLMessageSystem *msg = gMessageSystem;
@ -584,10 +554,9 @@ void LLFloaterBuyLandUI::updateCovenantInfo()
// static // static
void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data) void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data)
{ {
LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)user_data; if (user_data)
if(self)
{ {
self->refreshUI(); ((LLFloaterBuyLandUI*)user_data)->refreshUI();
} }
} }
@ -626,13 +595,13 @@ void LLFloaterBuyLandUI::updateFloaterEstateName(const std::string& name)
void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text) void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text)
{ {
LLTextBox* editor = getChild<LLTextBox>("covenant_timestamp_text"); LLTextBox* editor = getChild<LLTextBox>("covenant_timestamp_text");
if (editor) editor->setText(text); editor->setText(text);
} }
void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name) void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name)
{ {
LLTextBox* box = getChild<LLTextBox>("estate_owner_text"); LLTextBox* box = getChild<LLTextBox>("estate_owner_text");
if (box) box->setText(name); box->setText(name);
} }
void LLFloaterBuyLandUI::updateWebSiteInfo() void LLFloaterBuyLandUI::updateWebSiteInfo()
@ -640,9 +609,10 @@ void LLFloaterBuyLandUI::updateWebSiteInfo()
S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea; S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea;
S32 askCurrencyBuy = mCurrency.getAmount(); S32 askCurrencyBuy = mCurrency.getAmount();
if (mTransaction && mTransactionType == TransactionPreflight if (mTransaction &&
&& mPreflightAskBillableArea == askBillableArea mTransactionType == TransactionPreflight &&
&& mPreflightAskCurrencyBuy == askCurrencyBuy) mPreflightAskBillableArea == askBillableArea &&
mPreflightAskCurrencyBuy == askCurrencyBuy)
{ {
return; return;
} }
@ -664,27 +634,21 @@ void LLFloaterBuyLandUI::updateWebSiteInfo()
mSiteCurrencyEstimatedCost = 0; mSiteCurrencyEstimatedCost = 0;
#endif #endif
LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct(); LLSD params = LLSD::emptyMap();
keywordArgs.appendString("agentId", gAgent.getID().asString()); params["agentId"] = gAgent.getID().asString();
keywordArgs.appendString( params["secureSessionId"] = gAgent.getSecureSessionID().asString();
"secureSessionId", params["language"] = LLUI::getLanguage();
gAgent.getSecureSessionID().asString()); params["billableArea"] = mPreflightAskBillableArea;
keywordArgs.appendString("language", LLUI::getLanguage()); params["currencyBuy"] = mPreflightAskCurrencyBuy;
keywordArgs.appendInt("billableArea", mPreflightAskBillableArea);
keywordArgs.appendInt("currencyBuy", mPreflightAskCurrencyBuy);
LLXMLRPCValue params = LLXMLRPCValue::createArray();
params.append(keywordArgs);
startTransaction(TransactionPreflight, params); startTransaction(TransactionPreflight, params);
} }
void LLFloaterBuyLandUI::finishWebSiteInfo() void LLFloaterBuyLandUI::finishWebSiteInfo()
{ {
const LLSD& result = mTransaction->response();
LLXMLRPCValue result = mTransaction->responseValue(); mSiteValid = result["success"].asBoolean();
mSiteValid = result["success"].asBool();
if (!mSiteValid) if (!mSiteValid)
{ {
tellUserError( tellUserError(
@ -694,31 +658,30 @@ void LLFloaterBuyLandUI::finishWebSiteInfo()
return; return;
} }
LLXMLRPCValue membership = result["membership"]; const LLSD& membership = result["membership"];
mSiteMembershipUpgrade = membership["upgrade"].asBool(); mSiteMembershipUpgrade = membership["upgrade"].asBoolean();
mSiteMembershipAction = membership["action"].asString(); mSiteMembershipAction = membership["action"].asString();
mSiteMembershipPlanIDs.clear(); mSiteMembershipPlanIDs.clear();
mSiteMembershipPlanNames.clear(); mSiteMembershipPlanNames.clear();
LLXMLRPCValue levels = membership["levels"]; const LLSD& levels = membership["levels"];
for (LLXMLRPCValue level = levels.rewind(); for (auto it = levels.beginArray(); it != levels.endArray(); ++it)
level.isValid();
level = levels.next())
{ {
const LLSD& level = *it;
mSiteMembershipPlanIDs.push_back(level["id"].asString()); mSiteMembershipPlanIDs.push_back(level["id"].asString());
mSiteMembershipPlanNames.push_back(level["description"].asString()); mSiteMembershipPlanNames.push_back(level["description"].asString());
} }
mUserPlanChoice = 0; mUserPlanChoice = 0;
LLXMLRPCValue landUse = result["landUse"]; const LLSD& landUse = result["landUse"];
mSiteLandUseUpgrade = landUse["upgrade"].asBool(); mSiteLandUseUpgrade = landUse["upgrade"].asBoolean();
mSiteLandUseAction = landUse["action"].asString(); mSiteLandUseAction = landUse["action"].asString();
LLXMLRPCValue currency = result["currency"]; const LLSD& currency = result["currency"];
if (currency["estimatedCost"].isValid()) 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()); mCurrency.setLocalEstimate(currency["estimatedLocalCost"].asString());
} }
@ -760,35 +723,30 @@ void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password)
} }
} }
LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct(); LLSD params = LLSD::emptyMap();
keywordArgs.appendString("agentId", gAgent.getID().asString()); params["agentId"] = gAgent.getID().asString();
keywordArgs.appendString( params["secureSessionId"] = gAgent.getSecureSessionID().asString();
"secureSessionId", params["language"] = LLUI::getLanguage();
gAgent.getSecureSessionID().asString()); params["levelId"] = newLevel;
keywordArgs.appendString("language", LLUI::getLanguage()); params["billableArea"] = mIsForGroup ? 0 : mParcelBillableArea;
keywordArgs.appendString("levelId", newLevel); params["currencyBuy"] = mCurrency.getAmount();
keywordArgs.appendInt("billableArea", params["estimatedCost"] = mCurrency.getUSDEstimate();
mIsForGroup ? 0 : mParcelBillableArea); params["estimatedLocalCost"] = mCurrency.getLocalEstimate();
keywordArgs.appendInt("currencyBuy", mCurrency.getAmount()); params["confirm"] = mSiteConfirm;
keywordArgs.appendInt("estimatedCost", mCurrency.getUSDEstimate());
keywordArgs.appendString("estimatedLocalCost", mCurrency.getLocalEstimate());
keywordArgs.appendString("confirm", mSiteConfirm);
if (!password.empty()) if (!password.empty())
{ {
keywordArgs.appendString("password", password); params["password"] = password;
} }
LLXMLRPCValue params = LLXMLRPCValue::createArray();
params.append(keywordArgs);
startTransaction(TransactionBuy, params); startTransaction(TransactionBuy, params);
} }
void LLFloaterBuyLandUI::finishWebSitePrep() void LLFloaterBuyLandUI::finishWebSitePrep()
{ {
LLXMLRPCValue result = mTransaction->responseValue(); const LLSD& result = mTransaction->response();
bool success = result["success"].asBool(); bool success = result["success"].asBoolean();
if (!success) if (!success)
{ {
tellUserError( 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; delete mTransaction;
mTransaction = NULL; mTransaction = NULL;
@ -878,12 +836,7 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa
return; return;
} }
mTransaction = new LLXMLRPCTransaction( mTransaction = new LLXMLRPCTransaction(transaction_uri, method, params);
transaction_uri,
method,
params,
false /* don't use gzip */
);
} }
bool LLFloaterBuyLandUI::checkTransaction() bool LLFloaterBuyLandUI::checkTransaction()

View File

@ -33,9 +33,6 @@
#include "stringize.h" #include "stringize.h"
#include "llsdserialize.h" #include "llsdserialize.h"
// llmessage (!)
#include "llfiltersd2xmlrpc.h" // for xml_escape_string()
// login // login
#include "lllogin.h" #include "lllogin.h"
@ -612,7 +609,7 @@ std::string construct_start_string()
<< position[VX] << "&" << position[VX] << "&"
<< position[VY] << "&" << position[VY] << "&"
<< position[VZ]); << position[VZ]);
start = xml_escape_string(unescaped_start); start = LLStringFn::xml_encode(unescaped_start, true);
break; break;
} }
case LLSLURL::HOME_LOCATION: case LLSLURL::HOME_LOCATION:

View File

@ -32,13 +32,15 @@
#include "llpanellogin.h" #include "llpanellogin.h"
#include "llviewercontrol.h" #include "llviewercontrol.h"
#include "llviewernetwork.h" #include "llviewernetwork.h"
#include "llfiltersd2xmlrpc.h"
#include "curl/curl.h" #include "curl/curl.h"
const char* LLSLURL::SLURL_HTTP_SCHEME = "http"; const char* LLSLURL::SLURL_HTTP_SCHEME = "http";
const char* LLSLURL::SLURL_HTTPS_SCHEME = "https"; const char* LLSLURL::SLURL_HTTPS_SCHEME = "https";
const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife"; const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife";
const char* LLSLURL::SLURL_SECONDLIFE_PATH = "secondlife"; const char* LLSLURL::SLURL_SECONDLIFE_PATH = "secondlife";
const char* LLSLURL::SLURL_COM = "slurl.com"; 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 // 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 // text with www.slurl.com or a link explicitly pointing at www.slurl.com so testing for this
// version is required also. // 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; LL_WARNS("AppInit") << "Unexpected SLURL type (" << (int)mType << ")for login string" << LL_ENDL;
break; break;
} }
return xml_escape_string(unescaped_start.str()); return LLStringFn::xml_encode(unescaped_start.str(), true);
} }
bool LLSLURL::operator ==(const LLSLURL& rhs) bool LLSLURL::operator ==(const LLSLURL& rhs)

View File

@ -76,37 +76,37 @@ LLVersionInfo::~LLVersionInfo()
{ {
} }
S32 LLVersionInfo::getMajor() S32 LLVersionInfo::getMajor() const
{ {
return LL_VIEWER_VERSION_MAJOR; return LL_VIEWER_VERSION_MAJOR;
} }
S32 LLVersionInfo::getMinor() S32 LLVersionInfo::getMinor() const
{ {
return LL_VIEWER_VERSION_MINOR; return LL_VIEWER_VERSION_MINOR;
} }
S32 LLVersionInfo::getPatch() S32 LLVersionInfo::getPatch() const
{ {
return LL_VIEWER_VERSION_PATCH; return LL_VIEWER_VERSION_PATCH;
} }
U64 LLVersionInfo::getBuild() U64 LLVersionInfo::getBuild() const
{ {
return LL_VIEWER_VERSION_BUILD; return LL_VIEWER_VERSION_BUILD;
} }
std::string LLVersionInfo::getVersion() std::string LLVersionInfo::getVersion() const
{ {
return version; return version;
} }
std::string LLVersionInfo::getShortVersion() std::string LLVersionInfo::getShortVersion() const
{ {
return short_version; return short_version;
} }
std::string LLVersionInfo::getChannelAndVersion() std::string LLVersionInfo::getChannelAndVersion() const
{ {
if (mVersionChannel.empty()) if (mVersionChannel.empty())
{ {
@ -117,7 +117,7 @@ std::string LLVersionInfo::getChannelAndVersion()
return mVersionChannel; return mVersionChannel;
} }
std::string LLVersionInfo::getChannel() std::string LLVersionInfo::getChannel() const
{ {
return mWorkingChannelName; return mWorkingChannelName;
} }
@ -128,7 +128,7 @@ void LLVersionInfo::resetChannel(const std::string& channel)
mVersionChannel.clear(); // Reset version and channel string til next use. mVersionChannel.clear(); // Reset version and channel string til next use.
} }
LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() const
{ {
ViewerMaturity maturity; ViewerMaturity maturity;
@ -166,12 +166,12 @@ LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity()
} }
std::string LLVersionInfo::getBuildConfig() std::string LLVersionInfo::getBuildConfig() const
{ {
return build_configuration; return build_configuration;
} }
std::string LLVersionInfo::getReleaseNotes() std::string LLVersionInfo::getReleaseNotes() const
{ {
return mReleaseNotes; return mReleaseNotes;
} }

View File

@ -52,38 +52,38 @@ public:
~LLVersionInfo(); ~LLVersionInfo();
/// return the major version number as an integer /// return the major version number as an integer
S32 getMajor(); S32 getMajor() const;
/// return the minor version number as an integer /// return the minor version number as an integer
S32 getMinor(); S32 getMinor() const;
/// return the patch version number as an integer /// return the patch version number as an integer
S32 getPatch(); S32 getPatch() const;
/// return the build number as an integer /// 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" /// 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" /// 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 /// return the viewer version and channel as a string
/// like "Second Life Release 2.0.0.200030" /// like "Second Life Release 2.0.0.200030"
std::string getChannelAndVersion(); std::string getChannelAndVersion() const;
/// return the channel name, e.g. "Second Life" /// return the channel name, e.g. "Second Life"
std::string getChannel(); std::string getChannel() const;
/// return the CMake build type /// return the CMake build type
std::string getBuildConfig(); std::string getBuildConfig() const;
/// reset the channel name used by the viewer. /// reset the channel name used by the viewer.
void resetChannel(const std::string& channel); void resetChannel(const std::string& channel);
/// return the bit width of an address /// return the bit width of an address
S32 getAddressSize() { return ADDRESS_SIZE; } S32 getAddressSize() const { return ADDRESS_SIZE; }
typedef enum typedef enum
{ {
@ -92,11 +92,11 @@ public:
BETA_VIEWER, BETA_VIEWER,
RELEASE_VIEWER RELEASE_VIEWER
} ViewerMaturity; } ViewerMaturity;
ViewerMaturity getViewerMaturity(); ViewerMaturity getViewerMaturity() const;
/// get the release-notes URL, once it becomes available -- until then, /// get the release-notes URL, once it becomes available -- until then,
/// return empty string /// return empty string
std::string getReleaseNotes(); std::string getReleaseNotes() const;
private: private:
std::string version; std::string version;
@ -107,7 +107,7 @@ private:
std::string mWorkingChannelName; std::string mWorkingChannelName;
// Storage for the "version and channel" string. // Storage for the "version and channel" string.
// This will get reset too. // This will get reset too.
std::string mVersionChannel; mutable std::string mVersionChannel;
std::string build_configuration; std::string build_configuration;
std::string mReleaseNotes; std::string mReleaseNotes;
// Store unique_ptrs to the next couple things so we don't have to explain // Store unique_ptrs to the next couple things so we don't have to explain

View File

@ -39,12 +39,6 @@
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/range.hpp> // boost::begin(), boost::end() #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" #include "curl/curl.h"
// other Linden headers // other Linden headers
@ -178,13 +172,6 @@ public:
static const CURLcodeMapper sCURLcodeMapper; 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 * Capture an outstanding LLXMLRPCTransaction and poll it periodically until
* done. * done.
@ -213,38 +200,20 @@ public:
mMethod(command["method"]), mMethod(command["method"]),
mReplyPump(command["reply"]) mReplyPump(command["reply"])
{ {
// LL_ERRS if any of these are missing // LL_ERRS if any of these keys are missing or empty
const char* required[] = { "uri", "method", "reply" }; if (mUri.empty() || mMethod.empty() || mReplyPump.empty())
// 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)
{ {
// If the command does not contain this required entry, add it to 'missing'. LL_ERRS("LLXMLRPCListener")
if (! command.has(*ri)) << "Some params are missing: "
{ << "reply: '" << mReplyPump << "', "
missing.insert(*ri); << "method: '" << mMethod << "', "
} << "uri: '" << mUri << "'"
} << LL_ENDL;
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;
} }
// Build the XMLRPC request. LLSD request_params = LLSD::emptyMap();
XMLRPC_REQUEST request = XMLRPC_RequestNew();
XMLRPC_RequestSetMethodName(request, mMethod.c_str()); LLSD params = command.get("params");
XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
XMLRPC_VALUE xparams = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
LLSD params(command["params"]);
if (params.isMap()) if (params.isMap())
{ {
for (LLSD::map_const_iterator pi(params.beginMap()), pend(params.endMap()); for (LLSD::map_const_iterator pi(params.beginMap()), pend(params.endMap());
@ -252,44 +221,33 @@ public:
{ {
std::string name(pi->first); std::string name(pi->first);
LLSD param(pi->second); LLSD param(pi->second);
if (param.isString()) switch (param.type())
{ {
XMLRPC_VectorAppendString(xparams, name.c_str(), param.asString().c_str(), 0); case LLSD::TypeString:
} case LLSD::TypeInteger:
else if (param.isInteger() || param.isBoolean()) case LLSD::TypeReal:
{ request_params.insert(name, param);
XMLRPC_VectorAppendInt(xparams, name.c_str(), param.asInteger()); break;
} case LLSD::TypeBoolean:
else if (param.isReal()) request_params.insert(name, param.asInteger());
{ break;
XMLRPC_VectorAppendDouble(xparams, name.c_str(), param.asReal()); default:
} LL_ERRS("LLXMLRPCListener") << mMethod
else << " request param '" << name << "' has unknown type: " << param << LL_ENDL;
{
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()) if (options.isArray())
{ {
XMLRPC_VALUE xoptions = XMLRPC_CreateVector("options", xmlrpc_vector_array); request_params.insert("options", options);
for (LLSD::array_const_iterator oi(options.beginArray()), oend(options.endArray());
oi != oend; ++oi)
{
XMLRPC_VectorAppendString(xoptions, NULL, oi->asString().c_str(), 0);
} }
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); 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. // Now ensure that we get regular callbacks to poll for completion.
mBoundListener = mBoundListener =
LLEventPumps::instance(). LLEventPumps::instance().
@ -367,10 +325,8 @@ public:
// Given 'message', need we care? // Given 'message', need we care?
if (status == LLXMLRPCTransaction::StatusComplete) if (status == LLXMLRPCTransaction::StatusComplete)
{ {
// Success! Parse data. // Success! Retrieve response data.
std::string status_string(data["status"]); data["responses"] = mTransaction->response();
data["responses"] = parseResponse(status_string);
data["status"] = status_string;
} }
// whether successful or not, send reply on requested LLEventPump // whether successful or not, send reply on requested LLEventPump
@ -388,159 +344,6 @@ public:
} }
private: 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 LLReqID mReqID;
const std::string mUri; const std::string mUri;
const std::string mMethod; const std::string mMethod;
@ -550,11 +353,18 @@ private:
LLXMLRPCTransaction::EStatus mPreviousStatus; // To detect state changes. 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 // 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. // will check its own status and free itself on completion of the request.
(new Poller(command)); (new Poller(command));
// conventional event listener return // Conventional event listener return
return false; return false;
} }
))
{
}

View File

@ -42,9 +42,6 @@ public:
/// Specify the pump name on which to listen /// Specify the pump name on which to listen
LLXMLRPCListener(const std::string& pumpname); LLXMLRPCListener(const std::string& pumpname);
/// Handle request events on the event pump specified at construction time
bool process(const LLSD& command);
private: private:
LLTempBoundListener mBoundListener; LLTempBoundListener mBoundListener;
}; };

View File

@ -42,22 +42,11 @@
#include "bufferarray.h" #include "bufferarray.h"
#include "llversioninfo.h" #include "llversioninfo.h"
#include "llviewercontrol.h" #include "llviewercontrol.h"
#include "llxmlnode.h"
#include "stringize.h" #include "stringize.h"
// Have to include these last to avoid queue redefinition! // 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 "llappviewer.h"
#include "lltrans.h" #include "lltrans.h"
@ -75,111 +64,6 @@ namespace boost
// nothing. // nothing.
static LLXMLRPCListener listener("LLXMLRPCTransaction"); 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 class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler
{ {
public: public:
@ -192,6 +76,9 @@ public:
private: private:
bool parseResponse(LLXMLNodePtr root);
bool parseValue(LLSD& target, LLXMLNodePtr source);
LLXMLRPCTransaction::Impl *mImpl; LLXMLRPCTransaction::Impl *mImpl;
LLCore::HttpRequest::ptr_t mRequest; LLCore::HttpRequest::ptr_t mRequest;
}; };
@ -213,26 +100,26 @@ public:
LLCore::HttpHandle mPostH; LLCore::HttpHandle mPostH;
std::string mURI; std::string mURI;
std::string mProxyAddress; std::string mProxyAddress;
std::string mResponseText; std::string mResponseText;
XMLRPC_REQUEST mResponse; LLSD mResponseData;
std::string mCertStore; std::string mCertStore;
LLSD mErrorCertData; LLSD mErrorCertData;
Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams); Impl
Impl(const std::string& uri, (
const std::string& method, LLXMLRPCValue params, bool useGzip); const std::string& uri,
~Impl(); const std::string& method,
const LLSD& params,
const LLSD& httpParams
);
bool process(); bool process();
void setStatus(EStatus code, const std::string& message = "", const std::string& uri = ""); void setStatus(EStatus code, const std::string& message = "", const std::string& uri = "");
void setHttpStatus(const LLCore::HttpStatus &status); 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, LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request,
@ -275,89 +162,113 @@ void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle,
mImpl->setStatus(LLXMLRPCTransaction::StatusComplete); mImpl->setStatus(LLXMLRPCTransaction::StatusComplete);
mImpl->mTransferStats = response->getTransferStats(); 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. // will need to copy them into an contiguous block of memory for XMLRPC.
LLCore::BufferArray *body = response->getBody(); 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); LLXMLNodePtr root;
if (!LLXMLNode::parseBuffer(mImpl->mResponseText.data(), body->size(), root, nullptr))
delete[] bodydata;
bool hasError = false;
bool hasFault = false;
int faultCode = 0;
std::string faultString;
LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse));
if (error.isValid())
{ {
hasError = true; LL_WARNS() << "Failed parsing XML response; request URI: " << mImpl->mURI << LL_ENDL;
faultCode = error["faultCode"].asInt(); return;
faultString = error["faultString"].asString();
}
else if (XMLRPC_ResponseIsFault(mImpl->mResponse))
{
hasFault = true;
faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse);
faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse);
} }
if (hasError || hasFault) if (!parseResponse(root))
{ return;
mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
LL_WARNS() << "LLXMLRPCTransaction XMLRPC " LL_INFOS() << "XML response parsed successfully; request URI: " << mImpl->mURI << LL_ENDL;
<< (hasError ? "error " : "fault ")
<< faultCode << ": "
<< faultString << LL_ENDL;
LL_WARNS() << "LLXMLRPCTransaction 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, LLXMLRPCTransaction::Impl::Impl
XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams) (
: mHttpRequest(), const std::string& uri,
mStatus(LLXMLRPCTransaction::StatusNotStarted), const std::string& method,
mURI(uri), const LLSD& params,
mResponse(0) const LLSD& http_params
{ )
init(request, useGzip, httpParams); : mHttpRequest()
} , mStatus(LLXMLRPCTransaction::StatusNotStarted)
, mURI(uri)
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)
{ {
LLCore::HttpOptions::ptr_t httpOpts; LLCore::HttpOptions::ptr_t httpOpts;
LLCore::HttpHeaders::ptr_t httpHeaders; LLCore::HttpHeaders::ptr_t httpHeaders;
if (!mHttpRequest) if (!mHttpRequest)
{ {
mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest); 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 // LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()); 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->setMinBackoff(5E6L);
httpOpts->setMaxBackoff(20E6L); httpOpts->setMaxBackoff(20E6L);
httpOpts->setTimeout(httpParams.has("timeout") ? httpParams["timeout"].asInteger() : 40L); httpOpts->setTimeout(http_params.has("timeout") ? http_params["timeout"].asInteger() : 40L);
if (httpParams.has("retries")) 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"); 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); httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
std::string user_agent = stringize( const LLVersionInfo& vi(LLVersionInfo::instance());
LLVersionInfo::instance().getChannel(), ' ', std::string user_agent = vi.getChannel() + llformat(" %d.%d.%d (%llu)",
LLVersionInfo::instance().getMajor(), '.', vi.getMajor(), vi.getMinor(), vi.getPatch(), vi.getBuild());
LLVersionInfo::instance().getMinor(), '.',
LLVersionInfo::instance().getPatch(), " (",
LLVersionInfo::instance().getBuild(), ')');
httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); 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 */ //This might help with bug #503 */
//httpOpts->setDNSCacheTimeout(-1); //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()); 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 body->append(request.c_str(), request.size());
// not fond of the copy here.
int requestSize(0);
char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize);
body->append(requestText, requestSize);
XMLRPC_Free(requestText);
mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler(mHttpRequest, this)); mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler(mHttpRequest, this));
mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID, mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID,
mURI, body.get(), httpOpts, httpHeaders, mHandler); mURI, body.get(), httpOpts, httpHeaders, mHandler);
}
LLXMLRPCTransaction::Impl::~Impl()
{
if (mResponse)
{
XMLRPC_RequestFree(mResponse, 1);
}
} }
bool LLXMLRPCTransaction::Impl::process() bool LLXMLRPCTransaction::Impl::process()
@ -539,18 +435,16 @@ void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status)
} }
LLXMLRPCTransaction::LLXMLRPCTransaction
LLXMLRPCTransaction::LLXMLRPCTransaction( (
const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams)
: impl(* new Impl(uri, request, useGzip, httpParams))
{ }
LLXMLRPCTransaction::LLXMLRPCTransaction(
const std::string& uri, const std::string& uri,
const std::string& method, LLXMLRPCValue params, bool useGzip) const std::string& method,
: impl(* new Impl(uri, method, params, useGzip)) const LLSD& params,
{ } const LLSD& http_params
)
: impl(*new Impl(uri, method, params, http_params))
{
}
LLXMLRPCTransaction::~LLXMLRPCTransaction() LLXMLRPCTransaction::~LLXMLRPCTransaction()
{ {
@ -590,14 +484,9 @@ std::string LLXMLRPCTransaction::statusURI()
return impl.mStatusURI; return impl.mStatusURI;
} }
XMLRPC_REQUEST LLXMLRPCTransaction::response() const LLSD& LLXMLRPCTransaction::response()
{ {
return impl.mResponse; return impl.mResponseData;
}
LLXMLRPCValue LLXMLRPCTransaction::responseValue()
{
return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse));
} }

View File

@ -29,73 +29,22 @@
#include <string> #include <string>
typedef struct _xmlrpc_request* XMLRPC_REQUEST; /// An asynchronous request and responses via XML-RPC
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;
};
class LLXMLRPCTransaction class LLXMLRPCTransaction
// an asynchronous request and responses via XML-RPC
{ {
public: public:
LLXMLRPCTransaction(const std::string& uri, LLXMLRPCTransaction
XMLRPC_REQUEST request, bool useGzip = true, const LLSD& httpParams = LLSD()); (
// does not take ownership of the request object const std::string& uri,
// request can be freed as soon as the transaction is constructed const std::string& method,
const LLSD& params,
LLXMLRPCTransaction(const std::string& uri, const LLSD& http_params = LLSD()
const std::string& method, LLXMLRPCValue params, bool useGzip = true); );
// *does* take control of the request value, you must not free it
~LLXMLRPCTransaction(); ~LLXMLRPCTransaction();
typedef enum e_status { typedef enum e_status
{
StatusNotStarted, StatusNotStarted,
StatusStarted, StatusStarted,
StatusDownloading, StatusDownloading,
@ -105,26 +54,25 @@ public:
StatusOtherError StatusOtherError
} EStatus; } EStatus;
/// Run the request a little, returns true when done
bool process(); 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); EStatus status(int* curlCode);
// return status, and extended CURL code, if code isn't null
LLSD getErrorCertData(); LLSD getErrorCertData();
/// Return a message string, suitable for showing the user
std::string statusMessage(); 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(); std::string statusURI();
// return a URI for the user with more information
// can be empty
XMLRPC_REQUEST response(); /// Only non-empty if StatusComplete, otherwise Undefined
LLXMLRPCValue responseValue(); const LLSD& response();
// only valid if StatusComplete, otherwise NULL
// retains ownership of the result object, don't free it
/// Only valid if StsatusComplete, otherwise 0.0
F64 transferRate(); F64 transferRate();
// only valid if StsatusComplete, otherwise 0.0
private: private:
class Handler; class Handler;
@ -133,6 +81,4 @@ private:
Impl& impl; Impl& impl;
}; };
#endif // LLXMLRPCTRANSACTION_H #endif // LLXMLRPCTRANSACTION_H

View File

@ -69,7 +69,6 @@ OpenSSL Copyright (C) 1998-2002 The OpenSSL Project.
PCRE Copyright (c) 1997-2008 University of Cambridge PCRE Copyright (c) 1997-2008 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler. zlib Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler.
google-perftools Copyright (c) 2005, Google Inc. google-perftools Copyright (c) 2005, Google Inc.

View File

@ -28,7 +28,6 @@ mit Open-Source-Beiträgen von:</text>
PCRE Copyright (c) 1997-2012 University of Cambridge. PCRE Copyright (c) 1997-2012 University of Cambridge.
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga. SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga.
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com). SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com).
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2012 Jean-loup Gailly und Mark Adler. zlib Copyright (C) 1995-2012 Jean-loup Gailly und Mark Adler.

View File

@ -111,7 +111,6 @@ Dummy Name replaced at run time
PCRE Copyright (c) 1997-2012 University of Cambridge PCRE Copyright (c) 1997-2012 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.

View File

@ -28,7 +28,6 @@ con contribuciones de código abierto de:</text>
PCRE Copyright (c) 1997-2012 University of Cambridge PCRE Copyright (c) 1997-2012 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2012 Jean-loup Gailly y Mark Adler. zlib Copyright (C) 1995-2012 Jean-loup Gailly y Mark Adler.

View File

@ -28,7 +28,6 @@ avec les contributions Open Source de :</text>
PCRE Copyright (c) 1997-2012 University of Cambridge PCRE Copyright (c) 1997-2012 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2012 Jean-Loup Gailly et Mark Adler. zlib Copyright (C) 1995-2012 Jean-Loup Gailly et Mark Adler.

View File

@ -28,7 +28,6 @@ con contributi open source da:</text>
PCRE Copyright (c) 1997-2012 University of Cambridge PCRE Copyright (c) 1997-2012 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2012 Jean-loup Gailly e Mark Adler. zlib Copyright (C) 1995-2012 Jean-loup Gailly e Mark Adler.

View File

@ -33,7 +33,6 @@ OpenSSL Copyright (C) 1998-2008 The OpenSSL Project.
PCRE Copyright (c) 1997-2012 University of Cambridge PCRE Copyright (c) 1997-2012 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.

View File

@ -28,7 +28,6 @@ com contribuições de código aberto de:</text>
PCRE Copyright (c) 1997-2012 University of Cambridge PCRE Copyright (c) 1997-2012 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.

View File

@ -28,7 +28,6 @@
PCRE (c) 1997-2012, Кембриджский университет PCRE (c) 1997-2012, Кембриджский университет
SDL (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SDL (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay (C) 1995-1998 Eric Young (eay@cryptsoft.com) SSLeay (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib (C) 1995-2012 Jean-loup Gailly и Mark Adler. zlib (C) 1995-2012 Jean-loup Gailly и Mark Adler.

View File

@ -28,7 +28,6 @@ açık kaynak kod katkısında bulunanlar şunlardır:</text>
PCRE Telif Hakkı (c) 1997-2012 University of Cambridge PCRE Telif Hakkı (c) 1997-2012 University of Cambridge
SDL Telif Hakkı (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SDL Telif Hakkı (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Telif Hakkı (C) 1995-1998 Eric Young (eay@cryptsoft.com) 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. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Telif Hakkı (C) 1995-2012 Jean-loup Gailly ve Mark Adler. zlib Telif Hakkı (C) 1995-2012 Jean-loup Gailly ve Mark Adler.

View File

@ -28,7 +28,6 @@
PCRE Copyright (c) 1997-2012 University of Cambridge PCRE Copyright (c) 1997-2012 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet. xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.

View File

@ -66,6 +66,16 @@ public:
LLEventPump& getEventPump() { return mPump; } LLEventPump& getEventPump() { return mPump; }
private: 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, LLSD getProgressEventLLSD(const std::string& state, const std::string& change,
const LLSD& data = LLSD()) const LLSD& data = LLSD())
{ {
@ -83,6 +93,7 @@ private:
{ {
status_data["data"] = data; status_data["data"] = data;
} }
return status_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 // Launch a coroutine with our login_() method. Run the coroutine until
// its first wait; at that point, return here. // its first wait; at that point, return here.
std::string coroname = std::string coroname =
LLCoros::instance().launch("LLLogin::Impl::login_", LLCoros::instance().launch("LLLogin::Impl::login_", [&]() { loginCoro(uri, login_params); });
boost::bind(&Impl::loginCoro, this, uri, login_params));
LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL; 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 // Instantiate this rendezvous point at namespace scope so it's already
// present no matter how early the updater might post to it. // present no matter how early the updater might post to it.
// Use an LLEventMailDrop, which has future-like semantics: regardless of the // 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) void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
{ {
LLSD printable_params = login_params; LLSD printable_params = hidePasswd(login_params);
if (printable_params.has("params")
&& printable_params["params"].has("passwd"))
{
printable_params["params"]["passwd"] = "*******";
}
try try
{ {
LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::getName() LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::getName()
@ -171,12 +179,7 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
++attempts; ++attempts;
LLSD progress_data; LLSD progress_data;
progress_data["attempt"] = attempts; progress_data["attempt"] = attempts;
progress_data["request"] = request; progress_data["request"] = hidePasswd(request);
if (progress_data["request"].has("params")
&& progress_data["request"]["params"].has("passwd"))
{
progress_data["request"]["params"]["passwd"] = "*******";
}
sendProgressEvent("offline", "authenticating", progress_data); sendProgressEvent("offline", "authenticating", progress_data);
// We expect zero or more "Downloading" status events, followed by // We expect zero or more "Downloading" status events, followed by