#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>
<string>vlc-bin</string>
</map>
<key>xmlrpc-epi</key>
<map>
<key>platforms</key>
<map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>aa12611374876196b3ebb6bda8d419a697217b8b</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-darwin64-8a05acf.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>ad0c8b41ee4b4de216382bec46ee1c25962a3f12</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-linux64-8a05acf.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
<key>windows64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>e53fd38c14b8c47c7c84dead8a1b211bb8be170c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-xmlrpc-epi/releases/download/v0.54.1.8a05acf/xmlrpc_epi-0.54.1.8a05acf-windows64-8a05acf.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>license</key>
<string>xmlrpc-epi</string>
<key>license_file</key>
<string>LICENSES/xmlrpc-epi.txt</string>
<key>copyright</key>
<string>Copyright: (C) 2000 Epinions, Inc.</string>
<key>version</key>
<string>0.54.1.8a05acf</string>
<key>name</key>
<string>xmlrpc-epi</string>
<key>description</key>
<string>XMLRPC Library</string>
</map>
<key>vulkan_gltf</key>
<map>
<key>platforms</key>

View File

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

View File

@ -6,5 +6,3 @@ include(EXPAT)
include(Tracy)
include(xxHash)
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;
}
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)
{

View File

@ -67,6 +67,8 @@ public:
static int close(LLFILE * file);
static std::string getContents(const std::string& filename);
// perms is a permissions mask like 0777 or 0700. In most cases it will
// be overridden by the user's umask. It is ignored on Windows.
// mkdir() considers "directory already exists" to be SUCCESS.

View File

@ -30,6 +30,7 @@
#include "linden_common.h"
#include "llsd.h"
#include "llbase64.h"
#include "llerror.h"
#include "../llmath/llmath.h"
#include "llformat.h"
@ -142,6 +143,8 @@ public:
virtual const String& asStringRef() const { static const std::string empty; return empty; }
virtual String asXMLRPCValue() const { return "<nil/>"; }
virtual bool has(const String&) const { return false; }
virtual LLSD get(const String&) const { return LLSD(); }
virtual LLSD getKeys() const { return LLSD::emptyArray(); }
@ -222,6 +225,8 @@ namespace
virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; }
virtual LLSD::Real asReal() const { return mValue ? 1 : 0; }
virtual LLSD::String asString() const;
virtual LLSD::String asXMLRPCValue() const { return mValue ? "<boolean>1</boolean>" : "<boolean>0</boolean>"; }
};
LLSD::String ImplBoolean::asString() const
@ -243,6 +248,8 @@ namespace
virtual LLSD::Integer asInteger() const { return mValue; }
virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const;
virtual LLSD::String asXMLRPCValue() const { return "<int>" + std::to_string(mValue) + "</int>"; }
};
LLSD::String ImplInteger::asString() const
@ -259,6 +266,8 @@ namespace
virtual LLSD::Integer asInteger() const;
virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const;
virtual LLSD::String asXMLRPCValue() const { return "<double>" + std::to_string(mValue) + "</double>"; }
};
LLSD::Boolean ImplReal::asBoolean() const
@ -286,9 +295,11 @@ namespace
virtual LLSD::URI asURI() const { return LLURI(mValue); }
virtual size_t size() const { return mValue.size(); }
virtual const LLSD::String& asStringRef() const { return mValue; }
virtual LLSD::String asXMLRPCValue() const { return "<string>" + LLStringFn::xml_encode(mValue) + "</string>"; }
};
LLSD::Integer ImplString::asInteger() const
LLSD::Integer ImplString::asInteger() const
{
// This must treat "1.23" not as an error, but as a number, which is
// then truncated down to an integer. Hence, this code doesn't call
@ -298,7 +309,7 @@ namespace
return (int)asReal();
}
LLSD::Real ImplString::asReal() const
LLSD::Real ImplString::asReal() const
{
F64 v = 0.0;
std::istringstream i_stream(mValue);
@ -323,6 +334,8 @@ namespace
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::UUID asUUID() const { return mValue; }
virtual LLSD::String asXMLRPCValue() const { return "<string>" + mValue.asString() + "</string>"; }
};
@ -344,6 +357,8 @@ namespace
}
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::Date asDate() const { return mValue; }
virtual LLSD::String asXMLRPCValue() const { return "<dateTime.iso8601>" + mValue.toHTTPDateString("%FT%T") + "</dateTime.iso8601>"; }
};
@ -355,6 +370,8 @@ namespace
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::URI asURI() const { return mValue; }
virtual LLSD::String asXMLRPCValue() const { return "<string>" + LLStringFn::xml_encode(mValue.asString()) + "</string>"; }
};
@ -365,13 +382,15 @@ namespace
ImplBinary(const LLSD::Binary& v) : Base(v) { }
virtual const LLSD::Binary& asBinary() const{ return mValue; }
virtual LLSD::String asXMLRPCValue() const { return "<base64>" + LLBase64::encode(mValue.data(), mValue.size()) + "</base64>"; }
};
class ImplMap : public LLSD::Impl
{
private:
typedef std::map<LLSD::String, LLSD> DataMap;
typedef std::map<LLSD::String, LLSD> DataMap;
DataMap mData;
@ -387,6 +406,19 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
virtual LLSD::String asXMLRPCValue() const
{
std::ostringstream os;
os << "<struct>";
for (const auto& it : mData)
{
os << "<member><name>" << LLStringFn::xml_encode(it.first) << "</name>"
<< it.second.asXMLRPCValue() << "</member>";
}
os << "</struct>";
return os.str();
}
virtual bool has(const LLSD::String&) const;
using LLSD::Impl::get; // Unhiding get(size_t)
@ -511,7 +543,7 @@ namespace
class ImplArray : public LLSD::Impl
{
private:
typedef std::vector<LLSD> DataVector;
typedef std::vector<LLSD> DataVector;
DataVector mData;
@ -527,6 +559,18 @@ namespace
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
virtual LLSD::String asXMLRPCValue() const
{
std::ostringstream os;
os << "<array><data>";
for (const auto& it : mData)
{
os << it.asXMLRPCValue();
}
os << "</data></array>";
return os.str();
}
using LLSD::Impl::get; // Unhiding get(LLSD::String)
using LLSD::Impl::erase; // Unhiding erase(LLSD::String)
using LLSD::Impl::ref; // Unhiding ref(LLSD::String)
@ -872,6 +916,155 @@ const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); }
const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); }
LLSD::String LLSD::asXMLRPCValue() const { return "<value>" + safe(impl).asXMLRPCValue() + "</value>"; }
static bool inline check(bool condition, const char* warning_message)
{
if (!condition)
{
LL_WARNS() << warning_message << LL_ENDL;
}
return condition;
}
static bool parseXMLRPCArrayValue(LLSD& target, LLSD::TreeNode* node)
{
LLSD::TreeNode* data = node->getFirstChild();
if (!check(data, "No array inner XML element (<data> expected)") ||
!check(data->hasName("data"), "Invalid array inner XML element (<data> expected)") ||
!check(!data->getNextSibling(), "Multiple array inner XML elements (single <data> expected)"))
return false;
for (LLSD::TreeNode* item = data->getFirstChild(); item; item = item->getNextSibling())
{
LLSD value;
if (!value.fromXMLRPCValue(item))
return false;
target.append(value);
}
return true;
}
static bool parseXMLRPCStructValue(LLSD& target, LLSD::TreeNode* node)
{
for (LLSD::TreeNode* item = node->getFirstChild(); item; item = item->getNextSibling())
{
if (!check(item->hasName("member"), "Invalid struct inner XML element (<member> expected)"))
return false;
std::string name;
LLSD value;
for (LLSD::TreeNode* subitem = item->getFirstChild(); subitem; subitem = subitem->getNextSibling())
{
if (subitem->hasName("name"))
{
name = LLStringFn::xml_decode(subitem->getTextContents());
}
else if (!value.fromXMLRPCValue(subitem))
{
return false;
}
}
if (!check(!name.empty(), "Empty struct member name"))
return false;
target.insert(name, value);
}
return true;
}
bool LLSD::fromXMLRPCValue(TreeNode* node)
{
clear();
llassert(node);
if (!node)
return false;
if (!check(node->hasName("value"), "Invalid XML element (<value> expected)"))
return false;
TreeNode* inner = node->getFirstChild();
if (!inner)
{
check(false, "No inner XML element (value type expected)");
// Value with no type qualifier is treated as string
assign(LLStringFn::xml_decode(node->getTextContents()));
return true;
}
if (!check(!inner->getNextSibling(), "Multiple inner XML elements (single expected)"))
return false;
if (inner->hasName("string"))
{
assign(LLStringFn::xml_decode(inner->getTextContents()));
return true;
}
if (inner->hasName("int") || inner->hasName("i4"))
{
assign(std::stoi(inner->getTextContents()));
return true;
}
if (inner->hasName("double"))
{
assign(std::stod(inner->getTextContents()));
return true;
}
if (inner->hasName("boolean"))
{
assign(!!std::stoi(inner->getTextContents()));
return true;
}
if (inner->hasName("dateTime.iso8601"))
{
assign(Date(inner->getTextContents()));
return true;
}
if (inner->hasName("base64"))
{
std::string decoded = LLBase64::decodeAsString(inner->getTextContents());
Binary binary(decoded.size());
memcpy(binary.data(), decoded.data(), decoded.size());
assign(binary);
return true;
}
if (inner->hasName("array"))
{
if (!parseXMLRPCArrayValue(*this, inner))
{
clear();
return false;
}
return true;
}
if (inner->hasName("struct"))
{
if (!parseXMLRPCStructValue(*this, inner))
{
clear();
return false;
}
return true;
}
check(false, "Unknown inner XML element (known value type expected)");
// Value with unknown type qualifier is treated as string
assign(LLStringFn::xml_decode(inner->getTextContents()));
return true;
}
// const char * helpers
LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
void LLSD::assign(const char* v)

View File

@ -259,10 +259,24 @@ public:
UUID asUUID() const;
Date asDate() const;
URI asURI() const;
const Binary& asBinary() const;
const Binary& asBinary() const;
// 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 Integer() const { return asInteger(); }
@ -275,7 +289,7 @@ public:
// This is needed because most platforms do not automatically
// convert the boolean negation as a bool in an if statement.
bool operator!() const {return !asBoolean();}
bool operator!() const { return !asBoolean(); }
//@}
/** @name Character Pointer Helpers

View File

@ -1208,6 +1208,75 @@ namespace LLStringFn
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
* string.

View File

@ -889,6 +889,20 @@ namespace LLStringFn
LL_COMMON_API std::string strip_invalid_xml(const std::string& input);
/**
* @brief Replace all characters that are not allowed in XML 1.0
* with corresponding literals: [ < > & ] => [ &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
* string. This is safe for utf-8

View File

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

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

View File

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

View File

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

View File

@ -182,7 +182,7 @@ public:
void refreshUI();
void startTransaction(TransactionType type, const LLXMLRPCValue& params);
void startTransaction(TransactionType type, const LLSD& params);
bool checkTransaction();
void tellUserError(const std::string& message, const std::string& uri);
@ -396,11 +396,10 @@ void LLFloaterBuyLandUI::updateParcelInfo()
// Can't have more than region max tasks, regardless of parcel
// object bonus factor.
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
if(region)
if (region)
{
S32 max_tasks_per_region = (S32)region->getMaxTasks();
mParcelSupportedObjects = llmin(
mParcelSupportedObjects, max_tasks_per_region);
mParcelSupportedObjects = llmin(mParcelSupportedObjects, max_tasks_per_region);
}
mParcelSoldWithObjects = parcel->getSellWithObjects();
@ -423,7 +422,7 @@ void LLFloaterBuyLandUI::updateParcelInfo()
// checks that we can buy the land
if(mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
if (mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
{
mCannotBuyReason = getString("cant_buy_for_group");
return;
@ -492,85 +491,56 @@ void LLFloaterBuyLandUI::updateParcelInfo()
void LLFloaterBuyLandUI::updateCovenantInfo()
{
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
if(!region) return;
if (!region)
return;
U8 sim_access = region->getSimAccess();
std::string rating = LLViewerRegion::accessToString(sim_access);
LLTextBox* region_name = getChild<LLTextBox>("region_name_text");
if (region_name)
std::string region_name_txt = region->getName() + " ("+rating +")";
region_name->setText(region_name_txt);
LLIconCtrl* rating_icon = getChild<LLIconCtrl>("rating_icon");
LLRect rect = rating_icon->getRect();
S32 region_name_width = llmin(region_name->getRect().getWidth(), region_name->getTextBoundingRect().getWidth());
S32 icon_left_pad = region_name->getRect().mLeft + region_name_width + ICON_PAD;
region_name->setToolTip(region_name->getText());
rating_icon->setRect(rect.setOriginAndSize(icon_left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
switch (sim_access)
{
std::string region_name_txt = region->getName() + " ("+rating +")";
region_name->setText(region_name_txt);
case SIM_ACCESS_PG:
rating_icon->setValue(getString("icon_PG"));
break;
LLIconCtrl* rating_icon = getChild<LLIconCtrl>("rating_icon");
LLRect rect = rating_icon->getRect();
S32 region_name_width = llmin(region_name->getRect().getWidth(), region_name->getTextBoundingRect().getWidth());
S32 icon_left_pad = region_name->getRect().mLeft + region_name_width + ICON_PAD;
region_name->setToolTip(region_name->getText());
rating_icon->setRect(rect.setOriginAndSize(icon_left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
case SIM_ACCESS_ADULT:
rating_icon->setValue(getString("icon_R"));
break;
switch(sim_access)
{
case SIM_ACCESS_PG:
rating_icon->setValue(getString("icon_PG"));
break;
case SIM_ACCESS_ADULT:
rating_icon->setValue(getString("icon_R"));
break;
default:
rating_icon->setValue(getString("icon_M"));
}
default:
rating_icon->setValue(getString("icon_M"));
}
LLTextBox* region_type = getChild<LLTextBox>("region_type_text");
if (region_type)
{
region_type->setText(region->getLocalizedSimProductName());
region_type->setToolTip(region->getLocalizedSimProductName());
}
region_type->setText(region->getLocalizedSimProductName());
region_type->setToolTip(region->getLocalizedSimProductName());
LLTextBox* resellable_clause = getChild<LLTextBox>("resellable_clause");
if (resellable_clause)
{
if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL))
{
resellable_clause->setText(getString("can_not_resell"));
}
else
{
resellable_clause->setText(getString("can_resell"));
}
}
const char* can_resell = region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL) ? "can_not_resell" : "can_resell";
resellable_clause->setText(getString(can_resell));
LLTextBox* changeable_clause = getChild<LLTextBox>("changeable_clause");
if (changeable_clause)
{
if (region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES))
{
changeable_clause->setText(getString("can_change"));
}
else
{
changeable_clause->setText(getString("can_not_change"));
}
}
const char* can_change = region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES) ? "can_change" : "can_not_change";
changeable_clause->setText(getString(can_change));
LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant");
if(check)
{
check->set(false);
check->setEnabled(true);
check->setCommitCallback(onChangeAgreeCovenant, this);
}
check->set(false);
check->setEnabled(true);
check->setCommitCallback(onChangeAgreeCovenant, this);
LLTextBox* box = getChild<LLTextBox>("covenant_text");
if(box)
{
box->setVisible(false);
}
box->setVisible(false);
// send EstateCovenantInfo message
LLMessageSystem *msg = gMessageSystem;
@ -584,10 +554,9 @@ void LLFloaterBuyLandUI::updateCovenantInfo()
// static
void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data)
{
LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)user_data;
if(self)
if (user_data)
{
self->refreshUI();
((LLFloaterBuyLandUI*)user_data)->refreshUI();
}
}
@ -626,13 +595,13 @@ void LLFloaterBuyLandUI::updateFloaterEstateName(const std::string& name)
void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text)
{
LLTextBox* editor = getChild<LLTextBox>("covenant_timestamp_text");
if (editor) editor->setText(text);
editor->setText(text);
}
void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name)
{
LLTextBox* box = getChild<LLTextBox>("estate_owner_text");
if (box) box->setText(name);
box->setText(name);
}
void LLFloaterBuyLandUI::updateWebSiteInfo()
@ -640,9 +609,10 @@ void LLFloaterBuyLandUI::updateWebSiteInfo()
S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea;
S32 askCurrencyBuy = mCurrency.getAmount();
if (mTransaction && mTransactionType == TransactionPreflight
&& mPreflightAskBillableArea == askBillableArea
&& mPreflightAskCurrencyBuy == askCurrencyBuy)
if (mTransaction &&
mTransactionType == TransactionPreflight &&
mPreflightAskBillableArea == askBillableArea &&
mPreflightAskCurrencyBuy == askCurrencyBuy)
{
return;
}
@ -664,27 +634,21 @@ void LLFloaterBuyLandUI::updateWebSiteInfo()
mSiteCurrencyEstimatedCost = 0;
#endif
LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
keywordArgs.appendString("agentId", gAgent.getID().asString());
keywordArgs.appendString(
"secureSessionId",
gAgent.getSecureSessionID().asString());
keywordArgs.appendString("language", LLUI::getLanguage());
keywordArgs.appendInt("billableArea", mPreflightAskBillableArea);
keywordArgs.appendInt("currencyBuy", mPreflightAskCurrencyBuy);
LLXMLRPCValue params = LLXMLRPCValue::createArray();
params.append(keywordArgs);
LLSD params = LLSD::emptyMap();
params["agentId"] = gAgent.getID().asString();
params["secureSessionId"] = gAgent.getSecureSessionID().asString();
params["language"] = LLUI::getLanguage();
params["billableArea"] = mPreflightAskBillableArea;
params["currencyBuy"] = mPreflightAskCurrencyBuy;
startTransaction(TransactionPreflight, params);
}
void LLFloaterBuyLandUI::finishWebSiteInfo()
{
const LLSD& result = mTransaction->response();
LLXMLRPCValue result = mTransaction->responseValue();
mSiteValid = result["success"].asBool();
mSiteValid = result["success"].asBoolean();
if (!mSiteValid)
{
tellUserError(
@ -694,31 +658,30 @@ void LLFloaterBuyLandUI::finishWebSiteInfo()
return;
}
LLXMLRPCValue membership = result["membership"];
mSiteMembershipUpgrade = membership["upgrade"].asBool();
const LLSD& membership = result["membership"];
mSiteMembershipUpgrade = membership["upgrade"].asBoolean();
mSiteMembershipAction = membership["action"].asString();
mSiteMembershipPlanIDs.clear();
mSiteMembershipPlanNames.clear();
LLXMLRPCValue levels = membership["levels"];
for (LLXMLRPCValue level = levels.rewind();
level.isValid();
level = levels.next())
const LLSD& levels = membership["levels"];
for (auto it = levels.beginArray(); it != levels.endArray(); ++it)
{
const LLSD& level = *it;
mSiteMembershipPlanIDs.push_back(level["id"].asString());
mSiteMembershipPlanNames.push_back(level["description"].asString());
}
mUserPlanChoice = 0;
LLXMLRPCValue landUse = result["landUse"];
mSiteLandUseUpgrade = landUse["upgrade"].asBool();
const LLSD& landUse = result["landUse"];
mSiteLandUseUpgrade = landUse["upgrade"].asBoolean();
mSiteLandUseAction = landUse["action"].asString();
LLXMLRPCValue currency = result["currency"];
if (currency["estimatedCost"].isValid())
const LLSD& currency = result["currency"];
if (currency.has("estimatedCost"))
{
mCurrency.setUSDEstimate(currency["estimatedCost"].asInt());
mCurrency.setUSDEstimate(currency["estimatedCost"].asInteger());
}
if (currency["estimatedLocalCost"].isValid())
if (currency.has("estimatedLocalCost"))
{
mCurrency.setLocalEstimate(currency["estimatedLocalCost"].asString());
}
@ -760,35 +723,30 @@ void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password)
}
}
LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
keywordArgs.appendString("agentId", gAgent.getID().asString());
keywordArgs.appendString(
"secureSessionId",
gAgent.getSecureSessionID().asString());
keywordArgs.appendString("language", LLUI::getLanguage());
keywordArgs.appendString("levelId", newLevel);
keywordArgs.appendInt("billableArea",
mIsForGroup ? 0 : mParcelBillableArea);
keywordArgs.appendInt("currencyBuy", mCurrency.getAmount());
keywordArgs.appendInt("estimatedCost", mCurrency.getUSDEstimate());
keywordArgs.appendString("estimatedLocalCost", mCurrency.getLocalEstimate());
keywordArgs.appendString("confirm", mSiteConfirm);
LLSD params = LLSD::emptyMap();
params["agentId"] = gAgent.getID().asString();
params["secureSessionId"] = gAgent.getSecureSessionID().asString();
params["language"] = LLUI::getLanguage();
params["levelId"] = newLevel;
params["billableArea"] = mIsForGroup ? 0 : mParcelBillableArea;
params["currencyBuy"] = mCurrency.getAmount();
params["estimatedCost"] = mCurrency.getUSDEstimate();
params["estimatedLocalCost"] = mCurrency.getLocalEstimate();
params["confirm"] = mSiteConfirm;
if (!password.empty())
{
keywordArgs.appendString("password", password);
params["password"] = password;
}
LLXMLRPCValue params = LLXMLRPCValue::createArray();
params.append(keywordArgs);
startTransaction(TransactionBuy, params);
}
void LLFloaterBuyLandUI::finishWebSitePrep()
{
LLXMLRPCValue result = mTransaction->responseValue();
const LLSD& result = mTransaction->response();
bool success = result["success"].asBool();
bool success = result["success"].asBoolean();
if (!success)
{
tellUserError(
@ -850,7 +808,7 @@ void LLFloaterBuyLandUI::updateGroupName(const LLUUID& id,
}
}
void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params)
void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLSD& params)
{
delete mTransaction;
mTransaction = NULL;
@ -878,12 +836,7 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa
return;
}
mTransaction = new LLXMLRPCTransaction(
transaction_uri,
method,
params,
false /* don't use gzip */
);
mTransaction = new LLXMLRPCTransaction(transaction_uri, method, params);
}
bool LLFloaterBuyLandUI::checkTransaction()

View File

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

View File

@ -32,13 +32,15 @@
#include "llpanellogin.h"
#include "llviewercontrol.h"
#include "llviewernetwork.h"
#include "llfiltersd2xmlrpc.h"
#include "curl/curl.h"
const char* LLSLURL::SLURL_HTTP_SCHEME = "http";
const char* LLSLURL::SLURL_HTTPS_SCHEME = "https";
const char* LLSLURL::SLURL_SECONDLIFE_SCHEME = "secondlife";
const char* LLSLURL::SLURL_SECONDLIFE_PATH = "secondlife";
const char* LLSLURL::SLURL_COM = "slurl.com";
// For DnD - even though www.slurl.com redirects to slurl.com in a browser, you can copy and drag
// text with www.slurl.com or a link explicitly pointing at www.slurl.com so testing for this
// version is required also.
@ -437,7 +439,7 @@ std::string LLSLURL::getLoginString() const
LL_WARNS("AppInit") << "Unexpected SLURL type (" << (int)mType << ")for login string" << LL_ENDL;
break;
}
return xml_escape_string(unescaped_start.str());
return LLStringFn::xml_encode(unescaped_start.str(), true);
}
bool LLSLURL::operator ==(const LLSLURL& rhs)

View File

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

View File

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

View File

@ -39,12 +39,6 @@
#include <boost/scoped_ptr.hpp>
#include <boost/range.hpp> // boost::begin(), boost::end()
#ifdef LL_USESYSTEMLIBS
#include <xmlrpc.h>
#else
#include <xmlrpc-epi/xmlrpc.h>
#endif
#include "curl/curl.h"
// other Linden headers
@ -178,13 +172,6 @@ public:
static const CURLcodeMapper sCURLcodeMapper;
LLXMLRPCListener::LLXMLRPCListener(const std::string& pumpname):
mBoundListener(LLEventPumps::instance().
obtain(pumpname).
listen("LLXMLRPCListener", boost::bind(&LLXMLRPCListener::process, this, _1)))
{
}
/**
* Capture an outstanding LLXMLRPCTransaction and poll it periodically until
* done.
@ -213,38 +200,20 @@ public:
mMethod(command["method"]),
mReplyPump(command["reply"])
{
// LL_ERRS if any of these are missing
const char* required[] = { "uri", "method", "reply" };
// optional: "options" (array of string)
// Validate the request
std::set<std::string> missing;
for (const char** ri = boost::begin(required); ri != boost::end(required); ++ri)
// LL_ERRS if any of these keys are missing or empty
if (mUri.empty() || mMethod.empty() || mReplyPump.empty())
{
// If the command does not contain this required entry, add it to 'missing'.
if (! command.has(*ri))
{
missing.insert(*ri);
}
}
if (! missing.empty())
{
LL_ERRS("LLXMLRPCListener") << mMethod << " request missing params: ";
const char* separator = "";
for (std::set<std::string>::const_iterator mi(missing.begin()), mend(missing.end());
mi != mend; ++mi)
{
LL_CONT << separator << *mi;
separator = ", ";
}
LL_CONT << LL_ENDL;
LL_ERRS("LLXMLRPCListener")
<< "Some params are missing: "
<< "reply: '" << mReplyPump << "', "
<< "method: '" << mMethod << "', "
<< "uri: '" << mUri << "'"
<< LL_ENDL;
}
// Build the XMLRPC request.
XMLRPC_REQUEST request = XMLRPC_RequestNew();
XMLRPC_RequestSetMethodName(request, mMethod.c_str());
XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
XMLRPC_VALUE xparams = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
LLSD params(command["params"]);
LLSD request_params = LLSD::emptyMap();
LLSD params = command.get("params");
if (params.isMap())
{
for (LLSD::map_const_iterator pi(params.beginMap()), pend(params.endMap());
@ -252,44 +221,33 @@ public:
{
std::string name(pi->first);
LLSD param(pi->second);
if (param.isString())
switch (param.type())
{
XMLRPC_VectorAppendString(xparams, name.c_str(), param.asString().c_str(), 0);
}
else if (param.isInteger() || param.isBoolean())
{
XMLRPC_VectorAppendInt(xparams, name.c_str(), param.asInteger());
}
else if (param.isReal())
{
XMLRPC_VectorAppendDouble(xparams, name.c_str(), param.asReal());
}
else
{
LL_ERRS("LLXMLRPCListener") << mMethod << " request param "
<< name << " has unknown type: " << param << LL_ENDL;
case LLSD::TypeString:
case LLSD::TypeInteger:
case LLSD::TypeReal:
request_params.insert(name, param);
break;
case LLSD::TypeBoolean:
request_params.insert(name, param.asInteger());
break;
default:
LL_ERRS("LLXMLRPCListener") << mMethod
<< " request param '" << name << "' has unknown type: " << param << LL_ENDL;
}
}
}
LLSD options(command["options"]);
LLSD options = command.get("options");
if (options.isArray())
{
XMLRPC_VALUE xoptions = XMLRPC_CreateVector("options", xmlrpc_vector_array);
for (LLSD::array_const_iterator oi(options.beginArray()), oend(options.endArray());
oi != oend; ++oi)
{
XMLRPC_VectorAppendString(xoptions, NULL, oi->asString().c_str(), 0);
}
XMLRPC_AddValueToVector(xparams, xoptions);
request_params.insert("options", options);
}
XMLRPC_RequestSetData(request, xparams);
mTransaction.reset(new LLXMLRPCTransaction(mUri, request, true, command.has("http_params")? LLSD(command["http_params"]) : LLSD()));
LLSD http_params = command.get("http_params");
mTransaction.reset(new LLXMLRPCTransaction(mUri, mMethod, request_params, http_params));
mPreviousStatus = mTransaction->status(NULL);
// Free the XMLRPC_REQUEST object and the attached data values.
XMLRPC_RequestFree(request, 1);
// Now ensure that we get regular callbacks to poll for completion.
mBoundListener =
LLEventPumps::instance().
@ -323,7 +281,7 @@ public:
data["error"] = "";
data["transfer_rate"] = 0.0;
LLEventPump& replyPump(LLEventPumps::instance().obtain(mReplyPump));
if (! done)
if (!done)
{
// Not done yet, carry on.
if (status == LLXMLRPCTransaction::StatusDownloading
@ -367,10 +325,8 @@ public:
// Given 'message', need we care?
if (status == LLXMLRPCTransaction::StatusComplete)
{
// Success! Parse data.
std::string status_string(data["status"]);
data["responses"] = parseResponse(status_string);
data["status"] = status_string;
// Success! Retrieve response data.
data["responses"] = mTransaction->response();
}
// whether successful or not, send reply on requested LLEventPump
@ -388,159 +344,6 @@ public:
}
private:
/// Derived from LLUserAuth::parseResponse() and parseOptionInto()
LLSD parseResponse(std::string& status_string)
{
// Extract every member into data["responses"] (a map of string
// values).
XMLRPC_REQUEST response = mTransaction->response();
if (! response)
{
LL_DEBUGS("LLXMLRPCListener") << "No response" << LL_ENDL;
return LLSD();
}
XMLRPC_VALUE param = XMLRPC_RequestGetData(response);
if (! param)
{
LL_DEBUGS("LLXMLRPCListener") << "Response contains no data" << LL_ENDL;
return LLSD();
}
// Now, parse everything
return parseValues(status_string, "", param);
}
LLSD parseValue(std::string& status_string, const std::string& key, const std::string& key_pfx, XMLRPC_VALUE param)
{
LLSD response;
XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(param);
switch (type)
{
case xmlrpc_type_empty:
LL_INFOS("LLXMLRPCListener") << "Empty result for key " << key_pfx << key << LL_ENDL;
break;
case xmlrpc_type_base64:
{
S32 len = XMLRPC_GetValueStringLen(param);
const char* buf = XMLRPC_GetValueBase64(param);
if ((len > 0) && buf)
{
// During implementation this code was not tested
// If you encounter this, please make sure this is correct,
// then remove llassert
llassert(0);
LLSD::Binary data;
data.resize(len);
memcpy((void*)&data[0], (void*)buf, len);
response = data;
}
else
{
LL_WARNS("LLXMLRPCListener") << "Potentially malformed xmlrpc_type_base64 for key "
<< key_pfx << key << LL_ENDL;
}
break;
}
case xmlrpc_type_boolean:
{
response = LLSD::Boolean(XMLRPC_GetValueBoolean(param));
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
break;
}
case xmlrpc_type_datetime:
{
std::string iso8601_date(XMLRPC_GetValueDateTime_ISO8601(param));
LL_DEBUGS("LLXMLRPCListener") << "val: " << iso8601_date << LL_ENDL;
response = LLSD::Date(iso8601_date);
break;
}
case xmlrpc_type_double:
{
response = LLSD::Real(XMLRPC_GetValueDouble(param));
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
break;
}
case xmlrpc_type_int:
{
response = LLSD::Integer(XMLRPC_GetValueInt(param));
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
break;
}
case xmlrpc_type_string:
{
response = LLSD::String(XMLRPC_GetValueString(param));
LL_DEBUGS("LLXMLRPCListener") << "val: " << response << LL_ENDL;
break;
}
case xmlrpc_type_mixed:
case xmlrpc_type_array:
{
// We expect this to be an array of submaps. Walk the array,
// recursively parsing each submap and collecting them.
LLSD array;
int i = 0; // for descriptive purposes
for (XMLRPC_VALUE row = XMLRPC_VectorRewind(param); row;
row = XMLRPC_VectorNext(param), ++i)
{
// Recursive call. For the lower-level key_pfx, if 'key'
// is "foo", pass "foo[0]:", then "foo[1]:", etc. In the
// nested call, a subkey "bar" will then be logged as
// "foo[0]:bar", and so forth.
// Parse the scalar subkey/value pairs from this array
// entry into a temp submap. Collect such submaps in 'array'.
array.append(parseValue(status_string, "",
STRINGIZE(key_pfx << key << '[' << i << "]:"),
row));
}
// Having collected an 'array' of 'submap's, insert that whole
// 'array' as the value of this 'key'.
response = array;
break;
}
case xmlrpc_type_struct:
{
response = parseValues(status_string,
STRINGIZE(key_pfx << key << ':'),
param);
break;
}
case xmlrpc_type_none: // Not expected
default:
// whoops - unrecognized type
LL_WARNS("LLXMLRPCListener") << "Unhandled xmlrpc type " << type << " for key "
<< key_pfx << key << LL_ENDL;
response = STRINGIZE("<bad XMLRPC type " << type << '>');
status_string = "BadType";
}
return response;
}
/**
* Parse key/value pairs from a given XMLRPC_VALUE into an LLSD map.
* @param key_pfx Used to describe a given key in log messages. At top
* level, pass "". When parsing an options array, pass the top-level key
* name of the array plus the index of the array entry; to this we'll
* append the subkey of interest.
* @param param XMLRPC_VALUE iterator. At top level, pass
* XMLRPC_RequestGetData(XMLRPC_REQUEST).
*/
LLSD parseValues(std::string& status_string, const std::string& key_pfx, XMLRPC_VALUE param)
{
LLSD responses;
for (XMLRPC_VALUE current = XMLRPC_VectorRewind(param); current;
current = XMLRPC_VectorNext(param))
{
std::string key(XMLRPC_GetValueID(current));
LL_DEBUGS("LLXMLRPCListener") << "key: " << key_pfx << key << LL_ENDL;
responses.insert(key, parseValue(status_string, key, key_pfx, current));
}
return responses;
}
const LLReqID mReqID;
const std::string mUri;
const std::string mMethod;
@ -550,11 +353,18 @@ private:
LLXMLRPCTransaction::EStatus mPreviousStatus; // To detect state changes.
};
bool LLXMLRPCListener::process(const LLSD& command)
LLXMLRPCListener::LLXMLRPCListener(const std::string& pumpname)
: mBoundListener(LLEventPumps::instance().obtain(pumpname).listen
(
"LLXMLRPCListener",
[&](const LLSD& command) -> bool
{
// Allocate a new heap Poller, but do not save a pointer to it. Poller
// will check its own status and free itself on completion of the request.
(new Poller(command));
// Conventional event listener return
return false;
}
))
{
// Allocate a new heap Poller, but do not save a pointer to it. Poller
// will check its own status and free itself on completion of the request.
(new Poller(command));
// conventional event listener return
return false;
}

View File

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

View File

@ -42,22 +42,11 @@
#include "bufferarray.h"
#include "llversioninfo.h"
#include "llviewercontrol.h"
#include "llxmlnode.h"
#include "stringize.h"
// Have to include these last to avoid queue redefinition!
#ifdef LL_USESYSTEMLIBS
#include <xmlrpc.h>
#else
#include <xmlrpc-epi/xmlrpc.h>
#endif
// <xmlrpc-epi/queue.h> contains a harmful #define queue xmlrpc_queue. This
// breaks any use of std::queue. Ditch that #define: if any of our code wants
// to reference xmlrpc_queue, let it reference it directly.
#if defined(queue)
#undef queue
#endif
#include "llappviewer.h"
#include "lltrans.h"
@ -75,111 +64,6 @@ namespace boost
// nothing.
static LLXMLRPCListener listener("LLXMLRPCTransaction");
LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const
{
return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id));
}
std::string LLXMLRPCValue::asString() const
{
const char* s = XMLRPC_GetValueString(mV);
return s ? s : "";
}
int LLXMLRPCValue::asInt() const { return XMLRPC_GetValueInt(mV); }
bool LLXMLRPCValue::asBool() const { return XMLRPC_GetValueBoolean(mV) != 0; }
double LLXMLRPCValue::asDouble() const { return XMLRPC_GetValueDouble(mV); }
LLXMLRPCValue LLXMLRPCValue::rewind()
{
return LLXMLRPCValue(XMLRPC_VectorRewind(mV));
}
LLXMLRPCValue LLXMLRPCValue::next()
{
return LLXMLRPCValue(XMLRPC_VectorNext(mV));
}
bool LLXMLRPCValue::isValid() const
{
return mV != NULL;
}
LLXMLRPCValue LLXMLRPCValue::createArray()
{
return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_array));
}
LLXMLRPCValue LLXMLRPCValue::createStruct()
{
return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_struct));
}
void LLXMLRPCValue::append(LLXMLRPCValue& v)
{
XMLRPC_AddValueToVector(mV, v.mV);
}
void LLXMLRPCValue::appendString(const std::string& v)
{
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(NULL, v.c_str(), 0));
}
void LLXMLRPCValue::appendInt(int v)
{
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(NULL, v));
}
void LLXMLRPCValue::appendBool(bool v)
{
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(NULL, v));
}
void LLXMLRPCValue::appendDouble(double v)
{
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(NULL, v));
}
void LLXMLRPCValue::append(const char* id, LLXMLRPCValue& v)
{
XMLRPC_SetValueID(v.mV, id, 0);
XMLRPC_AddValueToVector(mV, v.mV);
}
void LLXMLRPCValue::appendString(const char* id, const std::string& v)
{
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(id, v.c_str(), 0));
}
void LLXMLRPCValue::appendInt(const char* id, int v)
{
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(id, v));
}
void LLXMLRPCValue::appendBool(const char* id, bool v)
{
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(id, v));
}
void LLXMLRPCValue::appendDouble(const char* id, double v)
{
XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(id, v));
}
void LLXMLRPCValue::cleanup()
{
XMLRPC_CleanupValue(mV);
mV = NULL;
}
XMLRPC_VALUE LLXMLRPCValue::getValue() const
{
return mV;
}
class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler
{
public:
@ -192,6 +76,9 @@ public:
private:
bool parseResponse(LLXMLNodePtr root);
bool parseValue(LLSD& target, LLXMLNodePtr source);
LLXMLRPCTransaction::Impl *mImpl;
LLCore::HttpRequest::ptr_t mRequest;
};
@ -213,26 +100,26 @@ public:
LLCore::HttpHandle mPostH;
std::string mURI;
std::string mProxyAddress;
std::string mResponseText;
XMLRPC_REQUEST mResponse;
std::string mCertStore;
LLSD mErrorCertData;
LLSD mResponseData;
Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams);
Impl(const std::string& uri,
const std::string& method, LLXMLRPCValue params, bool useGzip);
~Impl();
std::string mCertStore;
LLSD mErrorCertData;
Impl
(
const std::string& uri,
const std::string& method,
const LLSD& params,
const LLSD& httpParams
);
bool process();
void setStatus(EStatus code, const std::string& message = "", const std::string& uri = "");
void setHttpStatus(const LLCore::HttpStatus &status);
private:
void init(XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams);
};
LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request,
@ -275,89 +162,113 @@ void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle,
mImpl->setStatus(LLXMLRPCTransaction::StatusComplete);
mImpl->mTransferStats = response->getTransferStats();
// the contents of a buffer array are potentially noncontiguous, so we
// The contents of a buffer array are potentially noncontiguous, so we
// will need to copy them into an contiguous block of memory for XMLRPC.
LLCore::BufferArray *body = response->getBody();
char * bodydata = new char[body->size()];
mImpl->mResponseText.resize(body->size());
body->read(0, bodydata, body->size());
body->read(0, mImpl->mResponseText.data(), body->size());
mImpl->mResponse = XMLRPC_REQUEST_FromXML(bodydata, static_cast<int>(body->size()), 0);
delete[] bodydata;
bool hasError = false;
bool hasFault = false;
int faultCode = 0;
std::string faultString;
LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse));
if (error.isValid())
LLXMLNodePtr root;
if (!LLXMLNode::parseBuffer(mImpl->mResponseText.data(), body->size(), root, nullptr))
{
hasError = true;
faultCode = error["faultCode"].asInt();
faultString = error["faultString"].asString();
}
else if (XMLRPC_ResponseIsFault(mImpl->mResponse))
{
hasFault = true;
faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse);
faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse);
LL_WARNS() << "Failed parsing XML response; request URI: " << mImpl->mURI << LL_ENDL;
return;
}
if (hasError || hasFault)
{
mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
if (!parseResponse(root))
return;
LL_WARNS() << "LLXMLRPCTransaction XMLRPC "
<< (hasError ? "error " : "fault ")
<< faultCode << ": "
<< faultString << LL_ENDL;
LL_WARNS() << "LLXMLRPCTransaction request URI: "
<< mImpl->mURI << LL_ENDL;
LL_INFOS() << "XML response parsed successfully; request URI: " << mImpl->mURI << LL_ENDL;
}
struct XMLTreeNode final : public LLSD::TreeNode
{
XMLTreeNode(const LLXMLNodePtr impl)
: mImpl(impl)
, mFirstChild(impl ? create(impl->getFirstChild()) : nullptr)
, mNextSibling(impl ? create(impl->getNextSibling()) : nullptr)
{
}
static XMLTreeNode* create(LLXMLNodePtr node) { return node ? new XMLTreeNode(node) : nullptr; }
virtual bool hasName(const LLSD::String& name) const override { return mImpl && mImpl->hasName(name); }
virtual LLSD::String getTextContents() const override { return mImpl ? mImpl->getTextContents() : LLStringUtil::null; }
virtual TreeNode* getFirstChild() const override { return mFirstChild.get(); }
virtual TreeNode* getNextSibling() const override { return mNextSibling.get(); }
private:
const LLXMLNodePtr mImpl;
const std::shared_ptr<XMLTreeNode> mFirstChild;
const std::shared_ptr<XMLTreeNode> mNextSibling;
};
bool LLXMLRPCTransaction::Handler::parseResponse(LLXMLNodePtr root)
{
// We have alreasy checked in LLXMLNode::parseBuffer()
// that root contains exactly one child
if (!root->hasName("methodResponse"))
{
LL_WARNS() << "Invalid root element in XML response; request URI: " << mImpl->mURI << LL_ENDL;
return false;
}
LLXMLNodePtr first = root->getFirstChild();
LLXMLNodePtr second = first->getFirstChild();
if (!first->getNextSibling() && second && !second->getNextSibling())
{
if (first->hasName("fault"))
{
LLSD fault;
if (parseValue(fault, second) &&
fault.isMap() && fault.has("faultCode") && fault.has("faultString"))
{
LL_WARNS() << "Request failed;"
<< " faultCode: '" << fault.get("faultCode").asString() << "',"
<< " faultString: '" << fault.get("faultString").asString() << "',"
<< " request URI: " << mImpl->mURI << LL_ENDL;
return false;
}
}
else if (first->hasName("params") &&
second->hasName("param") && !second->getNextSibling())
{
LLXMLNodePtr third = second->getFirstChild();
if (third && !third->getNextSibling() && parseValue(mImpl->mResponseData, third))
{
return true;
}
}
}
LL_WARNS() << "Invalid response format; request URI: " << mImpl->mURI << LL_ENDL;
return false;
}
bool LLXMLRPCTransaction::Handler::parseValue(LLSD& target, LLXMLNodePtr source)
{
XMLTreeNode tn(source);
return target.fromXMLRPCValue(&tn);
}
//=========================================================================
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams)
: mHttpRequest(),
mStatus(LLXMLRPCTransaction::StatusNotStarted),
mURI(uri),
mResponse(0)
{
init(request, useGzip, httpParams);
}
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
const std::string& method, LLXMLRPCValue params, bool useGzip)
: mHttpRequest(),
mStatus(LLXMLRPCTransaction::StatusNotStarted),
mURI(uri),
mResponse(0)
{
XMLRPC_REQUEST request = XMLRPC_RequestNew();
XMLRPC_RequestSetMethodName(request, method.c_str());
XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
XMLRPC_RequestSetData(request, params.getValue());
init(request, useGzip, LLSD());
// DEV-28398: without this XMLRPC_RequestFree() call, it looks as though
// the 'request' object is simply leaked. It's less clear to me whether we
// should also ask to free request value data (second param 1), since the
// data come from 'params'.
XMLRPC_RequestFree(request, 1);
}
void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams)
LLXMLRPCTransaction::Impl::Impl
(
const std::string& uri,
const std::string& method,
const LLSD& params,
const LLSD& http_params
)
: mHttpRequest()
, mStatus(LLXMLRPCTransaction::StatusNotStarted)
, mURI(uri)
{
LLCore::HttpOptions::ptr_t httpOpts;
LLCore::HttpHeaders::ptr_t httpHeaders;
if (!mHttpRequest)
{
mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);
@ -366,37 +277,34 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const
// LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions());
// delay between repeats will start from 5 sec and grow to 20 sec with each repeat
// Delay between repeats will start from 5 sec and grow to 20 sec with each repeat
httpOpts->setMinBackoff(5E6L);
httpOpts->setMaxBackoff(20E6L);
httpOpts->setTimeout(httpParams.has("timeout") ? httpParams["timeout"].asInteger() : 40L);
if (httpParams.has("retries"))
httpOpts->setTimeout(http_params.has("timeout") ? http_params["timeout"].asInteger() : 40L);
if (http_params.has("retries"))
{
httpOpts->setRetries(httpParams["retries"].asInteger());
httpOpts->setRetries(http_params["retries"].asInteger());
}
if (httpParams.has("DNSCacheTimeout"))
if (http_params.has("DNSCacheTimeout"))
{
httpOpts->setDNSCacheTimeout(httpParams["DNSCacheTimeout"].asInteger());
httpOpts->setDNSCacheTimeout(http_params["DNSCacheTimeout"].asInteger());
}
bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
mCertStore = gSavedSettings.getString("CertStore");
httpOpts->setSSLVerifyPeer( vefifySSLCert );
httpOpts->setSSLVerifyHost( vefifySSLCert ? 2 : 0);
httpOpts->setSSLVerifyPeer(vefifySSLCert);
httpOpts->setSSLVerifyHost(vefifySSLCert ? 2 : 0);
// LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders());
httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
std::string user_agent = stringize(
LLVersionInfo::instance().getChannel(), ' ',
LLVersionInfo::instance().getMajor(), '.',
LLVersionInfo::instance().getMinor(), '.',
LLVersionInfo::instance().getPatch(), " (",
LLVersionInfo::instance().getBuild(), ')');
const LLVersionInfo& vi(LLVersionInfo::instance());
std::string user_agent = vi.getChannel() + llformat(" %d.%d.%d (%llu)",
vi.getMajor(), vi.getMinor(), vi.getPatch(), vi.getBuild());
httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent);
@ -404,31 +312,19 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const
//This might help with bug #503 */
//httpOpts->setDNSCacheTimeout(-1);
std::string request =
"<?xml version=\"1.0\"?><methodCall><methodName>" + method +
"</methodName><params><param>" + params.asXMLRPCValue() +
"</param></params></methodCall>";
LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray());
// TODO: See if there is a way to serialize to a preallocated buffer I'm
// not fond of the copy here.
int requestSize(0);
char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize);
body->append(request.c_str(), request.size());
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,
mURI, body.get(), httpOpts, httpHeaders, mHandler);
}
LLXMLRPCTransaction::Impl::~Impl()
{
if (mResponse)
{
XMLRPC_RequestFree(mResponse, 1);
}
}
bool LLXMLRPCTransaction::Impl::process()
@ -539,18 +435,16 @@ void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status)
}
LLXMLRPCTransaction::LLXMLRPCTransaction(
const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams)
: impl(* new Impl(uri, request, useGzip, httpParams))
{ }
LLXMLRPCTransaction::LLXMLRPCTransaction(
LLXMLRPCTransaction::LLXMLRPCTransaction
(
const std::string& uri,
const std::string& method, LLXMLRPCValue params, bool useGzip)
: impl(* new Impl(uri, method, params, useGzip))
{ }
const std::string& method,
const LLSD& params,
const LLSD& http_params
)
: impl(*new Impl(uri, method, params, http_params))
{
}
LLXMLRPCTransaction::~LLXMLRPCTransaction()
{
@ -590,14 +484,9 @@ std::string LLXMLRPCTransaction::statusURI()
return impl.mStatusURI;
}
XMLRPC_REQUEST LLXMLRPCTransaction::response()
const LLSD& LLXMLRPCTransaction::response()
{
return impl.mResponse;
}
LLXMLRPCValue LLXMLRPCTransaction::responseValue()
{
return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse));
return impl.mResponseData;
}

View File

@ -29,73 +29,22 @@
#include <string>
typedef struct _xmlrpc_request* XMLRPC_REQUEST;
typedef struct _xmlrpc_value* XMLRPC_VALUE;
// foward decl of types from xmlrpc.h (this usage is type safe)
class LLCertificate;
class LLXMLRPCValue
// a c++ wrapper around XMLRPC_VALUE
{
public:
LLXMLRPCValue() : mV(NULL) { }
LLXMLRPCValue(XMLRPC_VALUE value) : mV(value) { }
bool isValid() const;
std::string asString() const;
int asInt() const;
bool asBool() const;
double asDouble() const;
LLXMLRPCValue operator[](const char*) const;
LLXMLRPCValue rewind();
LLXMLRPCValue next();
static LLXMLRPCValue createArray();
static LLXMLRPCValue createStruct();
void append(LLXMLRPCValue&);
void appendString(const std::string&);
void appendInt(int);
void appendBool(bool);
void appendDouble(double);
void appendValue(LLXMLRPCValue&);
void append(const char*, LLXMLRPCValue&);
void appendString(const char*, const std::string&);
void appendInt(const char*, int);
void appendBool(const char*, bool);
void appendDouble(const char*, double);
void appendValue(const char*, LLXMLRPCValue&);
void cleanup();
// only call this on the top level created value
XMLRPC_VALUE getValue() const;
private:
XMLRPC_VALUE mV;
};
/// An asynchronous request and responses via XML-RPC
class LLXMLRPCTransaction
// an asynchronous request and responses via XML-RPC
{
public:
LLXMLRPCTransaction(const std::string& uri,
XMLRPC_REQUEST request, bool useGzip = true, const LLSD& httpParams = LLSD());
// does not take ownership of the request object
// request can be freed as soon as the transaction is constructed
LLXMLRPCTransaction(const std::string& uri,
const std::string& method, LLXMLRPCValue params, bool useGzip = true);
// *does* take control of the request value, you must not free it
LLXMLRPCTransaction
(
const std::string& uri,
const std::string& method,
const LLSD& params,
const LLSD& http_params = LLSD()
);
~LLXMLRPCTransaction();
typedef enum e_status {
typedef enum e_status
{
StatusNotStarted,
StatusStarted,
StatusDownloading,
@ -105,26 +54,25 @@ public:
StatusOtherError
} EStatus;
/// Run the request a little, returns true when done
bool process();
// run the request a little, returns true when done
/// Return a status, and extended CURL code, if code isn't null
EStatus status(int* curlCode);
// return status, and extended CURL code, if code isn't null
LLSD getErrorCertData();
/// Return a message string, suitable for showing the user
std::string statusMessage();
// return a message string, suitable for showing the user
/// Return a URI for the user with more information (can be empty)
std::string statusURI();
// return a URI for the user with more information
// can be empty
XMLRPC_REQUEST response();
LLXMLRPCValue responseValue();
// only valid if StatusComplete, otherwise NULL
// retains ownership of the result object, don't free it
/// Only non-empty if StatusComplete, otherwise Undefined
const LLSD& response();
/// Only valid if StsatusComplete, otherwise 0.0
F64 transferRate();
// only valid if StsatusComplete, otherwise 0.0
private:
class Handler;
@ -133,6 +81,4 @@ private:
Impl& impl;
};
#endif // LLXMLRPCTRANSACTION_H

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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
SDL Telif Hakkı (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Telif Hakkı (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Telif Hakkı (C) 2000 Epinions, Inc.
xxHash Copyright (C) 2012-2020 Yann Collet.
zlib Telif Hakkı (C) 1995-2012 Jean-loup Gailly ve Mark Adler.

View File

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

View File

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