diff --git a/indra/aistatemachine/aistatemachine.cpp b/indra/aistatemachine/aistatemachine.cpp index 6411c72a6..5d0e952a3 100644 --- a/indra/aistatemachine/aistatemachine.cpp +++ b/indra/aistatemachine/aistatemachine.cpp @@ -360,6 +360,7 @@ char const* AIStateMachine::event_str(event_type event) { switch(event) { + AI_CASE_RETURN(initial_run); AI_CASE_RETURN(schedule_run); AI_CASE_RETURN(normal_run); AI_CASE_RETURN(insert_abort); @@ -371,6 +372,9 @@ char const* AIStateMachine::event_str(event_type event) void AIStateMachine::multiplex(event_type event) { + // If this fails then you are using a pointer to a state machine instead of an LLPointer. + llassert(event == initial_run || getNumRefs() > 0); + DoutEntering(dc::statemachine, "AIStateMachine::multiplex(" << event_str(event) << ") [" << (void*)this << "]"); base_state_type state; @@ -463,6 +467,13 @@ void AIStateMachine::multiplex(event_type event) } // Any previous reason to run is voided by actually running. mDebugShouldRun = false; + // Make sure we only call ref() once and in balance with unref(). + if (state == bs_initialize) + { + // This -- and call to ref() (and the test when we're about to call unref()) -- is all done in the critical area of mMultiplexMutex. + llassert(!mDebugRefCalled); + mDebugRefCalled = true; + } #endif switch(state) @@ -503,6 +514,7 @@ void AIStateMachine::multiplex(event_type event) //================================= // Start of critical area of mState + // Unless the state is bs_multiplex or bs_killed, the state machine needs to keep calling multiplex(). bool need_new_run = true; if (event == normal_run || event == insert_abort) { @@ -518,8 +530,8 @@ void AIStateMachine::multiplex(event_type event) { // We have been aborted before we could even initialize, no de-initialization is possible. state_w->base_state = bs_killed; - // Immediately handle this. - destruct = true; + // Stop running. + need_new_run = false; } else { @@ -537,6 +549,8 @@ void AIStateMachine::multiplex(event_type event) { // Start actually running. state_w->base_state = bs_multiplex; + // If the state is bs_multiplex we only need to run again when need_run was set again in the meantime or when this state machine isn't idle. + need_new_run = sub_state_r->need_run || !sub_state_r->idle; } break; case bs_multiplex: @@ -550,7 +564,12 @@ void AIStateMachine::multiplex(event_type event) // finish() was called. state_w->base_state = bs_finish; } - // else continue in bs_multiplex. + else + { + // Continue in bs_multiplex. + // If the state is bs_multiplex we only need to run again when need_run was set again in the meantime or when this state machine isn't idle. + need_new_run = sub_state_r->need_run || !sub_state_r->idle; + } break; case bs_abort: // After calling abort_impl(), call finish_impl(). @@ -570,18 +589,16 @@ void AIStateMachine::multiplex(event_type event) { // After the call back, we're done. state_w->base_state = bs_killed; - // Immediately handle this. + // Call unref(). destruct = true; + // Stop running. + need_new_run = false; } break; default: // bs_killed // We never get here. break; } - - // Unless the state bs_multiplex or bs_killed, the state machine needs to keep calling multiplex(). - // If the state is bs_multiplex we only need to run again when need_run was set again in the mean time or when this state machine isn't idle. - need_new_run = !destruct && (state_w->base_state != bs_multiplex || sub_state_r->need_run || !sub_state_r->idle); } else // event == insert_abort { @@ -621,7 +638,6 @@ void AIStateMachine::multiplex(event_type event) if (keep_looping) { // Start a new loop. - llassert(AIThreadID::in_main_thread()); // AIFIXME: right now we should be in the main thread or something is wrong. run_state = begin_loop((state = state_w->base_state)); event = normal_run; } @@ -648,6 +664,13 @@ void AIStateMachine::multiplex(event_type event) #ifdef SHOW_ASSERT // Mark that we stop running the loop. mThreadId.clear(); + + if (destruct) + { + // We're about to call unref(). Make sure we call that in balance with ref()! + llassert(mDebugRefCalled); + mDebugRefCalled = false; + } #endif // End of critical area of mMultiplexMutex. @@ -673,7 +696,9 @@ void AIStateMachine::multiplex(event_type event) while (keep_looping); if (destruct) + { unref(); + } } AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state) @@ -723,7 +748,7 @@ void AIStateMachine::run(LLPointer parent, state_type new_parent (parent ? parent->state_str_impl(new_parent_state) : "NA") << ", abort_parent = " << (abort_parent ? "true" : "false") << ", on_abort_signal_parent = " << (on_abort_signal_parent ? "true" : "false") << - ", default_engine = " << default_engine->name() << ") [" << (void*)this << "]"); + ", default_engine = " << (default_engine ? default_engine->name() : "NULL") << ") [" << (void*)this << "]"); #ifdef SHOW_ASSERT { @@ -887,7 +912,7 @@ void AIStateMachine::reset() if (!inside_multiplex) { // Kick start the state machine. - multiplex(schedule_run); + multiplex(initial_run); } } diff --git a/indra/aistatemachine/aistatemachine.h b/indra/aistatemachine/aistatemachine.h index 5e47310f8..91e947478 100644 --- a/indra/aistatemachine/aistatemachine.h +++ b/indra/aistatemachine/aistatemachine.h @@ -107,6 +107,7 @@ class AIStateMachine : public LLThreadSafeRefCount protected: // The type of event that causes multiplex() to be called. enum event_type { + initial_run, schedule_run, normal_run, insert_abort @@ -189,13 +190,14 @@ class AIStateMachine : public LLThreadSafeRefCount bool mDebugContPending; // True while cont() was called by not handled yet. bool mDebugSetStatePending; // True while set_state() was called by not handled yet. bool mDebugAdvanceStatePending; // True while advance_state() was called by not handled yet. + bool mDebugRefCalled; // True when ref() is called (or will be called within the critial area of mMultiplexMutex). #endif public: AIStateMachine(void) : mCallback(NULL), mDefaultEngine(NULL), mYieldEngine(NULL) #ifdef SHOW_ASSERT , mDebugLastState(bs_killed), mDebugShouldRun(false), mDebugAborted(false), mDebugContPending(false), - mDebugSetStatePending(false), mDebugAdvanceStatePending(false) + mDebugSetStatePending(false), mDebugAdvanceStatePending(false), mDebugRefCalled(false) #endif { } diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index f64200c95..1f6765935 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -470,6 +470,7 @@ public: void unref() { + llassert(mRef > 0); if (!--mRef) delete this; } S32 getNumRefs() const diff --git a/indra/llmessage/aicurl.h b/indra/llmessage/aicurl.h index 16d1b14fd..3113e7e18 100644 --- a/indra/llmessage/aicurl.h +++ b/indra/llmessage/aicurl.h @@ -52,8 +52,6 @@ #include "stdtypes.h" // U16, S32, U32, F64 #include "llatomic.h" // LLAtomicU32 #include "aithreadsafe.h" -#include "llhttpstatuscodes.h" -#include "llhttpclient.h" // Debug Settings. extern bool gNoVerifySSLCert; diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index bb39bdddb..453d5e66c 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -36,9 +36,11 @@ #include "llrefcount.h" #include "aicurlperhost.h" #include "aihttptimeout.h" +#include "llhttpclient.h" class AIHTTPHeaders; class AICurlEasyRequestStateMachine; +class AITransferInfo; namespace AICurlPrivate { diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index de0471946..b55180c9e 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -195,18 +195,20 @@ public: LLAssetType::EType mAssetType; }; -static void request( - const std::string& url, +//static +void LLHTTPClient::request( + std::string const& url, LLURLRequest::ERequestAction method, Injector* body_injector, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), - EKeepAlive keepalive = keep_alive, - bool is_auth = false, - bool no_compression = false, - AIStateMachine* parent = NULL, - AIStateMachine::state_type new_parent_state = 0) + EKeepAlive keepalive, + bool is_auth, + bool no_compression, + AIStateMachine* parent, + AIStateMachine::state_type new_parent_state, + AIEngine* default_engine) { llassert(responder); @@ -231,7 +233,7 @@ static void request( return ; } - req->run(parent, new_parent_state, parent != NULL); + req->run(parent, new_parent_state, parent != NULL, true, default_engine); } void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) @@ -240,22 +242,22 @@ void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, R { headers.addHeader("Range", llformat("bytes=%d-%d", offset, offset + bytes - 1)); } - request(url, LLURLRequest::HTTP_GET, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); + request(url, HTTP_GET, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } void LLHTTPClient::head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) { - request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); + request(url, HTTP_HEAD, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } void LLHTTPClient::get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) { - request(url, LLURLRequest::HTTP_GET, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); + request(url, HTTP_GET, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } void LLHTTPClient::getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) { - request(url, LLURLRequest::HTTP_HEAD, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); + request(url, HTTP_HEAD, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } void LLHTTPClient::get(std::string const& url, LLSD const& query, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) @@ -686,17 +688,17 @@ U32 LLHTTPClient::blockingGetRaw(const std::string& url, std::string& body/*,*/ void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) { - request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); + request(url, HTTP_PUT, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive, AIStateMachine* parent, AIStateMachine::state_type new_parent_state) { - request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, false, false, parent, new_parent_state); + request(url, HTTP_POST, new LLSDInjector(body), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, false, false, parent, new_parent_state); } void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive) { - request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, true, false); // Does use compression. + request(url, HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, true, false); // Does use compression. } void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive) @@ -707,33 +709,33 @@ void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC XMLRPC_RequestSetData(xmlrpc_request, value); // XMLRPCInjector takes ownership of xmlrpc_request and will free it when done. // LLURLRequest takes ownership of the XMLRPCInjector object and will free it when done. - request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, true, true); // Does not use compression. + request(url, HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, true, true); // Does not use compression. } void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive) { - request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); + request(url, HTTP_POST, new RawInjector(data, size), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); } void LLHTTPClient::postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive) { - request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); + request(url, HTTP_POST, new FileInjector(filename), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); } void LLHTTPClient::postFile(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive) { - request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); + request(url, HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); } // static void LLHTTPClient::del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) { - request(url, LLURLRequest::HTTP_DELETE, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); + request(url, HTTP_DELETE, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } // static void LLHTTPClient::move(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) { headers.addHeader("Destination", destination); - request(url, LLURLRequest::HTTP_MOVE, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); + request(url, HTTP_MOVE, NULL, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 6142117b0..a7f955c5c 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -46,10 +46,13 @@ class AIHTTPTimeoutPolicy; class LLBufferArray; class LLChannelDescriptors; class AIStateMachine; +class Injector; +class AIEngine; extern AIHTTPTimeoutPolicy responderIgnore_timeout; typedef struct _xmlrpc_request* XMLRPC_REQUEST; typedef struct _xmlrpc_value* XMLRPC_VALUE; +extern AIEngine gMainThreadEngine; // Output parameter of AICurlPrivate::CurlEasyRequest::getResult. // Used in XMLRPCResponder. @@ -84,6 +87,20 @@ enum EDebugCurl { class LLHTTPClient { 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 + }; /** @name Responder base classes */ //@{ @@ -393,6 +410,21 @@ public: //@} + /** General API to request a transfer. */ + static void request( + std::string const& url, + ERequestAction method, + Injector* body_injector, + ResponderPtr responder, + AIHTTPHeaders& headers/*,*/ + DEBUG_CURLIO_PARAM(EDebugCurl debug), + EKeepAlive keepalive = keep_alive, + bool is_auth = false, + bool no_compression = false, + AIStateMachine* parent = NULL, + /*AIStateMachine::state_type*/ U32 new_parent_state = 0, + AIEngine* default_engine = &gMainThreadEngine); + /** @name non-blocking API */ //@{ static void head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)); diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 429a93627..18ea5c835 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -61,7 +61,7 @@ const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes"); // static std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) { - static int const array_size = HTTP_MOVE + 1; // INVALID == 0 + static int const array_size = LLHTTPClient::REQUEST_ACTION_COUNT; // INVALID == 0 static char const* const VERBS[array_size] = { "(invalid)", @@ -72,7 +72,7 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) "DELETE", "MOVE" }; - return VERBS[action >= array_size ? INVALID : action]; + return VERBS[action >= array_size ? LLHTTPClient::INVALID : action]; } // This might throw AICurlNoEasyHandle. @@ -94,13 +94,13 @@ void LLURLRequest::initialize_impl(void) useProxy(false); } - if (mAction == HTTP_PUT || mAction == HTTP_POST) + if (mAction == LLHTTPClient::HTTP_PUT || mAction == LLHTTPClient::HTTP_POST) { // If the Content-Type header was passed in we defer to the caller's wisdom, // but if they did not specify a Content-Type, then ask the injector. mHeaders.addHeader("Content-Type", mBody->contentType(), AIHTTPHeaders::keep_existing_header); } - else if (mAction != HTTP_HEAD) + else if (mAction != LLHTTPClient::HTTP_HEAD) { // Check to see if we have already set Accept or not. If no one // set it, set it to application/llsd+xml since that's what we @@ -108,7 +108,7 @@ void LLURLRequest::initialize_impl(void) mHeaders.addHeader("Accept", "application/llsd+xml", AIHTTPHeaders::keep_existing_header); } - if (mAction == HTTP_POST && gMessageSystem) + if (mAction == LLHTTPClient::HTTP_POST && gMessageSystem) { mHeaders.addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d", gMessageSystem->mPort)); } @@ -200,12 +200,12 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) { switch(mAction) { - case HTTP_HEAD: + case LLHTTPClient::HTTP_HEAD: curlEasyRequest_w->setopt(CURLOPT_NOBODY, 1); rv = true; break; - case HTTP_GET: + case LLHTTPClient::HTTP_GET: curlEasyRequest_w->setopt(CURLOPT_HTTPGET, 1); // Set Accept-Encoding to allow response compression @@ -213,7 +213,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) rv = true; break; - case HTTP_PUT: + case LLHTTPClient::HTTP_PUT: { // Disable the expect http 1.1 extension. POST and PUT default // to using this, causing the broken server to get confused. @@ -223,7 +223,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) rv = true; break; } - case HTTP_POST: + case LLHTTPClient::HTTP_POST: { // Set the handle for an http post curlEasyRequest_w->setPost(mBodySize, mKeepAlive); @@ -233,13 +233,13 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) rv = true; break; } - case HTTP_DELETE: + case LLHTTPClient::HTTP_DELETE: // Set the handle for an http post curlEasyRequest_w->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE"); rv = true; break; - case HTTP_MOVE: + case LLHTTPClient::HTTP_MOVE: // Set the handle for an http post curlEasyRequest_w->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE"); rv = true; diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index 9cdb132bb..aa85242db 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -51,20 +51,7 @@ class Injector 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 - }; + typedef LLHTTPClient::ERequestAction ERequestAction; /** * @brief Turn the request action into an http verb. diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index accd96b42..96b3f6319 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1083,18 +1083,17 @@ bool LLTextureFetchWorker::doWork(S32 param) mRequestedOffset--; } - try - { - // Will call callbackHttpGet when curl request completes - AIHTTPHeaders headers("Accept", "image/x-j2c"); - LLHTTPClient::getByteRange(mUrl, mRequestedOffset, mRequestedSize, - new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, mRequestedOffset, true), headers); - res = true; - } - catch(AICurlNoEasyHandle const& error) - { - llwarns << error.what() << llendl; - } + // Will call callbackHttpGet when curl request completes + AIHTTPHeaders headers("Accept", "image/x-j2c"); + // Call LLHTTPClient::request directly instead of LLHTTPClient::getByteRange, because we want to pass a NULL AIEngine. + if (mRequestedOffset > 0 || mRequestedSize > 0) + { + headers.addHeader("Range", llformat("bytes=%d-%d", mRequestedOffset, mRequestedOffset + mRequestedSize - 1)); + } + LLHTTPClient::request(mUrl, LLHTTPClient::HTTP_GET, NULL, + new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, mRequestedOffset, true), + headers/*,*/ DEBUG_CURLIO_PARAM(false), keep_alive, false, false, NULL, 0, NULL); + res = true; } if (!res) {