From 6f4d36634e980bb989b9a8b762c3c622804c43dd Mon Sep 17 00:00:00 2001
From: Rider Linden <none@none>
Date: Mon, 16 Mar 2015 17:14:34 -0700
Subject: [PATCH] Removal of RPCXML dep on LLCurl switching to LLCore::Html

---
 indra/llcorehttp/_httpoprequest.cpp     |  95 ++-
 indra/llcorehttp/_httpoprequest.h       |  11 +-
 indra/llcorehttp/_httppolicyglobal.cpp  |  30 +
 indra/llcorehttp/_httppolicyglobal.h    |   3 +
 indra/llcorehttp/_httpservice.cpp       |  80 ++-
 indra/llcorehttp/_httpservice.h         |   9 +-
 indra/llcorehttp/_refcounted.h          |  11 +
 indra/llcorehttp/bufferarray.h          |   2 +
 indra/llcorehttp/httpcommon.cpp         |  24 +-
 indra/llcorehttp/httpcommon.h           | 116 +++-
 indra/llcorehttp/httphandler.h          |   4 +-
 indra/llcorehttp/httpheaders.h          |   1 +
 indra/llcorehttp/httpoptions.cpp        |  39 +-
 indra/llcorehttp/httpoptions.h          |  31 +
 indra/llcorehttp/httprequest.cpp        |  17 +-
 indra/llcorehttp/httprequest.h          |  17 +-
 indra/llcorehttp/httpresponse.h         |  25 +
 indra/llmessage/llcurl.cpp              | 854 ++++++++++++------------
 indra/llmessage/llcurl.h                |   9 +-
 indra/llmessage/llhttpclient.cpp        |  49 ++
 indra/llmessage/llhttpclientadapter.cpp |  90 +--
 indra/llmessage/llhttpclientadapter.h   |   2 +
 indra/llmessage/llhttpclientinterface.h |  16 +-
 indra/llmessage/llsdrpcclient.h         |   8 +-
 indra/newview/llappcorehttp.cpp         |  69 ++
 indra/newview/llappcorehttp.h           |   4 +-
 indra/newview/llhttpretrypolicy.cpp     |   2 +-
 indra/newview/llvoavatarself.cpp        |   1 -
 indra/newview/llxmlrpctransaction.cpp   | 497 +++++++-------
 indra/newview/llxmlrpctransaction.h     |   4 +-
 30 files changed, 1280 insertions(+), 840 deletions(-)

diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index b9632a7921a..48e22468cd5 100755
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -115,8 +115,9 @@ namespace LLCore
 {
 
 
-HttpOpRequest::HttpOpRequest()
+HttpOpRequest::HttpOpRequest(HttpRequest const * const request)
 	: HttpOperation(),
+	  mRequest(request),
 	  mProcFlags(0U),
 	  mReqMethod(HOR_GET),
 	  mReqBody(NULL),
@@ -139,7 +140,8 @@ HttpOpRequest::HttpOpRequest()
 	  mPolicyRetries(0),
 	  mPolicy503Retries(0),
 	  mPolicyRetryAt(HttpTime(0)),
-	  mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT)
+	  mPolicyRetryLimit(HTTP_RETRY_COUNT_DEFAULT),
+	  mCallbackSSLVerify(NULL)
 {
 	// *NOTE:  As members are added, retry initialization/cleanup
 	// may need to be extended in @see prepareRequest().
@@ -267,6 +269,14 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
 		response->setContentType(mReplyConType);
 		response->setRetries(mPolicyRetries, mPolicy503Retries);
 		
+		HttpResponse::TransferStats::ptr_t stats = HttpResponse::TransferStats::ptr_t(new HttpResponse::TransferStats);
+
+		curl_easy_getinfo(mCurlHandle, CURLINFO_SIZE_DOWNLOAD, &stats->mSizeDownload);
+		curl_easy_getinfo(mCurlHandle, CURLINFO_TOTAL_TIME, &stats->mTotalTime);
+		curl_easy_getinfo(mCurlHandle, CURLINFO_SPEED_DOWNLOAD, &stats->mSpeedDownload);
+
+		response->setTransferStats(stats);
+
 		mUserHandler->onCompleted(static_cast<HttpHandle>(this), response);
 
 		response->release();
@@ -452,18 +462,8 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
 	code = curl_easy_setopt(mCurlHandle, CURLOPT_ENCODING, "");
 	check_curl_easy_code(code, CURLOPT_ENCODING);
 
-	// The Linksys WRT54G V5 router has an issue with frequent
-	// DNS lookups from LAN machines.  If they happen too often,
-	// like for every HTTP request, the router gets annoyed after
-	// about 700 or so requests and starts issuing TCP RSTs to
-	// new connections.  Reuse the DNS lookups for even a few
-	// seconds and no RSTs.
-	code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15);
-	check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);
 	code = curl_easy_setopt(mCurlHandle, CURLOPT_AUTOREFERER, 1);
 	check_curl_easy_code(code, CURLOPT_AUTOREFERER);
-	code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, 1);
-	check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION);
 	code = curl_easy_setopt(mCurlHandle, CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT);
 	check_curl_easy_code(code, CURLOPT_MAXREDIRS);
 	code = curl_easy_setopt(mCurlHandle, CURLOPT_WRITEFUNCTION, writeCallback);
@@ -474,11 +474,49 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
 	check_curl_easy_code(code, CURLOPT_READFUNCTION);
 	code = curl_easy_setopt(mCurlHandle, CURLOPT_READDATA, this);
 	check_curl_easy_code(code, CURLOPT_READDATA);
-	code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, 1);
+
+	code = curl_easy_setopt(mCurlHandle, CURLOPT_COOKIEFILE, "");
+	check_curl_easy_code(code, CURLOPT_COOKIEFILE);
+
+	if (gpolicy.mSslCtxCallback)
+	{
+		code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_FUNCTION, curlSslCtxCallback);
+		check_curl_easy_code(code, CURLOPT_SSL_CTX_FUNCTION);
+		code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_CTX_DATA, this);
+		check_curl_easy_code(code, CURLOPT_SSL_CTX_DATA);
+		mCallbackSSLVerify = gpolicy.mSslCtxCallback;
+	}
+
+	long follow_redirect(1L);
+	long sslPeerV(0L);
+	long sslHostV(0L);
+	long dnsCacheTimeout(15L);
+
+	if (mReqOptions)
+	{
+		follow_redirect = mReqOptions->getFollowRedirects() ? 1L : 0L;
+		sslPeerV = mReqOptions->getSSLVerifyHost() ? 0L : 1L;
+		sslHostV = mReqOptions->getSSLVerifyHost();
+		dnsCacheTimeout = mReqOptions->getDNSCacheTimeout();
+	}
+	code = curl_easy_setopt(mCurlHandle, CURLOPT_FOLLOWLOCATION, follow_redirect);
+	check_curl_easy_code(code, CURLOPT_FOLLOWLOCATION);
+
+	code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYPEER, sslPeerV);
 	check_curl_easy_code(code, CURLOPT_SSL_VERIFYPEER);
-	code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, 0);
+	code = curl_easy_setopt(mCurlHandle, CURLOPT_SSL_VERIFYHOST, sslHostV);
 	check_curl_easy_code(code, CURLOPT_SSL_VERIFYHOST);
 
+	// The Linksys WRT54G V5 router has an issue with frequent
+	// DNS lookups from LAN machines.  If they happen too often,
+	// like for every HTTP request, the router gets annoyed after
+	// about 700 or so requests and starts issuing TCP RSTs to
+	// new connections.  Reuse the DNS lookups for even a few
+	// seconds and no RSTs.
+	code = curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout);
+	check_curl_easy_code(code, CURLOPT_DNS_CACHE_TIMEOUT);
+
+
 	if (gpolicy.mUseLLProxy)
 	{
 		// Use the viewer-based thread-safe API which has a
@@ -873,6 +911,35 @@ size_t HttpOpRequest::headerCallback(void * data, size_t size, size_t nmemb, voi
 }
 
 
+CURLcode HttpOpRequest::curlSslCtxCallback(CURL *curl, void *sslctx, void *userdata)
+{
+	HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
+
+	if (op->mCallbackSSLVerify)
+	{
+		SSL_CTX * ctx = (SSL_CTX *)sslctx;
+		// disable any default verification for server certs
+		SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+		// set the verification callback.
+		SSL_CTX_set_cert_verify_callback(ctx, sslCertVerifyCallback, userdata);
+		// the calls are void
+	}
+
+	return CURLE_OK;
+}
+
+int HttpOpRequest::sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
+{
+	HttpOpRequest * op(static_cast<HttpOpRequest *>(param));
+
+	if (op->mCallbackSSLVerify)
+	{
+		op->mStatus = op->mCallbackSSLVerify(op->mReqURL, op->mUserHandler, ctx);
+	}
+
+	return (op->mStatus) ? 1 : 0;
+}
+
 int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffer, size_t len, void * userdata)
 {
 	HttpOpRequest * op(static_cast<HttpOpRequest *>(userdata));
diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h
index 2f628b5abad..7a4b7c189e7 100755
--- a/indra/llcorehttp/_httpoprequest.h
+++ b/indra/llcorehttp/_httpoprequest.h
@@ -33,6 +33,9 @@
 #include <string>
 #include <curl/curl.h>
 
+#include <openssl/x509_vfy.h>
+#include <openssl/ssl.h>
+
 #include "httpcommon.h"
 #include "httprequest.h"
 #include "_httpoperation.h"
@@ -63,7 +66,7 @@ class HttpOptions;
 class HttpOpRequest : public HttpOperation
 {
 public:
-	HttpOpRequest();
+	HttpOpRequest(HttpRequest const * const request);
 
 protected:
 	virtual ~HttpOpRequest();							// Use release()
@@ -151,6 +154,9 @@ class HttpOpRequest : public HttpOperation
 	static size_t writeCallback(void * data, size_t size, size_t nmemb, void * userdata);
 	static size_t readCallback(void * data, size_t size, size_t nmemb, void * userdata);
 	static size_t headerCallback(void * data, size_t size, size_t nmemb, void * userdata);
+	static CURLcode curlSslCtxCallback(CURL *curl, void *ssl_ctx, void *userptr);
+	static int sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
+
 	static int debugCallback(CURL *, curl_infotype info, char * buffer, size_t len, void * userdata);
 
 protected:
@@ -159,8 +165,11 @@ class HttpOpRequest : public HttpOperation
 	static const unsigned int	PF_SAVE_HEADERS = 0x00000002U;
 	static const unsigned int	PF_USE_RETRY_AFTER = 0x00000004U;
 
+	HttpRequest::policyCallback	mCallbackSSLVerify;
+
 public:
 	// Request data
+	HttpRequest const * const mRequest;
 	EMethod				mReqMethod;
 	std::string			mReqURL;
 	BufferArray *		mReqBody;
diff --git a/indra/llcorehttp/_httppolicyglobal.cpp b/indra/llcorehttp/_httppolicyglobal.cpp
index 1dc95f3dce1..c4ef38a815e 100755
--- a/indra/llcorehttp/_httppolicyglobal.cpp
+++ b/indra/llcorehttp/_httppolicyglobal.cpp
@@ -106,6 +106,20 @@ HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, const std::stri
 	return HttpStatus();
 }
 
+HttpStatus HttpPolicyGlobal::set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback value)
+{
+	switch (opt)
+	{
+	case HttpRequest::PO_SSL_VERIFY_CALLBACK:
+		mSslCtxCallback = value;
+		break;
+
+	default:
+		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
+	}
+
+	return HttpStatus();
+}
 
 HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, long * value) const
 {
@@ -154,4 +168,20 @@ HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, std::string * v
 	return HttpStatus();
 }
 
+
+HttpStatus HttpPolicyGlobal::get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback * value) const
+{
+	switch (opt)
+	{
+	case HttpRequest::PO_SSL_VERIFY_CALLBACK:
+		*value = mSslCtxCallback;
+		break;
+
+	default:
+		return HttpStatus(HttpStatus::LLCORE, HE_INVALID_ARG);
+	}
+
+	return HttpStatus();
+}
+
 }  // end namespace LLCore
diff --git a/indra/llcorehttp/_httppolicyglobal.h b/indra/llcorehttp/_httppolicyglobal.h
index 67c4ba9481d..1696238814d 100755
--- a/indra/llcorehttp/_httppolicyglobal.h
+++ b/indra/llcorehttp/_httppolicyglobal.h
@@ -60,8 +60,10 @@ class HttpPolicyGlobal
 public:
 	HttpStatus set(HttpRequest::EPolicyOption opt, long value);
 	HttpStatus set(HttpRequest::EPolicyOption opt, const std::string & value);
+	HttpStatus set(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback value);
 	HttpStatus get(HttpRequest::EPolicyOption opt, long * value) const;
 	HttpStatus get(HttpRequest::EPolicyOption opt, std::string * value) const;
+	HttpStatus get(HttpRequest::EPolicyOption opt, HttpRequest::policyCallback * value) const;
 	
 public:
 	long				mConnectionLimit;
@@ -70,6 +72,7 @@ class HttpPolicyGlobal
 	std::string			mHttpProxy;
 	long				mTrace;
 	long				mUseLLProxy;
+	HttpRequest::policyCallback	mSslCtxCallback;
 };  // end class HttpPolicyGlobal
 
 }  // end namespace LLCore
diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp
index c673e1be1d3..7b8aac35a8e 100755
--- a/indra/llcorehttp/_httpservice.cpp
+++ b/indra/llcorehttp/_httpservice.cpp
@@ -53,15 +53,16 @@ namespace LLCore
 
 const HttpService::OptionDescriptor HttpService::sOptionDesc[] =
 { //    isLong     isDynamic  isGlobal    isClass
-	{	true,		true,		true,		true	},		// PO_CONNECTION_LIMIT
-	{	true,		true,		false,		true	},		// PO_PER_HOST_CONNECTION_LIMIT
-	{	false,		false,		true,		false	},		// PO_CA_PATH
-	{	false,		false,		true,		false	},		// PO_CA_FILE
-	{	false,		true,		true,		false	},		// PO_HTTP_PROXY
-	{	true,		true,		true,		false	},		// PO_LLPROXY
-	{	true,		true,		true,		false	},		// PO_TRACE
-	{	true,		true,		false,		true	},		// PO_ENABLE_PIPELINING
-	{	true,		true,		false,		true	}		// PO_THROTTLE_RATE
+	{	true,		true,		true,		true,		false	},		// PO_CONNECTION_LIMIT
+	{	true,		true,		false,		true,		false	},		// PO_PER_HOST_CONNECTION_LIMIT
+	{	false,		false,		true,		false,		false	},		// PO_CA_PATH
+	{	false,		false,		true,		false,		false	},		// PO_CA_FILE
+	{	false,		true,		true,		false,		false	},		// PO_HTTP_PROXY
+	{	true,		true,		true,		false,		false	},		// PO_LLPROXY
+	{	true,		true,		true,		false,		false	},		// PO_TRACE
+	{	true,		true,		false,		true,		false	},		// PO_ENABLE_PIPELINING
+	{	true,		true,		false,		true,		false	},		// PO_THROTTLE_RATE
+	{   false,		false,		true,		false,		true	}		// PO_SSL_VERIFY_CALLBACK
 };
 HttpService * HttpService::sInstance(NULL);
 volatile HttpService::EState HttpService::sState(NOT_INITIALIZED);
@@ -413,6 +414,34 @@ HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
 	return status;
 }
 
+HttpStatus HttpService::getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
+	HttpRequest::policyCallback * ret_value)
+{
+	HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
+
+	if (opt < HttpRequest::PO_CONNECTION_LIMIT											// option must be in range
+		|| opt >= HttpRequest::PO_LAST													// ditto
+		|| (sOptionDesc[opt].mIsLong)													// datatype is string
+		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy)			// pclass in valid range
+		|| (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal)	// global setting permitted
+		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass))	// class setting permitted
+		// can always get, no dynamic check
+	{
+		return status;
+	}
+
+	// Only global has callback values
+	if (pclass == HttpRequest::GLOBAL_POLICY_ID)
+	{
+		HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
+
+		status = opts.get(opt, ret_value);
+	}
+
+	return status;
+}
+
+
 
 HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
 										long value, long * ret_value)
@@ -489,6 +518,37 @@ HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequ
 
 	return status;
 }
-	
+
+HttpStatus HttpService::setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t pclass,
+	HttpRequest::policyCallback value, HttpRequest::policyCallback * ret_value)
+{
+	HttpStatus status(HttpStatus::LLCORE, LLCore::HE_INVALID_ARG);
+
+	if (opt < HttpRequest::PO_CONNECTION_LIMIT											// option must be in range
+		|| opt >= HttpRequest::PO_LAST													// ditto
+		|| (sOptionDesc[opt].mIsLong)													// datatype is string
+		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && pclass > mLastPolicy)			// pclass in valid range
+		|| (pclass == HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsGlobal)	// global setting permitted
+		|| (pclass != HttpRequest::GLOBAL_POLICY_ID && !sOptionDesc[opt].mIsClass)		// class setting permitted
+		|| (RUNNING == sState && !sOptionDesc[opt].mIsDynamic))						// dynamic setting permitted
+	{
+		return status;
+	}
+
+	// Callbacks values are always global (at this time).
+	if (pclass == HttpRequest::GLOBAL_POLICY_ID)
+	{
+		HttpPolicyGlobal & opts(mPolicy->getGlobalOptions());
+
+		status = opts.set(opt, value);
+		if (status && ret_value)
+		{
+			status = opts.get(opt, ret_value);
+		}
+	}
+
+	return status;
+}
+
 
 }  // end namespace LLCore
diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h
index cf23f3ab61f..699a8eaa4f3 100755
--- a/indra/llcorehttp/_httpservice.h
+++ b/indra/llcorehttp/_httpservice.h
@@ -201,17 +201,24 @@ class HttpService
 		bool		mIsDynamic;
 		bool		mIsGlobal;
 		bool		mIsClass;
+		bool		mIsCallback;
 	};
 		
 	HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
 							   long * ret_value);
 	HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
 							   std::string * ret_value);
+	HttpStatus getPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
+								HttpRequest::policyCallback * ret_value);
+
 	HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
 							   long value, long * ret_value);
 	HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
 							   const std::string & value, std::string * ret_value);
-	
+	HttpStatus setPolicyOption(HttpRequest::EPolicyOption opt, HttpRequest::policy_t,
+								HttpRequest::policyCallback value, 
+								HttpRequest::policyCallback * ret_value);
+
 protected:
 	static const OptionDescriptor		sOptionDesc[HttpRequest::PO_LAST];
 	static HttpService *				sInstance;
diff --git a/indra/llcorehttp/_refcounted.h b/indra/llcorehttp/_refcounted.h
index 402e7251524..cd16e2e2b45 100755
--- a/indra/llcorehttp/_refcounted.h
+++ b/indra/llcorehttp/_refcounted.h
@@ -120,7 +120,18 @@ inline void RefCounted::destroySelf()
 	delete this;
 }
 
+inline void intrusive_ptr_add_ref(RefCounted* p)
+{
+	p->addRef();
+}
+
+inline void intrusive_ptr_release(RefCounted* p)
+{
+	p->release();
+}
+
 } // end namespace LLCoreInt
 
+
 #endif	// LLCOREINT__REFCOUNTED_H_
 
diff --git a/indra/llcorehttp/bufferarray.h b/indra/llcorehttp/bufferarray.h
index 1094a435b42..9c2b991de64 100755
--- a/indra/llcorehttp/bufferarray.h
+++ b/indra/llcorehttp/bufferarray.h
@@ -73,6 +73,8 @@ class BufferArray : public LLCoreInt::RefCounted
 	
 	BufferArray();
 
+	typedef boost::intrusive_ptr<BufferArray> ptr_t;
+
 protected:
 	virtual ~BufferArray();						// Use release()
 
diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp
index 7907e958a44..1aece696e39 100755
--- a/indra/llcorehttp/httpcommon.cpp
+++ b/indra/llcorehttp/httpcommon.cpp
@@ -42,7 +42,7 @@ HttpStatus::operator unsigned long() const
 {
 	static const int shift(sizeof(unsigned long) * 4);
 
-	unsigned long result(((unsigned long) mType) << shift | (unsigned long) (int) mStatus);
+	unsigned long result(((unsigned long)mDetails->mType) << shift | (unsigned long)(int)mDetails->mStatus);
 	return result;
 }
 
@@ -131,18 +131,18 @@ std::string HttpStatus::toString() const
 	{
 		return std::string("");
 	}
-	switch (mType)
+	switch (mDetails->mType)
 	{
 	case EXT_CURL_EASY:
-		return std::string(curl_easy_strerror(CURLcode(mStatus)));
+		return std::string(curl_easy_strerror(CURLcode(mDetails->mStatus)));
 
 	case EXT_CURL_MULTI:
-		return std::string(curl_multi_strerror(CURLMcode(mStatus)));
+		return std::string(curl_multi_strerror(CURLMcode(mDetails->mStatus)));
 
 	case LLCORE:
-		if (mStatus >= 0 && mStatus < llcore_errors_count)
+		if (mDetails->mStatus >= 0 && mDetails->mStatus < llcore_errors_count)
 		{
-			return std::string(llcore_errors[mStatus]);
+			return std::string(llcore_errors[mDetails->mStatus]);
 		}
 		break;
 
@@ -154,7 +154,7 @@ std::string HttpStatus::toString() const
 			while (true)
 			{
 				int at((bottom + top) / 2);
-				if (mType == http_errors[at].mCode)
+				if (mDetails->mType == http_errors[at].mCode)
 				{
 					return std::string(http_errors[at].mText);
 				}
@@ -162,7 +162,7 @@ std::string HttpStatus::toString() const
 				{
 					break;
 				}
-				else if (mType < http_errors[at].mCode)
+				else if (mDetails->mType < http_errors[at].mCode)
 				{
 					top = at;
 				}
@@ -182,9 +182,9 @@ std::string HttpStatus::toTerseString() const
 {
 	std::ostringstream result;
 
-	unsigned int error_value((unsigned short) mStatus);
+	unsigned int error_value((unsigned short)mDetails->mStatus);
 	
-	switch (mType)
+	switch (mDetails->mType)
 	{
 	case EXT_CURL_EASY:
 		result << "Easy_";
@@ -202,7 +202,7 @@ std::string HttpStatus::toTerseString() const
 		if (isHttpStatus())
 		{
 			result << "Http_";
-			error_value = mType;
+			error_value = mDetails->mType;
 		}
 		else
 		{
@@ -244,7 +244,7 @@ bool HttpStatus::isRetryable() const
 	// Disable the '*this == inv_status' test and look for 'Core_9'
 	// failures in log files.
 
-	return ((isHttpStatus() && mType >= 499 && mType <= 599) ||	// Include special 499 in retryables
+	return ((isHttpStatus() && mDetails->mType >= 499 && mDetails->mType <= 599) ||	// Include special 499 in retryables
 			*this == cant_connect ||	// Connection reset/endpoint problems
 			*this == cant_res_proxy ||	// DNS problems
 			*this == cant_res_host ||	// DNS problems
diff --git a/indra/llcorehttp/httpcommon.h b/indra/llcorehttp/httpcommon.h
index 9601f94125f..0244755272f 100755
--- a/indra/llcorehttp/httpcommon.h
+++ b/indra/llcorehttp/httpcommon.h
@@ -191,7 +191,6 @@
 
 #include <string>
 
-
 namespace LLCore
 {
 
@@ -292,35 +291,35 @@ struct HttpStatus
 	typedef unsigned short type_enum_t;
 	
 	HttpStatus()
-		: mType(LLCORE),
-		  mStatus(HE_SUCCESS)
-		{}
+		{
+			mDetails = std::unique_ptr<Details>(new Details(LLCORE, HE_SUCCESS));
+		}
 
 	HttpStatus(type_enum_t type, short status)
-		: mType(type),
-		  mStatus(status)
-		{}
+		{
+			mDetails = std::unique_ptr<Details>(new Details(type, status));
+		}
 	
 	HttpStatus(int http_status)
-		: mType(http_status),
-		  mStatus(http_status >= 200 && http_status <= 299
-				  ? HE_SUCCESS
-				  : HE_REPLY_ERROR)
 		{
+			mDetails = std::unique_ptr<Details>(new Details(http_status, 
+				(http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR));
 			llassert(http_status >= 100 && http_status <= 999);
 		}
 	
 	HttpStatus(const HttpStatus & rhs)
-		: mType(rhs.mType),
-		  mStatus(rhs.mStatus)
-		{}
+		{
+			mDetails = std::unique_ptr<Details>(new Details(*rhs.mDetails));
+		}
 
 	HttpStatus & operator=(const HttpStatus & rhs)
 		{
 			// Don't care if lhs & rhs are the same object
+			mDetails->mType = rhs.mDetails->mType;
+			mDetails->mStatus = rhs.mDetails->mStatus;
+			mDetails->mMessage = rhs.mDetails->mMessage;
+			mDetails->mErrorData = rhs.mDetails->mErrorData;
 
-			mType = rhs.mType;
-			mStatus = rhs.mStatus;
 			return *this;
 		}
 	
@@ -328,10 +327,6 @@ struct HttpStatus
 	static const type_enum_t EXT_CURL_MULTI = 1;		///< mStatus is an error from a curl_multi_*() call
 	static const type_enum_t LLCORE = 2;				///< mStatus is an HE_* error code
 														///< 100-999 directly represent HTTP status codes
-	
-	type_enum_t			mType;
-	short				mStatus;
-
 	/// Test for successful status in the code regardless
 	/// of error source (internal, libcurl).
 	///
@@ -339,7 +334,7 @@ struct HttpStatus
 	///
 	operator bool() const
 	{
-		return 0 == mStatus;
+		return 0 == mDetails->mStatus;
 	}
 
 	/// Inverse of previous operator.
@@ -347,14 +342,15 @@ struct HttpStatus
 	/// @return			'true' on any error condition
 	bool operator !() const
 	{
-		return 0 != mStatus;
+		return 0 != mDetails->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;
+		return (mDetails->mType == rhs.mDetails->mType) && 
+			(mDetails->mStatus == rhs.mDetails->mStatus);
 	}
 
 	bool operator!=(const HttpStatus & rhs) const
@@ -395,7 +391,7 @@ struct HttpStatus
 	/// HTTP response status (100 - 999).
 	bool isHttpStatus() const
 	{
-		return 	mType >= type_enum_t(100) && mType <= type_enum_t(999);
+		return 	mDetails->mType >= type_enum_t(100) && mDetails->mType <= type_enum_t(999);
 	}
 
 	/// Returns true if the status is one that will be retried
@@ -403,7 +399,77 @@ struct HttpStatus
 	/// where that logic needs to be replicated.  Only applies
 	/// to failed statuses, successful statuses will return false.
 	bool isRetryable() const;
-	
+
+	/// Returns the currently set status code as a raw number
+	///
+	short getStatus() const
+	{
+		return mDetails->mStatus;
+	}
+
+	/// Returns the currently set status type 
+	/// 
+	type_enum_t getType() const
+	{
+		return mDetails->mType;
+	}
+
+	// TODO: There must be a better way to do this.  Don't want to set these 
+	// values here since they increase the size of a structure that is already 
+	// being passed on the stack.  Consider my options
+	/// Returns an optional error message if one has been set.
+	///
+	std::string getMessage() const
+	{
+		return mDetails->mMessage;
+	}
+
+	/// Sets an optional error message
+	/// 
+	void setMessage(const std::string &message)
+	{
+		mDetails->mMessage = message;
+	}
+
+	/// Retrieves an optionally recorded SSL certificate.
+	void * getErrorData() const
+	{
+		return mDetails->mErrorData;
+	}
+
+	/// Optionally sets an SSL certificate on this status.
+	void setErrorData(void *data)
+	{
+		mDetails->mErrorData = data;
+	}
+
+private:
+
+	struct Details
+	{
+		Details(type_enum_t type, short status):
+			mType(type),
+			mStatus(status),
+			mMessage(),
+			mErrorData(NULL)
+		{}
+
+		Details(const Details &rhs) :
+			mType(rhs.mType),
+			mStatus(rhs.mStatus),
+			mMessage(rhs.mMessage),
+			mErrorData(rhs.mErrorData)
+		{}
+
+
+		type_enum_t	mType;
+		short		mStatus;
+		std::string	mMessage;
+		void *		mErrorData;
+	};
+
+	std::unique_ptr<Details>	mDetails;
+
 }; // end struct HttpStatus
 
 }  // end namespace LLCore
diff --git a/indra/llcorehttp/httphandler.h b/indra/llcorehttp/httphandler.h
index 9171e4e7b93..740e986dec1 100755
--- a/indra/llcorehttp/httphandler.h
+++ b/indra/llcorehttp/httphandler.h
@@ -45,7 +45,7 @@ class HttpResponse;
 /// be shared by any number of requests and across instances
 /// of HttpRequest running in the same thread.
 ///
-/// Threading:  HttpHandler itself is pure interface and is
+/// Threading:  HttpHandler itself is interface and is
 /// tread-compatible.  Most derivations, however, will have
 /// different constraints.
 ///
@@ -58,7 +58,7 @@ class HttpHandler
 {
 public:
 	virtual ~HttpHandler()
-		{}
+	{ }
 
 	/// Method invoked during calls to @see update().  Each invocation
 	/// represents the completion of some requested operation.  Caller
diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h
index f70cd898f39..c89d6af2222 100755
--- a/indra/llcorehttp/httpheaders.h
+++ b/indra/llcorehttp/httpheaders.h
@@ -92,6 +92,7 @@ class HttpHeaders : public LLCoreInt::RefCounted
 	/// the instance.
 	HttpHeaders();
 
+	typedef boost::intrusive_ptr<HttpHeaders> ptr_t;
 protected:
 	virtual ~HttpHeaders();						// Use release()
 
diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp
index 5bf1ecb4a5a..28c2c25e929 100755
--- a/indra/llcorehttp/httpoptions.cpp
+++ b/indra/llcorehttp/httpoptions.cpp
@@ -25,7 +25,7 @@
  */
 
 #include "httpoptions.h"
-
+#include "lldefs.h"
 #include "_httpinternal.h"
 
 
@@ -33,14 +33,17 @@ namespace LLCore
 {
 
 
-HttpOptions::HttpOptions()
-	: RefCounted(true),
-	  mWantHeaders(false),
-	  mTracing(HTTP_TRACE_OFF),
-	  mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT),
-	  mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT),
-	  mRetries(HTTP_RETRY_COUNT_DEFAULT),
-	  mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT)
+HttpOptions::HttpOptions() : RefCounted(true),
+	mWantHeaders(false),
+	mTracing(HTTP_TRACE_OFF),
+	mTimeout(HTTP_REQUEST_TIMEOUT_DEFAULT),
+	mTransferTimeout(HTTP_REQUEST_XFER_TIMEOUT_DEFAULT),
+	mRetries(HTTP_RETRY_COUNT_DEFAULT),
+	mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT),
+	mFollowRedirects(false),
+	mVerifyPeer(false),
+	mVerifyHost(0),
+	mDNSCacheTimeout(15)
 {}
 
 
@@ -82,5 +85,23 @@ void HttpOptions::setUseRetryAfter(bool use_retry)
 	mUseRetryAfter = use_retry;
 }
 
+void HttpOptions::setFollowRedirects(bool follow_redirect)
+{
+	mFollowRedirects = follow_redirect;
+}
+
+void HttpOptions::setSSLVerifyPeer(bool verify)
+{
+	mVerifyPeer = verify;
+}
 
+void HttpOptions::setSSLVerifyHost(unsigned int type)
+{
+	mVerifyHost = llclamp<unsigned int>(type, 0, 2);
+}
+
+void HttpOptions::setDNSCacheTimeout(int timeout)
+{
+	mDNSCacheTimeout = timeout;
+}
 }   // end namespace LLCore
diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h
index 4ab5ff18c43..d6d892213d8 100755
--- a/indra/llcorehttp/httpoptions.h
+++ b/indra/llcorehttp/httpoptions.h
@@ -61,6 +61,8 @@ class HttpOptions : public LLCoreInt::RefCounted
 public:
 	HttpOptions();
 
+	typedef boost::intrusive_ptr<HttpOptions> ptr_t;
+
 protected:
 	virtual ~HttpOptions();						// Use release()
 	
@@ -109,6 +111,31 @@ class HttpOptions : public LLCoreInt::RefCounted
 		{
 			return mUseRetryAfter;
 		}
+
+	// Default: false
+	void				setFollowRedirects(bool follow_redirect);
+	bool				getFollowRedirects() const
+		{
+			return mFollowRedirects;
+		}
+
+	void				setSSLVerifyPeer(bool verify);
+	bool				getSSLVerifyPeer() const
+		{
+			return mVerifyPeer;
+		}
+
+	void				setSSLVerifyHost(unsigned int type);
+	unsigned int		getSSLVerifyHost() const
+		{
+			return mVerifyHost;
+		}
+
+	void				setDNSCacheTimeout(int timeout);
+	int					getDNSCacheTimeout() const
+		{
+			return mDNSCacheTimeout;
+		}
 	
 protected:
 	bool				mWantHeaders;
@@ -117,6 +144,10 @@ class HttpOptions : public LLCoreInt::RefCounted
 	unsigned int		mTransferTimeout;
 	unsigned int		mRetries;
 	bool				mUseRetryAfter;
+	bool				mFollowRedirects;
+	bool				mVerifyPeer;
+	unsigned int		mVerifyHost;
+	int					mDNSCacheTimeout;
 }; // end class HttpOptions
 
 
diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp
index 7b1888e3eba..5f1ed3d43b9 100755
--- a/indra/llcorehttp/httprequest.cpp
+++ b/indra/llcorehttp/httprequest.cpp
@@ -117,6 +117,15 @@ HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass
 	return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
 }
 
+HttpStatus HttpRequest::setStaticPolicyOption(EPolicyOption opt, policy_t pclass, policyCallback value, policyCallback * ret_value)
+{
+	if (HttpService::RUNNING == HttpService::instanceOf()->getState())
+	{
+		return HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_DYNAMIC);
+	}
+
+	return HttpService::instanceOf()->setPolicyOption(opt, pclass, value, ret_value);
+}
 
 HttpHandle HttpRequest::setPolicyOption(EPolicyOption opt, policy_t pclass,
 										long value, HttpHandler * handler)
@@ -195,7 +204,7 @@ HttpHandle HttpRequest::requestGet(policy_t policy_id,
 	HttpStatus status;
 	HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
 
-	HttpOpRequest * op = new HttpOpRequest();
+	HttpOpRequest * op = new HttpOpRequest(this);
 	if (! (status = op->setupGet(policy_id, priority, url, options, headers)))
 	{
 		op->release();
@@ -229,7 +238,7 @@ HttpHandle HttpRequest::requestGetByteRange(policy_t policy_id,
 	HttpStatus status;
 	HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
 
-	HttpOpRequest * op = new HttpOpRequest();
+	HttpOpRequest * op = new HttpOpRequest(this);
 	if (! (status = op->setupGetByteRange(policy_id, priority, url, offset, len, options, headers)))
 	{
 		op->release();
@@ -262,7 +271,7 @@ HttpHandle HttpRequest::requestPost(policy_t policy_id,
 	HttpStatus status;
 	HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
 
-	HttpOpRequest * op = new HttpOpRequest();
+	HttpOpRequest * op = new HttpOpRequest(this);
 	if (! (status = op->setupPost(policy_id, priority, url, body, options, headers)))
 	{
 		op->release();
@@ -295,7 +304,7 @@ HttpHandle HttpRequest::requestPut(policy_t policy_id,
 	HttpStatus status;
 	HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
 
-	HttpOpRequest * op = new HttpOpRequest();
+	HttpOpRequest * op = new HttpOpRequest(this);
 	if (! (status = op->setupPut(policy_id, priority, url, body, options, headers)))
 	{
 		op->release();
diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h
index 7f23723b0b0..c90e056d627 100755
--- a/indra/llcorehttp/httprequest.h
+++ b/indra/llcorehttp/httprequest.h
@@ -97,6 +97,7 @@ class HttpRequest
 	typedef unsigned int policy_t;
 	typedef unsigned int priority_t;
 	
+	typedef std::shared_ptr<HttpRequest> ptr_t;
 public:
 	/// @name PolicyMethods
 	/// @{
@@ -163,7 +164,7 @@ class HttpRequest
 
 		/// Long value that if non-zero enables the use of the
 		/// traditional LLProxy code for http/socks5 support.  If
-		// enabled, has priority over GP_HTTP_PROXY.
+		/// enabled, has priority over GP_HTTP_PROXY.
 		///
 		/// Global only
 		PO_LLPROXY,
@@ -219,15 +220,25 @@ class HttpRequest
 		/// Controls whether client-side throttling should be
 		/// performed on this policy class.  Positive values
 		/// enable throttling and specify the request rate
-		/// (requests per second) that should be targetted.
+		/// (requests per second) that should be targeted.
 		/// A value of zero, the default, specifies no throttling.
 		///
 		/// Per-class only
 		PO_THROTTLE_RATE,
 		
+		/// Controls the callback function used to control SSL CTX 
+		/// certificate verification.
+		///
+		/// Global only
+		PO_SSL_VERIFY_CALLBACK,
+
 		PO_LAST  // Always at end
 	};
 
+	/// Prototype for policy based callbacks.  The callback methods will be executed
+	/// on the worker thread so no modifications should be made to the HttpHandler object.
+	typedef HttpStatus(*policyCallback)(const std::string &, HttpHandler const * const, void *);
+
 	/// Set a policy option for a global or class parameter at
 	/// startup time (prior to thread start).
 	///
@@ -243,6 +254,8 @@ class HttpRequest
 											long value, long * ret_value);
 	static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
 											const std::string & value, std::string * ret_value);
+	static HttpStatus setStaticPolicyOption(EPolicyOption opt, policy_t pclass,
+											policyCallback value, policyCallback * ret_value);;
 
 	/// Set a parameter on a class-based policy option.  Calls
 	/// made after the start of the servicing thread are
diff --git a/indra/llcorehttp/httpresponse.h b/indra/llcorehttp/httpresponse.h
index aee64e28784..01e9dd2bc61 100755
--- a/indra/llcorehttp/httpresponse.h
+++ b/indra/llcorehttp/httpresponse.h
@@ -69,6 +69,18 @@ class HttpResponse : public LLCoreInt::RefCounted
 	void operator=(const HttpResponse &);				// Not defined
 	
 public:
+	/// Statistics for the HTTP 
+	struct TransferStats
+	{
+		typedef std::shared_ptr<TransferStats> ptr_t;
+
+		TransferStats() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
+		F64 mSizeDownload;
+		F64 mTotalTime;
+		F64 mSpeedDownload;
+	};
+
+
 	/// Returns the final status of the requested operation.
 	///
 	HttpStatus getStatus() const
@@ -168,6 +180,17 @@ class HttpResponse : public LLCoreInt::RefCounted
 			m503Retries = retries_503;
 		}
 
+	void setTransferStats(TransferStats::ptr_t &stats) 
+		{
+			mStats = stats;
+		}
+
+	TransferStats::ptr_t getTransferStats()
+		{
+			return mStats;
+		}
+
+
 protected:
 	// Response data here
 	HttpStatus			mStatus;
@@ -179,6 +202,8 @@ class HttpResponse : public LLCoreInt::RefCounted
 	std::string			mContentType;
 	unsigned int		mRetries;
 	unsigned int		m503Retries;
+
+	TransferStats::ptr_t	mStats;
 };
 
 
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 73df47b933f..0080dd61383 100755
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -676,6 +676,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,
 }
 
 ////////////////////////////////////////////////////////////////////////////
+#if 1
 LLCurl::Multi::Multi(F32 idle_time_out)
 	: mQueued(0),
 	  mErrorCount(0),
@@ -1056,6 +1057,7 @@ void LLCurl::Multi::removeEasy(Easy* easy)
 	easyFree(easy);
 }
 
+#endif
 //------------------------------------------------------------
 //LLCurlThread
 LLCurlThread::CurlRequest::CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread) :
@@ -1176,428 +1178,428 @@ std::string LLCurl::strerror(CURLcode errorcode)
 // For generating a simple request for data
 // using one multi and one easy per request 
 
-LLCurlRequest::LLCurlRequest() :
-	mActiveMulti(NULL),
-	mActiveRequestCount(0)
-{
-	mProcessing = FALSE;
-}
-
-LLCurlRequest::~LLCurlRequest()
-{
-	//stop all Multi handle background threads
-	for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter)
-	{
-		LLCurl::getCurlThread()->killMulti(*iter) ;
-	}
-	mMultiSet.clear() ;
-}
-
-void LLCurlRequest::addMulti()
-{
-	LLCurl::Multi* multi = new LLCurl::Multi();
-	if(!multi->isValid())
-	{
-		LLCurl::getCurlThread()->killMulti(multi) ;
-		mActiveMulti = NULL ;
-		mActiveRequestCount = 0 ;
-		return;
-	}
-	
-	mMultiSet.insert(multi);
-	mActiveMulti = multi;
-	mActiveRequestCount = 0;
-}
-
-LLCurl::Easy* LLCurlRequest::allocEasy()
-{
-	if (!mActiveMulti ||
-		mActiveRequestCount	>= MAX_ACTIVE_REQUEST_COUNT ||
-		mActiveMulti->mErrorCount > 0)
-	{
-		addMulti();
-	}
-	if(!mActiveMulti)
-	{
-		return NULL ;
-	}
-
-	//llassert_always(mActiveMulti);
-	++mActiveRequestCount;
-	LLCurl::Easy* easy = mActiveMulti->allocEasy();
-	return easy;
-}
-
-bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
-{
-	llassert_always(mActiveMulti);
-	
-	if (mProcessing)
-	{
-		LL_ERRS() << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << LL_ENDL;
-	}
-	bool res = mActiveMulti->addEasy(easy);
-	return res;
-}
-
-void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
-{
-	getByteRange(url, headers_t(), 0, -1, responder);
-}
-
-// Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or
-// the remainder of the file if not.
-bool LLCurlRequest::getByteRange(const std::string& url,
-								 const headers_t& headers,
-								 S32 offset, S32 length,
-								 LLCurl::ResponderPtr responder)
-{
-	llassert(LLCurl::sNotQuitting);
-	LLCurl::Easy* easy = allocEasy();
-	if (!easy)
-	{
-		return false;
-	}
-	easy->prepRequest(url, headers, responder);
-	easy->setopt(CURLOPT_HTTPGET, 1);
-	if (length > 0)
-	{
-		std::string range = llformat("bytes=%d-%d", offset,offset+length-1);
-		easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
-	}
-	else if (offset > 0)
-	{
-		std::string range = llformat("bytes=%d-", offset);
-		easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
-	}
-	easy->setHeaders();
-	bool res = addEasy(easy);
-	return res;
-}
-
-bool LLCurlRequest::post(const std::string& url,
-						 const headers_t& headers,
-						 const LLSD& data,
-						 LLCurl::ResponderPtr responder, S32 time_out)
-{
-	llassert(LLCurl::sNotQuitting);
-	LLCurl::Easy* easy = allocEasy();
-	if (!easy)
-	{
-		return false;
-	}
-	easy->prepRequest(url, headers, responder, time_out);
-
-	LLSDSerialize::toXML(data, easy->getInput());
-	S32 bytes = easy->getInput().str().length();
-	
-	easy->setopt(CURLOPT_POST, 1);
-	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
-	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
-
-	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
-	easy->setHeaders();
-
-	LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
-	bool res = addEasy(easy);
-	return res;
-}
-
-bool LLCurlRequest::post(const std::string& url,
-						 const headers_t& headers,
-						 const std::string& data,
-						 LLCurl::ResponderPtr responder, S32 time_out)
-{
-	llassert(LLCurl::sNotQuitting);
-	LLCurl::Easy* easy = allocEasy();
-	if (!easy)
-	{
-		return false;
-	}
-	easy->prepRequest(url, headers, responder, time_out);
-
-	easy->getInput().write(data.data(), data.size());
-	S32 bytes = easy->getInput().str().length();
-	
-	easy->setopt(CURLOPT_POST, 1);
-	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
-	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
-
-	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM);
-	easy->setHeaders();
-
-	LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
-	bool res = addEasy(easy);
-	return res;
-}
-
-// Note: call once per frame
-S32 LLCurlRequest::process()
-{
-	S32 res = 0;
-
-	mProcessing = TRUE;
-	for (curlmulti_set_t::iterator iter = mMultiSet.begin();
-		 iter != mMultiSet.end(); )
-	{
-		curlmulti_set_t::iterator curiter = iter++;
-		LLCurl::Multi* multi = *curiter;
-
-		if(!multi->isValid())
-		{
-			if(multi == mActiveMulti)
-			{				
-				mActiveMulti = NULL ;
-				mActiveRequestCount = 0 ;
-			}
-			mMultiSet.erase(curiter) ;
-			LLCurl::getCurlThread()->killMulti(multi) ;
-			continue ;
-		}
-
-		S32 tres = multi->process();
-		res += tres;
-		if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
-		{
-			mMultiSet.erase(curiter);
-			LLCurl::getCurlThread()->killMulti(multi);
-		}
-	}
-	mProcessing = FALSE;
-	return res;
-}
-
-S32 LLCurlRequest::getQueued()
-{
-	S32 queued = 0;
-	for (curlmulti_set_t::iterator iter = mMultiSet.begin();
-		 iter != mMultiSet.end(); )
-	{
-		curlmulti_set_t::iterator curiter = iter++;
-		LLCurl::Multi* multi = *curiter;
-		
-		if(!multi->isValid())
-		{
-			if(multi == mActiveMulti)
-			{				
-				mActiveMulti = NULL ;
-				mActiveRequestCount = 0 ;
-			}
-			LLCurl::getCurlThread()->killMulti(multi);
-			mMultiSet.erase(curiter) ;
-			continue ;
-		}
-
-		queued += multi->mQueued;
-		if (multi->getState() != LLCurl::Multi::STATE_READY)
-		{
-			++queued;
-		}
-	}
-	return queued;
-}
-
-LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) : 
-	LLCurlRequest(), 
-	mConcurrency(concurrency),
-	mInQueue(0),
-	mMutex(NULL),
-	mHandleCounter(1),
-	mTotalIssuedRequests(0),
-	mTotalReceivedBits(0)
-{
-	mGlobalTimer.reset();
-}
-
-LLCurlTextureRequest::~LLCurlTextureRequest()
-{
-	mRequestMap.clear();
-
-	for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter)
-	{
-		delete *iter;
-	}
-	mCachedRequests.clear();
-}
-
-//return 0: success
-// > 0: cached handle
-U32 LLCurlTextureRequest::getByteRange(const std::string& url,
-								 const headers_t& headers,
-								 S32 offset, S32 length, U32 pri,
-								 LLCurl::ResponderPtr responder, F32 delay_time)
-{
-	U32 ret_val = 0;
-	bool success = false;	
-
-	if(mInQueue < mConcurrency && delay_time < 0.f)
-	{
-		success = LLCurlRequest::getByteRange(url, headers, offset, length, responder);		
-	}
-
-	LLMutexLock lock(&mMutex);
-
-	if(success)
-	{
-		mInQueue++;
-		mTotalIssuedRequests++;
-	}
-	else
-	{
-		request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder);
-		if(delay_time > 0.f)
-		{
-			request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time;
-		}
-
-		mCachedRequests.insert(request);
-		mRequestMap[mHandleCounter] = request;
-		ret_val = mHandleCounter;
-		mHandleCounter++;
-
-		if(!mHandleCounter)
-		{
-			mHandleCounter = 1;
-		}
-	}
-
-	return ret_val;
-}
-
-void LLCurlTextureRequest::completeRequest(S32 received_bytes)
-{
-	LLMutexLock lock(&mMutex);
-
-	llassert_always(mInQueue > 0);
-
-	mInQueue--;
-	mTotalReceivedBits += received_bytes * 8;
-}
-
-void LLCurlTextureRequest::nextRequests()
-{
-	if(mCachedRequests.empty() || mInQueue >= mConcurrency)
-	{
-		return;
-	}
-
-	F32 cur_time = mGlobalTimer.getElapsedTimeF32();
-
-	req_queue_t::iterator iter;	
-	{
-		LLMutexLock lock(&mMutex);
-		iter = mCachedRequests.begin();
-	}
-	while(1)
-	{
-		request_t* request = *iter;
-		if(request->mStartTime < cur_time)
-		{
-			if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder))
-			{
-				break;
-			}
-
-			LLMutexLock lock(&mMutex);
-			++iter;
-			mInQueue++;
-			mTotalIssuedRequests++;
-			mCachedRequests.erase(request);
-			mRequestMap.erase(request->mHandle);
-			delete request;
-
-			if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
-			{
-				break;
-			}
-		}
-		else
-		{
-			LLMutexLock lock(&mMutex);
-			++iter;
-			if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
-			{
-				break;
-			}
-		}
-	}
-
-	return;
-}
-
-void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri)
-{
-	if(!handle)
-	{
-		return;
-	}
-
-	LLMutexLock lock(&mMutex);
-
-	std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
-	if(iter != mRequestMap.end())
-	{
-		request_t* req = iter->second;
-		
-		if(req->mPriority != pri)
-		{
-			mCachedRequests.erase(req);
-			req->mPriority = pri;
-			mCachedRequests.insert(req);
-		}
-	}
-}
-
-void LLCurlTextureRequest::removeRequest(U32 handle)
-{
-	if(!handle)
-	{
-		return;
-	}
-
-	LLMutexLock lock(&mMutex);
-
-	std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
-	if(iter != mRequestMap.end())
-	{
-		request_t* req = iter->second;
-		mRequestMap.erase(iter);
-		mCachedRequests.erase(req);
-		delete req;
-	}
-}
-
-bool LLCurlTextureRequest::isWaiting(U32 handle)
-{
-	if(!handle)
-	{
-		return false;
-	}
-
-	LLMutexLock lock(&mMutex);
-	return mRequestMap.find(handle) != mRequestMap.end();
-}
-
-U32 LLCurlTextureRequest::getTotalReceivedBits()
-{
-	LLMutexLock lock(&mMutex);
-
-	U32 bits = mTotalReceivedBits;
-	mTotalReceivedBits = 0;
-	return bits;
-}
-
-U32 LLCurlTextureRequest::getTotalIssuedRequests()
-{
-	LLMutexLock lock(&mMutex);
-	return mTotalIssuedRequests;
-}
-
-S32 LLCurlTextureRequest::getNumRequests()
-{
-	LLMutexLock lock(&mMutex);
-	return mInQueue;
-}
+// LLCurlRequest::LLCurlRequest() :
+// 	mActiveMulti(NULL),
+// 	mActiveRequestCount(0)
+// {
+// 	mProcessing = FALSE;
+// }
+// 
+// LLCurlRequest::~LLCurlRequest()
+// {
+// 	//stop all Multi handle background threads
+// 	for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter)
+// 	{
+// 		LLCurl::getCurlThread()->killMulti(*iter) ;
+// 	}
+// 	mMultiSet.clear() ;
+// }
+// 
+// void LLCurlRequest::addMulti()
+// {
+// 	LLCurl::Multi* multi = new LLCurl::Multi();
+// 	if(!multi->isValid())
+// 	{
+// 		LLCurl::getCurlThread()->killMulti(multi) ;
+// 		mActiveMulti = NULL ;
+// 		mActiveRequestCount = 0 ;
+// 		return;
+// 	}
+// 	
+// 	mMultiSet.insert(multi);
+// 	mActiveMulti = multi;
+// 	mActiveRequestCount = 0;
+// }
+// 
+// LLCurl::Easy* LLCurlRequest::allocEasy()
+// {
+// 	if (!mActiveMulti ||
+// 		mActiveRequestCount	>= MAX_ACTIVE_REQUEST_COUNT ||
+// 		mActiveMulti->mErrorCount > 0)
+// 	{
+// 		addMulti();
+// 	}
+// 	if(!mActiveMulti)
+// 	{
+// 		return NULL ;
+// 	}
+// 
+// 	//llassert_always(mActiveMulti);
+// 	++mActiveRequestCount;
+// 	LLCurl::Easy* easy = mActiveMulti->allocEasy();
+// 	return easy;
+// }
+// 
+// bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
+// {
+// 	llassert_always(mActiveMulti);
+// 	
+// 	if (mProcessing)
+// 	{
+// 		LL_ERRS() << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << LL_ENDL;
+// 	}
+// 	bool res = mActiveMulti->addEasy(easy);
+// 	return res;
+// }
+// 
+// void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
+// {
+// 	getByteRange(url, headers_t(), 0, -1, responder);
+// }
+// 
+// // Note: (length==0) is interpreted as "the rest of the file", i.e. the whole file if (offset==0) or
+// // the remainder of the file if not.
+// bool LLCurlRequest::getByteRange(const std::string& url,
+// 								 const headers_t& headers,
+// 								 S32 offset, S32 length,
+// 								 LLCurl::ResponderPtr responder)
+// {
+// 	llassert(LLCurl::sNotQuitting);
+// 	LLCurl::Easy* easy = allocEasy();
+// 	if (!easy)
+// 	{
+// 		return false;
+// 	}
+// 	easy->prepRequest(url, headers, responder);
+// 	easy->setopt(CURLOPT_HTTPGET, 1);
+// 	if (length > 0)
+// 	{
+// 		std::string range = llformat("bytes=%d-%d", offset,offset+length-1);
+// 		easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
+// 	}
+// 	else if (offset > 0)
+// 	{
+// 		std::string range = llformat("bytes=%d-", offset);
+// 		easy->slist_append(HTTP_OUT_HEADER_RANGE, range);
+// 	}
+// 	easy->setHeaders();
+// 	bool res = addEasy(easy);
+// 	return res;
+// }
+// 
+// bool LLCurlRequest::post(const std::string& url,
+// 						 const headers_t& headers,
+// 						 const LLSD& data,
+// 						 LLCurl::ResponderPtr responder, S32 time_out)
+// {
+// 	llassert(LLCurl::sNotQuitting);
+// 	LLCurl::Easy* easy = allocEasy();
+// 	if (!easy)
+// 	{
+// 		return false;
+// 	}
+// 	easy->prepRequest(url, headers, responder, time_out);
+// 
+// 	LLSDSerialize::toXML(data, easy->getInput());
+// 	S32 bytes = easy->getInput().str().length();
+// 	
+// 	easy->setopt(CURLOPT_POST, 1);
+// 	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
+// 	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
+// 
+// 	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);
+// 	easy->setHeaders();
+// 
+// 	LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
+// 	bool res = addEasy(easy);
+// 	return res;
+// }
+// 
+// bool LLCurlRequest::post(const std::string& url,
+// 						 const headers_t& headers,
+// 						 const std::string& data,
+// 						 LLCurl::ResponderPtr responder, S32 time_out)
+// {
+// 	llassert(LLCurl::sNotQuitting);
+// 	LLCurl::Easy* easy = allocEasy();
+// 	if (!easy)
+// 	{
+// 		return false;
+// 	}
+// 	easy->prepRequest(url, headers, responder, time_out);
+// 
+// 	easy->getInput().write(data.data(), data.size());
+// 	S32 bytes = easy->getInput().str().length();
+// 	
+// 	easy->setopt(CURLOPT_POST, 1);
+// 	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
+// 	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
+// 
+// 	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM);
+// 	easy->setHeaders();
+// 
+// 	LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL;
+// 	bool res = addEasy(easy);
+// 	return res;
+// }
+// 
+// // Note: call once per frame
+// S32 LLCurlRequest::process()
+// {
+// 	S32 res = 0;
+// 
+// 	mProcessing = TRUE;
+// 	for (curlmulti_set_t::iterator iter = mMultiSet.begin();
+// 		 iter != mMultiSet.end(); )
+// 	{
+// 		curlmulti_set_t::iterator curiter = iter++;
+// 		LLCurl::Multi* multi = *curiter;
+// 
+// 		if(!multi->isValid())
+// 		{
+// 			if(multi == mActiveMulti)
+// 			{				
+// 				mActiveMulti = NULL ;
+// 				mActiveRequestCount = 0 ;
+// 			}
+// 			mMultiSet.erase(curiter) ;
+// 			LLCurl::getCurlThread()->killMulti(multi) ;
+// 			continue ;
+// 		}
+// 
+// 		S32 tres = multi->process();
+// 		res += tres;
+// 		if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
+// 		{
+// 			mMultiSet.erase(curiter);
+// 			LLCurl::getCurlThread()->killMulti(multi);
+// 		}
+// 	}
+// 	mProcessing = FALSE;
+// 	return res;
+// }
+// 
+// S32 LLCurlRequest::getQueued()
+// {
+// 	S32 queued = 0;
+// 	for (curlmulti_set_t::iterator iter = mMultiSet.begin();
+// 		 iter != mMultiSet.end(); )
+// 	{
+// 		curlmulti_set_t::iterator curiter = iter++;
+// 		LLCurl::Multi* multi = *curiter;
+// 		
+// 		if(!multi->isValid())
+// 		{
+// 			if(multi == mActiveMulti)
+// 			{				
+// 				mActiveMulti = NULL ;
+// 				mActiveRequestCount = 0 ;
+// 			}
+// 			LLCurl::getCurlThread()->killMulti(multi);
+// 			mMultiSet.erase(curiter) ;
+// 			continue ;
+// 		}
+// 
+// 		queued += multi->mQueued;
+// 		if (multi->getState() != LLCurl::Multi::STATE_READY)
+// 		{
+// 			++queued;
+// 		}
+// 	}
+// 	return queued;
+// }
+
+// LLCurlTextureRequest::LLCurlTextureRequest(S32 concurrency) : 
+// 	LLCurlRequest(), 
+// 	mConcurrency(concurrency),
+// 	mInQueue(0),
+// 	mMutex(NULL),
+// 	mHandleCounter(1),
+// 	mTotalIssuedRequests(0),
+// 	mTotalReceivedBits(0)
+// {
+// 	mGlobalTimer.reset();
+// }
+// 
+// LLCurlTextureRequest::~LLCurlTextureRequest()
+// {
+// 	mRequestMap.clear();
+// 
+// 	for(req_queue_t::iterator iter = mCachedRequests.begin(); iter != mCachedRequests.end(); ++iter)
+// 	{
+// 		delete *iter;
+// 	}
+// 	mCachedRequests.clear();
+// }
+// 
+// //return 0: success
+// // > 0: cached handle
+// U32 LLCurlTextureRequest::getByteRange(const std::string& url,
+// 								 const headers_t& headers,
+// 								 S32 offset, S32 length, U32 pri,
+// 								 LLCurl::ResponderPtr responder, F32 delay_time)
+// {
+// 	U32 ret_val = 0;
+// 	bool success = false;	
+// 
+// 	if(mInQueue < mConcurrency && delay_time < 0.f)
+// 	{
+// 		success = LLCurlRequest::getByteRange(url, headers, offset, length, responder);		
+// 	}
+// 
+// 	LLMutexLock lock(&mMutex);
+// 
+// 	if(success)
+// 	{
+// 		mInQueue++;
+// 		mTotalIssuedRequests++;
+// 	}
+// 	else
+// 	{
+// 		request_t* request = new request_t(mHandleCounter, url, headers, offset, length, pri, responder);
+// 		if(delay_time > 0.f)
+// 		{
+// 			request->mStartTime = mGlobalTimer.getElapsedTimeF32() + delay_time;
+// 		}
+// 
+// 		mCachedRequests.insert(request);
+// 		mRequestMap[mHandleCounter] = request;
+// 		ret_val = mHandleCounter;
+// 		mHandleCounter++;
+// 
+// 		if(!mHandleCounter)
+// 		{
+// 			mHandleCounter = 1;
+// 		}
+// 	}
+// 
+// 	return ret_val;
+// }
+// 
+// void LLCurlTextureRequest::completeRequest(S32 received_bytes)
+// {
+// 	LLMutexLock lock(&mMutex);
+// 
+// 	llassert_always(mInQueue > 0);
+// 
+// 	mInQueue--;
+// 	mTotalReceivedBits += received_bytes * 8;
+// }
+// 
+// void LLCurlTextureRequest::nextRequests()
+// {
+// 	if(mCachedRequests.empty() || mInQueue >= mConcurrency)
+// 	{
+// 		return;
+// 	}
+// 
+// 	F32 cur_time = mGlobalTimer.getElapsedTimeF32();
+// 
+// 	req_queue_t::iterator iter;	
+// 	{
+// 		LLMutexLock lock(&mMutex);
+// 		iter = mCachedRequests.begin();
+// 	}
+// 	while(1)
+// 	{
+// 		request_t* request = *iter;
+// 		if(request->mStartTime < cur_time)
+// 		{
+// 			if(!LLCurlRequest::getByteRange(request->mUrl, request->mHeaders, request->mOffset, request->mLength, request->mResponder))
+// 			{
+// 				break;
+// 			}
+// 
+// 			LLMutexLock lock(&mMutex);
+// 			++iter;
+// 			mInQueue++;
+// 			mTotalIssuedRequests++;
+// 			mCachedRequests.erase(request);
+// 			mRequestMap.erase(request->mHandle);
+// 			delete request;
+// 
+// 			if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
+// 			{
+// 				break;
+// 			}
+// 		}
+// 		else
+// 		{
+// 			LLMutexLock lock(&mMutex);
+// 			++iter;
+// 			if(iter == mCachedRequests.end() || mInQueue >= mConcurrency)
+// 			{
+// 				break;
+// 			}
+// 		}
+// 	}
+// 
+// 	return;
+// }
+// 
+// void LLCurlTextureRequest::updatePriority(U32 handle, U32 pri)
+// {
+// 	if(!handle)
+// 	{
+// 		return;
+// 	}
+// 
+// 	LLMutexLock lock(&mMutex);
+// 
+// 	std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
+// 	if(iter != mRequestMap.end())
+// 	{
+// 		request_t* req = iter->second;
+// 		
+// 		if(req->mPriority != pri)
+// 		{
+// 			mCachedRequests.erase(req);
+// 			req->mPriority = pri;
+// 			mCachedRequests.insert(req);
+// 		}
+// 	}
+// }
+// 
+// void LLCurlTextureRequest::removeRequest(U32 handle)
+// {
+// 	if(!handle)
+// 	{
+// 		return;
+// 	}
+// 
+// 	LLMutexLock lock(&mMutex);
+// 
+// 	std::map<S32, request_t*>::iterator iter = mRequestMap.find(handle);
+// 	if(iter != mRequestMap.end())
+// 	{
+// 		request_t* req = iter->second;
+// 		mRequestMap.erase(iter);
+// 		mCachedRequests.erase(req);
+// 		delete req;
+// 	}
+// }
+// 
+// bool LLCurlTextureRequest::isWaiting(U32 handle)
+// {
+// 	if(!handle)
+// 	{
+// 		return false;
+// 	}
+// 
+// 	LLMutexLock lock(&mMutex);
+// 	return mRequestMap.find(handle) != mRequestMap.end();
+// }
+// 
+// U32 LLCurlTextureRequest::getTotalReceivedBits()
+// {
+// 	LLMutexLock lock(&mMutex);
+// 
+// 	U32 bits = mTotalReceivedBits;
+// 	mTotalReceivedBits = 0;
+// 	return bits;
+// }
+// 
+// U32 LLCurlTextureRequest::getTotalIssuedRequests()
+// {
+// 	LLMutexLock lock(&mMutex);
+// 	return mTotalIssuedRequests;
+// }
+// 
+// S32 LLCurlTextureRequest::getNumRequests()
+// {
+// 	LLMutexLock lock(&mMutex);
+// 	return mInQueue;
+// }
 
 ////////////////////////////////////////////////////////////////////////////
 // For generating one easy request
@@ -1988,10 +1990,10 @@ void LLCurlFF::check_easy_code(CURLcode code)
 {
 	check_curl_code(code);
 }
-void LLCurlFF::check_multi_code(CURLMcode code)
-{
-	check_curl_multi_code(code);
-}
+// void LLCurlFF::check_multi_code(CURLMcode code)
+// {
+// 	check_curl_multi_code(code);
+// }
 
 
 // Static
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index 385d9fffa89..295e9c9fe5f 100755
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -309,6 +309,7 @@ class LLCurl::Easy
 	static void deleteAllFreeHandles();
 };
 
+#if 1
 class LLCurl::Multi
 {
 	LOG_CLASS(Multi);
@@ -379,6 +380,7 @@ class LLCurl::Multi
 	LLFrameTimer mIdleTimer ;
 	F32 mIdleTimeOut;
 };
+#endif
 
 class LLCurlThread : public LLQueuedThread
 {
@@ -417,7 +419,7 @@ class LLCurlThread : public LLQueuedThread
 	void cleanupMulti(LLCurl::Multi* multi) ;
 } ;
 
-
+#if 0
 class LLCurlRequest
 {
 public:
@@ -446,7 +448,9 @@ class LLCurlRequest
 	S32 mActiveRequestCount;
 	BOOL mProcessing;
 };
+#endif
 
+#if 0
 //for texture fetch only
 class LLCurlTextureRequest : public LLCurlRequest
 {
@@ -511,6 +515,7 @@ class LLCurlTextureRequest : public LLCurlRequest
 
 	LLFrameTimer mGlobalTimer;
 };
+#endif 
 
 class LLCurlEasyRequest
 {
@@ -550,7 +555,7 @@ class LLCurlEasyRequest
 namespace LLCurlFF
 {
 	void check_easy_code(CURLcode code);
-	void check_multi_code(CURLMcode code);
+	//void check_multi_code(CURLMcode code);
 }
 
 #endif // LL_LLCURL_H
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index 200116337d9..27c94b11824 100755
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -38,6 +38,10 @@
 #include "lluri.h"
 
 #include "message.h"
+#include "httpcommon.h"
+#include "httprequest.h"
+#include "httpoptions.h"
+
 #include <curl/curl.h>
 
 
@@ -214,6 +218,51 @@ void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback cal
 	LLHTTPClient::mCertVerifyCallback = callback;
 }
 
+#if 0
+typedef std::shared_ptr<LLCore::HttpRequest> HttpRequestPtr_t;
+typedef std::unique_ptr<LLCore::HttpOptions> HttpOptionsPtr_t;
+typedef std::unique_ptr<Injector> InjectorPtr_t;
+
+static void request_(
+	const std::string& url,
+	EHTTPMethod method,
+	Injector* body_injector,
+	LLCurl::ResponderPtr responder,
+	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
+	const LLSD& headers = LLSD(),
+	bool follow_redirects = true
+	)
+{
+	HttpRequestPtr_t httpReq = HttpRequestPtr_t(new LLCore::HttpRequest());
+
+	HttpOptionsPtr_t httpOpts = HttpOptionsPtr_t(new LLCore::HttpOptions());
+
+	httpOpts->setFollowRedirects(follow_redirects);
+	httpOpts->setRetries(12);
+	httpOpts->setUseRetryAfter(true);
+	// for the moment lets just truncate.  60 seconds vs 60.5 seconds 
+	httpOpts->setTransferTimeout((unsigned int)timeout); 
+
+	switch (method)
+	{
+	case HTTP_GET:
+		httpReq->requestGet(0, 0, url, httpOpts.get(), headers, handler);
+		break;
+	case HTTP_HEAD:
+		httpReq->requestHead(0, 0, url, httpOpts.get(), headers, handler);
+		break;
+	case HTTP_PUT:
+		httpReq->requestPut(0, 0, url, );
+		break;
+	case HTTP_POST:
+		httpReq->requestPost(0, 0, url, null, httpOpts.get(), headers, handler);
+		break;
+	}
+
+
+}
+#endif 
+
 static void request(
 	const std::string& url,
 	EHTTPMethod method,
diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp
index b56a804f942..8c2a0ad9cf2 100755
--- a/indra/llmessage/llhttpclientadapter.cpp
+++ b/indra/llmessage/llhttpclientadapter.cpp
@@ -26,48 +26,48 @@
 
 #include "llhttpclientadapter.h"
 #include "llhttpclient.h"
-
-LLHTTPClientAdapter::~LLHTTPClientAdapter() 
-{
-}
-
-void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder) 
-{
-	LLSD empty_pragma_header;
-	// Pragma is required to stop curl adding "no-cache"
-	// Space is required to stop llurlrequest from turning off proxying
-	empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " "; 
-	LLHTTPClient::get(url, responder, empty_pragma_header);
-}
-
-void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) 
-{
-	LLSD empty_pragma_header = headers;
-	if (!empty_pragma_header.has(HTTP_OUT_HEADER_PRAGMA))
-	{
-		// as above
-		empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";
-	}
-	LLHTTPClient::get(url, responder, empty_pragma_header);
-}
-
-void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) 
-{
-	LLHTTPClient::put(url, body, responder);
-}
-
-void LLHTTPClientAdapter::put(
-		const std::string& url,
-		const LLSD& body,
-		LLCurl::ResponderPtr responder,
-		const LLSD& headers)
-{
-	LLHTTPClient::put(url, body, responder, headers);
-}
-
-void LLHTTPClientAdapter::del(
-	const std::string& url,
-	LLCurl::ResponderPtr responder)
-{
-	LLHTTPClient::del(url, responder);
-}
+// 
+// LLHTTPClientAdapter::~LLHTTPClientAdapter() 
+// {
+// }
+// 
+// void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder) 
+// {
+// 	LLSD empty_pragma_header;
+// 	// Pragma is required to stop curl adding "no-cache"
+// 	// Space is required to stop llurlrequest from turning off proxying
+// 	empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " "; 
+// 	LLHTTPClient::get(url, responder, empty_pragma_header);
+// }
+// 
+// void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) 
+// {
+// 	LLSD empty_pragma_header = headers;
+// 	if (!empty_pragma_header.has(HTTP_OUT_HEADER_PRAGMA))
+// 	{
+// 		// as above
+// 		empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";
+// 	}
+// 	LLHTTPClient::get(url, responder, empty_pragma_header);
+// }
+// 
+// void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) 
+// {
+// 	LLHTTPClient::put(url, body, responder);
+// }
+// 
+// void LLHTTPClientAdapter::put(
+// 		const std::string& url,
+// 		const LLSD& body,
+// 		LLCurl::ResponderPtr responder,
+// 		const LLSD& headers)
+// {
+// 	LLHTTPClient::put(url, body, responder, headers);
+// }
+// 
+// void LLHTTPClientAdapter::del(
+// 	const std::string& url,
+// 	LLCurl::ResponderPtr responder)
+// {
+// 	LLHTTPClient::del(url, responder);
+// }
diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h
index 270282c66fb..0067703895b 100755
--- a/indra/llmessage/llhttpclientadapter.h
+++ b/indra/llmessage/llhttpclientadapter.h
@@ -30,6 +30,7 @@
 #include "llhttpclientinterface.h"
 #include "llsingleton.h"	// LLSingleton<>
 
+/*
 class LLHTTPClientAdapter : public LLHTTPClientInterface, public LLSingleton<LLHTTPClientAdapter>
 {
 public:
@@ -46,6 +47,7 @@ class LLHTTPClientAdapter : public LLHTTPClientInterface, public LLSingleton<LLH
 		const std::string& url,
 		LLCurl::ResponderPtr responder);
 };
+*/
 
 #endif
 
diff --git a/indra/llmessage/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h
index 12a3857a61d..9c1c8e7c113 100755
--- a/indra/llmessage/llhttpclientinterface.h
+++ b/indra/llmessage/llhttpclientinterface.h
@@ -32,14 +32,14 @@
 
 #include <string>
 
-class LLHTTPClientInterface
-{
-public:
-	virtual ~LLHTTPClientInterface() {}
-	virtual void get(const std::string& url, LLCurl::ResponderPtr responder) = 0;
-	virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) = 0;
-	virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) = 0;
-};
+// class LLHTTPClientInterface
+// {
+// public:
+// 	virtual ~LLHTTPClientInterface() {}
+// 	virtual void get(const std::string& url, LLCurl::ResponderPtr responder) = 0;
+// 	virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers) = 0;
+// 	virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder) = 0;
+// };
 
 #endif // LL_LLHTTPCLIENTINTERFACE_H
 
diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h
index c4e0333ca32..d097ecdff71 100755
--- a/indra/llmessage/llsdrpcclient.h
+++ b/indra/llmessage/llsdrpcclient.h
@@ -37,7 +37,9 @@
 #include "llchainio.h"
 #include "llfiltersd2xmlrpc.h"
 #include "lliopipe.h"
-#include "llurlrequest.h"
+#if 0
+//#include "llurlrequest.h"
+#endif
 
 /** 
  * @class LLSDRPCClientResponse
@@ -218,6 +220,7 @@ class LLSDRPCClient : public LLIOPipe
 	LLIOPipe::ptr_t mResponse;
 };
 
+#if 0
 /** 
  * @class LLSDRPCClientFactory
  * @brief Basic implementation for making an SD RPC client factory
@@ -267,7 +270,9 @@ class LLSDRPCClientFactory : public LLChainIOFactory
 protected:
 	std::string mURL;
 };
+#endif
 
+#if 0
 /** 
  * @class LLXMLSDRPCClientFactory
  * @brief Basic implementation for making an XMLRPC to SD RPC client factory
@@ -319,5 +324,6 @@ class LLXMLSDRPCClientFactory : public LLChainIOFactory
 protected:
 	std::string mURL;
 };
+#endif
 
 #endif // LL_LLSDRPCCLIENT_H
diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp
index f5f224b83ed..dd39b9a9593 100755
--- a/indra/newview/llappcorehttp.cpp
+++ b/indra/newview/llappcorehttp.cpp
@@ -31,6 +31,10 @@
 #include "llappviewer.h"
 #include "llviewercontrol.h"
 
+#include <openssl/x509_vfy.h>
+#include <openssl/ssl.h>
+#include "llsecapi.h"
+#include <curl/curl.h>
 
 // Here is where we begin to get our connection usage under control.
 // This establishes llcorehttp policy classes that, among other
@@ -151,6 +155,15 @@ void LLAppCoreHttp::init()
 						 << LL_ENDL;
 	}
 
+	// Set up SSL Verification call back.
+	status = LLCore::HttpRequest::setStaticPolicyOption(LLCore::HttpRequest::PO_SSL_VERIFY_CALLBACK,
+														LLCore::HttpRequest::GLOBAL_POLICY_ID,
+														sslVerify, NULL);
+	if (!status)
+	{
+		LL_WARNS("Init") << "Failed to set SSL Verification.  Reason:  " << status.toString() << LL_ENDL;
+	}
+
 	// Tracing levels for library & libcurl (note that 2 & 3 are beyond spammy):
 	// 0 - None
 	// 1 - Basic start, stop simple transitions
@@ -457,6 +470,62 @@ void LLAppCoreHttp::refreshSettings(bool initial)
 	}
 }
 
+LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url, 
+	LLCore::HttpHandler const * const handler, void *appdata)
+{
+	X509_STORE_CTX *ctx = static_cast<X509_STORE_CTX *>(appdata);
+	LLCore::HttpStatus result;
+	LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");
+	LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
+	LLSD validation_params = LLSD::emptyMap();
+	LLURI uri(url);
+
+	validation_params[CERT_HOSTNAME] = uri.hostName();
+
+	// *TODO*: In the case of an exception while validating the cert, we need a way
+	// to pass the offending(?) cert back out. *Rider*
+
+	try
+	{
+		// don't validate hostname.  Let libcurl do it instead.  That way, it'll handle redirects
+		store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
+	}
+	catch (LLCertValidationTrustException &cert_exception)
+	{
+		// this exception is is handled differently than the general cert
+		// exceptions, as we allow the user to actually add the certificate
+		// for trust.
+		// therefore we pass back a different error code
+		// NOTE: We're currently 'wired' to pass around CURL error codes.  This is
+		// somewhat clumsy, as we may run into errors that do not map directly to curl
+		// error codes.  Should be refactored with login refactoring, perhaps.
+		result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CACERT);
+		result.setMessage(cert_exception.getMessage());
+		LLPointer<LLCertificate> cert = cert_exception.getCert();
+		cert->ref(); // adding an extra ref here
+		result.setErrorData(cert.get());
+		// We should probably have a more generic way of passing information
+		// back to the error handlers.
+	}
+	catch (LLCertException &cert_exception)
+	{
+		result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_PEER_CERTIFICATE);
+		result.setMessage(cert_exception.getMessage());
+		LLPointer<LLCertificate> cert = cert_exception.getCert();
+		cert->ref(); // adding an extra ref here
+		result.setErrorData(cert.get());
+	}
+	catch (...)
+	{
+		// any other odd error, we just handle as a connect error.
+		result = LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_SSL_CONNECT_ERROR);
+	}
+
+	return result;
+}
+
+
+
 
 void LLAppCoreHttp::onCompleted(LLCore::HttpHandle, LLCore::HttpResponse *)
 {
diff --git a/indra/newview/llappcorehttp.h b/indra/newview/llappcorehttp.h
index 37d7a737e77..96163540939 100755
--- a/indra/newview/llappcorehttp.h
+++ b/indra/newview/llappcorehttp.h
@@ -233,7 +233,9 @@ class LLAppCoreHttp : public LLCore::HttpHandler
 	bool						mStopped;
 	HttpClass					mHttpClasses[AP_COUNT];
 	bool						mPipelined;				// Global setting
-	boost::signals2::connection mPipelinedSignal;		// Signal for 'HttpPipelining' setting
+	boost::signals2::connection	mPipelinedSignal;		// Signal for 'HttpPipelining' setting
+
+	static LLCore::HttpStatus	sslVerify(const std::string &uri, LLCore::HttpHandler const * const handler, void *appdata);
 };
 
 
diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp
index 2d4ce6c883a..530eb685fa3 100755
--- a/indra/newview/llhttpretrypolicy.cpp
+++ b/indra/newview/llhttpretrypolicy.cpp
@@ -87,7 +87,7 @@ void LLAdaptiveRetryPolicy::onFailure(const LLCore::HttpResponse *response)
 	F32 retry_header_time;
 	const LLCore::HttpHeaders *headers = response->getHeaders();
 	bool has_retry_header_time = getRetryAfter(headers,retry_header_time);
-	onFailureCommon(response->getStatus().mType, has_retry_header_time, retry_header_time);
+	onFailureCommon(response->getStatus().getType(), has_retry_header_time, retry_header_time);
 }
 
 void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time)
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index aa440c06a6e..4f080574778 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -2294,7 +2294,6 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
 	if (!caps_url.empty())
 	{
 		gPendingMetricsUploads++;
-		LLCurlRequest::headers_t headers;
 		LLHTTPClient::post(caps_url,
 						   msg,
 						   new ViewerAppearanceChangeMetricsResponder(report_sequence,
diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp
index c12c2cc24c3..e4e63afa163 100755
--- a/indra/newview/llxmlrpctransaction.cpp
+++ b/indra/newview/llxmlrpctransaction.cpp
@@ -35,6 +35,11 @@
 #include "llxmlrpclistener.h"
 
 #include "llcurl.h"
+#include "httpcommon.h"
+#include "httprequest.h"
+#include "httpoptions.h"
+#include "httpheaders.h"
+#include "bufferarray.h"
 #include "llviewercontrol.h"
 
 // Have to include these last to avoid queue redefinition!
@@ -155,55 +160,159 @@ XMLRPC_VALUE LLXMLRPCValue::getValue() const
 }
 
 
+class LLXMLRPCTransaction::Handler : public LLCore::HttpHandler
+{
+public: 
+	Handler(LLCore::HttpRequest::ptr_t &request, LLXMLRPCTransaction::Impl *impl);
+	virtual ~Handler();
+
+	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response);
+
+	typedef std::unique_ptr<LLXMLRPCTransaction::Handler> ptr_t;
+
+private:
+
+	LLXMLRPCTransaction::Impl *mImpl;
+	LLCore::HttpRequest::ptr_t mRequest;
+};
+
 class LLXMLRPCTransaction::Impl
 {
 public:
 	typedef LLXMLRPCTransaction::EStatus	EStatus;
 
-	LLCurlEasyRequest* mCurlRequest;
+	LLCore::HttpRequest::ptr_t	mHttpRequest;
+
+
+	EStatus				mStatus;
+	CURLcode			mCurlCode;
+	std::string			mStatusMessage;
+	std::string			mStatusURI;
+	LLCore::HttpResponse::TransferStats::ptr_t	mTransferStats;
+	Handler::ptr_t		mHandler;
+	LLCore::HttpHandle	mPostH;
 
-	EStatus		mStatus;
-	CURLcode	mCurlCode;
-	std::string	mStatusMessage;
-	std::string	mStatusURI;
-	LLCurl::TransferInfo mTransferInfo;
-	
 	std::string			mURI;
-	char*				mRequestText;
-	int					mRequestTextSize;
-	
+
 	std::string			mProxyAddress;
 
 	std::string			mResponseText;
 	XMLRPC_REQUEST		mResponse;
 	std::string         mCertStore;
 	LLPointer<LLCertificate> mErrorCert;
-	
+
 	Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip);
 	Impl(const std::string& uri,
-		 const std::string& method, LLXMLRPCValue params, bool useGzip);
+		const std::string& method, LLXMLRPCValue params, bool useGzip);
 	~Impl();
-	
+
 	bool process();
-	
-	void setStatus(EStatus code,
-				   const std::string& message = "", const std::string& uri = "");
-	void setCurlStatus(CURLcode);
+
+	void setStatus(EStatus code, const std::string& message = "", const std::string& uri = "");
+	void setHttpStatus(const LLCore::HttpStatus &status);
 
 private:
 	void init(XMLRPC_REQUEST request, bool useGzip);
-	static int _sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param);
-	static CURLcode _sslCtxFunction(CURL * curl, void *sslctx, void *param);
-	static size_t curlDownloadCallback(
-		char* data, size_t size, size_t nmemb, void* user_data);
 };
 
+LLXMLRPCTransaction::Handler::Handler(LLCore::HttpRequest::ptr_t &request, 
+		LLXMLRPCTransaction::Impl *impl) :
+	mImpl(impl),
+	mRequest(request)
+{
+}
+
+LLXMLRPCTransaction::Handler::~Handler()
+{
+}
+
+void LLXMLRPCTransaction::Handler::onCompleted(LLCore::HttpHandle handle, 
+	LLCore::HttpResponse * response)
+{
+	LLCore::HttpStatus status = response->getStatus();
+
+	if (!status)
+	{
+		if ((status.toULong() != CURLE_SSL_PEER_CERTIFICATE) &&
+			(status.toULong() != CURLE_SSL_CACERT))
+		{
+			// if we have a curl error that's not already been handled
+			// (a non cert error), then generate the error message as
+			// appropriate
+			mImpl->setHttpStatus(status);
+			LLCertificate *errordata = static_cast<LLCertificate *>(status.getErrorData());
+
+			if (errordata)
+			{
+				mImpl->mErrorCert = LLPointer<LLCertificate>(errordata);
+				status.setErrorData(NULL);
+				errordata->unref();
+			}
+
+			LL_WARNS() << "LLXMLRPCTransaction error "
+				<< status.toHex() << ": " << status.toString() << LL_ENDL;
+			LL_WARNS() << "LLXMLRPCTransaction request URI: "
+				<< mImpl->mURI << LL_ENDL;
+		}
+
+		return;
+	}
+
+	mImpl->setStatus(LLXMLRPCTransaction::StatusComplete);
+	mImpl->mTransferStats = response->getTransferStats();
+
+	// the contents of a buffer array are potentially noncontiguous, so we
+	// will need to copy them into an contiguous block of memory for XMLRPC.
+	LLCore::BufferArray *body = response->getBody();
+	char * bodydata = new char[body->size()];
+
+	body->read(0, bodydata, body->size());
+
+	mImpl->mResponse = XMLRPC_REQUEST_FromXML(bodydata, body->size(), 0);
+
+	delete[] bodydata;
+
+	bool		hasError = false;
+	bool		hasFault = false;
+	int			faultCode = 0;
+	std::string	faultString;
+
+	LLXMLRPCValue error(XMLRPC_RequestGetError(mImpl->mResponse));
+	if (error.isValid())
+	{
+		hasError = true;
+		faultCode = error["faultCode"].asInt();
+		faultString = error["faultString"].asString();
+	}
+	else if (XMLRPC_ResponseIsFault(mImpl->mResponse))
+	{
+		hasFault = true;
+		faultCode = XMLRPC_GetResponseFaultCode(mImpl->mResponse);
+		faultString = XMLRPC_GetResponseFaultString(mImpl->mResponse);
+	}
+
+	if (hasError || hasFault)
+	{
+		mImpl->setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
+
+		LL_WARNS() << "LLXMLRPCTransaction XMLRPC "
+			<< (hasError ? "error " : "fault ")
+			<< faultCode << ": "
+			<< faultString << LL_ENDL;
+		LL_WARNS() << "LLXMLRPCTransaction request URI: "
+			<< mImpl->mURI << LL_ENDL;
+	}
+
+}
+
+//=========================================================================
+
 LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
 		XMLRPC_REQUEST request, bool useGzip)
-	: mCurlRequest(0),
+	: mHttpRequest(0),
 	  mStatus(LLXMLRPCTransaction::StatusNotStarted),
 	  mURI(uri),
-	  mRequestText(0), 
+//	  mRequestText(0), 
 	  mResponse(0)
 {
 	init(request, useGzip);
@@ -212,10 +321,10 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
 
 LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
 		const std::string& method, LLXMLRPCValue params, bool useGzip)
-	: mCurlRequest(0),
+	: mHttpRequest(0),
 	  mStatus(LLXMLRPCTransaction::StatusNotStarted),
 	  mURI(uri),
-	  mRequestText(0), 
+//	  mRequestText(0), 
 	  mResponse(0)
 {
 	XMLRPC_REQUEST request = XMLRPC_RequestNew();
@@ -231,127 +340,53 @@ LLXMLRPCTransaction::Impl::Impl(const std::string& uri,
     XMLRPC_RequestFree(request, 1);
 }
 
-// _sslCertVerifyCallback
-// callback called when a cert verification is requested.
-// calls SECAPI to validate the context
-int LLXMLRPCTransaction::Impl::_sslCertVerifyCallback(X509_STORE_CTX *ctx, void *param)
+void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
 {
-	LLXMLRPCTransaction::Impl *transaction = (LLXMLRPCTransaction::Impl *)param;
-	LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(transaction->mCertStore);
-	LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
-	LLSD validation_params = LLSD::emptyMap();
-	LLURI uri(transaction->mURI);
-	validation_params[CERT_HOSTNAME] = uri.hostName();
-	try
-	{
-		// don't validate hostname.  Let libcurl do it instead.  That way, it'll handle redirects
-		store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
-	}
-	catch (LLCertValidationTrustException& cert_exception)
-	{
-		// this exception is is handled differently than the general cert
-		// exceptions, as we allow the user to actually add the certificate
-		// for trust.
-		// therefore we pass back a different error code
-		// NOTE: We're currently 'wired' to pass around CURL error codes.  This is
-		// somewhat clumsy, as we may run into errors that do not map directly to curl
-		// error codes.  Should be refactored with login refactoring, perhaps.
-		transaction->mCurlCode = CURLE_SSL_CACERT;
-		// set the status directly.  set curl status generates error messages and we want
-		// to use the fixed ones from the exceptions
-		transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string());
-		// We should probably have a more generic way of passing information
-		// back to the error handlers.
-		transaction->mErrorCert = cert_exception.getCert();
-		return 0;		
-	}
-	catch (LLCertException& cert_exception)
-	{
-		transaction->mCurlCode = CURLE_SSL_PEER_CERTIFICATE;
-		// set the status directly.  set curl status generates error messages and we want
-		// to use the fixed ones from the exceptions
-		transaction->setStatus(StatusCURLError, cert_exception.getMessage(), std::string());
-		transaction->mErrorCert = cert_exception.getCert();
-		return 0;
-	}
-	catch (...)
-	{
-		// any other odd error, we just handle as a connect error.
-		transaction->mCurlCode = CURLE_SSL_CONNECT_ERROR;
-		transaction->setCurlStatus(CURLE_SSL_CONNECT_ERROR);
-		return 0;
-	}
-	return 1;
-}
+	LLCore::HttpOptions::ptr_t httpOpts;
+	LLCore::HttpHeaders::ptr_t httpHeaders;
 
-// _sslCtxFunction
-// Callback function called when an SSL Context is created via CURL
-// used to configure the context for custom cert validate(<, <#const & xs#>, <#T * #>, <#long #>)tion
-// based on SECAPI
-
-CURLcode LLXMLRPCTransaction::Impl::_sslCtxFunction(CURL * curl, void *sslctx, void *param)
-{
-	SSL_CTX * ctx = (SSL_CTX *) sslctx;
-	// disable any default verification for server certs
-	SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
-	// set the verification callback.
-	SSL_CTX_set_cert_verify_callback(ctx, _sslCertVerifyCallback, param);
-	// the calls are void
-	return CURLE_OK;
-	
-}
 
-void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip)
-{
-	if (!mCurlRequest)
+	if (!mHttpRequest)
 	{
-		mCurlRequest = new LLCurlEasyRequest();
+		mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);
 	}
-	if(!mCurlRequest->isValid())
-	{
-		LL_WARNS() << "mCurlRequest is invalid." << LL_ENDL ;
 
-		delete mCurlRequest ;
-		mCurlRequest = NULL ;
-		return ;
-	}
+	// LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
+	httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false); 
 
-	mErrorCert = NULL;
+	httpOpts->setTimeout(40L);
 
-//	mCurlRequest->setopt(CURLOPT_VERBOSE, 1); // useful for debugging
-	mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
-	mCurlRequest->setWriteCallback(&curlDownloadCallback, (void*)this);
-	BOOL vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
+	bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert");
 	mCertStore = gSavedSettings.getString("CertStore");
-	mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, vefifySSLCert);
-	mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, vefifySSLCert ? 2 : 0);
-	// Be a little impatient about establishing connections.
-	mCurlRequest->setopt(CURLOPT_CONNECTTIMEOUT, 40L);
-	mCurlRequest->setSSLCtxCallback(_sslCtxFunction, (void *)this);
 
-	/* Setting the DNS cache timeout to -1 disables it completely.
-	   This might help with bug #503 */
-	mCurlRequest->setopt(CURLOPT_DNS_CACHE_TIMEOUT, -1);
+	httpOpts->setSSLVerifyPeer( vefifySSLCert );
+	httpOpts->setSSLVerifyHost( vefifySSLCert ? 2 : 0);
 
-    mCurlRequest->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
+	// LLRefCounted starts with a 1 ref, so don't add a ref in the smart pointer
+	httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false);
 
-	if (useGzip)
-	{
-		mCurlRequest->setoptString(CURLOPT_ENCODING, "");
-	}
+	httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);
+
+	///* Setting the DNS cache timeout to -1 disables it completely.
+	//This might help with bug #503 */
+	//httpOpts->setDNSCacheTimeout(-1);
+
+	LLCore::BufferArray::ptr_t body = LLCore::BufferArray::ptr_t(new LLCore::BufferArray(), false);
+
+	// TODO: See if there is a way to serialize to a preallocated buffer I'm 
+	// not fond of the copy here.
+	int	requestSize(0);
+	char * requestText = XMLRPC_REQUEST_ToXML(request, &requestSize);
+
+	body->append(requestText, requestSize);
 	
-	mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize);
-	if (mRequestText)
-	{
-		mCurlRequest->setoptString(CURLOPT_POSTFIELDS, mRequestText);
-		mCurlRequest->setopt(CURLOPT_POSTFIELDSIZE, mRequestTextSize);
-	}
-	else
-	{
-		setStatus(StatusOtherError);
-	}
+	XMLRPC_Free(requestText);
+
+	mHandler = LLXMLRPCTransaction::Handler::ptr_t(new Handler( mHttpRequest, this ));
+
+	mPostH = mHttpRequest->requestPost(LLCore::HttpRequest::DEFAULT_POLICY_ID, 0, 
+		mURI, body.get(), httpOpts.get(), httpHeaders.get(), mHandler.get());
 
-	mCurlRequest->sendRequest(mURI);
 }
 
 
@@ -362,27 +397,24 @@ LLXMLRPCTransaction::Impl::~Impl()
 		XMLRPC_RequestFree(mResponse, 1);
 	}
 	
-	if (mRequestText)
-	{
-		XMLRPC_Free(mRequestText);
-	}
+	//if (mRequestText)
+	//{
+	//	XMLRPC_Free(mRequestText);
+	//}
 	
-	delete mCurlRequest;
-	mCurlRequest = NULL ;
+	//delete mCurlRequest;
+	//mCurlRequest = NULL ;
 }
 
 bool LLXMLRPCTransaction::Impl::process()
 {
-	if(!mCurlRequest || !mCurlRequest->isValid())
+	if (!mPostH || !mHttpRequest)
 	{
-		LL_WARNS() << "transaction failed." << LL_ENDL ;
-
-		delete mCurlRequest ;
-		mCurlRequest = NULL ;
-		return true ; //failed, quit.
+		LL_WARNS() << "transaction failed." << LL_ENDL;
+		return true; //failed, quit.
 	}
 
-	switch(mStatus)
+	switch (mStatus)
 	{
 		case LLXMLRPCTransaction::StatusComplete:
 		case LLXMLRPCTransaction::StatusCURLError:
@@ -391,93 +423,25 @@ bool LLXMLRPCTransaction::Impl::process()
 		{
 			return true;
 		}
-		
+
 		case LLXMLRPCTransaction::StatusNotStarted:
 		{
 			setStatus(LLXMLRPCTransaction::StatusStarted);
 			break;
 		}
-		
+
 		default:
-		{
-			// continue onward
-		}
-	}
-		
-	if(!mCurlRequest->wait())
-	{
-		return false ;
+			break;
 	}
 
-	while(1)
-	{
-		CURLcode result;
-		bool newmsg = mCurlRequest->getResult(&result, &mTransferInfo);
-		if (newmsg)
-		{
-			if (result != CURLE_OK)
-			{
-				if ((result != CURLE_SSL_PEER_CERTIFICATE) &&
-					(result != CURLE_SSL_CACERT))
-				{
-					// if we have a curl error that's not already been handled
-					// (a non cert error), then generate the error message as
-					// appropriate
-					setCurlStatus(result);
-				
-					LL_WARNS() << "LLXMLRPCTransaction CURL error "
-					<< mCurlCode << ": " << mCurlRequest->getErrorString() << LL_ENDL;
-					LL_WARNS() << "LLXMLRPCTransaction request URI: "
-					<< mURI << LL_ENDL;
-				}
-					
-				return true;
-			}
-			
-			setStatus(LLXMLRPCTransaction::StatusComplete);
-
-			mResponse = XMLRPC_REQUEST_FromXML(
-					mResponseText.data(), mResponseText.size(), NULL);
-
-			bool		hasError = false;
-			bool		hasFault = false;
-			int			faultCode = 0;
-			std::string	faultString;
+	LLCore::HttpStatus status = mHttpRequest->update(0);
 
-			LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse));
-			if (error.isValid())
-			{
-				hasError = true;
-				faultCode = error["faultCode"].asInt();
-				faultString = error["faultString"].asString();
-			}
-			else if (XMLRPC_ResponseIsFault(mResponse))
-			{
-				hasFault = true;
-				faultCode = XMLRPC_GetResponseFaultCode(mResponse);
-				faultString = XMLRPC_GetResponseFaultString(mResponse);
-			}
-
-			if (hasError || hasFault)
-			{
-				setStatus(LLXMLRPCTransaction::StatusXMLRPCError);
-				
-				LL_WARNS() << "LLXMLRPCTransaction XMLRPC "
-						<< (hasError ? "error " : "fault ")
-						<< faultCode << ": "
-						<< faultString << LL_ENDL;
-				LL_WARNS() << "LLXMLRPCTransaction request URI: "
-						<< mURI << LL_ENDL;
-			}
-			
-			return true;
-		}
-		else
-		{
-			break; // done
-		}
+	status = mHttpRequest->getStatus();
+	if (!status) 
+	{
+		return false;
 	}
-	
+
 	return false;
 }
 
@@ -516,64 +480,49 @@ void LLXMLRPCTransaction::Impl::setStatus(EStatus status,
 	}
 }
 
-void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code)
+void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status)
 {
+	CURLcode code = static_cast<CURLcode>(status.toULong());
 	std::string message;
 	std::string uri = "http://secondlife.com/community/support.php";
-	
+
 	switch (code)
 	{
-		case CURLE_COULDNT_RESOLVE_HOST:
-			message =
-				"DNS could not resolve the host name.\n"
-				"Please verify that you can connect to the www.secondlife.com\n"
-				"web site.  If you can, but continue to receive this error,\n"
-				"please go to the support section and report this problem.";
-			break;
-			
-		case CURLE_SSL_PEER_CERTIFICATE:
-			message =
-				"The login server couldn't verify itself via SSL.\n"
-				"If you continue to receive this error, please go\n"
-				"to the Support section of the SecondLife.com web site\n"
-				"and report the problem.";
-			break;
-			
-		case CURLE_SSL_CACERT:
-		case CURLE_SSL_CONNECT_ERROR:
-			message =
-				"Often this means that your computer\'s clock is set incorrectly.\n"
-				"Please go to Control Panels and make sure the time and date\n"
-				"are set correctly.\n"
-				"Also check that your network and firewall are set up correctly.\n"
-				"If you continue to receive this error, please go\n"
-				"to the Support section of the SecondLife.com web site\n"
-				"and report the problem.";
-			break;
-			
-		default:
-				break;
+	case CURLE_COULDNT_RESOLVE_HOST:
+		message =
+			"DNS could not resolve the host name.\n"
+			"Please verify that you can connect to the www.secondlife.com\n"
+			"web site.  If you can, but continue to receive this error,\n"
+			"please go to the support section and report this problem.";
+		break;
+
+	case CURLE_SSL_PEER_CERTIFICATE:
+		message =
+			"The login server couldn't verify itself via SSL.\n"
+			"If you continue to receive this error, please go\n"
+			"to the Support section of the SecondLife.com web site\n"
+			"and report the problem.";
+		break;
+
+	case CURLE_SSL_CACERT:
+	case CURLE_SSL_CONNECT_ERROR:
+		message =
+			"Often this means that your computer\'s clock is set incorrectly.\n"
+			"Please go to Control Panels and make sure the time and date\n"
+			"are set correctly.\n"
+			"Also check that your network and firewall are set up correctly.\n"
+			"If you continue to receive this error, please go\n"
+			"to the Support section of the SecondLife.com web site\n"
+			"and report the problem.";
+		break;
+
+	default:
+		break;
 	}
-	
+
 	mCurlCode = code;
 	setStatus(StatusCURLError, message, uri);
-}
-
-size_t LLXMLRPCTransaction::Impl::curlDownloadCallback(
-		char* data, size_t size, size_t nmemb, void* user_data)
-{
-	Impl& impl(*(Impl*)user_data);
-	
-	size_t n = size * nmemb;
 
-	impl.mResponseText.append(data, n);
-	
-	if (impl.mStatus == LLXMLRPCTransaction::StatusStarted)
-	{
-		impl.setStatus(LLXMLRPCTransaction::StatusDownloading);
-	}
-	
-	return n;
 }
 
 
@@ -645,11 +594,11 @@ F64 LLXMLRPCTransaction::transferRate()
 		return 0.0L;
 	}
 	
-	double rate_bits_per_sec = impl.mTransferInfo.mSpeedDownload * 8.0;
+	double rate_bits_per_sec = impl.mTransferStats->mSpeedDownload * 8.0;
 	
 	LL_INFOS("AppInit") << "Buffer size:   " << impl.mResponseText.size() << " B" << LL_ENDL;
-	LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferInfo.mSizeDownload << " B" << LL_ENDL;
-	LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferInfo.mTotalTime << " s" << LL_ENDL;
+	LL_DEBUGS("AppInit") << "Transfer size: " << impl.mTransferStats->mSizeDownload << " B" << LL_ENDL;
+	LL_DEBUGS("AppInit") << "Transfer time: " << impl.mTransferStats->mTotalTime << " s" << LL_ENDL;
 	LL_INFOS("AppInit") << "Transfer rate: " << rate_bits_per_sec / 1000.0 << " Kb/s" << LL_ENDL;
 
 	return rate_bits_per_sec;
diff --git a/indra/newview/llxmlrpctransaction.h b/indra/newview/llxmlrpctransaction.h
index f2589c7f411..3a1c9c82b70 100755
--- a/indra/newview/llxmlrpctransaction.h
+++ b/indra/newview/llxmlrpctransaction.h
@@ -81,7 +81,7 @@ class LLXMLRPCValue
 
 
 class LLXMLRPCTransaction
-	// an asynchronous request and respones via XML-RPC
+	// an asynchronous request and responses via XML-RPC
 {
 public:
 	LLXMLRPCTransaction(const std::string& uri,
@@ -127,7 +127,9 @@ class LLXMLRPCTransaction
 		// only valid if StsatusComplete, otherwise 0.0
 		
 private:
+	class Handler;
 	class Impl;
+
 	Impl& impl;
 };
 
-- 
GitLab