WIP: work on rewriting LLURLRequest

This commit is contained in:
Aleric Inglewood
2012-07-29 01:26:28 +02:00
parent adaf5cd69c
commit af4ac8fb5f
15 changed files with 199 additions and 146 deletions

View File

@@ -1111,7 +1111,7 @@ static S32 const CURL_REQUEST_TIMEOUT = 30; // Seconds per operation.
LLChannelDescriptors const CurlResponderBuffer::sChannels; LLChannelDescriptors const CurlResponderBuffer::sChannels;
CurlResponderBuffer::CurlResponderBuffer() CurlResponderBuffer::CurlResponderBuffer() : mRequestTransferedBytes(0), mResponseTransferedBytes(0)
{ {
ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj(); ThreadSafeBufferedCurlEasyRequest* lockobj = get_lockobj();
AICurlEasyRequest_wat curl_easy_request_w(*lockobj); AICurlEasyRequest_wat curl_easy_request_w(*lockobj);
@@ -1230,9 +1230,12 @@ size_t CurlResponderBuffer::curlWriteCallback(char* data, size_t size, size_t nm
AICurlEasyRequest_wat buffered_easy_request_w(*lockobj); AICurlEasyRequest_wat buffered_easy_request_w(*lockobj);
AICurlResponderBuffer_wat buffer_w(*lockobj); AICurlResponderBuffer_wat buffer_w(*lockobj);
S32 n = size * nmemb; // CurlResponderBuffer::setBodyLimit is never called, so buffer_w->mBodyLimit is infinite.
buffer_w->getOutput()->append(sChannels.in(), (U8 const*)data, n); //S32 bytes = llmin(size * nmemb, buffer_w->mBodyLimit); buffer_w->mBodyLimit -= bytes;
return n; S32 bytes = size * nmemb;
buffer_w->getOutput()->append(sChannels.in(), (U8 const*)data, bytes);
mResponseTransferedBytes += bytes;
return bytes;
} }
//static //static

View File

@@ -119,9 +119,8 @@ void AICurlEasyRequestStateMachine::multiplex_impl(void)
// Set an inactivity timer. // Set an inactivity timer.
// This shouldn't really be necessary, except in the case of a bug // This shouldn't really be necessary, except in the case of a bug
// in libcurl; but lets be sure and set a timer for inactivity. // in libcurl; but lets be sure and set a timer for inactivity.
static LLCachedControl<F32> CurlRequestTimeOut("CurlRequestTimeOut", 40.f);
mTimer = new AIPersistentTimer; // Do not delete timer upon expiration. mTimer = new AIPersistentTimer; // Do not delete timer upon expiration.
mTimer->setInterval(CurlRequestTimeOut); mTimer->setInterval(sCurlRequestTimeOut);
mTimer->run(this, AICurlEasyRequestStateMachine_timedOut, false, false); mTimer->run(this, AICurlEasyRequestStateMachine_timedOut, false, false);
break; break;
} }
@@ -242,6 +241,15 @@ AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(bool buffered) : mB
Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(" << (buffered ? "true" : "false") << ") [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(" << (buffered ? "true" : "false") << ") [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
} }
//static
F32 AICurlEasyRequestStateMachine::sCurlRequestTimeOut = 40.f;
//static
void AICurlEasyRequestStateMachine::setCurlRequestTimeOut(F32 CurlRequestTimeOut)
{
sCurlRequestTimeOut = CurlRequestTimeOut;
}
AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine() AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine()
{ {
Dout(dc::statemachine, "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); Dout(dc::statemachine, "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");

View File

@@ -40,7 +40,7 @@
// Before calling cersm.run() initialize the object (cersm) as follows: // Before calling cersm.run() initialize the object (cersm) as follows:
// //
// AICurlEasyRequest_wat cersm_w(cersm); // AICurlEasyRequest_wat cersm_w(cersm);
// cersm_w->setopt(...); // etc, see the interface of AICurlPrivate::CurlEasyRequest and it's base class AICurlPrivate::CurlEasyHandle. // cersm_w->setopt(...); // etc, see the interface of AICurlPrivate::CurlEasyRequest.
// //
// When the state machine finishes, call aborted() to check // When the state machine finishes, call aborted() to check
// whether or not the statemachine succeeded in fetching // whether or not the statemachine succeeded in fetching
@@ -65,6 +65,12 @@ class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHa
bool mHandled; // Set when we processed the received data. bool mHandled; // Set when we processed the received data.
AITimer* mTimer; // Expiration timer. AITimer* mTimer; // Expiration timer.
static F32 sCurlRequestTimeOut; // The time out value for mTimer.
public:
// Called once to set a different timeout then the default of 40 seconds.
static void setCurlRequestTimeOut(F32 CurlRequestTimeOut);
protected: protected:
// AICurlEasyRequest Events. // AICurlEasyRequest Events.

View File

@@ -301,6 +301,9 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents {
// Called after removed_from_multi_handle was called. // Called after removed_from_multi_handle was called.
void processOutput(AICurlEasyRequest_wat& curl_easy_request_w); void processOutput(AICurlEasyRequest_wat& curl_easy_request_w);
// Do not write more than this amount.
//void setBodyLimit(U32 size) { mBodyLimit = size; }
protected: protected:
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w); /*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat& curl_easy_request_w);
/*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w); /*virtual*/ void finished(AICurlEasyRequest_wat& curl_easy_request_w);
@@ -311,6 +314,9 @@ class CurlResponderBuffer : protected AICurlEasyHandleEvents {
std::stringstream mHeaderOutput; std::stringstream mHeaderOutput;
LLIOPipe::buffer_ptr_t mOutput; LLIOPipe::buffer_ptr_t mOutput;
AICurlInterface::ResponderPtr mResponder; AICurlInterface::ResponderPtr mResponder;
//U32 mBodyLimit; // From the old LLURLRequestDetail::mBodyLimit, but never used.
S32 mByteAccumulator;
S32 mResponseTransferedBytes;
public: public:
static LLChannelDescriptors const sChannels; // Channel object for mOutput: we ONLY use channel 0, so this can be a constant. static LLChannelDescriptors const sChannels; // Channel object for mOutput: we ONLY use channel 0, so this can be a constant.

View File

@@ -39,8 +39,6 @@
extern F64 calc_clock_frequency(void); extern F64 calc_clock_frequency(void);
extern LLControlGroup gSavedSettings;
// Local variables. // Local variables.
namespace { namespace {
struct QueueElementComp; struct QueueElementComp;
@@ -68,19 +66,15 @@ namespace {
} }
// static // static
AIThreadSafeSimpleDC<U64> AIStateMachine::sMaxCount; U64 AIStateMachine::sMaxCount;
AIThreadSafeDC<AIStateMachine::csme_type> AIStateMachine::sContinuedStateMachinesAndMainloopEnabled; AIThreadSafeDC<AIStateMachine::csme_type> AIStateMachine::sContinuedStateMachinesAndMainloopEnabled;
void AIStateMachine::updateSettings(void) // static
void AIStateMachine::setMaxCount(F32 StateMachineMaxTime)
{ {
static const LLCachedControl<U32> StateMachineMaxTime("StateMachineMaxTime", 20); llassert(is_main_thread());
static U32 last_StateMachineMaxTime = 0; Dout(dc::statemachine, "(Re)calculating AIStateMachine::sMaxCount");
if (last_StateMachineMaxTime != StateMachineMaxTime) sMaxCount = calc_clock_frequency() * StateMachineMaxTime / 1000;
{
Dout(dc::statemachine, "Initializing AIStateMachine::sMaxCount");
*AIAccess<U64>(sMaxCount) = calc_clock_frequency() * StateMachineMaxTime / 1000;
last_StateMachineMaxTime = StateMachineMaxTime;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -511,7 +505,6 @@ void AIStateMachine::dowork(void)
llassert(!active_statemachines.empty()); llassert(!active_statemachines.empty());
// Run one or more state machines. // Run one or more state machines.
U64 total_clocks = 0; U64 total_clocks = 0;
U64 max_count = *AIAccess<U64>(sMaxCount);
for (active_statemachines_type::iterator iter = active_statemachines.begin(); iter != active_statemachines.end(); ++iter) for (active_statemachines_type::iterator iter = active_statemachines.begin(); iter != active_statemachines.end(); ++iter)
{ {
AIStateMachine& statemachine(iter->statemachine()); AIStateMachine& statemachine(iter->statemachine());
@@ -525,7 +518,7 @@ void AIStateMachine::dowork(void)
U64 delta = LLFastTimer::getCPUClockCount64() - start; U64 delta = LLFastTimer::getCPUClockCount64() - start;
iter->add(delta); iter->add(delta);
total_clocks += delta; total_clocks += delta;
if (total_clocks >= max_count) if (total_clocks >= sMaxCount)
{ {
#ifndef LL_RELEASE_FOR_DOWNLOAD #ifndef LL_RELEASE_FOR_DOWNLOAD
llwarns << "AIStateMachine::mainloop did run for " << (total_clocks * 1000 / calc_clock_frequency()) << " ms." << llendl; llwarns << "AIStateMachine::mainloop did run for " << (total_clocks * 1000 / calc_clock_frequency()) << " ms." << llendl;

View File

@@ -239,7 +239,7 @@ class AIStateMachine {
}; };
callback_type* mCallback; //!< Pointer to signal/connection, or NULL when not connected. callback_type* mCallback; //!< Pointer to signal/connection, or NULL when not connected.
static AIThreadSafeSimpleDC<U64> sMaxCount; //!< Number of cpu clocks below which we start a new state machine within the same frame. static U64 sMaxCount; //!< Number of cpu clocks below which we start a new state machine within the same frame.
static AIThreadSafeDC<csme_type> sContinuedStateMachinesAndMainloopEnabled; //!< Read/write locked variable pair. static AIThreadSafeDC<csme_type> sContinuedStateMachinesAndMainloopEnabled; //!< Read/write locked variable pair.
protected: protected:
@@ -254,7 +254,7 @@ class AIStateMachine {
#ifdef SHOW_ASSERT #ifdef SHOW_ASSERT
, mContThread(0), mCalledThreadUnsafeIdle(false) , mContThread(0), mCalledThreadUnsafeIdle(false)
#endif #endif
{ updateSettings(); } { }
protected: protected:
//! The user should call 'kill()', not delete a AIStateMachine (derived) directly. //! The user should call 'kill()', not delete a AIStateMachine (derived) directly.
@@ -349,7 +349,7 @@ class AIStateMachine {
// Other. // Other.
//! Called whenever the StateMachineMaxTime setting is changed. //! Called whenever the StateMachineMaxTime setting is changed.
static void updateSettings(void); static void setMaxCount(F32 StateMachineMaxTime);
//--------------------------------------- //---------------------------------------
// Accessors. // Accessors.

View File

@@ -20,6 +20,7 @@ include_directories(
) )
set(llmessage_SOURCE_FILES set(llmessage_SOURCE_FILES
llhttpclient.cpp
llares.cpp llares.cpp
llareslistener.cpp llareslistener.cpp
llassetstorage.cpp llassetstorage.cpp
@@ -36,7 +37,6 @@ set(llmessage_SOURCE_FILES
lldispatcher.cpp lldispatcher.cpp
llfiltersd2xmlrpc.cpp llfiltersd2xmlrpc.cpp
llhost.cpp llhost.cpp
llhttpclient.cpp
llhttpclientadapter.cpp llhttpclientadapter.cpp
llhttpnode.cpp llhttpnode.cpp
llhttpsender.cpp llhttpsender.cpp

View File

@@ -306,7 +306,7 @@ public:
typedef std::list<LLSegment> segment_list_t; typedef std::list<LLSegment> segment_list_t;
typedef segment_list_t::const_iterator const_segment_iterator_t; typedef segment_list_t::const_iterator const_segment_iterator_t;
typedef segment_list_t::iterator segment_iterator_t; typedef segment_list_t::iterator segment_iterator_t;
enum { npos = 0xffffffff }; static size_t const npos = (size_t)-1; // (U8*)npos is used as a magic address.
LLBufferArray(); LLBufferArray();
~LLBufferArray(); ~LLBufferArray();

View File

@@ -42,7 +42,9 @@
const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f; const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
#ifdef AI_UNUSED
LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL; LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL;
#endif // AI_UNUSED
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@@ -50,6 +52,7 @@ LLURLRequest::SSLCertVerifyCallback LLHTTPClient::mCertVerifyCallback = NULL;
namespace namespace
{ {
#if 0
class LLHTTPClientURLAdaptor : public LLURLRequestComplete class LLHTTPClientURLAdaptor : public LLURLRequestComplete
{ {
public: public:
@@ -93,6 +96,7 @@ namespace
std::string mReason; std::string mReason;
LLSD mHeaderOutput; LLSD mHeaderOutput;
}; };
#endif
class Injector : public LLIOPipe class Injector : public LLIOPipe
{ {
@@ -206,10 +210,12 @@ namespace
LLPumpIO* theClientPump = NULL; LLPumpIO* theClientPump = NULL;
} }
#ifdef AI_UNUSED
void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback) void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback)
{ {
LLHTTPClient::mCertVerifyCallback = callback; LLHTTPClient::mCertVerifyCallback = callback;
} }
#endif
static void request( static void request(
const std::string& url, const std::string& url,
@@ -245,11 +251,9 @@ static void request(
return ; return ;
} }
req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); //AIFIXME: getCertVerifyCallback() always return NULL, so we might as well not do this call: req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " " << headers << llendl;
lldebugs << LLURLRequest::actionAsVerb(method) << " " << url << " "
<< headers << llendl;
// Insert custom headers if the caller sent any // Insert custom headers if the caller sent any
if (headers.isMap()) if (headers.isMap())
@@ -293,7 +297,7 @@ static void request(
} }
} }
req->setCallback(new LLHTTPClientURLAdaptor(responder)); //AIFIXME: req->setCallback(new LLHTTPClientURLAdaptor(responder));
if (method == LLURLRequest::HTTP_POST && gMessageSystem) if (method == LLURLRequest::HTTP_POST && gMessageSystem)
{ {
@@ -319,7 +323,7 @@ static void request(
chain.push_back(LLIOPipe::ptr_t(body_injector)); chain.push_back(LLIOPipe::ptr_t(body_injector));
} }
chain.push_back(LLIOPipe::ptr_t(req)); //AIFIXEM: chain.push_back(LLIOPipe::ptr_t(req));
theClientPump->addChain(chain, timeout); theClientPump->addChain(chain, timeout);
} }
@@ -499,7 +503,7 @@ static LLSD blocking_request(
{ {
// We expect 404s, don't spam for them. // We expect 404s, don't spam for them.
llwarns << "CURL REQ URL: " << url << llendl; llwarns << "CURL REQ URL: " << url << llendl;
llwarns << "CURL REQ METHOD TYPE: " << method << llendl; llwarns << "CURL REQ METHOD TYPE: " << LLURLRequest::actionAsVerb(method) << llendl;
llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl; llwarns << "CURL REQ HEADERS: " << headers.asString() << llendl;
llwarns << "CURL REQ BODY: " << body_str << llendl; llwarns << "CURL REQ BODY: " << body_str << llendl;
llwarns << "CURL HTTP_STATUS: " << http_status << llendl; llwarns << "CURL HTTP_STATUS: " << http_status << llendl;
@@ -608,11 +612,13 @@ void LLHTTPClient::move(
} }
//static
void LLHTTPClient::setPump(LLPumpIO& pump) void LLHTTPClient::setPump(LLPumpIO& pump)
{ {
theClientPump = &pump; theClientPump = &pump;
} }
//static
bool LLHTTPClient::hasPump() bool LLHTTPClient::hasPump()
{ {
return theClientPump != NULL; return theClientPump != NULL;

View File

@@ -34,7 +34,7 @@
#include <string> #include <string>
#include <boost/intrusive_ptr.hpp> #include <boost/intrusive_ptr.hpp>
#include "llurlrequest.h" //#include "llurlrequest.h"
#include "llassettype.h" #include "llassettype.h"
#include "llcurl.h" #include "llcurl.h"
#include "lliopipe.h" #include "lliopipe.h"
@@ -156,11 +156,13 @@ public:
static LLPumpIO &getPump(); static LLPumpIO &getPump();
///< Hippo special ///< Hippo special
#ifdef AI_UNUSED
static void setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback); static void setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback callback);
static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; } static LLURLRequest::SSLCertVerifyCallback getCertVerifyCallback() { return mCertVerifyCallback; }
protected: protected:
static LLURLRequest::SSLCertVerifyCallback mCertVerifyCallback; static LLURLRequest::SSLCertVerifyCallback mCertVerifyCallback;
#endif // AI_UNUSED
}; };
#endif // LL_LLHTTPCLIENT_H #endif // LL_LLHTTPCLIENT_H

View File

@@ -36,7 +36,7 @@
#include <algorithm> #include <algorithm>
#include <openssl/x509_vfy.h> #include <openssl/x509_vfy.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include "llcurl.h" #include "aicurleasyrequeststatemachine.h"
#include "llfasttimer.h" #include "llfasttimer.h"
#include "llioutil.h" #include "llioutil.h"
#include "llmemtype.h" #include "llmemtype.h"
@@ -55,8 +55,9 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499;
const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes"); const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes");
static size_t headerCallback(char* data, size_t size, size_t nmemb, void* user); //static size_t headerCallback(char* data, size_t size, size_t nmemb, void* user);
#if 0
/** /**
* class LLURLRequestDetail * class LLURLRequestDetail
*/ */
@@ -66,23 +67,21 @@ public:
LLURLRequestDetail(); LLURLRequestDetail();
~LLURLRequestDetail(); ~LLURLRequestDetail();
std::string mURL; std::string mURL;
AICurlEasyRequest mCurlEasyRequest; AICurlEasyRequestStateMachine* mStateMachine;
LLIOPipe::buffer_ptr_t mResponseBuffer; LLIOPipe::buffer_ptr_t mResponseBuffer;
LLChannelDescriptors mChannels; LLChannelDescriptors mChannels;
U8* mLastRead; U8* mLastRead;
U32 mBodyLimit; U32 mBodyLimit;
S32 mByteAccumulator; S32 mByteAccumulator;
bool mIsBodyLimitSet; bool mIsBodyLimitSet;
LLURLRequest::SSLCertVerifyCallback mSSLVerifyCallback;
}; };
LLURLRequestDetail::LLURLRequestDetail() : LLURLRequestDetail::LLURLRequestDetail() :
mCurlEasyRequest(false), mStateMachine(new AICurlEasyRequestStateMachine(false)),
mLastRead(NULL), mLastRead(NULL),
mBodyLimit(0), mBodyLimit(0),
mByteAccumulator(0), mByteAccumulator(0),
mIsBodyLimitSet(false), mIsBodyLimitSet(false)
mSSLVerifyCallback(NULL)
{ {
} }
@@ -90,18 +89,19 @@ LLURLRequestDetail::~LLURLRequestDetail()
{ {
mLastRead = NULL; mLastRead = NULL;
} }
#endif
#if AI_UNUSED
void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param) void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param)
{ {
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
mDetail->mSSLVerifyCallback = callback; mDetail->mSSLVerifyCallback = callback;
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
curlEasyRequest_w->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this); curlEasyRequest_w->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this);
curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, true); curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYPEER, true);
curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYHOST, 2); curlEasyRequest_w->setopt(CURLOPT_SSL_VERIFYHOST, 2);
} }
// _sslCtxFunction // _sslCtxFunction
// Callback function called when an SSL Context is created via CURL // Callback function called when an SSL Context is created via CURL
// used to configure the context for custom cert validation // used to configure the context for custom cert validation
@@ -123,6 +123,7 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
return CURLE_OK; return CURLE_OK;
} }
#endif
/** /**
* class LLURLRequest * class LLURLRequest
@@ -131,7 +132,8 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)
// static // static
std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
{ {
static const std::string VERBS[] = static int const array_size = HTTP_MOVE + 1; // INVALID == 0
static char const* const VERBS[array_size] =
{ {
"(invalid)", "(invalid)",
"HEAD", "HEAD",
@@ -141,60 +143,45 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action)
"DELETE", "DELETE",
"MOVE" "MOVE"
}; };
if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT)) return VERBS[action >= array_size ? INVALID : action];
}
// This might throw AICurlNoEasyHandle.
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url) : AICurlEasyRequestStateMachine(false), mAction(action), mURL(url)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
{ {
return VERBS[0]; AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
//AIFIXME: we can't really use the other callbacks: they have to be extended... curlEasyRequest_w->setWriteCallback(&downCallback, (void*)this);
//AIFIXME: curlEasyRequest_w->setReadCallback(&upCallback, (void*)this);
} }
return VERBS[action];
//AIFIXME: stuff they have to be extended with... mRequestTransferedBytes = 0;
//AIFIXME: stuff they have to be extended with... mResponseTransferedBytes = 0;
//AIFIXME: start statemachine mState = STATE_INITIALIZED;
} }
LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action) : #if 0
mAction(action) void LLURLRequest::setURL2(const std::string& url)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
// This might throw AICurlNoEasyHandle.
initialize();
}
LLURLRequest::LLURLRequest(
LLURLRequest::ERequestAction action,
const std::string& url) :
mAction(action)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
// This might throw AICurlNoEasyHandle.
initialize();
setURL(url);
}
LLURLRequest::~LLURLRequest()
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
{
AICurlEasyRequest_wat curl_easy_request_w(*mDetail->mCurlEasyRequest);
curl_easy_request_w->revokeCallbacks();
curl_easy_request_w->send_events_to(NULL);
}
delete mDetail;
}
void LLURLRequest::setURL(const std::string& url)
{ {
mDetail->mURL = url; mDetail->mURL = url;
} }
std::string LLURLRequest::getURL() const std::string LLURLRequest::getURL2() const
{ {
return mDetail->mURL; return mDetail->mURL;
} }
#endif
void LLURLRequest::addHeader(const char* header) void LLURLRequest::addHeader(const char* header)
{ {
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
curlEasyRequest_w->addHeader(header); curlEasyRequest_w->addHeader(header);
} }
#ifdef AI_UNUSED
void LLURLRequest::setBodyLimit(U32 size) void LLURLRequest::setBodyLimit(U32 size)
{ {
mDetail->mBodyLimit = size; mDetail->mBodyLimit = size;
@@ -205,9 +192,10 @@ void LLURLRequest::setCallback(LLURLRequestComplete* callback)
{ {
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
mCompletionCallback = callback; mCompletionCallback = callback;
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
curlEasyRequest_w->setHeaderCallback(&headerCallback, (void*)callback); curlEasyRequest_w->setHeaderCallback(&headerCallback, (void*)callback);
} }
#endif
// Added to mitigate the effect of libcurl looking // Added to mitigate the effect of libcurl looking
// for the ALL_PROXY and http_proxy env variables // for the ALL_PROXY and http_proxy env variables
@@ -242,38 +230,41 @@ void LLURLRequest::useProxy(bool use_proxy)
lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = \"" << env_proxy << "\"" << llendl; lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = \"" << env_proxy << "\"" << llendl;
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
curlEasyRequest_w->setoptString(CURLOPT_PROXY, use_proxy ? env_proxy : std::string("")); curlEasyRequest_w->setoptString(CURLOPT_PROXY, use_proxy ? env_proxy : std::string(""));
} }
#ifdef AI_UNUSED
void LLURLRequest::useProxy(const std::string &proxy) void LLURLRequest::useProxy(const std::string &proxy)
{ {
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
curlEasyRequest_w->setoptString(CURLOPT_PROXY, proxy); curlEasyRequest_w->setoptString(CURLOPT_PROXY, proxy);
} }
#endif
void LLURLRequest::allowCookies() void LLURLRequest::allowCookies()
{ {
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
curlEasyRequest_w->setoptString(CURLOPT_COOKIEFILE, ""); curlEasyRequest_w->setoptString(CURLOPT_COOKIEFILE, "");
} }
#ifdef AI_UNUSED // no longer derived from LLIOPipe
//virtual //virtual
bool LLURLRequest::hasExpiration(void) const bool LLURLRequest::hasExpiration(void) const
{ {
// Currently, this ALWAYS returns false -- because only AICurlEasyRequestStateMachine uses buffered // Currently, this ALWAYS returns false -- because only AICurlEasyRequestStateMachine uses buffered
// AICurlEasyRequest objects, and LLURLRequest uses (unbuffered) AICurlEasyRequest directly, which // AICurlEasyRequest objects, and LLURLRequest uses (unbuffered) AICurlEasyRequest directly, which
// have no expiration facility. // have no expiration facility.
return mDetail->mCurlEasyRequest.isBuffered(); return mDetail->mStateMachine->isBuffered();
} }
//virtual //virtual
bool LLURLRequest::hasNotExpired(void) const bool LLURLRequest::hasNotExpired(void) const
{ {
if (!mDetail->mCurlEasyRequest.isBuffered()) if (!mDetail->mStateMachine->isBuffered())
return true; return true;
AICurlEasyRequest_wat buffered_easy_request_w(*mDetail->mCurlEasyRequest); AICurlEasyRequest_wat buffered_easy_request_w(*mCurlEasyRequest);
AICurlResponderBuffer_wat buffer_w(*mDetail->mCurlEasyRequest); AICurlResponderBuffer_wat buffer_w(*mCurlEasyRequest);
return buffer_w->isValid(); return buffer_w->isValid();
} }
@@ -285,20 +276,20 @@ LLIOPipe::EStatus LLURLRequest::handleError(
DoutEntering(dc::curl, "LLURLRequest::handleError(" << LLIOPipe::lookupStatusString(status) << ", " << (void*)pump << ")"); DoutEntering(dc::curl, "LLURLRequest::handleError(" << LLIOPipe::lookupStatusString(status) << ", " << (void*)pump << ")");
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST); LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
if (LL_LIKELY(!mDetail->mCurlEasyRequest.isBuffered())) // Currently always true. if (LL_LIKELY(!mDetail->mStateMachine->isBuffered())) // Currently always true.
{ {
// The last reference will be deleted when the pump that this chain belongs to // The last reference will be deleted when the pump that this chain belongs to
// is removed from the running chains vector, upon returning from this function. // is removed from the running chains vector, upon returning from this function.
// This keeps the CurlEasyRequest object alive until the curl thread cleanly removed it. // This keeps the CurlEasyRequest object alive until the curl thread cleanly removed it.
Dout(dc::curl, "Calling mDetail->mCurlEasyRequest.removeRequest()"); Dout(dc::curl, "Calling mDetail->mStateMachine->removeRequest()");
mDetail->mCurlEasyRequest.removeRequest(); mDetail->mStateMachine->removeRequest();
} }
else if (!hasNotExpired()) else if (!hasNotExpired())
{ {
// The buffered version has it's own time out handling, and that already expired, // The buffered version has it's own time out handling, and that already expired,
// so we can ignore the expiration of this timer (currently never happens). // so we can ignore the expiration of this timer (currently never happens).
// I left it here because it's what LL did (in the form if (!isValid() ...), // I left it here because it's what LL did (in the form if (!isValid() ...),
// and it would be relevant if this characteristic of mDetail->mCurlEasyRequest // and it would be relevant if this characteristic of mDetail->mStateMachine
// would change. --Aleric // would change. --Aleric
return STATUS_EXPIRED ; return STATUS_EXPIRED ;
} }
@@ -317,19 +308,6 @@ LLIOPipe::EStatus LLURLRequest::handleError(
return status; return status;
} }
void LLURLRequest::added_to_multi_handle(AICurlEasyRequest_wat&)
{
}
void LLURLRequest::finished(AICurlEasyRequest_wat&)
{
}
void LLURLRequest::removed_from_multi_handle(AICurlEasyRequest_wat&)
{
mRemoved = true;
}
static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST("URL Request"); static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST("URL Request");
// virtual // virtual
@@ -392,7 +370,7 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
} }
mRemoved = false; mRemoved = false;
mState = STATE_WAITING_FOR_RESPONSE; mState = STATE_WAITING_FOR_RESPONSE;
mDetail->mCurlEasyRequest.addRequest(); // Add easy handle to multi handle. mDetail->mStateMachine->addRequest(); // Add easy handle to multi handle.
return STATUS_BREAK; return STATUS_BREAK;
} }
@@ -418,7 +396,7 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result"); static LLFastTimer::DeclareTimer FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result");
AICurlEasyRequest_wat(*mDetail->mCurlEasyRequest)->getResult(&result); AICurlEasyRequest_wat(*mCurlEasyRequest)->getResult(&result);
mState = STATE_HAVE_RESPONSE; mState = STATE_HAVE_RESPONSE;
context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
@@ -488,23 +466,7 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
return STATUS_ERROR; return STATUS_ERROR;
} }
} }
#endif // AI_UNUSED
void LLURLRequest::initialize()
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
mState = STATE_INITIALIZED;
// This might throw AICurlNoEasyHandle.
mDetail = new LLURLRequestDetail;
{
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest);
curlEasyRequest_w->setWriteCallback(&downCallback, (void*)this);
curlEasyRequest_w->setReadCallback(&upCallback, (void*)this);
}
mRequestTransferedBytes = 0;
mResponseTransferedBytes = 0;
}
static LLFastTimer::DeclareTimer FTM_URL_REQUEST_CONFIGURE("URL Configure"); static LLFastTimer::DeclareTimer FTM_URL_REQUEST_CONFIGURE("URL Configure");
bool LLURLRequest::configure() bool LLURLRequest::configure()
@@ -517,7 +479,7 @@ bool LLURLRequest::configure()
mDetail->mChannels.in(), mDetail->mChannels.in(),
NULL); NULL);
{ {
AICurlEasyRequest_wat curlEasyRequest_w(*mDetail->mCurlEasyRequest); AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest);
switch(mAction) switch(mAction)
{ {
case HTTP_HEAD: case HTTP_HEAD:
@@ -582,12 +544,12 @@ bool LLURLRequest::configure()
if(rv) if(rv)
{ {
curlEasyRequest_w->finalizeRequest(mDetail->mURL); curlEasyRequest_w->finalizeRequest(mDetail->mURL);
curlEasyRequest_w->send_events_to(this);
} }
} }
return rv; return rv;
} }
#if 0
// static // static
size_t LLURLRequest::downCallback( size_t LLURLRequest::downCallback(
char* data, char* data,
@@ -713,7 +675,9 @@ static size_t headerCallback(char* header_line, size_t size, size_t nmemb, void*
return header_len; return header_len;
} }
#endif
#ifdef AI_UNUSED
/** /**
* LLURLRequestComplete * LLURLRequestComplete
*/ */
@@ -783,3 +747,4 @@ LLIOPipe::EStatus LLURLRequestComplete::process_impl(
complete(channels, buffer); complete(channels, buffer);
return STATUS_OK; return STATUS_OK;
} }
#endif

View File

@@ -7,6 +7,7 @@
* $LicenseInfo:firstyear=2005&license=viewerlgpl$ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code * Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc. * Copyright (C) 2010, Linden Research, Inc.
* Copyright (C) 2012, Aleric Inglewood.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@@ -35,12 +36,73 @@
*/ */
#include <string> #include <string>
#include "lliopipe.h" #include "aicurleasyrequeststatemachine.h"
#include "llchainio.h"
#include "llerror.h"
#include "llcurl.h"
class LLURLRequest : public AICurlEasyRequestStateMachine {
public:
/**
* @brief This enumeration is for specifying the type of request.
*/
enum ERequestAction
{
INVALID,
HTTP_HEAD,
HTTP_GET,
HTTP_PUT,
HTTP_POST,
HTTP_DELETE,
HTTP_MOVE, // Caller will need to set 'Destination' header
REQUEST_ACTION_COUNT
};
/**
* @brief Turn the request action into an http verb.
*/
static std::string actionAsVerb(ERequestAction action);
/**
* @brief Constructor.
*
* @param action One of the ERequestAction enumerations.
* @param url The url of the request. It should already be encoded.
*/
LLURLRequest(ERequestAction action, std::string const& url);
/**
* @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE.
*/
void allowCookies(void);
/**
* @ brief Turn off (or on) the CURLOPT_PROXY header.
*/
void useProxy(bool use_proxy);
/**
* @brief Add a header to the http post.
*
* The header must be correctly formatted for HTTP requests. This
* provides a raw interface if you know what kind of request you
* will be making during construction of this instance. All
* required headers will be automatically constructed, so this is
* usually useful for encoding parameters.
*/
void addHeader(char const* header);
private:
/**
* @brief Handle action specific url request configuration.
*
* @return Returns true if this is configured.
*/
bool configure(void);
private:
ERequestAction mAction;
std::string mURL;
};
#if 0
extern const std::string CONTEXT_REQUEST; extern const std::string CONTEXT_REQUEST;
extern const std::string CONTEXT_RESPONSE; extern const std::string CONTEXT_RESPONSE;
extern const std::string CONTEXT_TRANSFERED_BYTES; extern const std::string CONTEXT_TRANSFERED_BYTES;
@@ -65,7 +127,7 @@ typedef struct x509_store_ctx_st X509_STORE_CTX;
* worth the time and effort to eventually port this to a raw client * worth the time and effort to eventually port this to a raw client
* socket. * socket.
*/ */
class LLURLRequest : public LLIOPipe, protected AICurlEasyHandleEvents class LLURLRequest : public LLIOPipe
{ {
LOG_CLASS(LLURLRequest); LOG_CLASS(LLURLRequest);
public: public:
@@ -171,9 +233,6 @@ public:
void setCallback(LLURLRequestComplete* callback); void setCallback(LLURLRequestComplete* callback);
//@} //@}
/* @name LLIOPipe virtual implementations
*/
/** /**
* @ brief Turn off (or on) the CURLOPT_PROXY header. * @ brief Turn off (or on) the CURLOPT_PROXY header.
*/ */
@@ -189,6 +248,9 @@ public:
*/ */
void allowCookies(); void allowCookies();
/* @name LLIOPipe virtual implementations
*/
/*virtual*/ bool hasExpiration(void) const; /*virtual*/ bool hasExpiration(void) const;
/*virtual*/ bool hasNotExpired(void) const; /*virtual*/ bool hasNotExpired(void) const;
@@ -229,13 +291,7 @@ protected:
static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param); static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param);
// mRemoved is used instead of changing mState directly, because I'm not convinced the latter is atomic.
// Set to false before adding curl request and then only tested.
// Reset in removed_from_multi_handle (by another thread), this is thread-safe.
bool mRemoved; bool mRemoved;
/*virtual*/ void added_to_multi_handle(AICurlEasyRequest_wat&);
/*virtual*/ void finished(AICurlEasyRequest_wat&);
/*virtual*/ void removed_from_multi_handle(AICurlEasyRequest_wat&);
private: private:
/** /**
@@ -346,5 +402,6 @@ protected:
// depends on correct useage from the LLURLRequest instance. // depends on correct useage from the LLURLRequest instance.
EStatus mRequestStatus; EStatus mRequestStatus;
}; };
#endif
#endif // LL_LLURLREQUEST_H #endif // LL_LLURLREQUEST_H

View File

@@ -19,7 +19,7 @@
// ******************************************************************** // ********************************************************************
class HippoRestComplete : public LLURLRequestComplete class HippoRestComplete /* AIFIXME: public LLURLRequestComplete*/
{ {
public: public:
HippoRestComplete(HippoRestHandler *handler) : HippoRestComplete(HippoRestHandler *handler) :
@@ -40,6 +40,7 @@ class HippoRestComplete : public LLURLRequestComplete
mHandler->addHeader(header, value); mHandler->addHeader(header, value);
} }
#if 0 // AIFIXME: doesn't compile
// Always called on request completion, prior to complete // Always called on request completion, prior to complete
void httpStatus(U32 status, const std::string& reason) void httpStatus(U32 status, const std::string& reason)
{ {
@@ -52,6 +53,7 @@ class HippoRestComplete : public LLURLRequestComplete
{ {
mHandler->handle(mStatus, mReason, channels, buffer); mHandler->handle(mStatus, mReason, channels, buffer);
} }
#endif
private: private:
HippoRestHandler *mHandler; HippoRestHandler *mHandler;
@@ -265,7 +267,7 @@ static void request(const std::string &url,
llwarns << "Failed to create LLURLRequest: " << error.what() << llendl; llwarns << "Failed to create LLURLRequest: " << error.what() << llendl;
return; return;
} }
req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); //AIFIXME: req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
/* /*
// Insert custom headers if the caller sent any // Insert custom headers if the caller sent any
@@ -300,7 +302,7 @@ static void request(const std::string &url,
req->addHeader(accept.c_str()); req->addHeader(accept.c_str());
} }
req->setCallback(new HippoRestComplete(handler)); //AIFIXME: req->setCallback(new HippoRestComplete(handler));
if ((method == LLURLRequest::HTTP_PUT) || (method == LLURLRequest::HTTP_POST)) { if ((method == LLURLRequest::HTTP_PUT) || (method == LLURLRequest::HTTP_POST)) {
std::string content = "Content-Type: "; std::string content = "Content-Type: ";
@@ -309,7 +311,7 @@ static void request(const std::string &url,
chain.push_back(LLIOPipe::ptr_t(body)); chain.push_back(LLIOPipe::ptr_t(body));
} }
chain.push_back(LLIOPipe::ptr_t(req)); //AIFIXME: chain.push_back(LLIOPipe::ptr_t(req));
LLHTTPClient::getPump().addChain(chain, timeout); LLHTTPClient::getPump().addChain(chain, timeout);
} }

View File

@@ -118,6 +118,7 @@
// <edit> // <edit>
#include "lldelayeduidelete.h" #include "lldelayeduidelete.h"
#include "llbuildnewviewsscheduler.h" #include "llbuildnewviewsscheduler.h"
#include "aicurleasyrequeststatemachine.h"
// </edit> // </edit>
// The files below handle dependencies from cleanup. // The files below handle dependencies from cleanup.
#include "llcalc.h" #include "llcalc.h"
@@ -642,6 +643,9 @@ bool LLAppViewer::init()
mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
AIStateMachine::setMaxCount(gSavedSettings.getU32("StateMachineMaxTime"));
AICurlEasyRequestStateMachine::setCurlRequestTimeOut(gSavedSettings.getF32("CurlRequestTimeOut"));
initThreads(); initThreads();
LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ;

View File

@@ -124,7 +124,8 @@ static bool handleTerrainDetailChanged(const LLSD& newvalue)
bool handleStateMachineMaxTimeChanged(const LLSD& newvalue) bool handleStateMachineMaxTimeChanged(const LLSD& newvalue)
{ {
AIStateMachine::updateSettings(); F32 StateMachineMaxTime = newvalue.asFloat();
AIStateMachine::setMaxCount(StateMachineMaxTime);
return true; return true;
} }