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:
Aleric Inglewood
2012-10-28 17:38:25 +01:00
parent 2a88f7d7c4
commit 65e012c540
14 changed files with 290 additions and 131 deletions

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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> ";

View File

@@ -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(

View File

@@ -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);

View File

@@ -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)

View File

@@ -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.
*

View File

@@ -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 ----------------*/

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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:

View File

@@ -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;
}
}