summaryrefslogtreecommitdiff
path: root/indra/newview/llxmlrpctransaction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llxmlrpctransaction.cpp')
-rw-r--r--indra/newview/llxmlrpctransaction.cpp361
1 files changed, 125 insertions, 236 deletions
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index ec6e22cd7a..55622fb6b7 100644
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -42,22 +42,11 @@
#include "bufferarray.h"
#include "llversioninfo.h"
#include "llviewercontrol.h"
+#include "llxmlnode.h"
#include "stringize.h"
// Have to include these last to avoid queue redefinition!
-#ifdef LL_USESYSTEMLIBS
-#include <xmlrpc.h>
-#else
-#include <xmlrpc-epi/xmlrpc.h>
-#endif
-// <xmlrpc-epi/queue.h> contains a harmful #define queue xmlrpc_queue. This
-// breaks any use of std::queue. Ditch that #define: if any of our code wants
-// to reference xmlrpc_queue, let it reference it directly.
-#if defined(queue)
-#undef queue
-#endif
-
#include "llappviewer.h"
#include "lltrans.h"
@@ -75,111 +64,6 @@ namespace boost
// nothing.
static LLXMLRPCListener listener("LLXMLRPCTransaction");
-LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const
-{
- return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id));
-}
-
-std::string LLXMLRPCValue::asString() const
-{
- const char* s = XMLRPC_GetValueString(mV);
- return s ? s : "";
-}
-
-int LLXMLRPCValue::asInt() const { return XMLRPC_GetValueInt(mV); }
-bool LLXMLRPCValue::asBool() const { return XMLRPC_GetValueBoolean(mV) != 0; }
-double LLXMLRPCValue::asDouble() const { return XMLRPC_GetValueDouble(mV); }
-
-LLXMLRPCValue LLXMLRPCValue::rewind()
-{
- return LLXMLRPCValue(XMLRPC_VectorRewind(mV));
-}
-
-LLXMLRPCValue LLXMLRPCValue::next()
-{
- return LLXMLRPCValue(XMLRPC_VectorNext(mV));
-}
-
-bool LLXMLRPCValue::isValid() const
-{
- return mV != NULL;
-}
-
-LLXMLRPCValue LLXMLRPCValue::createArray()
-{
- return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_array));
-}
-
-LLXMLRPCValue LLXMLRPCValue::createStruct()
-{
- return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_struct));
-}
-
-
-void LLXMLRPCValue::append(LLXMLRPCValue& v)
-{
- XMLRPC_AddValueToVector(mV, v.mV);
-}
-
-void LLXMLRPCValue::appendString(const std::string& v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(NULL, v.c_str(), 0));
-}
-
-void LLXMLRPCValue::appendInt(int v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(NULL, v));
-}
-
-void LLXMLRPCValue::appendBool(bool v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(NULL, v));
-}
-
-void LLXMLRPCValue::appendDouble(double v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(NULL, v));
-}
-
-
-void LLXMLRPCValue::append(const char* id, LLXMLRPCValue& v)
-{
- XMLRPC_SetValueID(v.mV, id, 0);
- XMLRPC_AddValueToVector(mV, v.mV);
-}
-
-void LLXMLRPCValue::appendString(const char* id, const std::string& v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(id, v.c_str(), 0));
-}
-
-void LLXMLRPCValue::appendInt(const char* id, int v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(id, v));
-}
-
-void LLXMLRPCValue::appendBool(const char* id, bool v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(id, v));
-}
-
-void LLXMLRPCValue::appendDouble(const char* id, double v)
-{
- XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(id, v));
-}
-
-void LLXMLRPCValue::cleanup()
-{
- XMLRPC_CleanupValue(mV);
- mV = NULL;
-}
-
-XMLRPC_VALUE LLXMLRPCValue::getValue() const
-{
- return mV;
-}
-
-
class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler
{
public:
@@ -192,6 +76,9 @@ public:
private:
+ bool parseResponse(LLXMLNodePtr root);
+ bool parseValue(LLSD& target, LLXMLNodePtr source);
+
LLXMLRPCTransaction::Impl *mImpl;
LLCore::HttpRequest::ptr_t mRequest;
};
@@ -213,26 +100,26 @@ public:
LLCore::HttpHandle mPostH;
std::string mURI;
-
std::string mProxyAddress;
std::string mResponseText;
- XMLRPC_REQUEST mResponse;
+ LLSD mResponseData;
+
std::string mCertStore;
- LLSD mErrorCertData;
+ LLSD mErrorCertData;
- Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams);
- Impl(const std::string& uri,
- const std::string& method, LLXMLRPCValue params, bool useGzip);
- ~Impl();
+ Impl
+ (
+ const std::string& uri,
+ const std::string& method,
+ const LLSD& params,
+ const LLSD& httpParams
+ );
bool process();
void setStatus(EStatus code, const std::string& message = "", const std::string& uri = "");
void setHttpStatus(const LLCore::HttpStatus &status);
-
-private:
- void init(XMLRPC_REQUEST request, bool useGzip, const LLSD& httpParams);
};
LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request,
@@ -275,89 +162,113 @@ void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle,
mImpl->setStatus(LLXMLRPCTransaction::StatusComplete);
mImpl->mTransferStats = response->getTransferStats();
- // the contents of a buffer array are potentially noncontiguous, so we
+ // The contents of a buffer array are potentially noncontiguous, so we
// will need to copy them into an contiguous block of memory for XMLRPC.
LLCore::BufferArray *body = response->getBody();
- char * bodydata = new char[body->size()];
+ mImpl->mResponseText.resize(body->size());
- body->read(0, bodydata, body->size());
+ body->read(0, mImpl->mResponseText.data(), body->size());
- mImpl->mResponse = XMLRPC_REQUEST_FromXML(bodydata, static_cast<int>(body->size()), 0);
+ LLXMLNodePtr root;
+ if (!LLXMLNode::parseBuffer(mImpl->mResponseText.data(), body->size(), root, nullptr))
+ {
+ LL_WARNS() << "Failed parsing XML response; request URI: " << mImpl->mURI << LL_ENDL;
+ return;
+ }
- delete[] bodydata;
+ if (!parseResponse(root))
+ return;
- bool hasError = false;
- bool hasFault = false;
- int faultCode = 0;
- std::string faultString;
+ LL_INFOS() << "XML response parsed successfully; request URI: " << mImpl->mURI << LL_ENDL;
+}
- LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse));
- if (error.isValid())
+struct XMLTreeNode final : public LLSD::TreeNode
+{
+ XMLTreeNode(const LLXMLNodePtr impl)
+ : mImpl(impl)
+ , mFirstChild(impl ? create(impl->getFirstChild()) : nullptr)
+ , mNextSibling(impl ? create(impl->getNextSibling()) : nullptr)
{
- hasError = true;
- faultCode = error["faultCode"].asInt();
- faultString = error["faultString"].asString();
}
- else if (XMLRPC_ResponseIsFault(mImpl->mResponse))
+
+ 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"))
{
- hasFault = true;
- faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse);
- faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse);
+ LL_WARNS() << "Invalid root element in XML response; request URI: " << mImpl->mURI << LL_ENDL;
+ return false;
}
- if (hasError || hasFault)
+ LLXMLNodePtr first = root->getFirstChild();
+ LLXMLNodePtr second = first->getFirstChild();
+ if (!first->getNextSibling() && second && !second->getNextSibling())
{
- mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
-
- LL_WARNS() << "LLXMLRPCTransaction XMLRPC "
- << (hasError ? "error " : "fault ")
- << faultCode << ": "
- << faultString << LL_ENDL;
- LL_WARNS() << "LLXMLRPCTransaction request URI: "
- << mImpl->mURI << LL_ENDL;
+ 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;
-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);
+ return false;
}
-
-LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
- const std::string& method, LLXMLRPCValue params, bool useGzip)
- : mHttpRequest(),
- mStatus(LLXMLRPCTransaction::StatusNotStarted),
- mURI(uri),
- mResponse(0)
+bool LLXMLRPCTransaction::Handler::parseValue(LLSD& target, LLXMLNodePtr source)
{
- 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);
+ XMLTreeNode tn(source);
+ return target.fromXMLRPCValue(&tn);
}
-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);
- LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray());
+ std::string request =
+ "<?xml version=\"1.0\"?><methodCall><methodName>" + method +
+ "</methodName><params><param>" + params.asXMLRPCValue() +
+ "</param></params></methodCall>";
- // TODO: See if there is a way to serialize to a preallocated buffer I'm
- // not fond of the copy here.
- int requestSize(0);
- char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize);
-
- body->append(requestText, requestSize);
+ LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray());
- XMLRPC_Free(requestText);
+ body->append(request.c_str(), request.size());
- 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()
-{
- return impl.mResponse;
-}
-
-LLXMLRPCValue LLXMLRPCTransaction::responseValue()
+const LLSD& LLXMLRPCTransaction::response()
{
- return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse));
+ return impl.mResponseData;
}