From b9b5f1362437e2f0b1a527175b9884d3cb669c54 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Thu, 7 Mar 2013 01:52:21 +0100 Subject: [PATCH] Run HTTPGetResponder in any thread. This fixes a bug where unref() was called when a state machine was aborted before it reached bs_initialized. Debug code was added to detect errors related to that. In order to run HTTPGetResponder in any thread, I needed direct access to LLHTTPClient::request, so I had to move that to the header file, and therefore had to move ERequestAction from LLURLRequest to LLHTTPClient to avoid include problems. With this, textures are fetched with no latency: call to LLHTTPClient::request runs all the way till the state machine is idle (AICurlEasyRequestStateMachine_waitAdded). There is small delay till the curl thread wakes up, which then processes the request and opens the url etc. When the transaction is finished, it calls AIStateMachine::advance_state(AICurlEasyRequestStateMachine_removed_after_finished) which subsequently doesn't return until the state machine is completely finished (bs_killed). The LLURLRequest isn't deleted yet at that point because the AITimer of the LLURLRequest runs in the main thread: it is aborted, but only the next time the main thread state engines run that is deleted and the timer keeps an LLPointer to it's parent, the LLURLRequest, so only then the LLURLRequest object is destructed. This however has nothing to do with the texture-bandwidth loop. --- indra/aistatemachine/aistatemachine.cpp | 47 +++++++++++++++++++------ indra/aistatemachine/aistatemachine.h | 4 ++- indra/llcommon/llthread.h | 1 + indra/llmessage/aicurl.h | 2 -- indra/llmessage/aicurlprivate.h | 2 ++ indra/llmessage/llhttpclient.cpp | 44 ++++++++++++----------- indra/llmessage/llhttpclient.h | 32 +++++++++++++++++ indra/llmessage/llurlrequest.cpp | 22 ++++++------ indra/llmessage/llurlrequest.h | 15 +------- indra/newview/lltexturefetch.cpp | 23 ++++++------ 10 files changed, 120 insertions(+), 72 deletions(-) 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) {