More curl fixes and changes.
* Moved LegacyPolledResponder::mCode to ResponderBase::mCode. * Added a parameter to ResponderBase::finished (and pubError*) to set mCode. * Renamed ResponderBase::decode_body to decode_llsd_body and added ResponderBase::decode_raw_body. * Use LegacyPolledResponder::finished instead of LegacyPolledResponder::completed_headers to set remaining cached values. * Fixed assertion in case of -DCWDEBUG and upload finish detection failure in case of HEAD method (mDebugIsGetMethod -> mDebugIsHeadOrGetMethod). * Add XmlTreeInjector : support for LLXmlTree. * Split BlockingResponder into BlockingLLSDResponder and BlockingRawResponder. * Final blocking responders are now: BlockingLLSDPostResponder, BlockingLLSDGetResponder and BlockingRawGetResponder. * Added LLHTTPClient::blockingGetRaw * Got rid of hipporestrequest.* -- and fixed hippogridmanager.cpp to use LLHTTPClient::blockingGetRaw instead, and fixed llviewermessage.cpp to use AICurlInterface::ResponderWithCompleted and decode_raw_body instead of HippoRestHandlerRaw and LLHTTPClient::get4 instead of HippoRestRequest::get5.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <status> <reason>" 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<ResponderBase> 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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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> ";
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<LLXmlTree*>(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<BlockingResponder> 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)
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 ----------------*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user