Add XMLRPC support to LLHTTPClient and that instead of LLXMLRPCTransaction
This commit is contained in:
@@ -136,7 +136,7 @@ struct AICurlResponderBufferEvents {
|
||||
namespace AICurlInterface {
|
||||
|
||||
// Output parameter of AICurlPrivate::CurlEasyRequest::getResult.
|
||||
// Only used by LLXMLRPCTransaction::Impl.
|
||||
// Used in XMLRPCResponder.
|
||||
struct TransferInfo {
|
||||
TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) { }
|
||||
F64 mSizeDownload;
|
||||
|
||||
@@ -729,5 +729,5 @@ P(voiceCallCapResponder);
|
||||
P(voiceClientCapResponder);
|
||||
P(wholeModelFeeResponder);
|
||||
P(wholeModelUploadResponder);
|
||||
P2(XMLRPCTransaction, connect_40s);
|
||||
P2(XMLRPCResponder, connect_40s);
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "linden_common.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <xmlrpc-epi/xmlrpc.h>
|
||||
|
||||
#include "llhttpclient.h"
|
||||
#include "llbufferstream.h"
|
||||
@@ -40,6 +41,29 @@ extern AIHTTPTimeoutPolicy blockingPost_timeout;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class XMLRPCInjector : public Injector {
|
||||
public:
|
||||
XMLRPCInjector(XMLRPC_REQUEST request) : mRequest(request), mRequestText(NULL) { }
|
||||
~XMLRPCInjector() { XMLRPC_RequestFree(mRequest, 1); XMLRPC_Free(const_cast<char*>(mRequestText)); }
|
||||
|
||||
/*virtual*/ char const* contentType(void) const { return "text/xml"; }
|
||||
/*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer)
|
||||
{
|
||||
int requestTextSize;
|
||||
mRequestText = XMLRPC_REQUEST_ToXML(mRequest, &requestTextSize);
|
||||
if (!mRequestText)
|
||||
throw AICurlNoBody("XMLRPC_REQUEST_ToXML returned NULL.");
|
||||
LLBufferStream ostream(channels, buffer.get());
|
||||
ostream.write(mRequestText, requestTextSize);
|
||||
ostream << std::flush; // Always flush a LLBufferStream when done writing to it.
|
||||
return requestTextSize;
|
||||
}
|
||||
|
||||
private:
|
||||
XMLRPC_REQUEST const mRequest;
|
||||
char const* mRequestText;
|
||||
};
|
||||
|
||||
class LLSDInjector : public Injector
|
||||
{
|
||||
public:
|
||||
@@ -369,6 +393,22 @@ void LLHTTPClient::post4(std::string const& url, LLSD const& body, ResponderPtr
|
||||
request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers);
|
||||
}
|
||||
|
||||
void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, false); // Does use compression.
|
||||
}
|
||||
|
||||
void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
{
|
||||
XMLRPC_REQUEST xmlrpc_request = XMLRPC_RequestNew();
|
||||
XMLRPC_RequestSetMethodName(xmlrpc_request, method);
|
||||
XMLRPC_RequestSetRequestType(xmlrpc_request, xmlrpc_request_call);
|
||||
XMLRPC_RequestSetData(xmlrpc_request, value);
|
||||
// XMLRPCInjector takes ownership of xmlrpc_request and will free it when done.
|
||||
// LLURLRequest takes ownership of the XMLRPCInjector object and will free it when done.
|
||||
request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, true); // Does not use compression.
|
||||
}
|
||||
|
||||
void LLHTTPClient::postRaw4(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
{
|
||||
request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers);
|
||||
|
||||
@@ -43,6 +43,8 @@ class LLSD;
|
||||
class AIHTTPTimeoutPolicy;
|
||||
|
||||
extern AIHTTPTimeoutPolicy responderIgnore_timeout;
|
||||
typedef struct _xmlrpc_request* XMLRPC_REQUEST;
|
||||
typedef struct _xmlrpc_value* XMLRPC_VALUE;
|
||||
|
||||
class LLHTTPClient
|
||||
{
|
||||
@@ -84,6 +86,15 @@ public:
|
||||
static void post4(std::string const& url, LLSD const& body, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; post4(url, body, responder, headers); }
|
||||
|
||||
/** Takes ownership of request and deletes it when sent */
|
||||
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; postXMLRPC(url, request, responder, headers); }
|
||||
|
||||
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder)
|
||||
{ AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers); }
|
||||
|
||||
/** Takes ownership of data and deletes it when sent */
|
||||
static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers);
|
||||
static void postRaw4(std::string const& url, const char* data, S32 size, ResponderPtr responder)
|
||||
|
||||
@@ -544,7 +544,7 @@ set(viewer_SOURCE_FILES
|
||||
llworldmap.cpp
|
||||
llworldmipmap.cpp
|
||||
llworldmapview.cpp
|
||||
llxmlrpctransaction.cpp
|
||||
llxmlrpcresponder.cpp
|
||||
m7wlinterface.cpp
|
||||
NACLantispam.cpp
|
||||
noise.cpp
|
||||
@@ -1051,7 +1051,7 @@ set(viewer_HEADER_FILES
|
||||
llworldmap.h
|
||||
llworldmipmap.h
|
||||
llworldmapview.h
|
||||
llxmlrpctransaction.h
|
||||
llxmlrpcresponder.h
|
||||
m7wlinterface.h
|
||||
macmain.h
|
||||
NACLantispam.h
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
#include "llframetimer.h"
|
||||
#include "lllineeditor.h"
|
||||
#include "llviewchildren.h"
|
||||
#include "llxmlrpctransaction.h"
|
||||
#include "llxmlrpcresponder.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "llviewernetwork.h"
|
||||
|
||||
#include "hippogridmanager.h"
|
||||
@@ -89,8 +90,8 @@ public:
|
||||
};
|
||||
|
||||
TransactionType mTransactionType;
|
||||
LLXMLRPCTransaction* mTransaction;
|
||||
|
||||
boost::intrusive_ptr<XMLRPCResponder> mResponder;
|
||||
|
||||
bool mCurrencyChanged;
|
||||
LLFrameTimer mCurrencyKeyTimer;
|
||||
|
||||
@@ -128,14 +129,13 @@ LLCurrencyUIManager::Impl::Impl(LLPanel& dialog)
|
||||
mSiteCurrencyEstimated(false),
|
||||
mSiteCurrencyEstimatedCost(0),
|
||||
mBought(false),
|
||||
mTransactionType(TransactionNone), mTransaction(0),
|
||||
mTransactionType(TransactionNone),
|
||||
mCurrencyChanged(false)
|
||||
{
|
||||
}
|
||||
|
||||
LLCurrencyUIManager::Impl::~Impl()
|
||||
{
|
||||
delete mTransaction;
|
||||
}
|
||||
|
||||
void LLCurrencyUIManager::Impl::updateCurrencyInfo()
|
||||
@@ -166,7 +166,7 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo()
|
||||
|
||||
void LLCurrencyUIManager::Impl::finishCurrencyInfo()
|
||||
{
|
||||
LLXMLRPCValue result = mTransaction->responseValue();
|
||||
LLXMLRPCValue result = mResponder->responseValue();
|
||||
|
||||
bool success = result["success"].asBool();
|
||||
if (!success)
|
||||
@@ -219,7 +219,7 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
|
||||
|
||||
void LLCurrencyUIManager::Impl::finishCurrencyBuy()
|
||||
{
|
||||
LLXMLRPCValue result = mTransaction->responseValue();
|
||||
LLXMLRPCValue result = mResponder->responseValue();
|
||||
|
||||
bool success = result["success"].asBool();
|
||||
if (!success)
|
||||
@@ -246,34 +246,28 @@ void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
|
||||
transactionURI = LLViewerLogin::getInstance()->getHelperURI() + "currency.php";
|
||||
}
|
||||
|
||||
delete mTransaction;
|
||||
|
||||
mTransactionType = type;
|
||||
mTransaction = new LLXMLRPCTransaction(
|
||||
transactionURI,
|
||||
method,
|
||||
params,
|
||||
false /* don't use gzip */
|
||||
);
|
||||
mResponder = new XMLRPCResponder;
|
||||
LLHTTPClient::postXMLRPC(transactionURI, method, params.getValue(), mResponder);
|
||||
|
||||
clearError();
|
||||
}
|
||||
|
||||
bool LLCurrencyUIManager::Impl::checkTransaction()
|
||||
{
|
||||
if (!mTransaction)
|
||||
if (!mResponder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mTransaction->is_finished())
|
||||
if (!mResponder->is_finished())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete)
|
||||
if (mResponder->result_code() != CURLE_OK || mResponder->http_result() < 200 || mResponder->http_result() >= 400)
|
||||
{
|
||||
setError(mTransaction->statusMessage(), mTransaction->statusURI());
|
||||
setError(mResponder->reason(), mResponder->getURL());
|
||||
}
|
||||
else {
|
||||
switch (mTransactionType)
|
||||
@@ -283,11 +277,11 @@ bool LLCurrencyUIManager::Impl::checkTransaction()
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
delete mTransaction;
|
||||
mTransaction = NULL;
|
||||
|
||||
// We're done with this data.
|
||||
mResponder = NULL;
|
||||
mTransactionType = TransactionNone;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -309,7 +303,7 @@ void LLCurrencyUIManager::Impl::clearError()
|
||||
bool LLCurrencyUIManager::Impl::considerUpdateCurrency()
|
||||
{
|
||||
if (mCurrencyChanged
|
||||
&& !mTransaction
|
||||
&& !mResponder
|
||||
&& mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
|
||||
{
|
||||
updateCurrencyInfo();
|
||||
|
||||
@@ -62,8 +62,9 @@
|
||||
#include "llweb.h"
|
||||
#include "llwindow.h"
|
||||
#include "llworld.h"
|
||||
#include "llxmlrpctransaction.h"
|
||||
#include "llxmlrpcresponder.h"
|
||||
#include "llviewernetwork.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "roles_constants.h"
|
||||
|
||||
#include "hippogridmanager.h"
|
||||
@@ -158,7 +159,7 @@ private:
|
||||
TransactionCurrency,
|
||||
TransactionBuy
|
||||
};
|
||||
LLXMLRPCTransaction* mTransaction;
|
||||
boost::intrusive_ptr<XMLRPCResponder> mResponder;
|
||||
TransactionType mTransactionType;
|
||||
|
||||
LLViewerParcelMgr::ParcelBuyInfo* mParcelBuyInfo;
|
||||
@@ -283,7 +284,7 @@ LLFloaterBuyLandUI::LLFloaterBuyLandUI()
|
||||
mParcel(0),
|
||||
mBought(false),
|
||||
mParcelValid(false), mSiteValid(false),
|
||||
mChildren(*this), mCurrency(*this), mTransaction(0),
|
||||
mChildren(*this), mCurrency(*this),
|
||||
mParcelBuyInfo(0)
|
||||
{
|
||||
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_buy_land.xml");
|
||||
@@ -294,8 +295,6 @@ LLFloaterBuyLandUI::~LLFloaterBuyLandUI()
|
||||
{
|
||||
LLViewerParcelMgr::getInstance()->removeObserver(&mParcelSelectionObserver);
|
||||
LLViewerParcelMgr::getInstance()->deleteParcelBuy(&mParcelBuyInfo);
|
||||
|
||||
delete mTransaction;
|
||||
}
|
||||
|
||||
// virtual
|
||||
@@ -619,7 +618,7 @@ void LLFloaterBuyLandUI::updateWebSiteInfo()
|
||||
S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea;
|
||||
S32 askCurrencyBuy = mCurrency.getAmount();
|
||||
|
||||
if (mTransaction && mTransactionType == TransactionPreflight
|
||||
if (mResponder && mTransactionType == TransactionPreflight
|
||||
&& mPreflightAskBillableArea == askBillableArea
|
||||
&& mPreflightAskCurrencyBuy == askCurrencyBuy)
|
||||
{
|
||||
@@ -660,7 +659,7 @@ void LLFloaterBuyLandUI::updateWebSiteInfo()
|
||||
void LLFloaterBuyLandUI::finishWebSiteInfo()
|
||||
{
|
||||
|
||||
LLXMLRPCValue result = mTransaction->responseValue();
|
||||
LLXMLRPCValue result = mResponder->responseValue();
|
||||
|
||||
mSiteValid = result["success"].asBool();
|
||||
if (!mSiteValid)
|
||||
@@ -755,7 +754,7 @@ void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password)
|
||||
|
||||
void LLFloaterBuyLandUI::finishWebSitePrep()
|
||||
{
|
||||
LLXMLRPCValue result = mTransaction->responseValue();
|
||||
LLXMLRPCValue result = mResponder->responseValue();
|
||||
|
||||
bool success = result["success"].asBool();
|
||||
if (!success)
|
||||
@@ -825,9 +824,6 @@ void LLFloaterBuyLandUI::updateName(const LLUUID& id,
|
||||
|
||||
void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params)
|
||||
{
|
||||
delete mTransaction;
|
||||
mTransaction = NULL;
|
||||
|
||||
mTransactionType = type;
|
||||
|
||||
// Select a URI and method appropriate for the transaction type.
|
||||
@@ -851,29 +847,25 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa
|
||||
return;
|
||||
}
|
||||
|
||||
mTransaction = new LLXMLRPCTransaction(
|
||||
transaction_uri,
|
||||
method,
|
||||
params,
|
||||
false /* don't use gzip */
|
||||
);
|
||||
mResponder = new XMLRPCResponder;
|
||||
LLHTTPClient::postXMLRPC(transaction_uri, method, params.getValue(), mResponder);
|
||||
}
|
||||
|
||||
bool LLFloaterBuyLandUI::checkTransaction()
|
||||
{
|
||||
if (!mTransaction)
|
||||
if (!mResponder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mTransaction->is_finished())
|
||||
if (!mResponder->is_finished())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete)
|
||||
if (mResponder->result_code() != CURLE_OK || mResponder->http_result() < 200 || mResponder->http_result() >= 400)
|
||||
{
|
||||
tellUserError(mTransaction->statusMessage(), mTransaction->statusURI());
|
||||
tellUserError(mResponder->reason(), mResponder->getURL());
|
||||
}
|
||||
else {
|
||||
switch (mTransactionType)
|
||||
@@ -884,8 +876,8 @@ bool LLFloaterBuyLandUI::checkTransaction()
|
||||
}
|
||||
}
|
||||
|
||||
delete mTransaction;
|
||||
mTransaction = NULL;
|
||||
// We're done with this data.
|
||||
mResponder = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -918,7 +910,7 @@ BOOL LLFloaterBuyLandUI::postBuild()
|
||||
|
||||
void LLFloaterBuyLandUI::setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel)
|
||||
{
|
||||
if (mTransaction && mTransactionType == TransactionBuy)
|
||||
if (mResponder && mTransactionType == TransactionBuy)
|
||||
{
|
||||
// the user is buying, don't change the selection
|
||||
return;
|
||||
@@ -968,7 +960,7 @@ void LLFloaterBuyLandUI::draw()
|
||||
// virtual
|
||||
BOOL LLFloaterBuyLandUI::canClose()
|
||||
{
|
||||
bool can_close = (mTransaction ? FALSE : TRUE) && mCurrency.canCancel();
|
||||
bool can_close = !mResponder && mCurrency.canCancel();
|
||||
if (!can_close)
|
||||
{
|
||||
// explain to user why they can't do this, see DEV-9605
|
||||
@@ -1285,7 +1277,7 @@ void LLFloaterBuyLandUI::refreshUI()
|
||||
}
|
||||
|
||||
childSetEnabled("buy_btn",
|
||||
mCanBuy && mSiteValid && willHaveEnough && !mTransaction && agrees_to_covenant);
|
||||
mCanBuy && mSiteValid && willHaveEnough && !mResponder && agrees_to_covenant);
|
||||
}
|
||||
|
||||
void LLFloaterBuyLandUI::startBuyPreConfirm()
|
||||
|
||||
@@ -42,8 +42,9 @@
|
||||
#include "llappviewer.h"
|
||||
#include "llviewerbuild.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llxmlrpctransaction.h"
|
||||
#include "llxmlrpcresponder.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llhttpclient.h"
|
||||
#include "stringize.h"
|
||||
|
||||
// NOTE: MUST include these after otherincludes since queue gets redefined!?!!
|
||||
@@ -73,7 +74,6 @@ static const char* PLATFORM_STRING = "Sol";
|
||||
|
||||
|
||||
LLUserAuth::LLUserAuth() :
|
||||
mTransaction(NULL),
|
||||
mLastTransferRateBPS(0),
|
||||
mResult(LLSD())
|
||||
{
|
||||
@@ -87,13 +87,11 @@ LLUserAuth::~LLUserAuth()
|
||||
|
||||
void LLUserAuth::reset()
|
||||
{
|
||||
delete mTransaction;
|
||||
mTransaction = NULL;
|
||||
mResponder = NULL;
|
||||
mResponses.clear();
|
||||
mResult.clear();
|
||||
}
|
||||
|
||||
|
||||
void LLUserAuth::authenticate(
|
||||
const std::string& auth_uri,
|
||||
const std::string& method,
|
||||
@@ -168,15 +166,13 @@ void LLUserAuth::authenticate(
|
||||
// put the parameters on the request
|
||||
XMLRPC_RequestSetData(request, params);
|
||||
|
||||
mTransaction = new LLXMLRPCTransaction(auth_uri, request);
|
||||
|
||||
XMLRPC_RequestFree(request, 1);
|
||||
mResponder = new XMLRPCResponder;
|
||||
LLHTTPClient::postXMLRPC(auth_uri, request, mResponder);
|
||||
|
||||
LL_INFOS2("AppInit", "Authentication") << "LLUserAuth::authenticate: uri=" << auth_uri << LL_ENDL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Legacy version of constructor
|
||||
|
||||
// passwd is already MD5 hashed by the time we get to it.
|
||||
@@ -258,25 +254,25 @@ void LLUserAuth::authenticate(
|
||||
// put the parameters on the request
|
||||
XMLRPC_RequestSetData(request, params);
|
||||
|
||||
mTransaction = new LLXMLRPCTransaction(auth_uri, request);
|
||||
// Post the XML RPC.
|
||||
mResponder = new XMLRPCResponder;
|
||||
LLHTTPClient::postXMLRPC(auth_uri, request, mResponder);
|
||||
|
||||
XMLRPC_RequestFree(request, 1);
|
||||
|
||||
LL_INFOS2("AppInit", "Authentication") << "LLUserAuth::authenticate: uri=" << auth_uri << LL_ENDL;
|
||||
}
|
||||
|
||||
|
||||
LLUserAuth::UserAuthcode LLUserAuth::authResponse()
|
||||
{
|
||||
if (!mTransaction)
|
||||
if (!mResponder)
|
||||
{
|
||||
return mAuthResponse;
|
||||
}
|
||||
|
||||
bool done = mTransaction->is_finished();
|
||||
bool done = mResponder->is_finished();
|
||||
|
||||
if (!done) {
|
||||
if (LLXMLRPCTransaction::StatusDownloading == mTransaction->status(0))
|
||||
if (mResponder->is_downloading())
|
||||
{
|
||||
mAuthResponse = E_DOWNLOADING;
|
||||
}
|
||||
@@ -284,14 +280,11 @@ LLUserAuth::UserAuthcode LLUserAuth::authResponse()
|
||||
return mAuthResponse;
|
||||
}
|
||||
|
||||
|
||||
mLastTransferRateBPS = mTransaction->transferRate();
|
||||
mLastTransferRateBPS = mResponder->transferRate();
|
||||
mErrorMessage = mResponder->reason();
|
||||
|
||||
int result;
|
||||
mTransaction->status(&result);
|
||||
mErrorMessage = mTransaction->statusMessage();
|
||||
|
||||
// if curl was ok, parse the download area.
|
||||
CURLcode result = mResponder->result_code();
|
||||
switch (result)
|
||||
{
|
||||
case CURLE_OK:
|
||||
@@ -313,12 +306,12 @@ LLUserAuth::UserAuthcode LLUserAuth::authResponse()
|
||||
mAuthResponse = E_UNHANDLED_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
LL_INFOS2("AppInit", "Authentication") << "Processed response: " << result << LL_ENDL;
|
||||
|
||||
delete mTransaction;
|
||||
mTransaction = NULL;
|
||||
|
||||
// We're done with this data.
|
||||
mResponder = NULL;
|
||||
|
||||
return mAuthResponse;
|
||||
}
|
||||
|
||||
@@ -329,7 +322,7 @@ LLUserAuth::UserAuthcode LLUserAuth::parseResponse()
|
||||
// mOptions. For now, we will only be looking at mResponses, which
|
||||
// will all be string => string pairs.
|
||||
UserAuthcode rv = E_UNHANDLED_ERROR;
|
||||
XMLRPC_REQUEST response = mTransaction->response();
|
||||
XMLRPC_REQUEST response = mResponder->response();
|
||||
if(!response) return rv;
|
||||
|
||||
// clear out any old parsing
|
||||
|
||||
@@ -36,10 +36,13 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
typedef struct _xmlrpc_value* XMLRPC_VALUE;
|
||||
// forward ecl of types from xlrpc.h
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
class LLXMLRPCTransaction;
|
||||
class LLURLRequest;
|
||||
class XMLRPCResponder;
|
||||
|
||||
// forward decl of types from xlrpc.h
|
||||
typedef struct _xmlrpc_value* XMLRPC_VALUE;
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLUserAuth
|
||||
@@ -142,8 +145,7 @@ public:
|
||||
F64 getLastTransferRateBPS() const { return mLastTransferRateBPS; }
|
||||
|
||||
private:
|
||||
LLXMLRPCTransaction* mTransaction;
|
||||
|
||||
boost::intrusive_ptr<XMLRPCResponder> mResponder;
|
||||
|
||||
std::string mErrorMessage;
|
||||
|
||||
|
||||
322
indra/newview/llxmlrpcresponder.cpp
Normal file
322
indra/newview/llxmlrpcresponder.cpp
Normal file
@@ -0,0 +1,322 @@
|
||||
/**
|
||||
* @file llxmlrpcresponder.cpp
|
||||
* @brief LLXMLRPCResponder and related class implementations
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2006-2009, Linden Research, Inc.
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llxmlrpcresponder.h"
|
||||
#include "llhttpclient.h"
|
||||
|
||||
#include "llcurl.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llbufferstream.h"
|
||||
|
||||
// Have to include these last to avoid queue redefinition!
|
||||
#include <xmlrpc-epi/xmlrpc.h>
|
||||
|
||||
#include "llappviewer.h"
|
||||
|
||||
#include "hippogridmanager.h"
|
||||
#include "aicurleasyrequeststatemachine.h"
|
||||
|
||||
#ifdef CWDEBUG
|
||||
#include <libcwd/buf2str.h>
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void XMLRPCResponder::completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info)
|
||||
{
|
||||
mCode = code;
|
||||
if (info)
|
||||
{
|
||||
mTransferInfo = *info;
|
||||
}
|
||||
mStatus = status;
|
||||
mReason = reason;
|
||||
// Note: 'status' and 'reason' are the same as what is passed to completedRaw.
|
||||
}
|
||||
|
||||
void XMLRPCResponder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
|
||||
{
|
||||
if (mCode == CURLE_OK)
|
||||
{
|
||||
mBufferSize = buffer->count(channels.in());
|
||||
if (200 <= status && status < 400)
|
||||
{
|
||||
char* ptr;
|
||||
char* buf = NULL;
|
||||
LLMutexLock lock(buffer->getMutex());
|
||||
LLBufferArray::const_segment_iterator_t const end = buffer->endSegment();
|
||||
for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter)
|
||||
{
|
||||
LLSegment const& segment = *iter;
|
||||
if (segment.isOnChannel(channels.in()))
|
||||
{
|
||||
S32 const segment_size = segment.size();
|
||||
if (!buf)
|
||||
{
|
||||
if (segment_size == mBufferSize)
|
||||
{
|
||||
// It's contiguous, no need for copying.
|
||||
mResponse = XMLRPC_REQUEST_FromXML((char const*)segment.data(), mBufferSize, NULL);
|
||||
break;
|
||||
}
|
||||
ptr = buf = new char [mBufferSize];
|
||||
}
|
||||
llassert(ptr + segment_size <= buf + mBufferSize);
|
||||
memcpy(ptr, segment.data(), segment_size);
|
||||
ptr += segment_size;
|
||||
}
|
||||
}
|
||||
if (buf)
|
||||
{
|
||||
mResponse = XMLRPC_REQUEST_FromXML(buf, mBufferSize, NULL);
|
||||
delete [] buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
mFinished = true;
|
||||
}
|
||||
|
||||
LLXMLRPCValue XMLRPCResponder::responseValue(void) const
|
||||
{
|
||||
return LLXMLRPCValue(XMLRPC_RequestGetData(mResponse));
|
||||
}
|
||||
|
||||
#ifdef AI_UNUSED
|
||||
void LLXMLRPCTransaction::Impl::setStatus(Status status,
|
||||
const std::string& message, const std::string& uri)
|
||||
{
|
||||
mStatus = status;
|
||||
mStatusMessage = message;
|
||||
mStatusURI = uri;
|
||||
|
||||
if (mStatusMessage.empty())
|
||||
{
|
||||
switch (mStatus)
|
||||
{
|
||||
case StatusNotStarted:
|
||||
mStatusMessage = "(not started)";
|
||||
break;
|
||||
|
||||
case StatusStarted:
|
||||
mStatusMessage = "(waiting for server response)";
|
||||
break;
|
||||
|
||||
case StatusDownloading:
|
||||
mStatusMessage = "(reading server response)";
|
||||
break;
|
||||
|
||||
case StatusComplete:
|
||||
mStatusMessage = "(done)";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Usually this means that there's a problem with the login server,
|
||||
// not with the client. Direct user to status page.
|
||||
// NOTE: these should really be gHippoGridManager->getCurrentGrid()->getGridName()
|
||||
// but apparently that's broken as of 1.3 b2 -- MC
|
||||
mStatusMessage =
|
||||
"Despite our best efforts, something unexpected has gone wrong. \n"
|
||||
" \n"
|
||||
"Please check " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s status \n"
|
||||
"to see if there is a known problem with the service.";
|
||||
|
||||
//mStatusURI = "http://secondlife.com/status/";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code)
|
||||
{
|
||||
std::string message;
|
||||
std::string uri = gHippoGridManager->getCurrentGrid()->getSupportUrl();
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case CURLE_COULDNT_RESOLVE_HOST:
|
||||
message =
|
||||
"DNS could not resolve the host name.\n"
|
||||
"Please verify that you can connect to " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s\n"
|
||||
"web site. If you can, but continue to receive this error,\n"
|
||||
"please go to the support section and report this problem.";
|
||||
break;
|
||||
|
||||
case CURLE_SSL_PEER_CERTIFICATE:
|
||||
message =
|
||||
"The login server couldn't verify itself via SSL.\n"
|
||||
"If you continue to receive this error, please go\n"
|
||||
"to the Support section of " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s web site\n"
|
||||
"and report the problem.";
|
||||
break;
|
||||
|
||||
case CURLE_SSL_CACERT:
|
||||
case CURLE_SSL_CONNECT_ERROR:
|
||||
message =
|
||||
"Often this means that your computer's clock is set incorrectly.\n"
|
||||
"Please go to Control Panels and make sure the time and date\n"
|
||||
"are set correctly.\n"
|
||||
"\n"
|
||||
"If you continue to receive this error, please go\n"
|
||||
"to the Support section of " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s web site\n"
|
||||
"and report the problem.";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mCurlCode = code;
|
||||
setStatus(StatusCURLError, message, uri);
|
||||
}
|
||||
#endif // AI_UNUSED
|
||||
|
||||
F64 XMLRPCResponder::transferRate(void) const
|
||||
{
|
||||
if (mTransferInfo.mSpeedDownload == 0.0) // Don't print the below stats if this wasn't initialized.
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
F64 rate_bits_per_sec = mTransferInfo.mSpeedDownload * 8.0;
|
||||
|
||||
LL_INFOS("AppInit") << "Buffer size: " << mBufferSize << " B" << LL_ENDL;
|
||||
LL_DEBUGS("AppInit") << "Transfer size: " << mTransferInfo.mSizeDownload << " B" << LL_ENDL;
|
||||
LL_DEBUGS("AppInit") << "Transfer time: " << mTransferInfo.mTotalTime << " s" << LL_ENDL;
|
||||
LL_INFOS("AppInit") << "Transfer rate: " << rate_bits_per_sec / 1000.0 << " kb/s" << LL_ENDL;
|
||||
|
||||
return rate_bits_per_sec;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/**
|
||||
* @file llxmlrpctransaction.h
|
||||
* @brief LLXMLRPCTransaction and related class header file
|
||||
* @file llxmlrpcresponder.h
|
||||
* @brief LLXMLRPCResponder and related class header file
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2006-2009, Linden Research, Inc.
|
||||
* Copyright (c) 2012, Aleric Inglewood.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
@@ -30,10 +31,16 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LLXMLRPCTRANSACTION_H
|
||||
#define LLXMLRPCTRANSACTION_H
|
||||
#ifndef LLXMLRPCRESPONDER_H
|
||||
#define LLXMLRPCRESPONDER_H
|
||||
|
||||
#include <string>
|
||||
#include "llurlrequest.h" // Injector
|
||||
#include "llcurl.h"
|
||||
#include "llhttpstatuscodes.h"
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy XMLRPCResponder_timeout;
|
||||
|
||||
typedef struct _xmlrpc_request* XMLRPC_REQUEST;
|
||||
typedef struct _xmlrpc_value* XMLRPC_VALUE;
|
||||
@@ -84,56 +91,35 @@ private:
|
||||
XMLRPC_VALUE mV;
|
||||
};
|
||||
|
||||
|
||||
class LLXMLRPCTransaction
|
||||
// an asynchronous request and respones via XML-RPC
|
||||
{
|
||||
public:
|
||||
LLXMLRPCTransaction(const std::string& uri,
|
||||
XMLRPC_REQUEST request, bool useGzip = true);
|
||||
// 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();
|
||||
|
||||
typedef enum {
|
||||
StatusNotStarted,
|
||||
StatusStarted,
|
||||
StatusDownloading,
|
||||
StatusComplete,
|
||||
StatusCURLError,
|
||||
StatusXMLRPCError,
|
||||
StatusOtherError
|
||||
} Status;
|
||||
|
||||
bool is_finished(void) const;
|
||||
// Returns true when done.
|
||||
|
||||
Status status(int* curlCode);
|
||||
// return status, and extended CURL code, if code isn't null
|
||||
std::string statusMessage();
|
||||
// return a message string, suitable for showing the user
|
||||
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
|
||||
|
||||
F64 transferRate();
|
||||
// only valid if StatusComplete, otherwise 0.0
|
||||
|
||||
class XMLRPCResponder : public LLCurl::Responder {
|
||||
private:
|
||||
class Impl;
|
||||
Impl& impl;
|
||||
CURLcode mCode;
|
||||
U32 mStatus;
|
||||
AICurlInterface::TransferInfo mTransferInfo;
|
||||
S32 mBufferSize;
|
||||
bool mReceivedHTTPHeader;
|
||||
bool mFinished;
|
||||
std::string mReason;
|
||||
XMLRPC_REQUEST mResponse;
|
||||
|
||||
public:
|
||||
XMLRPCResponder(void) : mCode(CURLE_FAILED_INIT), mStatus(HTTP_INTERNAL_ERROR), mReceivedHTTPHeader(false), mFinished(false) { }
|
||||
|
||||
// Accessors.
|
||||
CURLcode result_code(void) const { return mCode; }
|
||||
U32 http_result(void) const { return mStatus; }
|
||||
F64 transferRate(void) const;
|
||||
bool is_downloading(void) const { return mReceivedHTTPHeader; }
|
||||
bool is_finished(void) const { return mFinished; }
|
||||
std::string const& reason(void) const { return mReason; }
|
||||
XMLRPC_REQUEST response(void) const { return mResponse; }
|
||||
LLXMLRPCValue responseValue(void) const;
|
||||
|
||||
/*virtual*/ bool needsHeaders(void) const { return true; }
|
||||
/*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLCurl::Responder::received_HTTP_header(); }
|
||||
/*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info);
|
||||
/*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer);
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return XMLRPCResponder_timeout; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // LLXMLRPCTRANSACTION_H
|
||||
#endif // LLXMLRPCRESPONDER_H
|
||||
@@ -1,577 +0,0 @@
|
||||
/**
|
||||
* @file llxmlrpctransaction.cpp
|
||||
* @brief LLXMLRPCTransaction and related class implementations
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2006-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llxmlrpctransaction.h"
|
||||
|
||||
#include "llcurl.h"
|
||||
#include "llviewercontrol.h"
|
||||
|
||||
// Have to include these last to avoid queue redefinition!
|
||||
#include <xmlrpc-epi/xmlrpc.h>
|
||||
|
||||
#include "llappviewer.h"
|
||||
|
||||
#include "hippogridmanager.h"
|
||||
#include "aicurleasyrequeststatemachine.h"
|
||||
|
||||
#ifdef CWDEBUG
|
||||
#include <libcwd/buf2str.h>
|
||||
#endif
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy XMLRPCTransaction_timeout;
|
||||
|
||||
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::Impl
|
||||
{
|
||||
public:
|
||||
typedef LLXMLRPCTransaction::Status Status;
|
||||
|
||||
AICurlEasyRequestStateMachine* mCurlEasyRequestStateMachinePtr;
|
||||
|
||||
Status mStatus;
|
||||
CURLcode mCurlCode;
|
||||
std::string mStatusMessage;
|
||||
std::string mStatusURI;
|
||||
LLCurl::TransferInfo mTransferInfo;
|
||||
|
||||
std::string mURI;
|
||||
|
||||
std::string mProxyAddress;
|
||||
|
||||
std::string mResponseText;
|
||||
XMLRPC_REQUEST mResponse;
|
||||
|
||||
Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip);
|
||||
Impl(const std::string& uri,
|
||||
const std::string& method, LLXMLRPCValue params, bool useGzip);
|
||||
~Impl();
|
||||
|
||||
bool is_finished(void) const;
|
||||
void curlEasyRequestCallback(bool success);
|
||||
|
||||
void setStatus(Status code,
|
||||
const std::string& message = "", const std::string& uri = "");
|
||||
void setCurlStatus(CURLcode);
|
||||
|
||||
private:
|
||||
void init(XMLRPC_REQUEST request, bool useGzip);
|
||||
|
||||
static size_t curlDownloadCallback(
|
||||
char* data, size_t size, size_t nmemb, void* user_data);
|
||||
};
|
||||
|
||||
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
|
||||
XMLRPC_REQUEST request, bool useGzip)
|
||||
: mCurlEasyRequestStateMachinePtr(NULL),
|
||||
mStatus(LLXMLRPCTransaction::StatusNotStarted),
|
||||
mURI(uri),
|
||||
mResponse(0)
|
||||
{
|
||||
init(request, useGzip);
|
||||
}
|
||||
|
||||
|
||||
LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
|
||||
const std::string& method, LLXMLRPCValue params, bool useGzip)
|
||||
: mCurlEasyRequestStateMachinePtr(NULL),
|
||||
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);
|
||||
}
|
||||
|
||||
// Store pointer to data allocated with XMLRPC_REQUEST_ToXML and call XMLRPC_Free to free it upon destruction.
|
||||
class AIXMLRPCData : public AIPostField
|
||||
{
|
||||
public:
|
||||
AIXMLRPCData(char const* allocated_data) : AIPostField(allocated_data) { }
|
||||
/*virtual*/ ~AIXMLRPCData() { XMLRPC_Free(const_cast<char*>(mData)); mData = NULL; }
|
||||
};
|
||||
|
||||
void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
mCurlEasyRequestStateMachinePtr = new AICurlEasyRequestStateMachine(false); // AIFIXME: This is the only unbuffered AICurlEasyRequestStateMachine left.
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
{
|
||||
llwarns << "Failed to initialize LLXMLRPCTransaction: " << error.what() << llendl;
|
||||
setStatus(StatusOtherError, "No curl easy handle");
|
||||
return;
|
||||
}
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequestStateMachinePtr->mCurlEasyRequest);
|
||||
|
||||
curlEasyRequest_w->setWriteCallback(&curlDownloadCallback, (void*)this);
|
||||
BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
|
||||
curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert);
|
||||
curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0);
|
||||
|
||||
/* Setting the DNS cache timeout to -1 disables it completely.
|
||||
This might help with bug #503 */
|
||||
curlEasyRequest_w->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1L);
|
||||
|
||||
curlEasyRequest_w->addHeader("Content-Type: text/xml");
|
||||
|
||||
if (useGzip)
|
||||
{
|
||||
curlEasyRequest_w->setoptString(CURLOPT_ENCODING, "");
|
||||
}
|
||||
|
||||
int requestTextSize;
|
||||
char* requestText = XMLRPC_REQUEST_ToXML(request, &requestTextSize);
|
||||
if (requestText)
|
||||
{
|
||||
curlEasyRequest_w->setPost(new AIXMLRPCData(requestText), requestTextSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
setStatus(StatusOtherError);
|
||||
}
|
||||
|
||||
curlEasyRequest_w->finalizeRequest(mURI, XMLRPCTransaction_timeout, mCurlEasyRequestStateMachinePtr);
|
||||
}
|
||||
if (mStatus == LLXMLRPCTransaction::StatusNotStarted) // It could be LLXMLRPCTransaction::StatusOtherError.
|
||||
{
|
||||
mCurlEasyRequestStateMachinePtr->run(boost::bind(&LLXMLRPCTransaction::Impl::curlEasyRequestCallback, this, _1));
|
||||
setStatus(LLXMLRPCTransaction::StatusStarted);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This deletes the statemachine immediately.
|
||||
mCurlEasyRequestStateMachinePtr->kill();
|
||||
mCurlEasyRequestStateMachinePtr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
LLXMLRPCTransaction::Impl::~Impl()
|
||||
{
|
||||
if (mCurlEasyRequestStateMachinePtr && mCurlEasyRequestStateMachinePtr->running())
|
||||
{
|
||||
llwarns << "Calling LLXMLRPCTransaction::Impl::~Impl while mCurlEasyRequestStateMachinePtr is still running" << llendl;
|
||||
mCurlEasyRequestStateMachinePtr->abort();
|
||||
}
|
||||
|
||||
if (mResponse)
|
||||
{
|
||||
XMLRPC_RequestFree(mResponse, 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool LLXMLRPCTransaction::Impl::is_finished(void) const
|
||||
{
|
||||
// Nothing to process anymore. Just wait till the statemachine finished.
|
||||
return mStatus != LLXMLRPCTransaction::StatusNotStarted &&
|
||||
mStatus != LLXMLRPCTransaction::StatusStarted &&
|
||||
mStatus != LLXMLRPCTransaction::StatusDownloading;
|
||||
}
|
||||
|
||||
void LLXMLRPCTransaction::Impl::curlEasyRequestCallback(bool success)
|
||||
{
|
||||
llassert(mStatus == LLXMLRPCTransaction::StatusStarted || mStatus == LLXMLRPCTransaction::StatusDownloading);
|
||||
|
||||
AICurlEasyRequestStateMachine* state_machine = mCurlEasyRequestStateMachinePtr;
|
||||
// We're done with the statemachine, one way or another.
|
||||
// Set mCurlEasyRequestStateMachinePtr to NULL so we won't call mCurlEasyRequestStateMachinePtr->running() in the destructor.
|
||||
// Note that the state machine auto-cleaning: it will be deleted by the main-thread after this function returns.
|
||||
mCurlEasyRequestStateMachinePtr = NULL;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
// AICurlEasyRequestStateMachine did abort.
|
||||
// This currently only happens when libcurl didn't finish before the timer expired, or when the viewer was quit.
|
||||
if (LLApp::isRunning())
|
||||
{
|
||||
std::ostringstream msg;
|
||||
F32 timeout_value = gSavedSettings.getF32("CurlRequestTimeout");
|
||||
msg << "Connection to " << mURI << " timed out (" << timeout_value << " s)!";
|
||||
if (timeout_value < 40)
|
||||
{
|
||||
msg << "\nTry increasing CurlRequestTimeout in Debug Settings.";
|
||||
}
|
||||
setStatus(LLXMLRPCTransaction::StatusOtherError, msg.str());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*state_machine->mCurlEasyRequest);
|
||||
CURLcode result;
|
||||
curlEasyRequest_w->getResult(&result, &mTransferInfo);
|
||||
|
||||
if (result != CURLE_OK)
|
||||
{
|
||||
setCurlStatus(result);
|
||||
llwarns << "LLXMLRPCTransaction CURL error: "
|
||||
<< AICurlInterface::strerror(mCurlCode) << llendl;
|
||||
llwarns << "LLXMLRPCTransaction request URI: "
|
||||
<< mURI << llendl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus(LLXMLRPCTransaction::StatusComplete);
|
||||
|
||||
mResponse = XMLRPC_REQUEST_FromXML(
|
||||
mResponseText.data(), mResponseText.size(), NULL);
|
||||
|
||||
bool hasError = false;
|
||||
bool hasFault = false;
|
||||
int faultCode = 0;
|
||||
std::string faultString;
|
||||
|
||||
LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
|
||||
if (error.isValid())
|
||||
{
|
||||
hasError = true;
|
||||
faultCode = error["faultCode"].asInt();
|
||||
faultString = error["faultString"].asString();
|
||||
}
|
||||
else if (XMLRPC_ResponseIsFault(mResponse))
|
||||
{
|
||||
hasFault = true;
|
||||
faultCode = XMLRPC_GetResponseFaultCode(mResponse);
|
||||
faultString = XMLRPC_GetResponseFaultString(mResponse);
|
||||
}
|
||||
|
||||
if (hasError || hasFault)
|
||||
{
|
||||
setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
|
||||
|
||||
llwarns << "LLXMLRPCTransaction XMLRPC "
|
||||
<< (hasError ? "error " : "fault ")
|
||||
<< faultCode << ": "
|
||||
<< faultString << llendl;
|
||||
llwarns << "LLXMLRPCTransaction request URI: "
|
||||
<< mURI << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
void LLXMLRPCTransaction::Impl::setStatus(Status status,
|
||||
const std::string& message, const std::string& uri)
|
||||
{
|
||||
mStatus = status;
|
||||
mStatusMessage = message;
|
||||
mStatusURI = uri;
|
||||
|
||||
if (mStatusMessage.empty())
|
||||
{
|
||||
switch (mStatus)
|
||||
{
|
||||
case StatusNotStarted:
|
||||
mStatusMessage = "(not started)";
|
||||
break;
|
||||
|
||||
case StatusStarted:
|
||||
mStatusMessage = "(waiting for server response)";
|
||||
break;
|
||||
|
||||
case StatusDownloading:
|
||||
mStatusMessage = "(reading server response)";
|
||||
break;
|
||||
|
||||
case StatusComplete:
|
||||
mStatusMessage = "(done)";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Usually this means that there's a problem with the login server,
|
||||
// not with the client. Direct user to status page.
|
||||
// NOTE: these should really be gHippoGridManager->getCurrentGrid()->getGridName()
|
||||
// but apparently that's broken as of 1.3 b2 -- MC
|
||||
mStatusMessage =
|
||||
"Despite our best efforts, something unexpected has gone wrong. \n"
|
||||
" \n"
|
||||
"Please check " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s status \n"
|
||||
"to see if there is a known problem with the service.";
|
||||
|
||||
//mStatusURI = "http://secondlife.com/status/";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code)
|
||||
{
|
||||
std::string message;
|
||||
std::string uri = gHippoGridManager->getCurrentGrid()->getSupportUrl();
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case CURLE_COULDNT_RESOLVE_HOST:
|
||||
message =
|
||||
"DNS could not resolve the host name.\n"
|
||||
"Please verify that you can connect to " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s\n"
|
||||
"web site. If you can, but continue to receive this error,\n"
|
||||
"please go to the support section and report this problem.";
|
||||
break;
|
||||
|
||||
case CURLE_SSL_PEER_CERTIFICATE:
|
||||
message =
|
||||
"The login server couldn't verify itself via SSL.\n"
|
||||
"If you continue to receive this error, please go\n"
|
||||
"to the Support section of " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s web site\n"
|
||||
"and report the problem.";
|
||||
break;
|
||||
|
||||
case CURLE_SSL_CACERT:
|
||||
case CURLE_SSL_CONNECT_ERROR:
|
||||
message =
|
||||
"Often this means that your computer's clock is set incorrectly.\n"
|
||||
"Please go to Control Panels and make sure the time and date\n"
|
||||
"are set correctly.\n"
|
||||
"\n"
|
||||
"If you continue to receive this error, please go\n"
|
||||
"to the Support section of " + gHippoGridManager->getCurrentGrid()->getGridName() + "'s web site\n"
|
||||
"and report the problem.";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mCurlCode = code;
|
||||
setStatus(StatusCURLError, message, uri);
|
||||
}
|
||||
|
||||
size_t LLXMLRPCTransaction::Impl::curlDownloadCallback(
|
||||
char* data, size_t size, size_t nmemb, void* user_data)
|
||||
{
|
||||
Impl& impl(*(Impl*)user_data);
|
||||
|
||||
size_t n = size * nmemb;
|
||||
|
||||
#ifdef CWDEBUG
|
||||
void* lockobj = impl.mCurlEasyRequestStateMachinePtr ? impl.mCurlEasyRequestStateMachinePtr->mCurlEasyRequest.get_ptr().get() : NULL;
|
||||
if (n < 80)
|
||||
Dout(dc::curl, "Entering LLXMLRPCTransaction::Impl::curlDownloadCallback(\"" <<
|
||||
buf2str(data, n) << "\", " << size << ", " << nmemb << ", " << user_data << ") [" << lockobj << ']');
|
||||
else
|
||||
Dout(dc::curl, "Entering LLXMLRPCTransaction::Impl::curlDownloadCallback(\"" <<
|
||||
buf2str(data, 40) << "\"...\"" << buf2str(data + n - 40, 40) << "\", " << size << ", " << nmemb << ", " << user_data << ") [" << lockobj << ']');
|
||||
#endif
|
||||
|
||||
impl.mResponseText.append(data, n);
|
||||
|
||||
if (impl.mStatus == LLXMLRPCTransaction::StatusStarted)
|
||||
{
|
||||
impl.setStatus(LLXMLRPCTransaction::StatusDownloading);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
LLXMLRPCTransaction::LLXMLRPCTransaction(
|
||||
const std::string& uri, XMLRPC_REQUEST request, bool useGzip)
|
||||
: impl(* new Impl(uri, request, useGzip))
|
||||
{ }
|
||||
|
||||
|
||||
LLXMLRPCTransaction::LLXMLRPCTransaction(
|
||||
const std::string& uri,
|
||||
const std::string& method, LLXMLRPCValue params, bool useGzip)
|
||||
: impl(* new Impl(uri, method, params, useGzip))
|
||||
{ }
|
||||
|
||||
LLXMLRPCTransaction::~LLXMLRPCTransaction()
|
||||
{
|
||||
delete &impl;
|
||||
}
|
||||
|
||||
bool LLXMLRPCTransaction::is_finished(void) const
|
||||
{
|
||||
return impl.is_finished();
|
||||
}
|
||||
|
||||
LLXMLRPCTransaction::Status LLXMLRPCTransaction::status(int* curlCode)
|
||||
{
|
||||
if (curlCode)
|
||||
{
|
||||
*curlCode =
|
||||
(impl.mStatus == StatusCURLError)
|
||||
? impl.mCurlCode
|
||||
: CURLE_OK;
|
||||
}
|
||||
|
||||
return impl.mStatus;
|
||||
}
|
||||
|
||||
std::string LLXMLRPCTransaction::statusMessage()
|
||||
{
|
||||
return impl.mStatusMessage;
|
||||
}
|
||||
|
||||
std::string LLXMLRPCTransaction::statusURI()
|
||||
{
|
||||
return impl.mStatusURI;
|
||||
}
|
||||
|
||||
XMLRPC_REQUEST LLXMLRPCTransaction::response()
|
||||
{
|
||||
return impl.mResponse;
|
||||
}
|
||||
|
||||
LLXMLRPCValue LLXMLRPCTransaction::responseValue()
|
||||
{
|
||||
return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse));
|
||||
}
|
||||
|
||||
|
||||
F64 LLXMLRPCTransaction::transferRate()
|
||||
{
|
||||
if (impl.mStatus != StatusComplete)
|
||||
{
|
||||
return 0.0L;
|
||||
}
|
||||
|
||||
double rate_bits_per_sec = impl.mTransferInfo.mSpeedDownload * 8.0;
|
||||
|
||||
LL_INFOS("AppInit") << "Buffer size: " << impl.mResponseText.size() << " B" << LL_ENDL;
|
||||
LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferInfo.mSizeDownload << " B" << LL_ENDL;
|
||||
LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferInfo.mTotalTime << " s" << LL_ENDL;
|
||||
LL_INFOS("AppInit") << "Transfer rate: " << rate_bits_per_sec / 1000.0 << " Kb/s" << LL_ENDL;
|
||||
|
||||
return rate_bits_per_sec;
|
||||
}
|
||||
Reference in New Issue
Block a user