From 2a88f7d7c47de9d2c85309b4a37a2efc29d956d8 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Fri, 26 Oct 2012 03:47:05 +0200 Subject: [PATCH] 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. --- indra/aistatemachine/aicurl.cpp | 81 ++++++++++++++----- indra/aistatemachine/aicurl.h | 76 ++++++++++++----- indra/llmessage/aihttptimeoutpolicy.cpp | 21 ++++- indra/llmessage/aihttptimeoutpolicy.h | 4 + indra/llmessage/llbuffer.cpp | 14 ++++ indra/llmessage/llbuffer.h | 6 ++ indra/llmessage/llcurlrequest.h | 4 +- indra/llmessage/llhttpclient.cpp | 23 ++---- indra/llmessage/llhttpclient.h | 4 +- indra/llmessage/llsdmessage.cpp | 49 +++++++---- indra/llmessage/llsdmessage.h | 18 ++--- indra/newview/lggdicdownload.cpp | 2 +- indra/newview/llagent.cpp | 1 + indra/newview/llcapabilitylistener.cpp | 19 ++--- indra/newview/lleventpoll.cpp | 26 +----- indra/newview/llfasttimerview.cpp | 6 +- indra/newview/llfloateractivespeakers.cpp | 6 +- indra/newview/llfloaterregiondebugconsole.cpp | 2 +- indra/newview/llfloaterregiondebugconsole.h | 4 +- indra/newview/llfloaterurlentry.cpp | 2 +- indra/newview/llimpanel.cpp | 4 +- indra/newview/llmeshrepository.cpp | 10 +-- indra/newview/llpanellogin.cpp | 19 ++--- indra/newview/lltexturefetch.cpp | 2 +- indra/newview/llviewerdisplayname.cpp | 2 +- indra/newview/llviewermedia.cpp | 6 +- indra/newview/llxmlrpcresponder.h | 2 +- 27 files changed, 244 insertions(+), 169 deletions(-) diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index 537d12e2f..c45c6f214 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -430,50 +430,92 @@ std::string strerror(CURLcode errorcode) } //----------------------------------------------------------------------------- -// class Responder +// class ResponderBase // -Responder::Responder(void) : mReferenceCount(0), mFinished(false) +ResponderBase::ResponderBase(void) : mReferenceCount(0), mFinished(false) { DoutEntering(dc::curl, "AICurlInterface::Responder() with this = " << (void*)this); } -Responder::~Responder() +ResponderBase::~ResponderBase() { - DoutEntering(dc::curl, "AICurlInterface::Responder::~Responder() with this = " << (void*)this << "; mReferenceCount = " << mReferenceCount); + DoutEntering(dc::curl, "AICurlInterface::ResponderBase::~ResponderBase() with this = " << (void*)this << "; mReferenceCount = " << mReferenceCount); llassert(mReferenceCount == 0); } -void Responder::setURL(std::string const& url) +void ResponderBase::setURL(std::string const& url) { // setURL is called from llhttpclient.cpp (request()), before calling any of the below (of course). // We don't need locking here therefore; it's a case of initializing before use. mURL = url; } -AIHTTPTimeoutPolicy const& Responder::getHTTPTimeoutPolicy(void) const +AIHTTPTimeoutPolicy const& ResponderBase::getHTTPTimeoutPolicy(void) const { return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout(); } +void ResponderBase::decode_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content) +{ + // If the status indicates success (and we get here) then we expect the body to be LLSD. + bool const should_be_llsd = (200 <= status && status < 300); + if (should_be_llsd) + { + LLBufferStream istr(channels, buffer.get()); + if (LLSDSerialize::fromXML(content, istr) == LLSDParser::PARSE_FAILURE) + { + // Unfortunately we can't show the body of the message... I think this is a pretty serious error + // though, so if this ever happens it has to be investigated by making a copy of the buffer + // before serializing it, as is done below. + llwarns << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl; + } + // LLSDSerialize::fromXML destructed buffer, we can't initialize content now. + return; + } + // Put the body in content as-is. + std::stringstream ss; + buffer->writeChannelTo(ss, channels.in()); + content = ss.str(); +#ifdef SHOW_ASSERT + if (!should_be_llsd) + { + // Make sure that the server indeed never returns LLSD as body when the http status is an error. + LLSD dummy; + bool server_sent_llsd_with_http_error = LLSDSerialize::fromXML(dummy, ss) > 0; + if (server_sent_llsd_with_http_error) + { + llwarns << "The server sent us a response with http status " << status << " and LLSD(!) body: \"" << ss.str() << "\"!" << llendl; + } + llassert(!server_sent_llsd_with_http_error); + } +#endif +} + // Called with HTML body. // virtual -void Responder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, LLIOPipe::buffer_ptr_t const& buffer) +void ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { LLSD content; - LLBufferStream istr(channels, buffer.get()); - if (!LLSDSerialize::fromXML(content, istr)) - { - llinfos << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl; - } + decode_body(status, reason, channels, buffer, content); // Allow derived class to override at this point. completed(status, reason, content); } // virtual -void Responder::completed(U32 status, std::string const& reason, LLSD const& content) +void ResponderWithCompleted::completed(U32 status, std::string const& reason, LLSD const& content) { + // Either completedRaw() or this method must be overridden by the derived class. Hence, we should never get here. + llassert_always(false); +} + +// virtual +void Responder::finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +{ + LLSD content; + decode_body(status, reason, channels, buffer, content); + // HTML status good? if (200 <= status && status < 300) { @@ -485,6 +527,7 @@ void Responder::completed(U32 status, std::string const& reason, LLSD const& con // Allow derived class to override at this point. errorWithContent(status, reason, content); } + mFinished = true; } // virtual @@ -500,20 +543,14 @@ void Responder::error(U32 status, std::string const& reason) llinfos << mURL << " [" << status << "]: " << reason << llendl; } -// virtual -void Responder::result(LLSD const&) -{ - // Nothing. -} - // Friend functions. -void intrusive_ptr_add_ref(Responder* responder) +void intrusive_ptr_add_ref(ResponderBase* responder) { responder->mReferenceCount++; } -void intrusive_ptr_release(Responder* responder) +void intrusive_ptr_release(ResponderBase* responder) { if (--responder->mReferenceCount == 0) { @@ -528,7 +565,7 @@ void LegacyPolledResponder::completed_headers(U32 status, std::string const& rea mStatus = status; mReason = reason; // Call base class implementation. - Responder::completed_headers(status, reason, code, info); + ResponderBase::completed_headers(status, reason, code, info); } } // namespace AICurlInterface diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 53f7af394..7a679d6f6 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -200,13 +200,16 @@ void setCAPath(std::string const& file); // destructed. Also, if any of those are destructed then the Responder is automatically // destructed too. // -class Responder : public AICurlResponderBufferEvents { +class ResponderBase : public AICurlResponderBufferEvents { public: typedef boost::shared_ptr buffer_ptr_t; protected: - Responder(void); - virtual ~Responder(); + ResponderBase(void); + virtual ~ResponderBase(); + + // Read body from buffer and put it into content. If status indicates success, interpret it as LLSD, otherwise copy it as-is. + void decode_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content); protected: // Associated URL, used for debug output. @@ -227,11 +230,7 @@ class Responder : public AICurlResponderBufferEvents { std::string const& getURL(void) const { return mURL; } // Called by CurlResponderBuffer::timed_out or CurlResponderBuffer::processOutput. - void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) - { - completedRaw(status, reason, channels, buffer); - mFinished = true; - } + virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0; // Return true if the curl thread is done with this transaction. // If this returns true then it is guaranteed that none of the @@ -279,6 +278,25 @@ class Responder : public AICurlResponderBufferEvents { // The default does nothing. } + private: + // Used by ResponderPtr. Object is deleted when reference count reaches zero. + LLAtomicU32 mReferenceCount; + + friend void intrusive_ptr_add_ref(ResponderBase* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr is made. + friend void intrusive_ptr_release(ResponderBase* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr is destroyed. + // This function must delete the ResponderBase object when the reference count reaches zero. +}; + +class ResponderWithCompleted : public ResponderBase { + protected: + virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + // Allow classes derived from ResponderBase to override completedRaw + // (if not they should override completed or be derived from Responder instead). + completedRaw(status, reason, channels, buffer); + mFinished = true; + } + // Derived classes can override this to get the raw data of the body of the HTML message that was received. // The default is to interpret the content as LLSD and call completed(). virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); @@ -287,9 +305,25 @@ class Responder : public AICurlResponderBufferEvents { // The default is to call result() (or errorWithContent() in case of a HTML status indicating an error). virtual void completed(U32 status, std::string const& reason, LLSD const& content); +#ifdef SHOW_ASSERT + // Responders derived from this class must override either completedRaw or completed. + // They may not attempt to override any of the virual functions defined by Responder. + // Define those functions here with different parameter in order to cause a compile + // warning when a class accidently tries to override them. + enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; + virtual void result(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void errorWithContent(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void error(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } +#endif +}; + +class Responder : public ResponderBase { + protected: + virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + // ... or, derived classes can override this to received the content of a body upon success. // The default does nothing. - virtual void result(LLSD const& content); + virtual void result(LLSD const& content) = 0; // Derived classes can override this to get informed when a bad HTML status code is received. // The default calls error(). @@ -303,27 +337,29 @@ class Responder : public AICurlResponderBufferEvents { // Called from LLSDMessage::ResponderAdapter::listener. // LLSDMessage::ResponderAdapter is a hack, showing among others by fact that these functions need to be public. - void pubErrorWithContent(U32 status, std::string const& reason, LLSD const& content) { errorWithContent(status, reason, content); } - void pubResult(LLSD const& content) { result(content); } + void pubErrorWithContent(U32 status, std::string const& reason, LLSD const& content) { errorWithContent(status, reason, content); mFinished = true; } + void pubResult(LLSD const& content) { result(content); mFinished = true; } - private: - // Used by ResponderPtr. Object is deleted when reference count reaches zero. - LLAtomicU32 mReferenceCount; - - friend void intrusive_ptr_add_ref(Responder* p); // Called by boost::intrusive_ptr when a new copy of a boost::intrusive_ptr is made. - friend void intrusive_ptr_release(Responder* p); // Called by boost::intrusive_ptr when a boost::intrusive_ptr is destroyed. - // This function must delete the Responder object when the reference count reaches zero. +#ifdef SHOW_ASSERT + // Responders derived from this class must override result, and either errorWithContent or error. + // They may not attempt to override any of the virual functions defined by ResponderWithCompleted. + // Define those functions here with different parameter in order to cause a compile + // warning when a class accidently tries to override them. + enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; + virtual void completedRaw(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void completed(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } +#endif }; // A Responder is passed around as ResponderPtr, which causes it to automatically // destruct when there are no pointers left pointing to it. -typedef boost::intrusive_ptr ResponderPtr; +typedef boost::intrusive_ptr ResponderPtr; // Same as above except that this class stores the result, allowing old polling // code to poll if the transaction finished by calling is_finished() (from the // main the thread) and then access the results-- as opposed to immediately // digesting the results when any of the virtual functions are called. -class LegacyPolledResponder : public Responder { +class LegacyPolledResponder : public ResponderWithCompleted { protected: CURLcode mCode; U32 mStatus; diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index 1a601db07..7db472f96 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -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); diff --git a/indra/llmessage/aihttptimeoutpolicy.h b/indra/llmessage/aihttptimeoutpolicy.h index bb11b033a..bf333b105 100644 --- a/indra/llmessage/aihttptimeoutpolicy.h +++ b/indra/llmessage/aihttptimeoutpolicy.h @@ -33,6 +33,7 @@ #include "stdtypes.h" #include +#include 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 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); diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index 0f31f7065..b9ca7ceb6 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -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, diff --git a/indra/llmessage/llbuffer.h b/indra/llmessage/llbuffer.h index 4940da2fe..c7624bde3 100644 --- a/indra/llmessage/llbuffer.h +++ b/indra/llmessage/llbuffer.h @@ -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. diff --git a/indra/llmessage/llcurlrequest.h b/indra/llmessage/llcurlrequest.h index d30418abd..4fe172b46 100644 --- a/indra/llmessage/llcurlrequest.h +++ b/indra/llmessage/llcurlrequest.h @@ -41,8 +41,8 @@ class AIHTTPHeaders; namespace AICurlInterface { // Forward declaration. -class Responder; -typedef boost::intrusive_ptr ResponderPtr; +class ResponderBase; +typedef boost::intrusive_ptr ResponderPtr; class Request { public: diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 26c7b39e0..96a38ea10 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -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 { diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index d6ffad888..c78917a82 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -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 */ //@{ diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index 441355b3b..be968c5db 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -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(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 ----------------*/ diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h index 3d1ae814c..b839cbc74 100644 --- a/indra/llmessage/llsdmessage.h +++ b/indra/llmessage/llsdmessage.h @@ -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: diff --git a/indra/newview/lggdicdownload.cpp b/indra/newview/lggdicdownload.cpp index 7bcaaac49..154d29063 100644 --- a/indra/newview/lggdicdownload.cpp +++ b/indra/newview/lggdicdownload.cpp @@ -52,7 +52,7 @@ class lggDicDownloadFloater; class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy emeraldDicDownloader_timeout; -class EmeraldDicDownloader : public LLHTTPClient::Responder +class EmeraldDicDownloader : public AICurlInterface::ResponderWithCompleted { public: EmeraldDicDownloader(lggDicDownloadFloater* spanel, std::string sname); diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3a3c38c20..b2e1c2181 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2188,6 +2188,7 @@ void LLAgent::setStartPosition( U32 location_id ) request["payload"] = body; request["reply"] = adapter->getReplyName(); request["error"] = adapter->getErrorName(); + request["timeoutpolicy"] = adapter->getTimeoutPolicyName(); gAgent.getRegion()->getCapAPI().post(request); diff --git a/indra/newview/llcapabilitylistener.cpp b/indra/newview/llcapabilitylistener.cpp index 75934c156..2ebaffd4f 100644 --- a/indra/newview/llcapabilitylistener.cpp +++ b/indra/newview/llcapabilitylistener.cpp @@ -84,7 +84,7 @@ bool LLCapabilityListener::capListener(const LLSD& request) 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 "message" key, we doubt it was intended // for this listener. if (cap.empty()) @@ -95,24 +95,15 @@ bool LLCapabilityListener::capListener(const LLSD& request) << LL_ENDL; return false; // in case fatal-error function isn't } -#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 // Look up the url for the requested capability name. std::string url = mProvider.getCapability(cap); if (! url.empty()) { + LLSDMessage::EventResponder* responder = + new LLSDMessage::EventResponder(LLEventPumps::instance(), request, mProvider.getDescription(), cap, reply, error); + responder->setTimeoutPolicy(timeoutpolicy); // This capability is supported by the region to which we're talking. - LLHTTPClient::post4(url, payload, - new LLSDMessage::EventResponder(LLEventPumps::instance(), - request, - mProvider.getDescription(), - cap, reply, error)); + LLHTTPClient::post4(url, payload, responder); } else { diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index e7442483f..be7ede224 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -73,14 +73,10 @@ namespace void handleMessage(const LLSD& content); - virtual void error(U32 status, const std::string& reason); + virtual void error(U32 status, const std::string& reason); virtual void result(const LLSD& content); virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return eventPollResponder_timeout; } - virtual void completedRaw(U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const buffer_ptr_t& buffer); private: bool mDone; @@ -160,24 +156,6 @@ namespace << mPollURL << llendl; } - // virtual - void LLEventPollResponder::completedRaw(U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const buffer_ptr_t& buffer) - { - if (status == HTTP_BAD_GATEWAY) - { - // These errors are not parsable as LLSD, - // which LLHTTPClient::Responder::completedRaw will try to do. - completed(status, reason, LLSD()); - } - else - { - LLHTTPClient::Responder::completedRaw(status,reason,channels,buffer); - } - } - void LLEventPollResponder::makeRequest() { LLSD request; @@ -295,7 +273,7 @@ LLEventPoll::LLEventPoll(const std::string& poll_url, const LLHost& sender) LLEventPoll::~LLEventPoll() { - LLHTTPClient::Responder* responderp = mImpl.get(); + AICurlInterface::ResponderBase* responderp = mImpl.get(); LLEventPollResponder* event_poll_responder = dynamic_cast(responderp); if (event_poll_responder) event_poll_responder->stop(); } diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index eeb53a98d..9f1cbca6c 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -1146,7 +1146,7 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t { //read base log into memory S32 i = 0; std::ifstream is(base.c_str()); - while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + while (!is.eof() && LLSDSerialize::fromXML(cur, is) > 0) { base_data[i++] = cur; } @@ -1159,7 +1159,7 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t { //read current log into memory S32 i = 0; std::ifstream is(target.c_str()); - while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + while (!is.eof() && LLSDSerialize::fromXML(cur, is) > 0) { cur_data[i++] = cur; @@ -1450,7 +1450,7 @@ LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is) stats_map_t time_stats; stats_map_t sample_stats; - while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + while (!is.eof() && LLSDSerialize::fromXML(cur, is) > 0) { for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) { diff --git a/indra/newview/llfloateractivespeakers.cpp b/indra/newview/llfloateractivespeakers.cpp index 3b8bde610..968228fb2 100644 --- a/indra/newview/llfloateractivespeakers.cpp +++ b/indra/newview/llfloateractivespeakers.cpp @@ -849,7 +849,7 @@ void LLPanelActiveSpeakers::onModeratorMuteVoice(LLUICtrl* ctrl, void* user_data // ctrl value represents ability to type, so invert data["params"]["mute_info"]["voice"] = !ctrl->getValue(); - class MuteVoiceResponder : public LLHTTPClient::Responder + class MuteVoiceResponder : public LLHTTPClient::ResponderIgnoreBody { public: MuteVoiceResponder(const LLUUID& session_id) @@ -916,7 +916,7 @@ void LLPanelActiveSpeakers::onModeratorMuteText(LLUICtrl* ctrl, void* user_data) // ctrl value represents ability to type, so invert data["params"]["mute_info"]["text"] = !ctrl->getValue(); - class MuteTextResponder : public LLHTTPClient::Responder + class MuteTextResponder : public LLHTTPClient::ResponderIgnoreBody { public: MuteTextResponder(const LLUUID& session_id) @@ -990,7 +990,7 @@ void LLPanelActiveSpeakers::onChangeModerationMode(LLUICtrl* ctrl, void* user_da data["params"]["update_info"]["moderated_mode"]["voice"] = true; } - struct ModerationModeResponder : public LLHTTPClient::Responder + struct ModerationModeResponder : public LLHTTPClient::ResponderIgnoreBody { virtual void error(U32 status, const std::string& reason) { diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index ad3e873eb..e0720d2b0 100644 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -77,7 +77,7 @@ namespace // we assume that the simulator has received our request. Error will be // called if this request times out. // - class AsyncConsoleResponder : public LLHTTPClient::Responder + class AsyncConsoleResponder : public LLHTTPClient::ResponderIgnoreBody { public: /* virtual */ diff --git a/indra/newview/llfloaterregiondebugconsole.h b/indra/newview/llfloaterregiondebugconsole.h index 2636b6426..fdf975c48 100644 --- a/indra/newview/llfloaterregiondebugconsole.h +++ b/indra/newview/llfloaterregiondebugconsole.h @@ -40,14 +40,12 @@ extern AIHTTPTimeoutPolicy floaterRegionDebugConsole_timeout; typedef boost::signals2::signal< void (const std::string& output)> console_reply_signal_t; -class LLFloaterRegionDebugConsole : public LLFloater, public LLHTTPClient::Responder, public LLSingleton +class LLFloaterRegionDebugConsole : public LLFloater, public LLSingleton { public: LLFloaterRegionDebugConsole(); virtual ~LLFloaterRegionDebugConsole(); - virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return floaterRegionDebugConsole_timeout; } - // virtual BOOL postBuild(); void onClose(bool app_quitting); diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index f43619553..416458617 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -53,7 +53,7 @@ static LLFloaterURLEntry* sInstance = NULL; // Move this to its own file. // helper class that tries to download a URL from a web site and calls a method // on the Panel Land Media and to discover the MIME type -class LLMediaTypeResponder : public LLHTTPClient::Responder +class LLMediaTypeResponder : public LLHTTPClient::ResponderIgnoreBody { public: LLMediaTypeResponder( const LLHandle parent ) : diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 2d5ee2293..fe1bab58a 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -184,7 +184,7 @@ void start_deprecated_conference_chat( delete[] bucket; } -class LLStartConferenceChatResponder : public LLHTTPClient::Responder +class LLStartConferenceChatResponder : public LLHTTPClient::ResponderIgnoreBody { public: LLStartConferenceChatResponder( @@ -1558,7 +1558,7 @@ void LLFloaterIMPanel::draw() LLFloater::draw(); } -class LLSessionInviteResponder : public LLHTTPClient::Responder +class LLSessionInviteResponder : public LLHTTPClient::ResponderIgnoreBody { public: LLSessionInviteResponder(const LLUUID& session_id) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index cc2b7306f..cd406e3c5 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -210,7 +210,7 @@ S32 LLMeshRepoThread::sActiveHeaderRequests = 0; S32 LLMeshRepoThread::sActiveLODRequests = 0; U32 LLMeshRepoThread::sMaxConcurrentRequests = 1; -class LLMeshHeaderResponder : public LLCurl::Responder +class LLMeshHeaderResponder : public LLCurl::ResponderWithCompleted { public: LLVolumeParams mMeshParams; @@ -233,7 +233,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshHeaderResponder_timeout; } }; -class LLMeshLODResponder : public LLCurl::Responder +class LLMeshLODResponder : public LLCurl::ResponderWithCompleted { public: LLVolumeParams mMeshParams; @@ -259,7 +259,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshLODResponder_timeout; } }; -class LLMeshSkinInfoResponder : public LLCurl::Responder +class LLMeshSkinInfoResponder : public LLCurl::ResponderWithCompleted { public: LLUUID mMeshID; @@ -278,7 +278,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshSkinInfoResponder_timeout; } }; -class LLMeshDecompositionResponder : public LLCurl::Responder +class LLMeshDecompositionResponder : public LLCurl::ResponderWithCompleted { public: LLUUID mMeshID; @@ -297,7 +297,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshDecompositionResponder_timeout; } }; -class LLMeshPhysicsShapeResponder : public LLCurl::Responder +class LLMeshPhysicsShapeResponder : public LLCurl::ResponderWithCompleted { public: LLUUID mMeshID; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index a10e9f0cb..1bfbcc702 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -168,7 +168,7 @@ std::string gFullName; // helper class that trys to download a URL from a web site and calls a method // on parent class indicating if the web server is working or not -class LLIamHereLogin : public LLHTTPClient::Responder +class LLIamHereLogin : public AICurlInterface::ResponderWithCompleted { private: LLIamHereLogin( LLPanelLogin* parent ) : @@ -193,20 +193,11 @@ class LLIamHereLogin : public LLHTTPClient::Responder const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - completed(status, reason, LLSD()); // will call result() or error() + if (mParent) + { + mParent->setSiteIsAlive(200 <= status && status < 300); + } } - - virtual void result( const LLSD& content ) - { - if ( mParent ) - mParent->setSiteIsAlive( true ); - }; - - virtual void error( U32 status, const std::string& reason ) - { - if ( mParent ) - mParent->setSiteIsAlive( false ); - }; virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return iamHereLogin_timeout; } }; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 159110fc0..561c19129 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -292,7 +292,7 @@ private: }; ////////////////////////////////////////////////////////////////////////////// -class HTTPGetResponder : public LLCurl::Responder +class HTTPGetResponder : public AICurlInterface::ResponderWithCompleted { LOG_CLASS(HTTPGetResponder); public: diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index e5590de87..d4a89d3a4 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -58,7 +58,7 @@ namespace LLViewerDisplayName } -class LLSetDisplayNameResponder : public LLHTTPClient::Responder +class LLSetDisplayNameResponder : public LLHTTPClient::ResponderIgnoreBody { public: // only care about errors diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 25acb0b83..b818ae50c 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -71,7 +71,7 @@ const int RIGHT_BUTTON = 1; /////////////////////////////////////////////////////////////////////////////// // Helper class that tries to download a URL from a web site and calls a method // on the Panel Land Media and to discover the MIME type -class LLMimeDiscoveryResponder : public LLHTTPClient::Responder +class LLMimeDiscoveryResponder : public AICurlInterface::ResponderWithCompleted { LOG_CLASS(LLMimeDiscoveryResponder); public: @@ -111,7 +111,7 @@ public: bool mInitialized; }; -class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder +class LLViewerMediaOpenIDResponder : public AICurlInterface::ResponderWithCompleted { LOG_CLASS(LLViewerMediaOpenIDResponder); public: @@ -150,7 +150,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerMediaOpenIDResponder_timeout; } }; -class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder +class LLViewerMediaWebProfileResponder : public AICurlInterface::ResponderWithCompleted { LOG_CLASS(LLViewerMediaWebProfileResponder); public: diff --git a/indra/newview/llxmlrpcresponder.h b/indra/newview/llxmlrpcresponder.h index ffb06f14d..c52756f03 100644 --- a/indra/newview/llxmlrpcresponder.h +++ b/indra/newview/llxmlrpcresponder.h @@ -105,7 +105,7 @@ public: XMLRPC_REQUEST response(void) const { return mResponse; } LLXMLRPCValue responseValue(void) const; - /*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLCurl::Responder::received_HTTP_header(); } + /*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLCurl::ResponderBase::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; }