diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt
index 81c502b64298086d03db61ebb960b22fb1570352..ae92fb96fde00a66a75df17365773f98bfb6b994 100644
--- a/indra/llcorehttp/CMakeLists.txt
+++ b/indra/llcorehttp/CMakeLists.txt
@@ -30,6 +30,7 @@ set(llcorehttp_SOURCE_FILES
     _httprequestqueue.cpp
     _httpoperation.cpp
     _httpoprequest.cpp
+    _httpopcancel.cpp
     _httpreplyqueue.cpp
     _httppolicy.cpp
     _httplibcurl.cpp
@@ -49,6 +50,7 @@ set(llcorehttp_HEADER_FILES
     httpresponse.h
     _httpoperation.h
     _httpoprequest.h
+    _httpopcancel.h
     _httprequestqueue.h
     _httpreplyqueue.h
     _httpservice.h
diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp
index 15be977adf1529f023898d8a9dccdca6ba80365c..1b951818e413569b47e9a8b7ee57275c09a6bb47 100644
--- a/indra/llcorehttp/_httplibcurl.cpp
+++ b/indra/llcorehttp/_httplibcurl.cpp
@@ -27,7 +27,6 @@
 #include "_httplibcurl.h"
 
 #include "httpheaders.h"
-
 #include "_httpoprequest.h"
 #include "_httpservice.h"
 
@@ -173,8 +172,11 @@ void HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode
 	{
 		int http_status(200);
 
-		curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &status);
-		op->mReplyStatus = http_status;
+		curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_status);
+		op->mStatus = LLCore::HttpStatus(http_status,
+										 (http_status >= 200 && http_status <= 299
+										  ? HE_SUCCESS
+										  : HE_REPLY_ERROR));
 	}
 
 	// Detach from multi and recycle handle
@@ -202,7 +204,8 @@ int HttpLibcurl::activeCount() const
 struct curl_slist * append_headers_to_slist(const HttpHeaders * headers, struct curl_slist * slist)
 {
 	for (HttpHeaders::container_t::const_iterator it(headers->mHeaders.begin());
-		 headers->mHeaders.end() != it;
+
+		headers->mHeaders.end() != it;
 		 ++it)
 	{
 		slist = curl_slist_append(slist, (*it).c_str());
diff --git a/indra/llcorehttp/_httplibcurl.h b/indra/llcorehttp/_httplibcurl.h
index 01c68320afb08417a7348ce969b4090ec5aca0ce..807196628de256e9434567d6ba20d5e0ead18927 100644
--- a/indra/llcorehttp/_httplibcurl.h
+++ b/indra/llcorehttp/_httplibcurl.h
@@ -45,6 +45,7 @@ class HttpOpRequest;
 class HttpHeaders;
 
 
+/// Implements libcurl-based transport for an HttpService instance.
 class HttpLibcurl
 {
 public:
@@ -71,7 +72,7 @@ class HttpLibcurl
 	typedef std::set<HttpOpRequest *> active_set_t;
 	
 protected:
-	HttpService *		mService;
+	HttpService *		mService;				// Simple reference, not owner
 	active_set_t		mActiveOps;
 	CURLM *				mMultiHandles[1];
 };  // end class HttpLibcurl
diff --git a/indra/llcorehttp/_httpopcancel.cpp b/indra/llcorehttp/_httpopcancel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..69dbff4bb4726003dfa6675c6abb65b186c06cc8
--- /dev/null
+++ b/indra/llcorehttp/_httpopcancel.cpp
@@ -0,0 +1,82 @@
+/**
+ * @file _httpopcancel.cpp
+ * @brief Definitions for internal class HttpOpCancel
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "_httpopcancel.h"
+
+#include <cstdio>
+#include <algorithm>
+
+#include "httpcommon.h"
+#include "httphandler.h"
+#include "httpresponse.h"
+
+#include "_httprequestqueue.h"
+#include "_httpreplyqueue.h"
+#include "_httpservice.h"
+#include "_httppolicy.h"
+#include "_httplibcurl.h"
+
+
+namespace LLCore
+{
+
+
+// ==================================
+// HttpOpCancel
+// ==================================
+
+
+HttpOpCancel::HttpOpCancel(HttpHandle handle)
+	: HttpOperation(),
+	  mHandle(handle)
+{}
+
+
+HttpOpCancel::~HttpOpCancel()
+{}
+
+
+void HttpOpCancel::stageFromRequest(HttpService * service)
+{
+	// *FIXME:  Need cancel functionality into services
+	addAsReply();
+}
+
+
+void HttpOpCancel::visitNotifier(HttpRequest * request)
+{
+	if (mLibraryHandler)
+	{
+		HttpResponse * response = new HttpResponse();
+		mLibraryHandler->onCompleted(static_cast<HttpHandle>(this), response);
+		response->release();
+	}
+}
+
+
+}   // end namespace LLCore
+
+		
diff --git a/indra/llcorehttp/_httpopcancel.h b/indra/llcorehttp/_httpopcancel.h
new file mode 100644
index 0000000000000000000000000000000000000000..38ccc585ed474438fc05bc5b4e36d4046554cf67
--- /dev/null
+++ b/indra/llcorehttp/_httpopcancel.h
@@ -0,0 +1,75 @@
+/**
+ * @file _httpopcancel.h
+ * @brief Internal declarations for the HttpOpCancel subclass
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef	_LLCORE_HTTP_OPCANCEL_H_
+#define	_LLCORE_HTTP_OPCANCEL_H_
+
+
+#include "linden_common.h"		// Modifies curl/curl.h interfaces
+
+#include "httpcommon.h"
+
+#include <curl/curl.h>
+
+#include "_httpoperation.h"
+#include "_refcounted.h"
+
+
+namespace LLCore
+{
+
+
+/// HttpOpCancel requests that a previously issued request
+/// be canceled, if possible.  Requests that have been made
+/// active and are available for sending on the wire cannot
+/// be canceled.
+
+class HttpOpCancel : public HttpOperation
+{
+public:
+	HttpOpCancel(HttpHandle handle);
+	virtual ~HttpOpCancel();
+
+private:
+	HttpOpCancel(const HttpOpCancel &);					// Not defined
+	void operator=(const HttpOpCancel &);				// Not defined
+
+public:
+	virtual void stageFromRequest(HttpService *);
+
+	virtual void visitNotifier(HttpRequest * request);
+			
+public:
+	// Request data
+	HttpHandle			mHandle;
+
+};  // end class HttpOpCancel
+
+
+}   // end namespace LLCore
+
+#endif	// _LLCORE_HTTP_OPCANCEL_H_
+
diff --git a/indra/llcorehttp/_httpoperation.h b/indra/llcorehttp/_httpoperation.h
index d04961c47b759d5515dbe63c2ad77da68fa5ba02..5d06a28586ac5c5958fffd8de84f513493345469 100644
--- a/indra/llcorehttp/_httpoperation.h
+++ b/indra/llcorehttp/_httpoperation.h
@@ -87,31 +87,6 @@ class HttpOperation : public LLCoreInt::RefCounted
 };  // end class HttpOperation
 
 
-/// HttpOpCancel requests that a previously issued request
-/// be canceled, if possible.  Requests that have been made
-/// active and are available for sending on the wire cannot
-/// be canceled.
-
-class HttpOpCancel : public HttpOperation
-{
-public:
-	HttpOpCancel();
-	virtual ~HttpOpCancel();
-
-private:
-	HttpOpCancel(const HttpOpCancel &);					// Not defined
-	void operator=(const HttpOpCancel &);				// Not defined
-
-public:
-	virtual void stageFromRequest(HttpService *);
-	virtual void stageFromReady(HttpService *);
-	virtual void stageFromActive(HttpService *);
-
-public:
-	HttpHandle			mHandle;
-};  // end class HttpOpCancel
-
-
 /// HttpOpStop requests the servicing thread to shutdown
 /// operations, cease pulling requests from the request
 /// queue and release shared resources (particularly
diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index 3c9eb71b9a315fc9cc2c1456024636261f96649d..521bd5b8797c0b31cf839bf3bce9211ee14068cb 100644
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -86,53 +86,53 @@ HttpOpRequest::HttpOpRequest()
 	  mReqMethod(HOR_GET),
 	  mReqBody(NULL),
 	  mReqOffset(0),
-	  mReqLen(0),
+	  mReqLength(0),
 	  mReqHeaders(NULL),
 	  mReqOptions(NULL),
 	  mCurlActive(false),
 	  mCurlHandle(NULL),
-	  mCurlHeaders(NULL),
 	  mCurlService(NULL),
-	  mReplyStatus(200),
+	  mCurlHeaders(NULL),
 	  mReplyBody(NULL),
 	  mReplyOffset(0),
-	  mReplyLen(0),
+	  mReplyLength(0),
 	  mReplyHeaders(NULL)
 {}
 
 
 HttpOpRequest::~HttpOpRequest()
 {
-	if (mCurlHandle)
-	{
-		curl_easy_cleanup(mCurlHandle);
-		mCurlHandle = NULL;
-	}
-
-	if (mCurlHeaders)
-	{
-		curl_slist_free_all(mCurlHeaders);
-		mCurlHeaders = NULL;
-	}
-
-	mCurlService = NULL;
-	
 	if (mReqBody)
 	{
 		mReqBody->release();
 		mReqBody = NULL;
 	}
 	
+	if (mReqOptions)
+	{
+		mReqOptions->release();
+		mReqOptions = NULL;
+	}
+
 	if (mReqHeaders)
 	{
-		curl_slist_free_all(mReqHeaders);
+		mReqHeaders->release();
 		mReqHeaders = NULL;
 	}
 
-	if (mReqOptions)
+	if (mCurlHandle)
 	{
-		mReqOptions->release();
-		mReqOptions = NULL;
+		curl_easy_cleanup(mCurlHandle);
+		mCurlHandle = NULL;
+	}
+
+	mCurlService = NULL;
+	
+
+	if (mCurlHeaders)
+	{
+		curl_slist_free_all(mCurlHeaders);
+		mCurlHeaders = NULL;
 	}
 
 	if (mReplyBody)
@@ -165,28 +165,29 @@ void HttpOpRequest::stageFromReady(HttpService * service)
 
 void HttpOpRequest::stageFromActive(HttpService * service)
 {
-	if (mReplyLen)
+	if (mReplyLength)
 	{
 		// If non-zero, we received and processed a Content-Range
 		// header with the response.  Verify that what it says
 		// is consistent with the received data.
-		if (mReplyLen != mReplyBody->size())
+		if (mReplyLength != mReplyBody->size())
 		{
 			// Not as expected, fail the request
 			mStatus = HttpStatus(HttpStatus::LLCORE, HE_INV_CONTENT_RANGE_HDR);
 		}
 	}
 	
-	if (mReqHeaders)
+	if (mCurlHeaders)
 	{
 		// We take these headers out of the request now as they were
 		// allocated originally in this thread and the notifier doesn't
 		// need them.  This eliminates one source of heap moving across
 		// threads.
 
-		curl_slist_free_all(mReqHeaders);
-		mReqHeaders = NULL;
+		curl_slist_free_all(mCurlHeaders);
+		mCurlHeaders = NULL;
 	}
+
 	addAsReply();
 }
 
@@ -196,12 +197,24 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
 	if (mLibraryHandler)
 	{
 		HttpResponse * response = new HttpResponse();
-
-		// *FIXME:  add http status, offset, length
 		response->setStatus(mStatus);
-		response->setReplyStatus(mReplyStatus);
 		response->setBody(mReplyBody);
 		response->setHeaders(mReplyHeaders);
+		unsigned int offset(0), length(0);
+		if (mReplyOffset || mReplyLength)
+		{
+			// Got an explicit offset/length in response
+			offset = mReplyOffset;
+			length = mReplyLength;
+		}
+		else if (mReplyBody)
+		{
+			// Provide implicit offset/length from request/response
+			offset = mReqOffset;
+			length = mReplyBody->size();
+		}
+		response->setRange(offset, length);
+
 		mLibraryHandler->onCompleted(static_cast<HttpHandle>(this), response);
 
 		response->release();
@@ -235,14 +248,15 @@ HttpStatus HttpOpRequest::setupGetByteRange(unsigned int policy_id,
 	mReqMethod = HOR_GET;
 	mReqURL = url;
 	mReqOffset = offset;
-	mReqLen = len;
+	mReqLength = len;
 	if (offset || len)
 	{
 		mProcFlags |= PF_SCAN_RANGE_HEADER;
 	}
 	if (headers && ! mReqHeaders)
 	{
-		mReqHeaders = append_headers_to_slist(headers, mReqHeaders);
+		headers->addRef();
+		mReqHeaders = headers;
 	}
 	if (options && ! mReqOptions)
 	{
@@ -257,7 +271,7 @@ HttpStatus HttpOpRequest::prepareForGet(HttpService * service)
 {
 	// *FIXME:  better error handling later
 	HttpStatus status;
-	
+
 	mCurlHandle = curl_easy_init();
 	curl_easy_setopt(mCurlHandle, CURLOPT_TIMEOUT, 30);
 	curl_easy_setopt(mCurlHandle, CURLOPT_CONNECTTIMEOUT, 30);
@@ -268,14 +282,18 @@ HttpStatus HttpOpRequest::prepareForGet(HttpService * service)
 	curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
 	// curl_easy_setopt(handle, CURLOPT_PROXY, "");
 
-	mCurlHeaders = curl_slist_append(mCurlHeaders, "Pragma:");
 	curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
-	curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders);
 	curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1);
 	curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback);
 	curl_easy_setopt(mCurlHandle, CURLOPT_WRITEDATA, mCurlHandle);
 
-	if (mReqOffset || mReqLen)
+	if (mReqHeaders)
+	{
+		mCurlHeaders = append_headers_to_slist(mReqHeaders, mCurlHeaders);
+	}
+	mCurlHeaders = curl_slist_append(mCurlHeaders, "Pragma:");
+	
+	if (mReqOffset || mReqLength)
 	{
 		static const char * fmt1("Range: bytes=%d-%d");
 		static const char * fmt2("Range: bytes=%d-");
@@ -284,16 +302,17 @@ HttpStatus HttpOpRequest::prepareForGet(HttpService * service)
 
 #if defined(WIN32)
 		_snprintf_s(range_line, sizeof(range_line), sizeof(range_line) - 1,
-					(mReqLen ? fmt1 : fmt2),
-					mReqOffset, mReqOffset + mReqLen - 1);
+					(mReqLength ? fmt1 : fmt2),
+					mReqOffset, mReqOffset + mReqLength - 1);
 #else
 		snprintf(range_line, sizeof(range_line),
-				 (mReqLen ? fmt1 : fmt2),
-				 mReqOffset, mReqOffset + mReqLen - 1);
+				 (mReqLength ? fmt1 : fmt2),
+				 mReqOffset, mReqOffset + mReqLength - 1);
 #endif // defined(WIN32)
 		range_line[sizeof(range_line) - 1] = '\0';
 		mCurlHeaders = curl_slist_append(mCurlHeaders, range_line);
 	}
+	curl_easy_setopt(mCurlHandle, CURLOPT_HTTPHEADER, mCurlHeaders);
 	
 	if (mProcFlags & (PF_SCAN_RANGE_HEADER | PF_SAVE_HEADERS))
 	{
@@ -347,8 +366,9 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
 	if (hdr_size >= status_line_len && ! strncmp(status_line, hdr_data, status_line_len))
 	{
 		// One of possibly several status lines.  Reset what we know and start over
+		// taking results from the last header stanza we receive.
 		op->mReplyOffset = 0;
-		op->mReplyLen = 0;
+		op->mReplyLength = 0;
 		op->mStatus = HttpStatus();
 	}
 	else if (op->mProcFlags & PF_SCAN_RANGE_HEADER)
@@ -371,7 +391,7 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
 			{
 				// Success, record the fragment position
 				op->mReplyOffset = first;
-				op->mReplyLen = last - first + 1;
+				op->mReplyLength = last - first + 1;
 			}
 			else if (-1 == status)
 			{
@@ -390,6 +410,7 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
 	if (op->mProcFlags & PF_SAVE_HEADERS)
 	{
 		// Save headers in response
+		// *FIXME:  Implement this...
 		;
 		
 	}
diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h
index 232ee841d61082ce773f7273228b560ceab68d0e..601937a943e4de12f2ce84b05ab9395bf4cb6c8c 100644
--- a/indra/llcorehttp/_httpoprequest.h
+++ b/indra/llcorehttp/_httpoprequest.h
@@ -103,22 +103,21 @@ class HttpOpRequest : public HttpOperation
 	std::string			mReqURL;
 	BufferArray *		mReqBody;
 	off_t				mReqOffset;
-	size_t				mReqLen;
-	curl_slist *		mReqHeaders;
+	size_t				mReqLength;
+	HttpHeaders *		mReqHeaders;
 	HttpOptions *		mReqOptions;
 
 	// Transport data
 	bool				mCurlActive;
 	CURL *				mCurlHandle;
-	curl_slist *		mCurlHeaders;
 	HttpService *		mCurlService;
+	curl_slist *		mCurlHeaders;
 	
 	// Result data
 	HttpStatus			mStatus;
-	int					mReplyStatus;
 	BufferArray *		mReplyBody;
 	off_t				mReplyOffset;
-	size_t				mReplyLen;
+	size_t				mReplyLength;
 	HttpHeaders *		mReplyHeaders;
 };  // end class HttpOpRequest
 
diff --git a/indra/llcorehttp/_httppolicy.h b/indra/llcorehttp/_httppolicy.h
index 28aea27f38032bcd43c3b528ad1ea82c6ebe64a4..192bc73b31db30dbc4f6738307d3ec2dc287f990 100644
--- a/indra/llcorehttp/_httppolicy.h
+++ b/indra/llcorehttp/_httppolicy.h
@@ -39,6 +39,7 @@ class HttpService;
 class HttpOpRequest;
 
 
+/// Implements class-based queuing policies for an HttpService instance.
 class HttpPolicy
 {
 public:
@@ -58,7 +59,7 @@ class HttpPolicy
 	typedef std::vector<HttpOpRequest *> ready_queue_t;
 	
 protected:
-	HttpService *		mService;				// Naked pointer, not refcounted
+	HttpService *		mService;				// Naked pointer, not refcounted, not owner
 	ready_queue_t		mReadyQueue;
 	
 };  // end class HttpPolicy
diff --git a/indra/llcorehttp/_httpreplyqueue.h b/indra/llcorehttp/_httpreplyqueue.h
index 56dadec87c2f92c146fe128b5fb336022d671910..28cb1d68b7922bac5d973b0413a7846c5494a8cd 100644
--- a/indra/llcorehttp/_httpreplyqueue.h
+++ b/indra/llcorehttp/_httpreplyqueue.h
@@ -58,7 +58,7 @@ class HttpOperation;
 /// will be coded anyway so it shouldn't be too much of a
 /// burden.
 
-class HttpReplyQueue: public LLCoreInt::RefCounted
+class HttpReplyQueue : public LLCoreInt::RefCounted
 {
 public:
 	/// Caller acquires a Refcount on construction
diff --git a/indra/llcorehttp/_httprequestqueue.h b/indra/llcorehttp/_httprequestqueue.h
index 3a9ce0c3c683057e8a25e99480eb5ebe02360a0b..f96bd7520c7cbe6d128ab92aad5a5982649f6231 100644
--- a/indra/llcorehttp/_httprequestqueue.h
+++ b/indra/llcorehttp/_httprequestqueue.h
@@ -46,7 +46,7 @@ class HttpOperation;
 /// requests from all HttpRequest instances into the
 /// singleton HttpService instance.
 
-class HttpRequestQueue: public LLCoreInt::RefCounted
+class HttpRequestQueue : public LLCoreInt::RefCounted
 {
 protected:
 	/// Caller acquires a Refcount on construction
diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h
index c052e35452c936c4293c0c705a57fc0e7e9e9886..ba76e1eeca0c1fec0e00d4ef099bb837370ae5dc 100644
--- a/indra/llcorehttp/_httpservice.h
+++ b/indra/llcorehttp/_httpservice.h
@@ -152,8 +152,8 @@ class HttpService
 	LLCoreInt::HttpThread *		mThread;
 
 	// === working-thread-only data ===
-	HttpPolicy *				mPolicy;
-	HttpLibcurl *				mTransport;
+	HttpPolicy *				mPolicy;		// Simple pointer, has ownership
+	HttpLibcurl *				mTransport;		// Simple pointer, has ownership
 	
 };  // end class HttpService
 
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp
index c37d081150a648cd8ff6084cfa4310f9dc4a8d25..b5872606b8948e18c0f06f410bbcf267a2a9ed0b 100644
--- a/indra/llcorehttp/httpcommon.cpp
+++ b/indra/llcorehttp/httpcommon.cpp
@@ -37,22 +37,82 @@ HttpStatus::type_enum_t EXT_CURL_EASY;
 HttpStatus::type_enum_t EXT_CURL_MULTI;
 HttpStatus::type_enum_t LLCORE;
 
+HttpStatus::operator unsigned long() const
+{
+	static const int shift(sizeof(unsigned long) * 4);
+
+	unsigned long result(((unsigned long) mType) << shift | (unsigned long) (int) mStatus);
+	return result;
+}
+
+
 std::string HttpStatus::toString() const
 {
 	static const char * llcore_errors[] =
 		{
 			"",
+			"HTTP error reply status",
 			"Services shutting down",
 			"Operation canceled",
 			"Invalid Content-Range header encountered"
 		};
 	static const int llcore_errors_count(sizeof(llcore_errors) / sizeof(llcore_errors[0]));
+
+	static const struct
+	{
+		type_enum_t		mCode;
+		char *			mText;
+	}
+	http_errors[] =
+		{
+			// Keep sorted by mCode, we binary search this list.
+			{ 100, "Continue" },
+			{ 101, "Switching Protocols" },
+			{ 200, "OK" },
+			{ 201, "Created" },
+			{ 202, "Accepted" },
+			{ 203, "Non-Authoritative Information" },
+			{ 204, "No Content" },
+			{ 205, "Reset Content" },
+			{ 206, "Partial Content" },
+			{ 300, "Multiple Choices" },
+			{ 301, "Moved Permanently" },
+			{ 302, "Found" },
+			{ 303, "See Other" },
+			{ 304, "Not Modified" },
+			{ 305, "Use Proxy" },
+			{ 307, "Temporary Redirect" },
+			{ 400, "Bad Request" },
+			{ 401, "Unauthorized" },
+			{ 402, "Payment Required" },
+			{ 403, "Forbidden" },
+			{ 404, "Not Found" },
+			{ 405, "Method Not Allowed" },
+			{ 406, "Not Acceptable" },
+			{ 407, "Proxy Authentication Required" },
+			{ 408, "Request Time-out" },
+			{ 409, "Conflict" },
+			{ 410, "Gone" },
+			{ 411, "Length Required" },
+			{ 412, "Precondition Failed" },
+			{ 413, "Request Entity Too Large" },
+			{ 414, "Request-URI Too Large" },
+			{ 415, "Unsupported Media Type" },
+			{ 416, "Requested range not satisfiable" },
+			{ 417, "Expectation Failed" },
+			{ 500, "Internal Server Error" },
+			{ 501, "Not Implemented" },
+			{ 502, "Bad Gateway" },
+			{ 503, "Service Unavailable" },
+			{ 504, "Gateway Time-out" },
+			{ 505, "HTTP Version not supported" }
+		};
+	static const int http_errors_count(sizeof(http_errors) / sizeof(http_errors[0]));
 	
 	if (*this)
 	{
 		return std::string("");
 	}
-
 	switch (mType)
 	{
 	case EXT_CURL_EASY:
@@ -67,7 +127,33 @@ std::string HttpStatus::toString() const
 			return std::string(llcore_errors[mStatus]);
 		}
 		break;
-		
+
+	default:
+		if (isHttpStatus())
+		{
+			int bottom(0), top(http_errors_count);
+			while (true)
+			{
+				int at((bottom + top) / 2);
+				if (mType == http_errors[at].mCode)
+				{
+					return std::string(http_errors[at].mText);
+				}
+				if (at == bottom)
+				{
+					break;
+				}
+				else if (mType < http_errors[at].mCode)
+				{
+					top = at;
+				}
+				else
+				{
+					bottom = at;
+				}
+			}
+		}
+		break;
 	}
 	return std::string("Unknown error");
 }
diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h
index 9de5769d5739ce84a4556731239d2226b9d5ac90..f81be7103eb33632b7f3c61e336a11f99ffb9e1c 100644
--- a/indra/llcorehttp/httpcommon.h
+++ b/indra/llcorehttp/httpcommon.h
@@ -122,23 +122,38 @@ enum HttpError
 	// Successful value compatible with the libcurl codes.
 	HE_SUCCESS = 0,
 
+	// Intended for HTTP reply codes 100-999, indicates that
+	// the reply should be considered an error by the application.
+	HE_REPLY_ERROR = 1,
+	
 	// Service is shutting down and requested operation will
 	// not be queued or performed.
-	HE_SHUTTING_DOWN = 1,
+	HE_SHUTTING_DOWN = 2,
 	
 	// Operation was canceled by request.
-	HE_OP_CANCELED = 2,
+	HE_OP_CANCELED = 3,
 	
 	// Invalid content range header received.
-	HE_INV_CONTENT_RANGE_HDR = 3
+	HE_INV_CONTENT_RANGE_HDR = 4
 	
 }; // end enum HttpError
 
 
-/// HttpStatus encapsulates errors from libcurl (easy, multi) as well as
-/// internal errors.  The encapsulation isn't expected to completely
-/// isolate the caller from libcurl but basic operational tests (success
-/// or failure) are provided.
+/// HttpStatus encapsulates errors from libcurl (easy, multi), HTTP
+/// reply status codes and internal errors as well.  The encapsulation
+/// isn't expected to completely isolate the caller from libcurl but
+/// basic operational tests (success or failure) are provided.
+///
+/// Non-HTTP status are encoded as (type, status) with type being
+/// one of:  EXT_CURL_EASY, EXT_CURL_MULTI or LLCORE and status
+/// being the success/error code from that domain.  HTTP status
+/// is encoded as (status, error_flag).  Status should be in the
+/// range [100, 999] and error_flag is either HE_SUCCESS or
+/// HE_REPLY_ERROR to indicate whether this should be treated as
+/// a successful status or an error.  The application is responsible
+/// for making that determination and a range like [200, 299] isn't
+/// automatically assumed to be definitive.
+
 struct HttpStatus
 {
 	typedef unsigned short type_enum_t;
@@ -192,12 +207,42 @@ struct HttpStatus
 		return 0 != mStatus;
 	}
 
+	/// Equality and inequality tests to bypass bool conversion
+	/// which will do the wrong thing in conditional expressions.
+	bool operator==(const HttpStatus & rhs) const
+	{
+		return mType == rhs.mType && mStatus == rhs.mStatus;
+	}
+
+	bool operator!=(const HttpStatus & rhs) const
+	{
+		return ! operator==(rhs);
+	}
+
+	/// Convert to single numeric representation.  Mainly
+	/// for logging or other informal purposes.  Also
+	/// creates an ambiguous second path to integer conversion
+	/// which tends to find programming errors such as formatting
+	/// the status to a stream (operator<<).
+	operator unsigned long() const;
+	unsigned long toULong() const
+	{
+		return operator unsigned long();
+	}
+	
 	/// Convert status to a string representation.  For
 	/// success, returns an empty string.  For failure
 	/// statuses, a string as appropriate for the source of
 	/// the error code (libcurl easy, libcurl multi, or
 	/// LLCore itself).
 	std::string toString() const;
+
+	/// Returns true if the status value represents an
+	/// HTTP response status (100 - 999).
+	bool isHttpStatus() const
+	{
+		return 	mType >= type_enum_t(100) && mType <= type_enum_t(999);
+	}
 	
 }; // end struct HttpStatus
 
diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp
index 2a87f5231a9b0a2265143ba7a3c676d0e3a997ae..6c62f931ff19fdfc601fdf6346830f66c9858955 100644
--- a/indra/llcorehttp/httprequest.cpp
+++ b/indra/llcorehttp/httprequest.cpp
@@ -31,6 +31,7 @@
 #include "_httpservice.h"
 #include "_httpoperation.h"
 #include "_httpoprequest.h"
+#include "_httpopcancel.h"
 
 
 namespace
@@ -189,6 +190,22 @@ HttpHandle HttpRequest::requestGetByteRange(unsigned int policy_id,
 }
 
 
+HttpHandle HttpRequest::requestCancel(HttpHandle handle, HttpHandler * user_handler)
+{
+	HttpStatus status;
+	HttpHandle ret_handle(LLCORE_HTTP_HANDLE_INVALID);
+
+	HttpOpCancel * op = new HttpOpCancel(handle);
+	op->setHandlers(mReplyQueue, mSelfHandler, user_handler);
+	mRequestQueue->addOp(op);			// transfer refcount as well
+
+	mLastReqStatus = status;
+	ret_handle = static_cast<HttpHandle>(op);
+	
+	return ret_handle;
+}
+
+
 HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler)
 {
 	HttpStatus status;
diff --git a/indra/llcorehttp/httpresponse.cpp b/indra/llcorehttp/httpresponse.cpp
index 9ac8276f050f9c2061ae5d9c836cb6996490c536..3dcdadb33747684ea3d1b7883a026da9d2c4fd65 100644
--- a/indra/llcorehttp/httpresponse.cpp
+++ b/indra/llcorehttp/httpresponse.cpp
@@ -35,7 +35,8 @@ namespace LLCore
 
 HttpResponse::HttpResponse()
 	: LLCoreInt::RefCounted(true),
-	  mReplyStatus(0U),
+	  mReplyOffset(0U),
+	  mReplyLength(0U),
 	  mBufferArray(NULL),
 	  mHeaders(NULL)
 {}
diff --git a/indra/llcorehttp/httpresponse.h b/indra/llcorehttp/httpresponse.h
index a25e22aef6862254be94981e043df9056d56ba68..5cf3a919f41ad36ad7ef16d8e430a1511255c922 100644
--- a/indra/llcorehttp/httpresponse.h
+++ b/indra/llcorehttp/httpresponse.h
@@ -67,8 +67,6 @@ class HttpResponse : public LLCoreInt::RefCounted
 public:
 	/// Returns the final status of the requested operation.
 	///
-	// *FIXME:  Haven't incorporated HTTP status into this yet.
-	// Will do soon.
 	HttpStatus getStatus() const
 		{
 			return mStatus;
@@ -79,19 +77,6 @@ class HttpResponse : public LLCoreInt::RefCounted
 			mStatus = status;
 		}
 
-	/// Fetch the HTTP reply status.  This is only guaranteed to be
-	/// valid if the HttpStatus tests successful and was the result
-	/// of a completed HTTP request.
-	unsigned int getReplyStatus() const
-		{
-			return mReplyStatus;
-		}
-
-	void setReplyStatus(unsigned int status)
-		{
-			mReplyStatus = status;
-		}
-			
 	/// Simple getter for the response body returned as a scatter/gather
 	/// buffer.  If the operation doesn't produce data (such as the Null
 	/// or StopThread operations), this may be NULL.
@@ -122,11 +107,26 @@ class HttpResponse : public LLCoreInt::RefCounted
 
 	/// Behaves like @see setResponse() but for header data.
 	void setHeaders(HttpHeaders * headers);
+
+	/// If a 'Range:' header was used, these methods are involved
+	/// in setting and returning data about the actual response.
+	void getRange(unsigned int * offset, unsigned int * length) const
+		{
+			*offset = mReplyOffset;
+			*length = mReplyLength;
+		}
+
+	void setRange(unsigned int offset, unsigned int length)
+		{
+			mReplyOffset = offset;
+			mReplyLength = length;
+		}
 			
 protected:
 	// Response data here
 	HttpStatus			mStatus;
-	unsigned int		mReplyStatus;
+	unsigned int		mReplyOffset;
+	unsigned int		mReplyLength;
 	BufferArray *		mBufferArray;
 	HttpHeaders *		mHeaders;
 };
diff --git a/indra/llcorehttp/tests/test_httpstatus.hpp b/indra/llcorehttp/tests/test_httpstatus.hpp
index 38bf494dec5a98304e8c522f356321eefd512b97..f7b542d3b5e110b709e3b4c0dcdfd29a5d3e1838 100644
--- a/indra/llcorehttp/tests/test_httpstatus.hpp
+++ b/indra/llcorehttp/tests/test_httpstatus.hpp
@@ -157,6 +157,108 @@ void HttpStatusTestObjectType::test<4>()
 	ensure(! msg.empty());
 }
 
+template <> template <>
+void HttpStatusTestObjectType::test<5>()
+{
+	set_test_name("HttpStatus equality/inequality testing");
+
+	// Make certain equality/inequality tests do not pass
+	// through the bool conversion.  Distinct successful
+	// and error statuses should compare unequal.
+
+	HttpStatus status1(HttpStatus::LLCORE, HE_SUCCESS);
+	HttpStatus status2(HttpStatus::EXT_CURL_EASY, HE_SUCCESS);
+	ensure(status1 != status2);
+
+	status1.mType = HttpStatus::LLCORE;
+	status1.mStatus = HE_REPLY_ERROR;
+	status2.mType = HttpStatus::LLCORE;
+	status2.mStatus= HE_SHUTTING_DOWN;
+	ensure(status1 != status2);
+}
+
+template <> template <>
+void HttpStatusTestObjectType::test<6>()
+{
+	set_test_name("HttpStatus basic HTTP status encoding");
+	
+	HttpStatus status;
+	status.mType = 200;
+	status.mStatus = HE_SUCCESS;
+	std::string msg = status.toString();
+	ensure(msg.empty());
+	ensure(bool(status));
+
+	// Normally a success but application says error
+	status.mStatus = HE_REPLY_ERROR;
+	msg = status.toString();
+	ensure(! msg.empty());
+	ensure(! bool(status));
+	ensure(status.toULong() > 1UL);				// Biggish number, not a bool-to-ulong
+
+	// Same statuses with distinct success/fail are distinct
+	status.mType = 200;
+	status.mStatus = HE_SUCCESS;
+	HttpStatus status2(200, HE_REPLY_ERROR);
+	ensure(status != status2);
+
+	// Normally an error but application says okay
+	status.mType = 406;
+	status.mStatus = HE_SUCCESS;
+	msg = status.toString();
+	ensure(msg.empty());
+	ensure(bool(status));
+
+	// Different statuses but both successful are distinct
+	status.mType = 200;
+	status.mStatus = HE_SUCCESS;
+	status2.mType = 201;
+	status2.mStatus = HE_SUCCESS;
+	ensure(status != status2);
+
+	// Different statuses but both failed are distinct
+	status.mType = 200;
+	status.mStatus = HE_REPLY_ERROR;
+	status2.mType = 201;
+	status2.mStatus = HE_REPLY_ERROR;
+	ensure(status != status2);
+}
+
+template <> template <>
+void HttpStatusTestObjectType::test<7>()
+{
+	set_test_name("HttpStatus HTTP error text strings");
+
+	HttpStatus status(100, HE_REPLY_ERROR);
+	std::string msg(status.toString());
+	ensure(! msg.empty());				// Should be something
+	ensure(msg == "Continue");
+
+	status.mStatus = HE_SUCCESS;
+	msg = status.toString();
+	ensure(msg.empty());				// Success is empty
+
+	status.mType = 199;
+	status.mStatus = HE_REPLY_ERROR;
+	msg = status.toString();
+	ensure(msg == "Unknown error");
+
+	status.mType = 505;					// Last defined string
+	status.mStatus = HE_REPLY_ERROR;
+	msg = status.toString();
+	ensure(msg == "HTTP Version not supported");
+
+	status.mType = 506;					// One beyond
+	status.mStatus = HE_REPLY_ERROR;
+	msg = status.toString();
+	ensure(msg == "Unknown error");
+
+	status.mType = 999;					// Last HTTP status
+	status.mStatus = HE_REPLY_ERROR;
+	msg = status.toString();
+	ensure(msg == "Unknown error");
+}
+
 } // end namespace tut
 
 #endif	// TEST_HTTP_STATUS_H
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 1174d108d2b971b9d43ec40cc20fc3463d8a205c..8e6deb9ccee2fb3c13c35ab3091c8053d0881a45 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -212,6 +212,11 @@
 #include "llmachineid.h"
 #include "llmainlooprepeater.h"
 
+// LLCore::HTTP
+#include "httpcommon.h"
+#include "httprequest.h"
+#include "httphandler.h"
+
 // *FIX: These extern globals should be cleaned up.
 // The globals either represent state/config/resource-storage of either 
 // this app, or another 'component' of the viewer. App globals should be 
@@ -326,6 +331,53 @@ static std::string gLaunchFileOnQuit;
 // Used on Win32 for other apps to identify our window (eg, win_setup)
 const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
 
+namespace
+{
+
+// This class manages the lifecyle of the core http library.
+// Slightly different style than traditional code but reflects
+// the use of handler classes and light-weight interface
+// object instances of the new libraries.  To be used
+// as a singleton and static construction is fine.
+class CoreHttp : public LLCore::HttpHandler
+{
+public:
+	CoreHttp();
+	~CoreHttp();
+	
+	// Initialize the LLCore::HTTP library creating service classes
+	// and starting the servicing thread.  Caller is expected to do
+	// other initializations (SSL mutex, thread hash function) appropriate
+	// for the application.
+	void init();
+
+	// Request that the servicing thread stop servicing requests,
+	// release resource references and stop.
+	void requestStop();
+	
+	// Terminate LLCore::HTTP library services.  Caller is expected
+	// to have made a best-effort to shutdown the servicing thread
+	// by issuing a requestThreadStop() and waiting for completion
+	// notification that the stop has completed.
+	void cleanup();
+
+	// Notification when the stop request is complete.
+	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+private:
+	static const F64			MAX_THREAD_WAIT_TIME;
+	
+private:
+	LLCore::HttpRequest *		mRequest;
+	LLCore::HttpHandle			mStopHandle;
+	F64							mStopRequested;
+	bool						mStopped;
+};
+
+CoreHttp coreHttpLib;
+	
+}  // end anonymous namespace
+
 //-- LLDeferredTaskList ------------------------------------------------------
 
 /**
@@ -720,6 +772,9 @@ bool LLAppViewer::init()
 	LLViewerStatsRecorder::initClass();
 #endif
 
+	// Initialize the non-LLCurl libcurl library
+	coreHttpLib.init();
+	
     // *NOTE:Mani - LLCurl::initClass is not thread safe. 
     // Called before threads are created.
     LLCurl::initClass(gSavedSettings.getF32("CurlRequestTimeOut"), 
@@ -1807,6 +1862,7 @@ bool LLAppViewer::cleanup()
 
 	// Delete workers first
 	// shotdown all worker threads before deleting them in case of co-dependencies
+	coreHttpLib.requestStop();
 	sTextureFetch->shutdown();
 	sTextureCache->shutdown();	
 	sImageDecodeThread->shutdown();
@@ -1890,6 +1946,9 @@ bool LLAppViewer::cleanup()
 	// *NOTE:Mani - The following call is not thread safe. 
 	LLCurl::cleanupClass();
 
+	// Non-LLCurl libcurl library
+	coreHttpLib.cleanup();
+
 	// If we're exiting to launch an URL, do that here so the screen
 	// is at the right resolution before we launch IE.
 	if (!gLaunchFileOnQuit.empty())
@@ -5267,3 +5326,103 @@ void LLAppViewer::metricsSend(bool enable_reporting)
 	gViewerAssetStatsMain->reset();
 }
 
+namespace
+{
+
+const F64 CoreHttp::MAX_THREAD_WAIT_TIME(10.0);
+
+CoreHttp::CoreHttp()
+	: mRequest(NULL),
+	  mStopHandle(LLCORE_HTTP_HANDLE_INVALID),
+	  mStopRequested(0.0),
+	  mStopped(false)
+{}
+
+
+CoreHttp::~CoreHttp()
+{
+	delete mRequest;
+	mRequest = NULL;
+}
+
+
+void CoreHttp::init()
+{
+	LLCore::HttpStatus status = LLCore::HttpRequest::createService();
+	if (! status)
+	{
+		LL_ERRS("Init") << "Failed to initialize HTTP services.  Reason:  "
+						<< status.toString()
+						<< LL_ENDL;
+	}
+
+	status = LLCore::HttpRequest::startThread();
+	if (! status)
+	{
+		LL_ERRS("Init") << "Failed to start HTTP servicing thread.  Reason:  "
+						<< status.toString()
+						<< LL_ENDL;
+	}
+
+	mRequest = new LLCore::HttpRequest;
+}
+
+
+void CoreHttp::requestStop()
+{
+	llassert_always(mRequest);
+
+	mStopHandle = mRequest->requestStopThread(this);
+	if (LLCORE_HTTP_HANDLE_INVALID != mStopHandle)
+	{
+		mStopRequested = LLTimer::getTotalSeconds();
+	}
+}
+
+
+void CoreHttp::cleanup()
+{
+	if (LLCORE_HTTP_HANDLE_INVALID == mStopHandle)
+	{
+		// Should have been started already...
+		requestStop();
+	}
+	
+	if (LLCORE_HTTP_HANDLE_INVALID == mStopHandle)
+	{
+		LL_WARNS("Cleanup") << "Attempting to cleanup HTTP services without thread shutdown"
+							<< LL_ENDL;
+	}
+	else
+	{
+		while (! mStopped && LLTimer::getTotalSeconds() < (mStopRequested + MAX_THREAD_WAIT_TIME))
+		{
+			mRequest->update(200);
+			ms_sleep(50);
+		}
+		if (! mStopped)
+		{
+			LL_WARNS("Cleanup") << "Attempting to cleanup HTTP services with thread shutdown incomplete"
+								<< LL_ENDL;
+		}
+	}
+
+	delete mRequest;
+	mRequest = NULL;
+
+	LLCore::HttpStatus status = LLCore::HttpRequest::destroyService();
+	if (! status)
+	{
+		LL_WARNS("Cleanup") << "Failed to shutdown HTTP services, continuing.  Reason:  "
+							<< status.toString()
+							<< LL_ENDL;
+	}
+}
+
+
+void CoreHttp::onCompleted(LLCore::HttpHandle, LLCore::HttpResponse *)
+{
+	mStopped = true;
+}
+
+}  // end anonymous namespace
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index f18aa8b4e61b05cefaf821af67165f368855ec08..17c68f7c22c65ee8c26cac80f616e8f13a317f57 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -4,7 +4,7 @@
  *
  * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2012, Linden Research, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -33,7 +33,6 @@
 
 #include "lltexturefetch.h"
 
-#include "llcurl.h"
 #include "lldir.h"
 #include "llhttpclient.h"
 #include "llhttpstatuscodes.h"
@@ -53,11 +52,17 @@
 #include "llviewerassetstats.h"
 #include "llworld.h"
 
+#include "httprequest.h"
+#include "httphandler.h"
+#include "httpresponse.h"
+#include "bufferarray.h"
+
+
 //////////////////////////////////////////////////////////////////////////////
-class LLTextureFetchWorker : public LLWorkerClass
+class LLTextureFetchWorker : public LLWorkerClass, public LLCore::HttpHandler
+
 {
 	friend class LLTextureFetch;
-	friend class HTTPGetResponder;
 	
 private:
 	class CacheReadResponder : public LLTextureCache::ReadResponder
@@ -147,15 +152,14 @@ class LLTextureFetchWorker : public LLWorkerClass
 	~LLTextureFetchWorker();
 	// void relese() { --mActiveCount; }
 
-	S32 callbackHttpGet(const LLChannelDescriptors& channels,
-						 const LLIOPipe::buffer_ptr_t& buffer,
-						 bool partial, bool success);
+	S32 callbackHttpGet(LLCore::HttpResponse * response,
+						bool partial, bool success);
 	void callbackCacheRead(bool success, LLImageFormatted* image,
 						   S32 imagesize, BOOL islocal);
 	void callbackCacheWrite(bool success);
 	void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux);
 	
-	void setGetStatus(U32 status, const std::string& reason)
+	void setGetStatus(LLCore::HttpStatus status, const std::string& reason)
 	{
 		LLMutexLock lock(&mWorkMutex);
 
@@ -167,6 +171,9 @@ class LLTextureFetchWorker : public LLWorkerClass
 	bool getCanUseHTTP() const { return mCanUseHTTP; }
 
 	LLTextureFetch & getFetcher() { return *mFetcher; }
+
+	// Inherited from LLCore::HttpHandler
+	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
 	
 protected:
 	LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
@@ -191,9 +198,15 @@ class LLTextureFetchWorker : public LLWorkerClass
 	void lockWorkMutex() { mWorkMutex.lock(); }
 	void unlockWorkMutex() { mWorkMutex.unlock(); }
 
+	void recordTextureStart(bool is_http);
+	void recordTextureDone(bool is_http);
+
 private:
 	enum e_state // mState
 	{
+		// *NOTE:  Do not change the order/value of state variables, some code
+		// depends upon specific ordering/adjacency.
+		
 		// NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack)
 		INVALID = 0,
 		INIT,
@@ -244,9 +257,8 @@ class LLTextureFetchWorker : public LLWorkerClass
 	LLFrameTimer mFetchTimer;
 	LLTextureCache::handle_t mCacheReadHandle;
 	LLTextureCache::handle_t mCacheWriteHandle;
-	U8* mBuffer;
-	S32 mBufferSize;
 	S32 mRequestedSize;
+	S32 mRequestedOffset;
 	S32 mDesiredSize;
 	S32 mFileSize;
 	S32 mCachedSize;	
@@ -263,7 +275,7 @@ class LLTextureFetchWorker : public LLWorkerClass
 	S32 mHTTPFailCount;
 	S32 mRetryAttempt;
 	S32 mActiveCount;
-	U32 mGetStatus;
+	LLCore::HttpStatus mGetStatus;
 	std::string mGetReason;
 	
 	// Work Data
@@ -283,106 +295,17 @@ class LLTextureFetchWorker : public LLWorkerClass
 	U8 mImageCodec;
 
 	LLViewerAssetStats::duration_t mMetricsStartTime;
+
+	LLCore::HttpHandle		mHttpHandle;
+	LLCore::BufferArray	*	mHttpBufferArray;
+	int						mHttpPolicyClass;
+	bool					mHttpActive;
+	unsigned int			mHttpReplySize;
+	unsigned int			mHttpReplyOffset;
 };
 
 //////////////////////////////////////////////////////////////////////////////
 
-class HTTPGetResponder : public LLCurl::Responder
-{
-	LOG_CLASS(HTTPGetResponder);
-public:
-	HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset, bool redir)
-		: mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset), mFollowRedir(redir)
-	{
-	}
-	~HTTPGetResponder()
-	{
-	}
-
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
-	{
-		static LLCachedControl<bool> log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog");
-		static LLCachedControl<bool> log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator");
-		static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
-
-		if (log_to_viewer_log || log_to_sim)
-		{
-			mFetcher->mTextureInfo.setRequestStartTime(mID, mStartTime);
-			U64 timeNow = LLTimer::getTotalTime();
-			mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
-			mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize);
-			mFetcher->mTextureInfo.setRequestOffset(mID, mOffset);
-			mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);
-		}
-
-		lldebugs << "HTTP COMPLETE: " << mID << llendl;
-		LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
-		if (worker)
-		{
-			bool success = false;
-			bool partial = false;
-			if (HTTP_OK <= status &&  status < HTTP_MULTIPLE_CHOICES)
-			{
-				success = true;
-				if (HTTP_PARTIAL_CONTENT == status) // partial information
-				{
-					partial = true;
-				}
-			}
-
-			if (!success)
-			{
-				worker->setGetStatus(status, reason);
-// 				llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
-			}
-			
-			S32 data_size = worker->callbackHttpGet(channels, buffer, partial, success);
-			
-			if(log_texture_traffic && data_size > 0)
-			{
-				LLViewerTexture* tex = LLViewerTextureManager::findTexture(mID) ;
-				if(tex)
-				{
-					gTotalTextureBytesPerBoostLevel[tex->getBoostLevel()] += data_size ;
-				}
-			}
-
-			mFetcher->removeFromHTTPQueue(mID, data_size);
-
-			if (worker->mMetricsStartTime)
-			{
-				LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
-															  true,
-															  LLImageBase::TYPE_AVATAR_BAKE == worker->mType,
-															  LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime);
-				worker->mMetricsStartTime = 0;
-			}
-			LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
-														 true,
-														 LLImageBase::TYPE_AVATAR_BAKE == worker->mType);
-		}
-		else
-		{
-			mFetcher->removeFromHTTPQueue(mID);
- 			llwarns << "Worker not found: " << mID << llendl;
-		}
-	}
-
-	virtual bool followRedir()
-	{
-		return mFollowRedir;
-	}
-	
-private:
-	LLTextureFetch* mFetcher;
-	LLUUID mID;
-	U64 mStartTime;
-	S32 mRequestedSize;
-	U32 mOffset;
-	bool mFollowRedir;
-};
 
 //////////////////////////////////////////////////////////////////////////////
 
@@ -639,6 +562,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 										   S32 discard,			// Desired discard
 										   S32 size)			// Desired size
 	: LLWorkerClass(fetcher, "TextureFetch"),
+	  LLCore::HttpHandler(),
 	  mState(INIT),
 	  mWriteToCacheState(NOT_WRITE),
 	  mFetcher(fetcher),
@@ -655,9 +579,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 	  mDecodedDiscard(-1),
 	  mCacheReadHandle(LLTextureCache::nullHandle()),
 	  mCacheWriteHandle(LLTextureCache::nullHandle()),
-	  mBuffer(NULL),
-	  mBufferSize(0),
 	  mRequestedSize(0),
+	  mRequestedOffset(0),
 	  mDesiredSize(TEXTURE_CACHE_ENTRY_SIZE),
 	  mFileSize(0),
 	  mCachedSize(0),
@@ -673,13 +596,18 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 	  mHTTPFailCount(0),
 	  mRetryAttempt(0),
 	  mActiveCount(0),
-	  mGetStatus(0),
 	  mWorkMutex(NULL),
 	  mFirstPacket(0),
 	  mLastPacket(-1),
 	  mTotalPackets(0),
 	  mImageCodec(IMG_CODEC_INVALID),
-	  mMetricsStartTime(0)
+	  mMetricsStartTime(0),
+	  mHttpHandle(LLCORE_HTTP_HANDLE_INVALID),
+	  mHttpBufferArray(NULL),
+	  mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+	  mHttpActive(false),
+	  mHttpReplySize(0U),
+	  mHttpReplyOffset(0U)
 {
 	mCanUseNET = mUrl.empty() ;
 
@@ -701,6 +629,11 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
 // 			<< " Requested=" << mRequestedDiscard
 // 			<< " Desired=" << mDesiredDiscard << llendl;
 	llassert_always(!haveWork());
+	if (mHttpActive)
+	{
+		LL_WARNS("Texture") << "Deleting worker object while HTTP request is active."
+							<< LL_ENDL;
+	}
 	lockWorkMutex();
 	if (mCacheReadHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache)
 	{
@@ -714,6 +647,11 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
 	clearPackets();
 	unlockWorkMutex();
 	mFetcher->removeFromHTTPQueue(mID);
+	if (mHttpBufferArray)
+	{
+		mHttpBufferArray->release();
+		mHttpBufferArray = NULL;
+	}
 }
 
 void LLTextureFetchWorker::clearPackets()
@@ -797,7 +735,7 @@ void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size)
 	if ((prioritize && mState == INIT) || mState == DONE)
 	{
 		mState = INIT;
-		U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
+		U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_LOW;
 		setPriority(work_priority);
 	}
 }
@@ -810,16 +748,18 @@ void LLTextureFetchWorker::setImagePriority(F32 priority)
 	{
 		mImagePriority = priority;
 		calcWorkPriority();
-		U32 work_priority = mWorkPriority | (getPriority() & LLWorkerThread::PRIORITY_HIGHBITS);
+		U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_LOW;
 		setPriority(work_priority);
 	}
 }
 
 void LLTextureFetchWorker::resetFormattedData()
 {
-	FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);
-	mBuffer = NULL;
-	mBufferSize = 0;
+	if (mHttpBufferArray)
+	{
+		mHttpBufferArray->release();
+		mHttpBufferArray = NULL;
+	}
 	if (mFormattedImage.notNull())
 	{
 		mFormattedImage->deleteData();
@@ -875,6 +815,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		mFetchTimer.reset();
 	}
 
+	static LLUUID last_id;
+	if (mID != last_id)
+	{
+		// LL_WARNS("Texture") << "DOWORK SWITCH: " << last_id << " to: " << mID
+		// << LL_ENDL;
+		last_id = mID;
+	}
+	
 	if (mState == INIT)
 	{		
 		mRawImage = NULL ;
@@ -882,15 +830,18 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		mLoadedDiscard = -1;
 		mDecodedDiscard = -1;
 		mRequestedSize = 0;
+		mRequestedOffset = 0;
 		mFileSize = 0;
 		mCachedSize = 0;
 		mLoaded = FALSE;
 		mSentRequest = UNSENT;
 		mDecoded  = FALSE;
 		mWritten  = FALSE;
-		FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);
-		mBuffer = NULL;
-		mBufferSize = 0;
+		if (mHttpBufferArray)
+		{
+			mHttpBufferArray->release();
+			mHttpBufferArray = NULL;
+		}
 		mHaveAllData = FALSE;
 		clearPackets(); // TODO: Shouldn't be necessary
 		mCacheReadHandle = LLTextureCache::nullHandle();
@@ -904,6 +855,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 
 	if (mState == LOAD_FROM_TEXTURE_CACHE)
 	{
+		setPriority(0); // Set priority first since Responder may change it
 		if (mCacheReadHandle == LLTextureCache::nullHandle())
 		{
 			U32 cache_priority = mWorkPriority;
@@ -919,8 +871,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			
 			if (mUrl.compare(0, 7, "file://") == 0)
 			{
-				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
-
 				// read file from local disk
 				std::string filename = mUrl.substr(7, std::string::npos);
 				CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
@@ -929,8 +879,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			}
 			else if (mUrl.empty())
 			{
-				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
-
 				CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
 				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
 																		  offset, size, responder);
@@ -942,12 +890,12 @@ bool LLTextureFetchWorker::doWork(S32 param)
 					// *TODO:?remove this warning
 					llwarns << "Unknown URL Type: " << mUrl << llendl;
 				}
-				setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+				setPriority(LLWorkerThread::PRIORITY_HIGH);
 				mState = SEND_HTTP_REQ;
 			}
 			else
 			{
-				setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+				setPriority(LLWorkerThread::PRIORITY_HIGH);
 				mState = LOAD_FROM_NETWORK;
 			}
 		}
@@ -959,6 +907,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			{
 				mCacheReadHandle = LLTextureCache::nullHandle();
 				mState = CACHE_POST;
+				setPriority(LLWorkerThread::PRIORITY_HIGH);
 				// fall through
 			}
 			else
@@ -982,6 +931,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			llassert_always(mFormattedImage->getDataSize() > 0);
 			mLoadedDiscard = mDesiredDiscard;
 			mState = DECODE_IMAGE;
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
 			mWriteToCacheState = NOT_WRITE ;
 			LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize()
 								 << " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight())
@@ -999,6 +949,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			else
 			{
 				LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL;
+				setPriority(LLWorkerThread::PRIORITY_HIGH);
 				mState = LOAD_FROM_NETWORK;
 			}
 			// fall through
@@ -1009,6 +960,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 	{
 		static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP");
 
+		setPriority(0);
 // 		if (mHost != LLHost::invalid) get_url = false;
 		if ( use_http && mCanUseHTTP && mUrl.empty())//get http url.
 		{
@@ -1040,8 +992,8 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		}
 		if (mCanUseHTTP && !mUrl.empty())
 		{
-			mState = LLTextureFetchWorker::SEND_HTTP_REQ;
-			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+			mState = SEND_HTTP_REQ;
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
 			if(mWriteToCacheState != NOT_WRITE)
 			{
 				mWriteToCacheState = CAN_WRITE ;
@@ -1057,14 +1009,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			mRequestedDiscard = mDesiredDiscard;
 			mSentRequest = QUEUED;
 			mFetcher->addToNetworkQueue(this);
-			if (! mMetricsStartTime)
-			{
-				mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
-			}
-			LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
-														 false,
-														 LLImageBase::TYPE_AVATAR_BAKE == mType);
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			recordTextureStart(false);
 			
 			return false;
 		}
@@ -1074,12 +1019,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			//llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end());
 			// Make certain this is in the network queue
 			//mFetcher->addToNetworkQueue(this);
-			//if (! mMetricsStartTime)
-			//{
-			//   mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
-			//}
-			//LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false,
-			//                                             LLImageBase::TYPE_AVATAR_BAKE == mType);
+			//recordTextureStart(false);
 			//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
 			return false;
 		}
@@ -1087,6 +1027,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 	
 	if (mState == LOAD_FROM_SIMULATOR)
 	{
+		setPriority(0);
 		if (mFormattedImage.isNull())
 		{
 			mFormattedImage = new LLImageJ2C;
@@ -1101,39 +1042,22 @@ bool LLTextureFetchWorker::doWork(S32 param)
 // 				llwarns << "processSimulatorPackets() failed to load buffer" << llendl;
 				return true; // failed
 			}
-			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
 			mState = DECODE_IMAGE;
 			mWriteToCacheState = SHOULD_WRITE;
-
-			if (mMetricsStartTime)
-			{
-				LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
-															  false,
-															  LLImageBase::TYPE_AVATAR_BAKE == mType,
-															  LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime);
-				mMetricsStartTime = 0;
-			}
-			LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
-														 false,
-														 LLImageBase::TYPE_AVATAR_BAKE == mType);
+			recordTextureDone(false);
 		}
 		else
 		{
 			mFetcher->addToNetworkQueue(this); // failsafe
-			if (! mMetricsStartTime)
-			{
-				mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
-			}
-			LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
-														 false,
-														 LLImageBase::TYPE_AVATAR_BAKE == mType);
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			recordTextureStart(false);
 		}
 		return false;
 	}
 	
 	if (mState == SEND_HTTP_REQ)
 	{
+		setPriority(0);
 		if(mCanUseHTTP)
 		{
 			//NOTE:
@@ -1159,6 +1083,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 					{
 						// We already have all the data, just decode it
 						mLoadedDiscard = mFormattedImage->getDiscardLevel();
+						setPriority(LLWorkerThread::PRIORITY_HIGH);
 						mState = DECODE_IMAGE;
 						return false;
 					}
@@ -1171,44 +1096,48 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			mRequestedSize = mDesiredSize;
 			mRequestedDiscard = mDesiredDiscard;
 			mRequestedSize -= cur_size;
-			S32 offset = cur_size;
-			mBufferSize = cur_size; // This will get modified by callbackHttpGet()
+			mRequestedOffset = cur_size;
 			
-			bool res = false;
+			mHttpHandle = LLCORE_HTTP_HANDLE_INVALID;
 			if (!mUrl.empty())
 			{
 				mLoaded = FALSE;
-				mGetStatus = 0;
+				mGetStatus = LLCore::HttpStatus();
 				mGetReason.clear();
-				LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << offset
+				LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << mRequestedOffset
 									 << " Bytes: " << mRequestedSize
 									 << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << mFetcher->mMaxBandwidth
 									 << LL_ENDL;
-				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-				mState = WAIT_HTTP_REQ;	
-
-				mFetcher->addToHTTPQueue(mID);
-				if (! mMetricsStartTime)
-				{
-					mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
-				}
-				LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
-															 true,
-															 LLImageBase::TYPE_AVATAR_BAKE == mType);
+// 				LL_WARNS("Texture") << "HTTP GET: " << mID << " Offset: " << mRequestedOffset
+// 									<< " Bytes: " << mRequestedSize
+// 									<< " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << mFetcher->mMaxBandwidth
+// 									<< LL_ENDL;
 
 				// Will call callbackHttpGet when curl request completes
-				std::vector<std::string> headers;
-				headers.push_back("Accept: image/x-j2c");
-				res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize,
-															  new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset, true));
+				// *FIXME:  enable redirection follow
+				mHttpHandle = mFetcher->mHttpRequest->requestGetByteRange(mHttpPolicyClass,
+																		  mRequestedPriority,
+																		  mUrl,
+																		  mRequestedOffset,
+																		  mRequestedSize,
+																		  mFetcher->mHttpOptions,
+																		  mFetcher->mHttpHeaders,
+																		  this);
 			}
-			if (!res)
+			if (LLCORE_HTTP_HANDLE_INVALID == mHttpHandle)
 			{
 				llwarns << "HTTP GET request failed for " << mID << llendl;
 				resetFormattedData();
 				++mHTTPFailCount;
 				return true; // failed
 			}
+
+			mHttpActive = true;
+			mFetcher->addToHTTPQueue(mID);
+			recordTextureStart(true);
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
+			mState = WAIT_HTTP_REQ;	
+
 			// fall through
 		}
 		else //can not use http fetch.
@@ -1219,27 +1148,28 @@ bool LLTextureFetchWorker::doWork(S32 param)
 	
 	if (mState == WAIT_HTTP_REQ)
 	{
+		setPriority(0);
 		if (mLoaded)
 		{
 			S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
 			if (mRequestedSize < 0)
 			{
 				S32 max_attempts;
-				if (mGetStatus == HTTP_NOT_FOUND)
+				if (mGetStatus == LLCore::HttpStatus(HTTP_NOT_FOUND, LLCore::HE_REPLY_ERROR))
 				{
 					mHTTPFailCount = max_attempts = 1; // Don't retry
 					llwarns << "Texture missing from server (404): " << mUrl << llendl;
 
 					//roll back to try UDP
-					if(mCanUseNET)
+					if (mCanUseNET)
 					{
-						mState = INIT ;
-						mCanUseHTTP = false ;
-						setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-						return false ;
+						mState = INIT;
+						mCanUseHTTP = false;
+						setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+						return false;
 					}
 				}
-				else if (mGetStatus == HTTP_SERVICE_UNAVAILABLE)
+				else if (mGetStatus == LLCore::HttpStatus(HTTP_SERVICE_UNAVAILABLE, LLCore::HE_REPLY_ERROR))
 				{
 					// *TODO: Should probably introduce a timer here to delay future HTTP requsts
 					// for a short time (~1s) to ease server load? Ideally the server would queue
@@ -1254,7 +1184,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 					max_attempts = HTTP_MAX_RETRY_COUNT + 1;
 					++mHTTPFailCount;
 					llinfos << "HTTP GET failed for: " << mUrl
-							<< " Status: " << mGetStatus << " Reason: '" << mGetReason << "'"
+							<< " Status: " << mGetStatus.toULong() << " Reason: '" << mGetReason << "'"
 							<< " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl;
 				}
 
@@ -1264,12 +1194,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
 					{
 						// Use available data
 						mLoadedDiscard = mFormattedImage->getDiscardLevel();
+						setPriority(LLWorkerThread::PRIORITY_HIGH);
 						mState = DECODE_IMAGE;
 						return false; 
 					}
 					else
 					{
 						resetFormattedData();
+						setPriority(LLWorkerThread::PRIORITY_HIGH);
 						mState = DONE;
 						return true; // failed
 					}
@@ -1281,17 +1213,25 @@ bool LLTextureFetchWorker::doWork(S32 param)
 				}
 			}
 			
-			llassert_always(mBufferSize == cur_size + mRequestedSize);
-			if(!mBufferSize)//no data received.
+			if (! mHttpBufferArray || ! mHttpBufferArray->size())
 			{
-				FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); 
-				mBuffer = NULL;
+				// no data received.
+				if (mHttpBufferArray)
+				{
+					mHttpBufferArray->release();
+					mHttpBufferArray = NULL;
+				}
 
-				//abort.
+				// abort.
+				setPriority(LLWorkerThread::PRIORITY_HIGH);
 				mState = DONE;
 				return true;
 			}
 
+			const S32 append_size(mHttpBufferArray->size());
+			const S32 total_size(cur_size + append_size);
+			llassert_always(append_size == mRequestedSize);
+			
 			if (mFormattedImage.isNull())
 			{
 				// For now, create formatted image based on extension
@@ -1305,49 +1245,52 @@ bool LLTextureFetchWorker::doWork(S32 param)
 						
 			if (mHaveAllData && mRequestedDiscard == 0) //the image file is fully loaded.
 			{
-				mFileSize = mBufferSize;
+				mFileSize = total_size;
 			}
 			else //the file size is unknown.
 			{
-				mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded.
+				mFileSize = total_size + 1 ; //flag the file is not fully loaded.
 			}
 			
-			U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mBufferSize);
+			U8 * buffer = (U8 *) ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_size);
 			if (cur_size > 0)
 			{
 				memcpy(buffer, mFormattedImage->getData(), cur_size);
 			}
-			memcpy(buffer + cur_size, mBuffer, mRequestedSize); // append
+			mHttpBufferArray->seek(0);
+			mHttpBufferArray->read((char *) buffer + cur_size, append_size);
+
 			// NOTE: setData releases current data and owns new data (buffer)
-			mFormattedImage->setData(buffer, mBufferSize);
-			// delete temp data
-			FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); // Note: not 'buffer' (assigned in setData())
-			mBuffer = NULL;
-			mBufferSize = 0;
+			mFormattedImage->setData(buffer, total_size);
+
+			// Done with buffer array
+			mHttpBufferArray->release();
+			mHttpBufferArray = NULL;
+			
 			mLoadedDiscard = mRequestedDiscard;
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
 			mState = DECODE_IMAGE;
-			if(mWriteToCacheState != NOT_WRITE)
+			if (mWriteToCacheState != NOT_WRITE)
 			{
 				mWriteToCacheState = SHOULD_WRITE ;
 			}
-			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
 			return false;
 		}
 		else
 		{
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
 			return false;
 		}
 	}
 	
 	if (mState == DECODE_IMAGE)
 	{
+		setPriority(0);
 		static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled");
-		if(textures_decode_disabled)
+		if (textures_decode_disabled)
 		{
 			// for debug use, don't decode
 			mState = DONE;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
 			return true;
 		}
 
@@ -1355,7 +1298,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		{
 			// We aborted, don't decode
 			mState = DONE;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
 			return true;
 		}
 		
@@ -1365,7 +1308,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			
 			//abort, don't decode
 			mState = DONE;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
 			return true;
 		}
 		if (mLoadedDiscard < 0)
@@ -1374,10 +1317,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
 
 			//abort, don't decode
 			mState = DONE;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
 			return true;
 		}
-		setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
+
 		mRawImage = NULL;
 		mAuxImage = NULL;
 		llassert_always(mFormattedImage.notNull());
@@ -1394,6 +1337,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 	
 	if (mState == DECODE_IMAGE_UPDATE)
 	{
+		setPriority(0);
 		if (mDecoded)
 		{
 			if (mDecodedDiscard < 0)
@@ -1406,13 +1350,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
 					llassert_always(mDecodeHandle == 0);
 					mFormattedImage = NULL;
 					++mRetryAttempt;
-					setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+					setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
 					mState = INIT;
 					return false;
 				}
 				else
 				{
 // 					llwarns << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << llendl;
+					setPriority(LLWorkerThread::PRIORITY_HIGH);
 					mState = DONE; // failed
 				}
 			}
@@ -1421,7 +1366,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 				llassert_always(mRawImage.notNull());
 				LL_DEBUGS("Texture") << mID << ": Decoded. Discard: " << mDecodedDiscard
 						<< " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL;
-				setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+				setPriority(LLWorkerThread::PRIORITY_HIGH);
 				mState = WRITE_TO_CACHE;
 			}
 			// fall through
@@ -1434,10 +1379,12 @@ bool LLTextureFetchWorker::doWork(S32 param)
 
 	if (mState == WRITE_TO_CACHE)
 	{
+		setPriority(0);
 		if (mWriteToCacheState != SHOULD_WRITE || mFormattedImage.isNull())
 		{
 			// If we're in a local cache or we didn't actually receive any new data,
 			// or we failed to load anything, skip
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
 			mState = DONE;
 			return false;
 		}
@@ -1457,6 +1404,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
 		U32 cache_priority = mWorkPriority;
 		mWritten = FALSE;
+		setPriority(LLWorkerThread::PRIORITY_HIGH);
 		mState = WAIT_ON_WRITE;
 		CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID);
 		mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority,
@@ -1467,8 +1415,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
 	
 	if (mState == WAIT_ON_WRITE)
 	{
+		setPriority(0);
 		if (writeToCacheComplete())
 		{
+			setPriority(LLWorkerThread::PRIORITY_HIGH);
 			mState = DONE;
 			// fall through
 		}
@@ -1487,16 +1437,15 @@ bool LLTextureFetchWorker::doWork(S32 param)
 
 	if (mState == DONE)
 	{
+		setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
 		if (mDecodedDiscard >= 0 && mDesiredDiscard < mDecodedDiscard)
 		{
 			// More data was requested, return to INIT
 			mState = INIT;
-			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
 			return false;
 		}
 		else
 		{
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
 			return true;
 		}
 	}
@@ -1504,6 +1453,71 @@ bool LLTextureFetchWorker::doWork(S32 param)
 	return false;
 }
 
+// virtual
+void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
+{
+	static LLCachedControl<bool> log_to_viewer_log(gSavedSettings, "LogTextureDownloadsToViewerLog");
+	static LLCachedControl<bool> log_to_sim(gSavedSettings, "LogTextureDownloadsToSimulator");
+	static LLCachedControl<bool> log_texture_traffic(gSavedSettings, "LogTextureNetworkTraffic") ;
+
+	mHttpActive = false;
+	
+	if (log_to_viewer_log || log_to_sim)
+	{
+		U64 timeNow = LLTimer::getTotalTime();
+		mFetcher->mTextureInfo.setRequestStartTime(mID, mMetricsStartTime);
+		mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+		mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize);
+		mFetcher->mTextureInfo.setRequestOffset(mID, mRequestedOffset);
+		mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);
+	}
+
+	bool success = true;
+	bool partial = false;
+	LLCore::HttpStatus status(response->getStatus());
+	
+	lldebugs << "HTTP COMPLETE: " << mID
+			 << " status: " << status.toULong() << " '" << status.toString() << "'"
+			 << llendl;
+	unsigned int offset(0), length(0);
+	response->getRange(&offset, &length);
+// 	llwarns << "HTTP COMPLETE: " << mID << " handle: " << handle
+// 			<< " status: " << status.toULong() << " '" << status.toString() << "'"
+// 			<< " req offset: " << mRequestedOffset << " req length: " << mRequestedSize
+// 			<< " offset: " << offset << " length: " << length
+// 			<< llendl;
+
+	if (! status)
+	{
+		success = false;
+		std::string reason(status.toString());
+		setGetStatus(status, reason);
+ 		llwarns << "CURL GET FAILED, status:" << status.toULong() << " reason:" << reason << llendl;
+	}
+	else
+	{
+		static const LLCore::HttpStatus par_status(LLCore::HttpStatus(HTTP_PARTIAL_CONTENT, LLCore::HE_SUCCESS));
+
+		partial = (par_status == status);
+	}
+	
+	S32 data_size = callbackHttpGet(response, partial, success);
+			
+	if (log_texture_traffic && data_size > 0)
+	{
+		LLViewerTexture* tex = LLViewerTextureManager::findTexture(mID);
+		if (tex)
+		{
+			gTotalTextureBytesPerBoostLevel[tex->getBoostLevel()] += data_size ;
+		}
+	}
+
+	mFetcher->removeFromHTTPQueue(mID);
+	
+	recordTextureDone(true);
+}
+
+
 // Called from MAIN thread
 void LLTextureFetchWorker::endWork(S32 param, bool aborted)
 {
@@ -1537,6 +1551,14 @@ void LLTextureFetchWorker::finishWork(S32 param, bool completed)
 bool LLTextureFetchWorker::deleteOK()
 {
 	bool delete_ok = true;
+
+	if (mHttpActive)
+	{
+		// HTTP library has a pointer to this worker
+		// and will dereference it to do notification.
+		delete_ok = false;
+	}
+	
 	// Allow any pending reads or writes to complete
 	if (mCacheReadHandle != LLTextureCache::nullHandle())
 	{
@@ -1642,9 +1664,8 @@ bool LLTextureFetchWorker::processSimulatorPackets()
 
 //////////////////////////////////////////////////////////////////////////////
 
-S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
-										   const LLIOPipe::buffer_ptr_t& buffer,
-										   bool partial, bool success)
+S32 LLTextureFetchWorker::callbackHttpGet(LLCore::HttpResponse * response,
+										  bool partial, bool success)
 {
 	S32 data_size = 0 ;
 
@@ -1664,15 +1685,22 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
 	if (success)
 	{
 		// get length of stream:
-		data_size = buffer->countAfter(channels.in(), NULL);		
-	
+		LLCore::BufferArray * body(response->getBody());
+		data_size = body ? body->size() : 0;
+
 		LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL;
 		if (data_size > 0)
 		{
 			// *TODO: set the formatted image data here directly to avoid the copy
-			mBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), data_size);
-			buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
-			mBufferSize += data_size;
+			// *FIXME:  deal with actual offset and actual datasize, don't assume
+			// server gave exactly what was asked for.
+			
+			llassert_always(NULL == mHttpBufferArray);
+
+			// Hold on to body for later copy
+			body->addRef();
+			mHttpBufferArray = body;
+
 			if (data_size < mRequestedSize && mRequestedDiscard == 0)
 			{
 				mHaveAllData = TRUE;
@@ -1684,7 +1712,6 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
 				mHaveAllData = TRUE;
 				llassert_always(mDecodeHandle == 0);
 				mFormattedImage = NULL; // discard any previous data we had
-				mBufferSize = data_size;
 			}
 		}
 		else
@@ -1700,7 +1727,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
 		mRequestedSize = -1; // error
 	}
 	mLoaded = TRUE;
-	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+	setPriority(LLWorkerThread::PRIORITY_HIGH);
 
 	return data_size ;
 }
@@ -1729,7 +1756,7 @@ void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* ima
 		}
 	}
 	mLoaded = TRUE;
-	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+	setPriority(LLWorkerThread::PRIORITY_HIGH);
 }
 
 void LLTextureFetchWorker::callbackCacheWrite(bool success)
@@ -1741,7 +1768,7 @@ void LLTextureFetchWorker::callbackCacheWrite(bool success)
 		return;
 	}
 	mWritten = TRUE;
-	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+	setPriority(LLWorkerThread::PRIORITY_HIGH);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1779,7 +1806,7 @@ void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImag
 	}
 	mDecoded = TRUE;
 // 	llinfos << mID << " : DECODE COMPLETE " << llendl;
-	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+	setPriority(LLWorkerThread::PRIORITY_HIGH);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1806,6 +1833,34 @@ bool LLTextureFetchWorker::writeToCacheComplete()
 }
 
 
+void LLTextureFetchWorker::recordTextureStart(bool is_http)
+{
+	if (! mMetricsStartTime)
+	{
+		mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+	}
+	LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
+												 is_http,
+												 LLImageBase::TYPE_AVATAR_BAKE == mType);
+}
+
+
+void LLTextureFetchWorker::recordTextureDone(bool is_http)
+{
+	if (mMetricsStartTime)
+	{
+		LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
+													  is_http,
+													  LLImageBase::TYPE_AVATAR_BAKE == mType,
+													  LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime);
+		mMetricsStartTime = 0;
+	}
+	LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
+												 is_http,
+												 LLImageBase::TYPE_AVATAR_BAKE == mType);
+}
+
+
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 // public
@@ -1823,17 +1878,26 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 	  mTextureBandwidth(0),
 	  mHTTPTextureBits(0),
 	  mTotalHTTPRequests(0),
-	  mCurlGetRequest(NULL),
-	  mQAMode(qa_mode)
+	  mQAMode(qa_mode),
+	  mHttpRequest(NULL),
+	  mHttpOptions(NULL),
+	  mHttpHeaders(NULL)
 {
 	mCurlPOSTRequestCount = 0;
 	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
 	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
+	
+	mHttpRequest = new LLCore::HttpRequest;
+	mHttpOptions = new LLCore::HttpOptions;
+	mHttpHeaders = new LLCore::HttpHeaders;
+	mHttpHeaders->mHeaders.push_back("Accept: image/x-j2c");
 }
 
 LLTextureFetch::~LLTextureFetch()
 {
-	clearDeleteList() ;
+	cancelHttpRequests();
+	
+	clearDeleteList();
 
 	while (! mCommands.empty())
 	{
@@ -1841,7 +1905,22 @@ LLTextureFetch::~LLTextureFetch()
 		mCommands.erase(mCommands.begin());
 		delete req;
 	}
-	
+
+	if (mHttpOptions)
+	{
+		mHttpOptions->release();
+		mHttpOptions = NULL;
+	}
+
+	if (mHttpHeaders)
+	{
+		mHttpHeaders->release();
+		mHttpHeaders = NULL;
+	}
+
+	delete mHttpRequest;
+	mHttpRequest = NULL;
+
 	// ~LLQueuedThread() called here
 }
 
@@ -1984,6 +2063,28 @@ void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size)
 	mHTTPTextureBits += received_size * 8; // Approximate - does not include header bits	
 }
 
+void LLTextureFetch::cancelHttpRequests()
+{
+	for (queue_t::iterator iter(mHTTPTextureQueue.begin());
+		 mHTTPTextureQueue.end() != iter;
+		 ++iter)
+	{
+		LLTextureFetchWorker* worker = getWorker(*iter);
+		if (worker && worker->mHttpActive)
+		{
+			mHttpRequest->requestCancel(worker->mHttpHandle, NULL);
+		}
+	}
+
+	// *FIXME:  Do this better with less time wasting.
+	int tries(10);
+	while (! mHTTPTextureQueue.empty() && --tries)
+	{
+		mHttpRequest->update(100);
+		ms_sleep(100);
+	}
+}
+
 void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
 {
 	lockQueue() ;
@@ -2194,11 +2295,21 @@ void LLTextureFetch::commonUpdate()
 	cmdDoWork();
 	
 	// Update Curl on same thread as mCurlGetRequest was constructed
-	S32 processed = mCurlGetRequest->process();
+	LLCore::HttpStatus status = mHttpRequest->update(200);
+	if (! status)
+	{
+		LL_INFOS_ONCE("Texture") << "Problem during HTTP servicing.  Reason:  "
+								 << status.toString()
+								 << LL_ENDL;
+	}
+		
+#if 0
+	// *FIXME:  maybe implement this another way...
 	if (processed > 0)
 	{
 		lldebugs << "processed: " << processed << " messages." << llendl;
 	}
+#endif
 }
 
 
@@ -2256,22 +2367,22 @@ void LLTextureFetch::shutDownImageDecodeThread()
 // WORKER THREAD
 void LLTextureFetch::startThread()
 {
-	// Construct mCurlGetRequest from Worker Thread
-	mCurlGetRequest = new LLCurlRequest();
 }
 
 // WORKER THREAD
+//
+// This detaches the texture fetch thread from the LLCore
+// HTTP library but doesn't stop the thread running in that
+// library...
 void LLTextureFetch::endThread()
 {
-	// Destroy mCurlGetRequest from Worker Thread
-	delete mCurlGetRequest;
-	mCurlGetRequest = NULL;
+	cancelHttpRequests();
 }
 
 // WORKER THREAD
 void LLTextureFetch::threadedUpdate()
 {
-	llassert_always(mCurlGetRequest);
+	llassert_always(mHttpRequest);
 	
 	// Limit update frequency
 	const F32 PROCESS_TIME = 0.05f; 
@@ -2579,7 +2690,7 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
 	llassert_always(totalbytes > 0);
 	llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize);
 	res = worker->insertPacket(0, data, data_size);
-	worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
+	worker->setPriority(LLWorkerThread::PRIORITY_HIGH);
 	worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
 	worker->unlockWorkMutex();
 	return res;
@@ -2623,7 +2734,7 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
 	if ((worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) ||
 		(worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK))
 	{
-		worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
+		worker->setPriority(LLWorkerThread::PRIORITY_HIGH);
 		worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
 	}
 	else
@@ -2730,6 +2841,14 @@ void LLTextureFetch::dump()
 				<< " STATE: " << worker->sStateDescs[worker->mState]
 				<< llendl;
 	}
+
+	llinfos << "LLTextureFetch ACTIVE_HTTP:" << llendl;
+	for (queue_t::const_iterator iter(mHTTPTextureQueue.begin());
+		 mHTTPTextureQueue.end() != iter;
+		 ++iter)
+	{
+		llinfos << " ID: " << (*iter) << llendl;
+	}
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -2942,6 +3061,8 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	if (! mCapsURL.empty())
 	{
 		LLCurlRequest::headers_t headers;
+#if 0
+		// *FIXME:  Going to need a post op after all...
 		fetcher->getCurlRequest().post(mCapsURL,
 									   headers,
 									   merged_llsd,
@@ -2950,6 +3071,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
                                                          report_sequence,
                                                          LLTextureFetch::svMetricsDataBreak,
 														 reporting_started));
+#endif
 	}
 	else
 	{
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 35df7d816f20b91e28b319c40c9767e1a428c7b6..402b1982461a922dd86938be2be19c648d72ceb1 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -4,7 +4,7 @@
  *
  * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2012, Linden Research, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -31,9 +31,11 @@
 #include "llimage.h"
 #include "lluuid.h"
 #include "llworkerthread.h"
-#include "llcurl.h"
 #include "lltextureinfo.h"
 #include "llapr.h"
+#include "httprequest.h"
+#include "httpoptions.h"
+#include "httpheaders.h"
 
 class LLViewerTexture;
 class LLTextureFetchWorker;
@@ -98,7 +100,7 @@ class LLTextureFetch : public LLWorkerThread
 							LLViewerAssetStats * main_stats);
 	void commandDataBreak();
 
-	LLCurlRequest & getCurlRequest()	{ return *mCurlGetRequest; }
+	LLCore::HttpRequest & getHttpRequest()	{ return *mHttpRequest; }
 
 	bool isQAMode() const				{ return mQAMode; }
 
@@ -112,7 +114,8 @@ class LLTextureFetch : public LLWorkerThread
 	void addToHTTPQueue(const LLUUID& id);
 	void removeFromHTTPQueue(const LLUUID& id, S32 received_size = 0);
 	void removeRequest(LLTextureFetchWorker* worker, bool cancel);
-
+	void cancelHttpRequests();
+	
 	// Overrides from the LLThread tree
 	bool runCondition();
 
@@ -166,7 +169,6 @@ class LLTextureFetch : public LLWorkerThread
 
 	LLTextureCache* mTextureCache;
 	LLImageDecodeThread* mImageDecodeThread;
-	LLCurlRequest* mCurlGetRequest;
 	
 	// Map of all requests by UUID
 	typedef std::map<LLUUID,LLTextureFetchWorker*> map_t;
@@ -203,6 +205,13 @@ class LLTextureFetch : public LLWorkerThread
 	// use the LLCurl module's request counter as it isn't thread compatible.
 	// *NOTE:  Don't mix Atomic and static, apr_initialize must be called first.
 	LLAtomic32<S32> mCurlPOSTRequestCount;
+
+	// Interfaces and objects into the core http library used
+	// to make our HTTP requests.  These replace the various
+	// LLCurl interfaces used in the past.
+	LLCore::HttpRequest *		mHttpRequest;
+	LLCore::HttpOptions *		mHttpOptions;
+	LLCore::HttpHeaders *		mHttpHeaders;
 	
 public:
 	// A probabilistically-correct indicator that the current