diff --git a/indra/aistatemachine/aicurl.cpp b/indra/aistatemachine/aicurl.cpp index c45c6f214..d4353226f 100644 --- a/indra/aistatemachine/aicurl.cpp +++ b/indra/aistatemachine/aicurl.cpp @@ -433,7 +433,7 @@ std::string strerror(CURLcode errorcode) // class ResponderBase // -ResponderBase::ResponderBase(void) : mReferenceCount(0), mFinished(false) +ResponderBase::ResponderBase(void) : mReferenceCount(0), mCode(CURLE_FAILED_INIT), mFinished(false) { DoutEntering(dc::curl, "AICurlInterface::Responder() with this = " << (void*)this); } @@ -456,7 +456,7 @@ 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) +void ResponderBase::decode_llsd_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); @@ -492,12 +492,25 @@ void ResponderBase::decode_body(U32 status, std::string const& reason, LLChannel #endif } +void ResponderBase::decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content) +{ + 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) + { + if (iter->isOnChannel(channels.in())) + { + content.append((char*)iter->data(), iter->size()); + } + } +} + // Called with HTML body. // virtual void ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { LLSD content; - decode_body(status, reason, channels, buffer, content); + decode_llsd_body(status, reason, channels, buffer, content); // Allow derived class to override at this point. completed(status, reason, content); @@ -511,13 +524,15 @@ void ResponderWithCompleted::completed(U32 status, std::string const& reason, LL } // virtual -void Responder::finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +void Responder::finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - LLSD content; - decode_body(status, reason, channels, buffer, content); + mCode = code; - // HTML status good? - if (200 <= status && status < 300) + LLSD content; + decode_llsd_body(http_status, reason, channels, buffer, content); + + // HTTP status good? + if (200 <= http_status && http_status < 300) { // Allow derived class to override at this point. result(content); @@ -525,8 +540,9 @@ void Responder::finished(U32 status, std::string const& reason, LLChannelDescrip else { // Allow derived class to override at this point. - errorWithContent(status, reason, content); + errorWithContent(http_status, reason, content); } + mFinished = true; } @@ -558,16 +574,6 @@ void intrusive_ptr_release(ResponderBase* responder) } } -// virtual -void LegacyPolledResponder::completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info) -{ - mCode = code; - mStatus = status; - mReason = reason; - // Call base class implementation. - ResponderBase::completed_headers(status, reason, code, info); -} - } // namespace AICurlInterface //================================================================================== @@ -1377,7 +1383,7 @@ CurlResponderBuffer::~CurlResponderBuffer() void CurlResponderBuffer::timed_out(void) { - mResponder->finished(HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput); + mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR, "Request timeout, aborted.", sChannels, mOutput); mResponder = NULL; } diff --git a/indra/aistatemachine/aicurl.h b/indra/aistatemachine/aicurl.h index 7a679d6f6..5174b0cd6 100644 --- a/indra/aistatemachine/aicurl.h +++ b/indra/aistatemachine/aicurl.h @@ -180,7 +180,7 @@ void setCAPath(std::string const& file); //----------------------------------------------------------------------------- // Global classes. -// Responder - base class for Request::get* and Request::post API. +// ResponderBase - base class for all Responders. // // The life cycle of classes derived from this class is as follows: // They are allocated with new on the line where get(), getByteRange() or post() is called, @@ -209,7 +209,10 @@ class ResponderBase : public AICurlResponderBufferEvents { 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); + void decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content); + + // Read body from buffer and put it into content. Always copy it as-is. + void decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content); protected: // Associated URL, used for debug output. @@ -218,6 +221,9 @@ class ResponderBase : public AICurlResponderBufferEvents { // Headers received from the server. AIHTTPReceivedHeaders mReceivedHeaders; + // The curl result code. + CURLcode mCode; + // Set when the transaction finished (with or without errors). bool mFinished; @@ -226,11 +232,12 @@ class ResponderBase : public AICurlResponderBufferEvents { // used only when printing debug output regarding activity of the Responder. void setURL(std::string const& url); - // Accessor. + // Accessors. std::string const& getURL(void) const { return mURL; } + CURLcode result_code(void) const { return mCode; } // Called by CurlResponderBuffer::timed_out or CurlResponderBuffer::processOutput. - virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0; + virtual void finished(CURLcode code, U32 http_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 @@ -240,6 +247,8 @@ class ResponderBase : public AICurlResponderBufferEvents { bool is_finished(void) const { return mFinished; } protected: + // AICurlResponderBufferEvents + // Called when the "HTTP/1.x " header is received. /*virtual*/ void received_HTTP_header(void) { @@ -264,13 +273,13 @@ class ResponderBase : public AICurlResponderBufferEvents { // Derived classes that implement completed_headers()/completedHeaders() should return true here. virtual bool needsHeaders(void) const { return false; } - // Timeout policy to use. - virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; - // A derived class should return true if curl should follow redirections. // The default is not to follow redirections. virtual bool followRedir(void) { return false; } + // Timeout policy to use. + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; + protected: // Derived classes can override this to get the HTML headers that were received, when the message is completed. virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) @@ -287,28 +296,37 @@ class ResponderBase : public AICurlResponderBufferEvents { // This function must delete the ResponderBase object when the reference count reaches zero. }; +// ResponderWithCompleted - base class for Responders that implement completed, or completedRaw if the response is not LLSD. class ResponderWithCompleted : public ResponderBase { protected: - virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + // ResponderBase event + + // The responder finished. Do not override this function in derived classes; override completedRaw instead. + /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { + mCode = code; // 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); + completedRaw(http_status, reason, channels, buffer); mFinished = true; } + protected: + // Events generated by this class. + // 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); - // ... or, derived classes can override this to get the LLSD content when the message is completed. - // The default is to call result() (or errorWithContent() in case of a HTML status indicating an error). + // ... or, derived classes can override this to get LLSD content when the message is completed. + // The default aborts, as it should never be called (can't make it pure virtual though, so + // classes that override completedRaw don't need to implement this function, too). 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 + // They may not attempt to override any of the virual functions defined by ResponderBase. + // Define those functions here with different parameters 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) { } @@ -317,12 +335,18 @@ class ResponderWithCompleted : public ResponderBase { #endif }; +// Responder - base class for reponders that expect LLSD in the body of the reply. +// +// Classes derived from Responder must implement result, and either errorWithContent or error. class Responder : public ResponderBase { protected: - virtual void finished(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + // The responder finished. Do not override this function in derived classes; use ResponderWithCompleted instead. + /*virtual*/ void finished(CURLcode code, U32 http_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. + protected: + // Events generated by this class. + + // Derived classes must override this to receive the content of a body upon success. virtual void result(LLSD const& content) = 0; // Derived classes can override this to get informed when a bad HTML status code is received. @@ -335,10 +359,10 @@ class Responder : public ResponderBase { public: // Called from LLSDMessage::ResponderAdapter::listener. - // LLSDMessage::ResponderAdapter is a hack, showing among others by fact that these functions need to be public. + // LLSDMessage::ResponderAdapter is a hack, showing among others by fact that it needs these functions. - 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; } + void pubErrorWithContent(CURLcode code, U32 status, std::string const& reason, LLSD const& content) { mCode = code; errorWithContent(status, reason, content); mFinished = true; } + void pubResult(LLSD const& content) { mCode = CURLE_OK; result(content); mFinished = true; } #ifdef SHOW_ASSERT // Responders derived from this class must override result, and either errorWithContent or error. @@ -361,20 +385,25 @@ typedef boost::intrusive_ptr ResponderPtr; // digesting the results when any of the virtual functions are called. class LegacyPolledResponder : public ResponderWithCompleted { protected: - CURLcode mCode; U32 mStatus; std::string mReason; + protected: + // The responder finished. Do not override this function in derived classes. + /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + mStatus = http_status; + mReason = reason; + // Call base class implementation. + ResponderWithCompleted::finished(code, http_status, reason, channels, buffer); + } + public: - LegacyPolledResponder(void) : mCode(CURLE_FAILED_INIT), mStatus(HTTP_INTERNAL_ERROR) { } + LegacyPolledResponder(void) : mStatus(HTTP_INTERNAL_ERROR) { } // Accessors. - CURLcode result_code(void) const { return mCode; } U32 http_status(void) const { return mStatus; } std::string const& reason(void) const { return mReason; } - - /*virtual*/ bool needsHeaders(void) const { return true; } - /*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info); }; } // namespace AICurlInterface diff --git a/indra/aistatemachine/aicurlprivate.h b/indra/aistatemachine/aicurlprivate.h index fbf70fcce..1dfd500d6 100644 --- a/indra/aistatemachine/aicurlprivate.h +++ b/indra/aistatemachine/aicurlprivate.h @@ -377,7 +377,7 @@ class CurlEasyRequest : public CurlEasyHandle { bool mTimeoutIsOrphan; // Set to true when mTimeout is not (yet) associated with a CurlSocketInfo. #if defined(CWDEBUG) || defined(DEBUG_CURLIO) public: - bool mDebugIsGetMethod; + bool mDebugIsHeadOrGetMethod; #endif public: @@ -398,7 +398,7 @@ class CurlEasyRequest : public CurlEasyHandle { // Throws AICurlNoEasyHandle. CurlEasyRequest(void) : mHeaders(NULL), mEventsTarget(NULL), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL), mTimeoutIsOrphan(false) #if defined(CWDEBUG) || defined(DEBUG_CURLIO) - , mDebugIsGetMethod(false) + , mDebugIsHeadOrGetMethod(false) #endif { applyDefaultOptions(); } public: diff --git a/indra/aistatemachine/aicurlthread.cpp b/indra/aistatemachine/aicurlthread.cpp index 61a1a1961..ce80c4b4b 100644 --- a/indra/aistatemachine/aicurlthread.cpp +++ b/indra/aistatemachine/aicurlthread.cpp @@ -1789,9 +1789,9 @@ bool HTTPTimeout::data_received(size_t n) { // mUploadFinished not being set this point should only happen for GET requests (in fact, then it is normal), // because in that case it is impossible to detect the difference between connecting and waiting for a reply without - // using CURLOPT_DEBUGFUNCTION. Note that mDebugIsGetMethod is only valid when the debug channel 'curlio' is on, + // using CURLOPT_DEBUGFUNCTION. Note that mDebugIsHeadOrGetMethod is only valid when the debug channel 'curlio' is on, // because it is set in the debug callback function. - Debug(llassert(AICurlEasyRequest_wat(*mLockObj)->mDebugIsGetMethod || !dc::curlio.is_on())); + Debug(llassert(AICurlEasyRequest_wat(*mLockObj)->mDebugIsHeadOrGetMethod || !dc::curlio.is_on())); // 'Upload finished' detection failed, generate it now. upload_finished(); } @@ -2094,24 +2094,20 @@ void CurlResponderBuffer::processOutput(AICurlEasyRequest_wat& curl_easy_request curl_easy_request_w->setopt(CURLOPT_FRESH_CONNECT, TRUE); } - llassert(mResponder); // AIFIXME: We always have a responder now, no? - if (mResponder) - { - if (code != CURLE_OK) - { - curl_easy_request_w->print_diagnostics(curl_easy_request_w, code); - } - if (mEventsTarget) - { - // Only the responder registers for these events. - llassert(mEventsTarget == mResponder.get()); - // Allow clients to parse result codes and headers before we attempt to parse - // the body and provide completed/result/error calls. - mEventsTarget->completed_headers(responseCode, responseReason, code, (code == CURLE_FAILED_INIT) ? NULL : &info); - } - mResponder->finished(responseCode, responseReason, sChannels, mOutput); - mResponder = NULL; + if (code != CURLE_OK) + { + curl_easy_request_w->print_diagnostics(curl_easy_request_w, code); } + if (mEventsTarget) + { + // Only the responder registers for these events. + llassert(mEventsTarget == mResponder.get()); + // Allow clients to parse result codes and headers before we attempt to parse + // the body and provide completed/result/error calls. + mEventsTarget->completed_headers(responseCode, responseReason, code, (code == CURLE_FAILED_INIT) ? NULL : &info); + } + mResponder->finished(code, responseCode, responseReason, sChannels, mOutput); + mResponder = NULL; resetState(curl_easy_request_w); } @@ -2297,8 +2293,8 @@ int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* break; case CURLINFO_HEADER_OUT: LibcwDoutStream << "H< "; - if (size >= 4 && strncmp(buf, "GET ", 4) == 0) - request->mDebugIsGetMethod = true; + if (size >= 5 && (strncmp(buf, "GET ", 4) == 0 || strncmp(buf, "HEAD ", 5) == 0)) + request->mDebugIsHeadOrGetMethod = true; break; case CURLINFO_DATA_IN: LibcwDoutStream << "D> "; diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index ec697c4a3..046e77b0e 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -8,6 +8,7 @@ include(AIStateMachine) include(LLMath) include(LLMessage) include(LLVFS) +include(LLXML) include_directories (${CMAKE_CURRENT_SOURCE_DIR}) @@ -17,6 +18,7 @@ include_directories( ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} + ${LLXML_INCLUDE_DIRS} ) set(llmessage_SOURCE_FILES @@ -244,7 +246,8 @@ if (LL_TESTS) ${LLVFS_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} - ${GOOGLEMOCK_LIBRARIES} + ${GOOGLEMOCK_LIBRARIES} + ${LLXML_LIBRARIES} ) LL_ADD_INTEGRATION_TEST( diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index 7db472f96..2292b93f2 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -679,10 +679,12 @@ P(accountingCostResponder); P(agentStateResponder); P(assetUploadResponder); P(asyncConsoleResponder); +P(authHandler); P(avatarNameResponder); P2(baseCapabilitiesComplete, transfer_18s); -P(blockingGet); -P(blockingPost); +P(blockingLLSDPost); +P(blockingLLSDGet); +P(blockingRawGet); P(charactersResponder); P(classifiedStatsResponder); P(consoleResponder); diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 96a38ea10..33edb311a 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -34,10 +34,12 @@ #include "llsdserialize.h" #include "llvfile.h" #include "llurlrequest.h" +#include "llxmltree.h" class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy blockingGet_timeout; -extern AIHTTPTimeoutPolicy blockingPost_timeout; +extern AIHTTPTimeoutPolicy blockingLLSDPost_timeout; +extern AIHTTPTimeoutPolicy blockingLLSDGet_timeout; +extern AIHTTPTimeoutPolicy blockingRawGet_timeout; //////////////////////////////////////////////////////////////////////////// @@ -64,6 +66,27 @@ private: char const* mRequestText; }; +class XmlTreeInjector : public Injector +{ + public: + XmlTreeInjector(LLXmlTree const* tree) : mTree(tree) { } + ~XmlTreeInjector() { delete const_cast(mTree); } + + /*virtual*/ char const* contentType(void) const { return "application/xml"; } + /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) + { + std::string data; + mTree->write(data); + LLBufferStream ostream(channels, buffer.get()); + ostream.write(data.data(), data.size()); + ostream << std::flush; // Always flush a LLBufferStream when done writing to it. + return data.size(); + } + + private: + LLXmlTree const* mTree; +}; + class LLSDInjector : public Injector { public: @@ -230,28 +253,27 @@ void LLHTTPClient::get4(std::string const& url, LLSD const& query, ResponderPtr get4(uri.asString(), responder, headers); } +//============================================================================= +// Blocking Responders. +// + class BlockingResponder : public AICurlInterface::LegacyPolledResponder { private: - LLCondition mSignal; - LLSD mResponse; + LLCondition mSignal; // Wait condition to wait till mFinished is true. + static LLSD LLSD_dummy; + static std::string Raw_dummy; public: - void wait(void); - LLSD const& response(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } + void wait(void); // Blocks until mFinished is true. + virtual LLSD const& getLLSD(void) const { llassert(false); return LLSD_dummy; } + virtual std::string const& getRaw(void) const { llassert(false); return Raw_dummy; } - /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); +protected: + void wakeup(void); // Call this at the end of completedRaw. }; -void BlockingResponder::completedRaw(U32, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) -{ - 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(); - mFinished = true; - mSignal.unlock(); - mSignal.signal(); -} +LLSD BlockingResponder::LLSD_dummy; +std::string BlockingResponder::Raw_dummy; void BlockingResponder::wait(void) { @@ -273,18 +295,68 @@ void BlockingResponder::wait(void) } } -class BlockingPostResponder : public BlockingResponder { -public: - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingPost_timeout; } +void BlockingResponder::wakeup(void) +{ + // 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(); + mFinished = true; + mSignal.unlock(); + mSignal.signal(); +} + +class BlockingLLSDResponder : public BlockingResponder { +private: + LLSD mResponse; + +protected: + /*virtual*/ LLSD const& getLLSD(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } + /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + decode_llsd_body(mCode, reason, channels, buffer, mResponse); // This puts the body asString() in mResponse in case of http error. + wakeup(); + } }; -class BlockingGetResponder : public BlockingResponder { -public: - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingGet_timeout; } +class BlockingRawResponder : public BlockingResponder { +private: + std::string mResponse; + +protected: + /*virtual*/ std::string const& getRaw(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } + /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + { + decode_raw_body(mCode, reason, channels, buffer, mResponse); + wakeup(); + } }; +class BlockingLLSDPostResponder : public BlockingLLSDResponder { +public: + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingLLSDPost_timeout; } +}; + +class BlockingLLSDGetResponder : public BlockingLLSDResponder { +public: + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingLLSDGet_timeout; } +}; + +class BlockingRawGetResponder : public BlockingRawResponder { +public: + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingRawGet_timeout; } +}; + +// End blocking responders. +//============================================================================= + // These calls are blocking! This is usually bad, unless you're a dataserver. Then it's awesome. +enum EBlockingRequestAction { + HTTP_LLSD_POST, + HTTP_LLSD_GET, + HTTP_RAW_GET +}; + /** @brief does a blocking request on the url, returning the data or bad status. @@ -303,22 +375,26 @@ public: */ static LLSD blocking_request( std::string const& url, - LLURLRequest::ERequestAction method, - LLSD const& body, - AIHTTPHeaders& headers) + EBlockingRequestAction method, + LLSD const& body) // Only used for HTTP_LLSD_POST { lldebugs << "blockingRequest of " << url << llendl; + AIHTTPHeaders headers; boost::intrusive_ptr responder; - if (method == LLURLRequest::HTTP_POST) + if (method == HTTP_LLSD_POST) { - responder = new BlockingPostResponder; + responder = new BlockingLLSDPostResponder; LLHTTPClient::post4(url, body, responder, headers); } - else + else if (method == HTTP_LLSD_GET) { - llassert(method == LLURLRequest::HTTP_GET); - responder = new BlockingGetResponder; + responder = new BlockingLLSDGetResponder; + LLHTTPClient::get4(url, responder, headers); + } + else // method == HTTP_RAW_GET + { + responder = new BlockingRawGetResponder; LLHTTPClient::get4(url, responder, headers); } @@ -328,9 +404,18 @@ static LLSD blocking_request( LLSD response = LLSD::emptyMap(); CURLcode result = responder->result_code(); - if (result == CURLE_OK && (http_status = responder->http_status()) >= 200 && http_status < 300) + http_status = responder->http_status(); + bool http_success = http_status >= 200 && http_status < 300; + if (result == CURLE_OK && http_success) { - response["body"] = responder->response(); + if (method == HTTP_RAW_GET) + { + response["body"] = responder->getRaw(); + } + else + { + response["body"] = responder->getLLSD(); + } } else if (result == CURLE_OK) { @@ -338,16 +423,30 @@ static LLSD blocking_request( if (http_status != 404) { llwarns << "CURL REQ URL: " << url << llendl; - llwarns << "CURL REQ METHOD TYPE: " << LLURLRequest::actionAsVerb(method) << llendl; + llwarns << "CURL REQ METHOD TYPE: " << method << llendl; llwarns << "CURL REQ HEADERS: " << headers << llendl; - if (method == LLURLRequest::HTTP_POST) + if (method == HTTP_LLSD_POST) { llwarns << "CURL REQ BODY: " << body.asString() << llendl; } llwarns << "CURL HTTP_STATUS: " << http_status << llendl; - llwarns << "CURL ERROR BODY: " << responder->response().asString() << llendl; + if (method == HTTP_RAW_GET) + { + llwarns << "CURL ERROR BODY: " << responder->getRaw() << llendl; + } + else + { + llwarns << "CURL ERROR BODY: " << responder->getLLSD().asString() << llendl; + } + } + if (method == HTTP_RAW_GET) + { + response["body"] = responder->getRaw(); + } + else + { + response["body"] = responder->getLLSD().asString(); } - response["body"] = responder->response().asString(); } else { @@ -358,16 +457,21 @@ static LLSD blocking_request( return response; } -LLSD LLHTTPClient::blockingGet(const std::string& url) -{ - AIHTTPHeaders empty_headers; - return blocking_request(url, LLURLRequest::HTTP_GET, LLSD(), empty_headers); -} - LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body) { - AIHTTPHeaders empty_headers; - return blocking_request(url, LLURLRequest::HTTP_POST, body, empty_headers); + return blocking_request(url, HTTP_LLSD_POST, body); +} + +LLSD LLHTTPClient::blockingGet(const std::string& url) +{ + return blocking_request(url, HTTP_LLSD_GET, LLSD()); +} + +U32 LLHTTPClient::blockingGetRaw(const std::string& url, std::string& body) +{ + LLSD result = blocking_request(url, HTTP_RAW_GET, LLSD()); + body = result["body"].asString(); + return result["status"].asInteger(); } void LLHTTPClient::put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index c78917a82..6c8718344 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -130,13 +130,22 @@ public: //@} /** - * @brief Blocking HTTP get that returns an LLSD map of status and body. + * @brief Blocking HTTP GET that returns an LLSD map of status and body. * * @param url the complete serialized (and escaped) url to get * @return An LLSD of { 'status':status, 'body':payload } */ static LLSD blockingGet(std::string const& url); + /** + * @brief Blocking HTTP GET that returns the raw body. + * + * @param url the complete serialized (and escaped) url to get + * @param result the target string to write the body to + * @return HTTP status + */ + static U32 blockingGetRaw(const std::string& url, std::string& result); + /** * @brief Blocking HTTP POST that returns an LLSD map of status and body. * diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index be968c5db..e833abee5 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -128,6 +128,7 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string LLSD info(mReqID.makeResponse()); info["target"] = mTarget; info["message"] = mMessage; + info["code"] = mCode; info["status"] = LLSD::Integer(status); info["reason"] = reason; info["content"] = content; @@ -172,7 +173,7 @@ bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success) } else { - responder->pubErrorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]); + responder->pubErrorWithContent((CURLcode)payload["code"].asInteger(), payload["status"].asInteger(), payload["reason"], payload["content"]); } /*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/ diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8d7f6c323..058df371f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -91,7 +91,6 @@ set(viewer_SOURCE_FILES hippogridmanager.cpp hippolimits.cpp hippopanelgrids.cpp - hipporestrequest.cpp importtracker.cpp jcfloaterareasearch.cpp lggdicdownload.cpp @@ -591,7 +590,6 @@ set(viewer_HEADER_FILES hippogridmanager.h hippolimits.h hippopanelgrids.h - hipporestrequest.h importtracker.h jcfloaterareasearch.h lggdicdownload.h diff --git a/indra/newview/hippogridmanager.cpp b/indra/newview/hippogridmanager.cpp index fac276e7a..c0ceef71d 100644 --- a/indra/newview/hippogridmanager.cpp +++ b/indra/newview/hippogridmanager.cpp @@ -17,8 +17,6 @@ #include "llviewercontrol.h" #include "llweb.h" -#include "hipporestrequest.h" - // ******************************************************************** // Global Variables @@ -491,7 +489,7 @@ bool HippoGridInfo::retrieveGridInfo() uri += '/'; } std::string reply; - int result = HippoRestRequest::getBlocking(uri + "get_grid_info", &reply); + int result = LLHTTPClient::blockingGetRaw(uri + "get_grid_info", reply); if (result != 200) return false; llinfos << "Received: " << reply << llendl; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index cd406e3c5..d90a9483d 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -366,7 +366,7 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s } } -class LLWholeModelFeeResponder: public LLCurl::Responder +class LLWholeModelFeeResponder: public LLCurl::ResponderWithCompleted { LLMeshUploadThread* mThread; LLSD mModelData; @@ -420,7 +420,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return wholeModelFeeResponder_timeout; } }; -class LLWholeModelUploadResponder: public LLCurl::Responder +class LLWholeModelUploadResponder: public LLCurl::ResponderWithCompleted { LLMeshUploadThread* mThread; LLSD mModelData; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index b818ae50c..74526a61d 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 AICurlInterface::ResponderWithCompleted +class LLMimeDiscoveryResponder : public LLHTTPClient::ResponderIgnoreBody { LOG_CLASS(LLMimeDiscoveryResponder); public: diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 3084f61f9..57c65caea 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -165,7 +165,6 @@ #include "hippogridmanager.h" #include "hippolimits.h" -#include "hipporestrequest.h" #include "hippofloaterxml.h" #include "sgversion.h" #include "m7wlinterface.h" @@ -188,6 +187,8 @@ static const boost::regex NEWLINES("\\n{1}"); // NaCl End +extern AIHTTPTimeoutPolicy authHandler_timeout; + // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) #include "llfloateravatarinfo.h" extern LLMap< const LLUUID, LLFloaterAvatarInfo* > gAvatarInfoInstances; // Only defined in llfloateravatarinfo.cpp @@ -3349,12 +3350,24 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL hist // defined in llchatbar.cpp, but not declared in any header void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); -class AuthHandler : public HippoRestHandlerRaw +class AuthHandler : public AICurlInterface::ResponderWithCompleted { - void result(const std::string &content) +protected: + /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); + std::string content; + decode_raw_body(status, reason, channels, buffer, content); + if (status == HTTP_OK) + { + send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); + } + else + { + llwarns << "Hippo AuthHandler: non-OK HTTP status " << status << " for URL " << mURL << " (" << reason << "). Error body: \"" << content << "\"." << llendl; + } } + + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return authHandler_timeout; } }; void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) @@ -3612,7 +3625,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) std::string authUrl = mesg.substr(8); authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; authUrl += gAuthString; - HippoRestRequest::get5(authUrl, new AuthHandler()); + LLHTTPClient::get4(authUrl, new AuthHandler); return; } }