ResponderAdapter stuff
Renamed AICurlInterface::Responder to AICurlInterface::ResponderBase, but without the virtual 'event' methods. Derived from that: Responder and ReponderWithCompleted, where the first defines result = 0, ErrorWithContent and error, and the latter completedRaw and completed. Added HttpClient::IgnoreBody, derived from Responder and implementing 'result' doing nothing; HttpClient::Ignore is now derived from IgnoreBody and defines the still pure virtual getHTTPTimeoutPolicy. Added ResponderBase::decode_body, which is now the sole place where the code makes the decision wether some response data might be LLSD or not based on the http status result. Before it just tried to decode everything as LLSD, which seems a bit nonsense. ResponderWithCompleted::completed no longer does anything, since classes derived from ResponderWithCompleted are expected to override it, or never call it by overriding completedRaw. Entry point is now ResponderBase::finished = 0, instead of completedRaw, where ResponderWithCompleted implements finished by called completedRaw, but Responder doesn't: that directly calls result/errorWithContent/error. Or, for the hack ResponderAdapter, the entry points are pubResult/pubErrorWithContent. Those are now the ONLY public methods, so more confusion. mFinished is now set in all cases. As a result of all that, it is no longer possible to accidently pass a responder to ResponderAdapter that would break because it expects completed() and completedRaw() to be called. Added LLBufferArray::writeChannelTo. Fixed bug for BlockingResponder::body (returned reference to temporary). LLSDMessage::ResponderAdapter now allows a "timeoutpolicy" name to be passed (not doing so results in the default timings), so that the timeout policy of the used responder is retained. Fixed llfasttimerview.cpp to test LLSDSerialize::fromXML() to return a positive value instead of non-zero, because it may return -1 when the parsing fails (three places). Removed LLHTTPClient::Responder as base class from LLFloaterRegionDebugConsole completely: it isn't a responder! Several other responder classes were simplified a bit in order to compile again with the above changes.
This commit is contained in:
@@ -186,6 +186,7 @@ AIHTTPTimeoutPolicy::AIHTTPTimeoutPolicy(char const* name, AIHTTPTimeoutPolicyBa
|
||||
mMaximumCurlTransaction(mBase->mMaximumCurlTransaction),
|
||||
mMaximumTotalDelay(mBase->mMaximumTotalDelay)
|
||||
{
|
||||
sNameMap.insert(namemap_t::value_type(name, this));
|
||||
// Register for changes to the base policy.
|
||||
mBase->derived(this);
|
||||
}
|
||||
@@ -645,6 +646,24 @@ AIHTTPTimeoutPolicyBase connect_40s(AIHTTPTimeoutPolicyBase::getDebugSettingsCur
|
||||
// End of policy definitions.
|
||||
//=======================================================================================================
|
||||
|
||||
//static
|
||||
AIHTTPTimeoutPolicy::namemap_t AIHTTPTimeoutPolicy::sNameMap;
|
||||
|
||||
//static
|
||||
AIHTTPTimeoutPolicy const* AIHTTPTimeoutPolicy::getTimeoutPolicyByName(std::string const& name)
|
||||
{
|
||||
namemap_t::iterator iter = sNameMap.find(name);
|
||||
if (iter == sNameMap.end())
|
||||
{
|
||||
if (!name.empty())
|
||||
{
|
||||
llwarns << "Cannot find AIHTTPTimeoutPolicy with name \"" << name << "\"." << llendl;
|
||||
}
|
||||
return &sDebugSettingsCurlTimeout;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
//=======================================================================================================
|
||||
// Start of Responder timeout policy list.
|
||||
|
||||
@@ -674,9 +693,7 @@ P(environmentApplyResponder);
|
||||
P(environmentRequestResponder);
|
||||
P(estateChangeInfoResponder);
|
||||
P(eventPollResponder);
|
||||
P(eventResponder);
|
||||
P(fetchInventoryResponder);
|
||||
P(floaterRegionDebugConsole);
|
||||
P(fnPtrResponder);
|
||||
P2(groupProposalBallotResponder, transfer_300s);
|
||||
P(homeLocationResponder);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class AIHTTPTimeoutPolicyBase;
|
||||
|
||||
@@ -52,6 +53,8 @@ class AIHTTPTimeoutPolicy {
|
||||
char const* const mName; // The name of this policy, for debugging purposes.
|
||||
AIHTTPTimeoutPolicyBase* const mBase; // Policy this policy was based on.
|
||||
static AIHTTPTimeoutPolicyBase sDebugSettingsCurlTimeout; // CurlTimeout* debug settings.
|
||||
typedef std::map<std::string, AIHTTPTimeoutPolicy*> namemap_t; // Type of sNameMap.
|
||||
static namemap_t sNameMap; // Map of name of timeout policies (as returned by name()) to AIHTTPTimeoutPolicy* (this).
|
||||
|
||||
private:
|
||||
U16 mDNSLookupGrace; // Extra connect timeout the first time we connect to a host (this is to allow for DNS lookups).
|
||||
@@ -97,6 +100,7 @@ class AIHTTPTimeoutPolicy {
|
||||
U16 getCurlTransaction(void) const { return mMaximumCurlTransaction; }
|
||||
U16 getTotalDelay(void) const { return mMaximumTotalDelay; }
|
||||
static AIHTTPTimeoutPolicy const& getDebugSettingsCurlTimeout(void);
|
||||
static AIHTTPTimeoutPolicy const* getTimeoutPolicyByName(std::string const& name);
|
||||
|
||||
// Called once at start up of viewer to set a different default timeout policy than HTTPTimeoutPolicy_default.
|
||||
static void setDefaultCurlTimeout(AIHTTPTimeoutPolicy const& defaultCurlTimeout);
|
||||
|
||||
@@ -650,6 +650,20 @@ U8* LLBufferArray::readAfter(
|
||||
return rv;
|
||||
}
|
||||
|
||||
void LLBufferArray::writeChannelTo(std::ostream& ostr, S32 channel) const
|
||||
{
|
||||
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
|
||||
LLMutexLock lock(mMutexp) ;
|
||||
const_segment_iterator_t const end = mSegments.end();
|
||||
for (const_segment_iterator_t it = mSegments.begin(); it != end; ++it)
|
||||
{
|
||||
if (it->isOnChannel(channel))
|
||||
{
|
||||
ostr.write((char*)it->data(), it->size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U8* LLBufferArray::seek(
|
||||
S32 channel,
|
||||
U8* start,
|
||||
|
||||
@@ -592,6 +592,12 @@ public:
|
||||
void setThreaded(bool threaded);
|
||||
//@}
|
||||
|
||||
/**
|
||||
* @brief Read channel channel of LLBufferArray and write it to ostr.
|
||||
* This is a Singularity extension.
|
||||
*/
|
||||
void writeChannelTo(std::ostream& ostr, S32 channel) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Optimally put data in buffers, and reutrn segments.
|
||||
|
||||
@@ -41,8 +41,8 @@ class AIHTTPHeaders;
|
||||
namespace AICurlInterface {
|
||||
|
||||
// Forward declaration.
|
||||
class Responder;
|
||||
typedef boost::intrusive_ptr<Responder> ResponderPtr;
|
||||
class ResponderBase;
|
||||
typedef boost::intrusive_ptr<ResponderBase> ResponderPtr;
|
||||
|
||||
class Request {
|
||||
public:
|
||||
|
||||
@@ -234,30 +234,17 @@ class BlockingResponder : public AICurlInterface::LegacyPolledResponder {
|
||||
private:
|
||||
LLCondition mSignal;
|
||||
LLSD mResponse;
|
||||
std::ostringstream mBody;
|
||||
|
||||
public:
|
||||
void wait(void);
|
||||
LLSD const& response(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; }
|
||||
std::string const& body(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus != HTTP_OK); return mBody.str(); }
|
||||
|
||||
/*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer);
|
||||
};
|
||||
|
||||
void BlockingResponder::completedRaw(U32, std::string const&, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
|
||||
void BlockingResponder::completedRaw(U32, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
|
||||
{
|
||||
if (mCode == CURLE_OK)
|
||||
{
|
||||
LLBufferStream istr(channels, buffer.get());
|
||||
if (mStatus == HTTP_OK)
|
||||
{
|
||||
LLSDSerialize::fromXML(mResponse, istr);
|
||||
}
|
||||
else
|
||||
{
|
||||
mBody << istr;
|
||||
}
|
||||
}
|
||||
decode_body(mCode, reason, channels, buffer, mResponse); // This puts the body asString() in mResponse in case of http error.
|
||||
// Normally mFinished is set immediately after returning from this function,
|
||||
// but we do it here, because we need to set it before calling mSignal.signal().
|
||||
mSignal.lock();
|
||||
@@ -341,7 +328,7 @@ static LLSD blocking_request(
|
||||
LLSD response = LLSD::emptyMap();
|
||||
CURLcode result = responder->result_code();
|
||||
|
||||
if (result == CURLE_OK && (http_status = responder->http_status()) == HTTP_OK)
|
||||
if (result == CURLE_OK && (http_status = responder->http_status()) >= 200 && http_status < 300)
|
||||
{
|
||||
response["body"] = responder->response();
|
||||
}
|
||||
@@ -358,9 +345,9 @@ static LLSD blocking_request(
|
||||
llwarns << "CURL REQ BODY: " << body.asString() << llendl;
|
||||
}
|
||||
llwarns << "CURL HTTP_STATUS: " << http_status << llendl;
|
||||
llwarns << "CURL ERROR BODY: " << responder->body() << llendl;
|
||||
llwarns << "CURL ERROR BODY: " << responder->response().asString() << llendl;
|
||||
}
|
||||
response["body"] = responder->body();
|
||||
response["body"] = responder->response().asString();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -53,8 +53,8 @@ public:
|
||||
typedef LLCurl::Responder Responder;
|
||||
typedef LLCurl::ResponderPtr ResponderPtr;
|
||||
|
||||
// The default actually already ignores responses.
|
||||
class ResponderIgnore : public Responder { virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return responderIgnore_timeout;} };
|
||||
class ResponderIgnoreBody : public Responder { void result(LLSD const&) { } };
|
||||
class ResponderIgnore : public ResponderIgnoreBody { virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return responderIgnore_timeout;} };
|
||||
|
||||
/** @name non-blocking API */
|
||||
//@{
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "llhost.h"
|
||||
#include "message.h"
|
||||
#include "llsdutil.h"
|
||||
#include "aihttptimeoutpolicy.h"
|
||||
|
||||
// Declare a static LLSDMessage instance to ensure that we have a listener as
|
||||
// soon as someone tries to post on our canonical LLEventPump name.
|
||||
@@ -62,13 +63,15 @@ LLSDMessage::LLSDMessage():
|
||||
|
||||
bool LLSDMessage::httpListener(const LLSD& request)
|
||||
{
|
||||
llassert(false); // This function is never called. --Aleric
|
||||
|
||||
// Extract what we want from the request object. We do it all up front
|
||||
// partly to document what we expect.
|
||||
LLSD::String url(request["url"]);
|
||||
LLSD payload(request["payload"]);
|
||||
LLSD::String reply(request["reply"]);
|
||||
LLSD::String error(request["error"]);
|
||||
LLSD::Real timeout(request["timeout"]);
|
||||
LLSD::String timeoutpolicy(request["timeoutpolicy"]);
|
||||
// If the LLSD doesn't even have a "url" key, we doubt it was intended for
|
||||
// this listener.
|
||||
if (url.empty())
|
||||
@@ -77,21 +80,25 @@ bool LLSDMessage::httpListener(const LLSD& request)
|
||||
out << "request event without 'url' key to '" << mEventPump.getName() << "'";
|
||||
throw ArgError(out.str());
|
||||
}
|
||||
#if 0 // AIFIXME: ignore this for now
|
||||
// Establish default timeout. This test relies on LLSD::asReal() returning
|
||||
// exactly 0.0 for an undef value.
|
||||
if (! timeout)
|
||||
{
|
||||
timeout = HTTP_REQUEST_EXPIRY_SECS;
|
||||
}
|
||||
#endif
|
||||
LLHTTPClient::post4(url, payload,
|
||||
new LLSDMessage::EventResponder(LLEventPumps::instance(),
|
||||
request,
|
||||
url, "POST", reply, error));
|
||||
LLSDMessage::EventResponder* responder =
|
||||
new LLSDMessage::EventResponder(LLEventPumps::instance(), request, url, "POST", reply, error);
|
||||
responder->setTimeoutPolicy(timeoutpolicy);
|
||||
LLHTTPClient::post4(url, payload, responder);
|
||||
return false;
|
||||
}
|
||||
|
||||
LLSDMessage::EventResponder::EventResponder(LLEventPumps& pumps, LLSD const& request, std::string const& target,
|
||||
std::string const& message, std::string const& replyPump, std::string const& errorPump) :
|
||||
mPumps(pumps), mReqID(request), mTarget(target), mMessage(message), mReplyPump(replyPump), mErrorPump(errorPump),
|
||||
mHTTPTimeoutPolicy(AIHTTPTimeoutPolicy::getTimeoutPolicyByName(std::string()))
|
||||
{
|
||||
}
|
||||
|
||||
void LLSDMessage::EventResponder::setTimeoutPolicy(std::string const& name)
|
||||
{
|
||||
mHTTPTimeoutPolicy = AIHTTPTimeoutPolicy::getTimeoutPolicyByName(name);
|
||||
}
|
||||
|
||||
void LLSDMessage::EventResponder::result(const LLSD& data)
|
||||
{
|
||||
// If our caller passed an empty replyPump name, they're not
|
||||
@@ -137,7 +144,7 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string
|
||||
}
|
||||
}
|
||||
|
||||
LLSDMessage::ResponderAdapter::ResponderAdapter(LLHTTPClient::ResponderPtr responder,
|
||||
LLSDMessage::ResponderAdapter::ResponderAdapter(LLHTTPClient::Responder* responder,
|
||||
const std::string& name):
|
||||
mResponder(responder),
|
||||
mReplyPump(name + ".reply", true), // tweak name for uniqueness
|
||||
@@ -147,15 +154,25 @@ LLSDMessage::ResponderAdapter::ResponderAdapter(LLHTTPClient::ResponderPtr respo
|
||||
mErrorPump.listen("self", boost::bind(&ResponderAdapter::listener, this, _1, false));
|
||||
}
|
||||
|
||||
std::string LLSDMessage::ResponderAdapter::getTimeoutPolicyName(void) const
|
||||
{
|
||||
return mResponder->getHTTPTimeoutPolicy().name();
|
||||
}
|
||||
|
||||
bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success)
|
||||
{
|
||||
AICurlInterface::Responder* responder = dynamic_cast<AICurlInterface::Responder*>(mResponder.get());
|
||||
// If this assertion fails then ResponderAdapter has been used for a ResponderWithCompleted derived class,
|
||||
// which is not allowed because ResponderAdapter can only work for classes derived from Responder that
|
||||
// implement result() and errorWithContent (or just error).
|
||||
llassert_always(responder);
|
||||
if (success)
|
||||
{
|
||||
mResponder->pubResult(payload);
|
||||
responder->pubResult(payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
mResponder->pubErrorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]);
|
||||
responder->pubErrorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]);
|
||||
}
|
||||
|
||||
/*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/
|
||||
|
||||
@@ -90,13 +90,15 @@ public:
|
||||
* interesting if you suspect some usage will lead to an exception or
|
||||
* log message.
|
||||
*/
|
||||
ResponderAdapter(LLHTTPClient::ResponderPtr responder,
|
||||
ResponderAdapter(LLHTTPClient::Responder* responder,
|
||||
const std::string& name="ResponderAdapter");
|
||||
|
||||
/// EventPump name on which LLSDMessage should post reply event
|
||||
std::string getReplyName() const { return mReplyPump.getName(); }
|
||||
/// EventPump name on which LLSDMessage should post error event
|
||||
std::string getErrorName() const { return mErrorPump.getName(); }
|
||||
/// Name of timeout policy to use.
|
||||
std::string getTimeoutPolicyName() const;
|
||||
|
||||
private:
|
||||
// We have two different LLEventStreams, though we route them both to
|
||||
@@ -126,7 +128,7 @@ private:
|
||||
class EventResponder: public LLHTTPClient::Responder
|
||||
{
|
||||
public:
|
||||
virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return eventResponder_timeout; }
|
||||
virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return *mHTTPTimeoutPolicy; }
|
||||
|
||||
/**
|
||||
* LLHTTPClient::Responder that dispatches via named LLEventPump instances.
|
||||
@@ -144,14 +146,9 @@ private:
|
||||
EventResponder(LLEventPumps& pumps,
|
||||
const LLSD& request,
|
||||
const std::string& target, const std::string& message,
|
||||
const std::string& replyPump, const std::string& errorPump):
|
||||
mPumps(pumps),
|
||||
mReqID(request),
|
||||
mTarget(target),
|
||||
mMessage(message),
|
||||
mReplyPump(replyPump),
|
||||
mErrorPump(errorPump)
|
||||
{}
|
||||
const std::string& replyPump, const std::string& errorPump);
|
||||
|
||||
void setTimeoutPolicy(std::string const& name);
|
||||
|
||||
virtual void result(const LLSD& data);
|
||||
virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
|
||||
@@ -160,6 +157,7 @@ private:
|
||||
LLEventPumps& mPumps;
|
||||
LLReqID mReqID;
|
||||
const std::string mTarget, mMessage, mReplyPump, mErrorPump;
|
||||
AIHTTPTimeoutPolicy const* mHTTPTimeoutPolicy;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user