Fixes blocking_request. Adds LegacyPolledResponder and BlockingResponder.
XMLRPCResponder also uses the new LegacyPolledResponder now. Renamed http_result() -> http_status().
This commit is contained in:
@@ -456,14 +456,6 @@ AIHTTPTimeoutPolicy const& Responder::getHTTPTimeoutPolicy(void) const
|
||||
return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout();
|
||||
}
|
||||
|
||||
// Called with HTML header.
|
||||
// virtual
|
||||
void Responder::completedHeaders(U32, std::string const&, AIHTTPReceivedHeaders const&)
|
||||
{
|
||||
// This should not be called unless a derived class implemented it.
|
||||
llerrs << "Unexpected call to completedHeaders()." << llendl;
|
||||
}
|
||||
|
||||
// Called with HTML body.
|
||||
// virtual
|
||||
void Responder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, LLIOPipe::buffer_ptr_t const& buffer)
|
||||
@@ -529,6 +521,16 @@ void intrusive_ptr_release(Responder* 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.
|
||||
Responder::completed_headers(status, reason, code, info);
|
||||
}
|
||||
|
||||
} // namespace AICurlInterface
|
||||
//==================================================================================
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "stdtypes.h" // U16, S32, U32, F64
|
||||
#include "llatomic.h" // LLAtomicU32
|
||||
#include "aithreadsafe.h"
|
||||
#include "llhttpstatuscodes.h"
|
||||
#include "aihttpheaders.h"
|
||||
|
||||
extern bool gNoVerifySSLCert;
|
||||
@@ -244,11 +245,13 @@ class Responder : public AICurlResponderBufferEvents {
|
||||
}
|
||||
|
||||
// Derived classes can override this to get the HTML headers that were received, when the message is completed.
|
||||
// The default does nothing.
|
||||
virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers);
|
||||
virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers)
|
||||
{
|
||||
// The default does nothing.
|
||||
}
|
||||
|
||||
public:
|
||||
// Derived classes that implement completedHeaders() should return true here.
|
||||
// Derived classes that implement completed_headers()/completedHeaders() should return true here.
|
||||
virtual bool needsHeaders(void) const { return false; }
|
||||
|
||||
// Timeout policy to use.
|
||||
@@ -299,6 +302,32 @@ class Responder : public AICurlResponderBufferEvents {
|
||||
// destruct when there are no pointers left pointing to it.
|
||||
typedef boost::intrusive_ptr<Responder> ResponderPtr;
|
||||
|
||||
// Same as above except that this class stores the result, allowing old polling
|
||||
// code to poll if the transaction finished by calling is_finished() (from the
|
||||
// main the thread) and then access the results-- as opposed to immediately
|
||||
// digesting the results when any of the virtual functions are called.
|
||||
class LegacyPolledResponder : public Responder {
|
||||
protected:
|
||||
CURLcode mCode;
|
||||
U32 mStatus;
|
||||
std::string mReason;
|
||||
bool mFinished;
|
||||
|
||||
public:
|
||||
LegacyPolledResponder(void) : mCode(CURLE_FAILED_INIT), mStatus(HTTP_INTERNAL_ERROR), mFinished(false) { }
|
||||
|
||||
// Accessors.
|
||||
CURLcode result_code(void) const { return mCode; }
|
||||
U32 http_status(void) const { return mStatus; }
|
||||
bool is_finished(void) const { return mFinished; }
|
||||
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);
|
||||
// This must be defined by the derived class and set mFinished = true at the end.
|
||||
/*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0;
|
||||
};
|
||||
|
||||
} // namespace AICurlInterface
|
||||
|
||||
// Forward declaration (see aicurlprivate.h).
|
||||
|
||||
@@ -230,39 +230,68 @@ void LLHTTPClient::get4(std::string const& url, LLSD const& query, ResponderPtr
|
||||
get4(uri.asString(), responder, headers);
|
||||
}
|
||||
|
||||
// A simple class for managing data returned from a curl http request.
|
||||
class LLHTTPBuffer
|
||||
{
|
||||
public:
|
||||
LLHTTPBuffer() { }
|
||||
|
||||
static size_t curl_write(char* ptr, size_t size, size_t nmemb, void* user_data)
|
||||
{
|
||||
LLHTTPBuffer* self = (LLHTTPBuffer*)user_data;
|
||||
|
||||
size_t bytes = (size * nmemb);
|
||||
self->mBuffer.append(ptr,bytes);
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
LLSD asLLSD()
|
||||
{
|
||||
LLSD content;
|
||||
|
||||
if (mBuffer.empty()) return content;
|
||||
|
||||
std::istringstream istr(mBuffer);
|
||||
LLSDSerialize::fromXML(content, istr);
|
||||
return content;
|
||||
}
|
||||
|
||||
std::string asString()
|
||||
{
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
class BlockingResponder : public AICurlInterface::LegacyPolledResponder {
|
||||
private:
|
||||
std::string mBuffer;
|
||||
LLCondition mSignal;
|
||||
LLSD mResponse;
|
||||
std::ostringstream mBody;
|
||||
|
||||
public:
|
||||
void wait(void);
|
||||
LLSD const& response(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; }
|
||||
std::string const& body(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus != HTTP_OK); return mBody.str(); }
|
||||
|
||||
/*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer);
|
||||
};
|
||||
|
||||
void BlockingResponder::completedRaw(U32, std::string const&, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
|
||||
{
|
||||
if (mCode == CURLE_OK)
|
||||
{
|
||||
LLBufferStream istr(channels, buffer.get());
|
||||
if (mStatus == HTTP_OK)
|
||||
{
|
||||
LLSDSerialize::fromXML(mResponse, istr);
|
||||
}
|
||||
else
|
||||
{
|
||||
mBody << istr;
|
||||
}
|
||||
}
|
||||
mSignal.lock();
|
||||
mFinished = true;
|
||||
mSignal.unlock();
|
||||
mSignal.signal();
|
||||
}
|
||||
|
||||
void BlockingResponder::wait(void)
|
||||
{
|
||||
if (AIThreadID::in_main_thread())
|
||||
{
|
||||
// We're the main thread, so we have to give AIStateMachine CPU cycles.
|
||||
while (!mFinished)
|
||||
{
|
||||
AIStateMachine::mainloop();
|
||||
ms_sleep(10);
|
||||
}
|
||||
}
|
||||
else // Hopefully not the curl thread :p
|
||||
{
|
||||
mSignal.lock();
|
||||
while (!mFinished)
|
||||
mSignal.wait();
|
||||
mSignal.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
class BlockingPostResponder : public BlockingResponder {
|
||||
public:
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingPost_timeout; }
|
||||
};
|
||||
|
||||
class BlockingGetResponder : public BlockingResponder {
|
||||
public:
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return blockingGet_timeout; }
|
||||
};
|
||||
|
||||
// These calls are blocking! This is usually bad, unless you're a dataserver. Then it's awesome.
|
||||
@@ -287,85 +316,54 @@ static LLSD blocking_request(
|
||||
std::string const& url,
|
||||
LLURLRequest::ERequestAction method,
|
||||
LLSD const& body,
|
||||
AIHTTPHeaders& headers,
|
||||
AIHTTPTimeoutPolicy const& timeout)
|
||||
AIHTTPHeaders& headers)
|
||||
{
|
||||
lldebugs << "blockingRequest of " << url << llendl;
|
||||
|
||||
S32 http_status = 499;
|
||||
LLSD response = LLSD::emptyMap();
|
||||
|
||||
#if 0 // AIFIXME: rewrite to use AICurlEasyRequestStateMachine
|
||||
try
|
||||
boost::intrusive_ptr<BlockingResponder> responder;
|
||||
if (method == LLURLRequest::HTTP_POST)
|
||||
{
|
||||
AICurlEasyRequest easy_request(false);
|
||||
AICurlEasyRequest_wat curlEasyRequest_w(*easy_request);
|
||||
responder = new BlockingPostResponder;
|
||||
LLHTTPClient::post4(url, body, responder, headers);
|
||||
}
|
||||
else
|
||||
{
|
||||
llassert(method == LLURLRequest::HTTP_GET);
|
||||
responder = new BlockingGetResponder;
|
||||
LLHTTPClient::get4(url, responder, headers);
|
||||
}
|
||||
|
||||
LLHTTPBuffer http_buffer;
|
||||
|
||||
// * Set curl handle options
|
||||
curlEasyRequest_w->setopt(CURLOPT_TIMEOUT, (long)timeout); // seconds, see warning at top of function.
|
||||
curlEasyRequest_w->setWriteCallback(&LLHTTPBuffer::curl_write, &http_buffer);
|
||||
responder->wait();
|
||||
|
||||
// * Setup headers.
|
||||
if (headers.isMap())
|
||||
{
|
||||
LLSD::map_const_iterator iter = headers.beginMap();
|
||||
LLSD::map_const_iterator end = headers.endMap();
|
||||
for (; iter != end; ++iter)
|
||||
{
|
||||
std::ostringstream header;
|
||||
header << iter->first << ": " << iter->second.asString() ;
|
||||
lldebugs << "header = " << header.str() << llendl;
|
||||
curlEasyRequest_w->addHeader(header.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Needs to stay alive until after the call to perform().
|
||||
std::ostringstream ostr;
|
||||
S32 http_status = HTTP_INTERNAL_ERROR;
|
||||
LLSD response = LLSD::emptyMap();
|
||||
CURLcode result = responder->result_code();
|
||||
|
||||
// * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy)
|
||||
if (method == LLURLRequest::HTTP_GET)
|
||||
if (result == CURLE_OK && (http_status = responder->http_status()) == HTTP_OK)
|
||||
{
|
||||
response["body"] = responder->response();
|
||||
}
|
||||
else if (result == CURLE_OK)
|
||||
{
|
||||
// We expect 404s, don't spam for them.
|
||||
if (http_status != 404)
|
||||
{
|
||||
curlEasyRequest_w->setopt(CURLOPT_HTTPGET, 1);
|
||||
}
|
||||
else if (method == LLURLRequest::HTTP_POST)
|
||||
{
|
||||
//copied from PHP libs, correct?
|
||||
curlEasyRequest_w->addHeader("Content-Type: application/llsd+xml");
|
||||
LLSDSerialize::toXML(body, ostr);
|
||||
curlEasyRequest_w->setPost(ostr.str().c_str(), ostr.str().length());
|
||||
}
|
||||
|
||||
// * Do the action using curl, handle results
|
||||
curlEasyRequest_w->addHeader("Accept: application/llsd+xml");
|
||||
curlEasyRequest_w->finalizeRequest(url);
|
||||
|
||||
S32 curl_success = curlEasyRequest_w->perform();
|
||||
curlEasyRequest_w->getinfo(CURLINFO_RESPONSE_CODE, &http_status);
|
||||
// if we get a non-404 and it's not a 200 OR maybe it is but you have error bits,
|
||||
if ( http_status != 404 && (http_status != 200 || curl_success != 0) )
|
||||
{
|
||||
// We expect 404s, don't spam for them.
|
||||
llwarns << "CURL REQ URL: " << url << llendl;
|
||||
llwarns << "CURL REQ METHOD TYPE: " << LLURLRequest::actionAsVerb(method) << llendl;
|
||||
llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl;
|
||||
llwarns << "CURL REQ BODY: " << ostr.str() << llendl;
|
||||
llwarns << "CURL REQ HEADERS: " << headers << llendl;
|
||||
if (method == LLURLRequest::HTTP_POST)
|
||||
{
|
||||
llwarns << "CURL REQ BODY: " << body.asString() << llendl;
|
||||
}
|
||||
llwarns << "CURL HTTP_STATUS: " << http_status << llendl;
|
||||
llwarns << "CURL ERROR BODY: " << http_buffer.asString() << llendl;
|
||||
response["body"] = http_buffer.asString();
|
||||
}
|
||||
else
|
||||
{
|
||||
response["body"] = http_buffer.asLLSD();
|
||||
lldebugs << "CURL response: " << http_buffer.asString() << llendl;
|
||||
llwarns << "CURL ERROR BODY: " << responder->body() << llendl;
|
||||
}
|
||||
response["body"] = responder->body();
|
||||
}
|
||||
catch(AICurlNoEasyHandle const& error)
|
||||
else
|
||||
{
|
||||
response["body"] = error.what();
|
||||
response["body"] = responder->reason();
|
||||
}
|
||||
#endif
|
||||
|
||||
response["status"] = http_status;
|
||||
return response;
|
||||
@@ -374,13 +372,13 @@ static LLSD blocking_request(
|
||||
LLSD LLHTTPClient::blockingGet(const std::string& url)
|
||||
{
|
||||
AIHTTPHeaders empty_headers;
|
||||
return blocking_request(url, LLURLRequest::HTTP_GET, LLSD(), empty_headers, blockingGet_timeout);
|
||||
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, blockingPost_timeout);
|
||||
return blocking_request(url, LLURLRequest::HTTP_POST, body, empty_headers);
|
||||
}
|
||||
|
||||
void LLHTTPClient::put4(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers)
|
||||
|
||||
@@ -265,7 +265,7 @@ bool LLCurrencyUIManager::Impl::checkTransaction()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mResponder->result_code() != CURLE_OK || mResponder->http_result() < 200 || mResponder->http_result() >= 400)
|
||||
if (mResponder->result_code() != CURLE_OK || mResponder->http_status() < 200 || mResponder->http_status() >= 400)
|
||||
{
|
||||
setError(mResponder->reason(), mResponder->getURL());
|
||||
}
|
||||
|
||||
@@ -863,7 +863,7 @@ bool LLFloaterBuyLandUI::checkTransaction()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mResponder->result_code() != CURLE_OK || mResponder->http_result() < 200 || mResponder->http_result() >= 400)
|
||||
if (mResponder->result_code() != CURLE_OK || mResponder->http_status() < 200 || mResponder->http_status() >= 400)
|
||||
{
|
||||
tellUserError(mResponder->reason(), mResponder->getURL());
|
||||
}
|
||||
|
||||
@@ -158,14 +158,12 @@ XMLRPC_VALUE LLXMLRPCValue::getValue() const
|
||||
|
||||
void XMLRPCResponder::completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info)
|
||||
{
|
||||
mCode = code;
|
||||
if (info)
|
||||
{
|
||||
mTransferInfo = *info;
|
||||
}
|
||||
mStatus = status;
|
||||
mReason = reason;
|
||||
// Note: 'status' and 'reason' are the same as what is passed to completedRaw.
|
||||
// Call base class implementation.
|
||||
LegacyPolledResponder::completed_headers(status, reason, code, info);
|
||||
}
|
||||
|
||||
void XMLRPCResponder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
|
||||
|
||||
@@ -91,31 +91,20 @@ private:
|
||||
XMLRPC_VALUE mV;
|
||||
};
|
||||
|
||||
class XMLRPCResponder : public LLCurl::Responder {
|
||||
class XMLRPCResponder : public AICurlInterface::LegacyPolledResponder {
|
||||
private:
|
||||
CURLcode mCode;
|
||||
U32 mStatus;
|
||||
AICurlInterface::TransferInfo mTransferInfo;
|
||||
S32 mBufferSize;
|
||||
bool mReceivedHTTPHeader;
|
||||
bool mFinished;
|
||||
std::string mReason;
|
||||
XMLRPC_REQUEST mResponse;
|
||||
|
||||
public:
|
||||
XMLRPCResponder(void) : mCode(CURLE_FAILED_INIT), mStatus(HTTP_INTERNAL_ERROR), mReceivedHTTPHeader(false), mFinished(false) { }
|
||||
|
||||
// Accessors.
|
||||
CURLcode result_code(void) const { return mCode; }
|
||||
U32 http_result(void) const { return mStatus; }
|
||||
F64 transferRate(void) const;
|
||||
bool is_downloading(void) const { return mReceivedHTTPHeader; }
|
||||
bool is_finished(void) const { return mFinished; }
|
||||
std::string const& reason(void) const { return mReason; }
|
||||
XMLRPC_REQUEST response(void) const { return mResponse; }
|
||||
LLXMLRPCValue responseValue(void) const;
|
||||
|
||||
/*virtual*/ bool needsHeaders(void) const { return true; }
|
||||
/*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLCurl::Responder::received_HTTP_header(); }
|
||||
/*virtual*/ void completed_headers(U32 status, std::string const& reason, CURLcode code, AICurlInterface::TransferInfo* info);
|
||||
/*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer);
|
||||
|
||||
Reference in New Issue
Block a user