diff options
30 files changed, 1280 insertions, 840 deletions
| diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index b9632a7921..48e22468cd 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 2f628b5aba..7a4b7c189e 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 @@ protected:  	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 @@ protected:  	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 1dc95f3dce..c4ef38a815 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 67c4ba9481..1696238814 100755 --- a/indra/llcorehttp/_httppolicyglobal.h +++ b/indra/llcorehttp/_httppolicyglobal.h @@ -60,8 +60,10 @@ private:  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 @@ public:  	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 c673e1be1d..7b8aac35a8 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 cf23f3ab61..699a8eaa4f 100755 --- a/indra/llcorehttp/_httpservice.h +++ b/indra/llcorehttp/_httpservice.h @@ -201,17 +201,24 @@ protected:  		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 402e725152..cd16e2e2b4 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 1094a435b4..9c2b991de6 100755 --- a/indra/llcorehttp/bufferarray.h +++ b/indra/llcorehttp/bufferarray.h @@ -73,6 +73,8 @@ public:  	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 7907e958a4..1aece696e3 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 9601f94125..0244755272 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 9171e4e7b9..740e986dec 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 f70cd898f3..c89d6af222 100755 --- a/indra/llcorehttp/httpheaders.h +++ b/indra/llcorehttp/httpheaders.h @@ -92,6 +92,7 @@ public:  	/// 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 5bf1ecb4a5..28c2c25e92 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 4ab5ff18c4..d6d892213d 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 @@ public:  		{  			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 @@ protected:  	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 7b1888e3eb..5f1ed3d43b 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 7f23723b0b..c90e056d62 100755 --- a/indra/llcorehttp/httprequest.h +++ b/indra/llcorehttp/httprequest.h @@ -97,6 +97,7 @@ public:  	typedef unsigned int policy_t;  	typedef unsigned int priority_t; +	typedef std::shared_ptr<HttpRequest> ptr_t;  public:  	/// @name PolicyMethods  	/// @{ @@ -163,7 +164,7 @@ public:  		/// 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 @@ public:  		/// 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 @@ public:  											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 aee64e2878..01e9dd2bc6 100755 --- a/indra/llcorehttp/httpresponse.h +++ b/indra/llcorehttp/httpresponse.h @@ -69,6 +69,18 @@ protected:  	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 @@ public:  			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 @@ protected:  	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 73df47b933..0080dd6138 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 385d9fffa8..295e9c9fe5 100755 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -309,6 +309,7 @@ private:  	static void deleteAllFreeHandles();  }; +#if 1  class LLCurl::Multi  {  	LOG_CLASS(Multi); @@ -379,6 +380,7 @@ private:  	LLFrameTimer mIdleTimer ;  	F32 mIdleTimeOut;  }; +#endif  class LLCurlThread : public LLQueuedThread  { @@ -417,7 +419,7 @@ private:  	void cleanupMulti(LLCurl::Multi* multi) ;  } ; - +#if 0  class LLCurlRequest  {  public: @@ -446,7 +448,9 @@ private:  	S32 mActiveRequestCount;  	BOOL mProcessing;  }; +#endif +#if 0  //for texture fetch only  class LLCurlTextureRequest : public LLCurlRequest  { @@ -511,6 +515,7 @@ private:  	LLFrameTimer mGlobalTimer;  }; +#endif   class LLCurlEasyRequest  { @@ -550,7 +555,7 @@ private:  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 200116337d..27c94b1182 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 b56a804f94..8c2a0ad9cf 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 270282c66f..0067703895 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 @@ public:  		const std::string& url,  		LLCurl::ResponderPtr responder);  }; +*/  #endif diff --git a/indra/llmessage/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h index 12a3857a61..9c1c8e7c11 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 c4e0333ca3..d097ecdff7 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 @@ protected:  	LLIOPipe::ptr_t mResponse;  }; +#if 0  /**    * @class LLSDRPCClientFactory   * @brief Basic implementation for making an SD RPC client factory @@ -267,7 +270,9 @@ public:  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 @@ public:  protected:  	std::string mURL;  }; +#endif  #endif // LL_LLSDRPCCLIENT_H diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index f5f224b83e..dd39b9a959 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 37d7a737e7..9616354093 100755 --- a/indra/newview/llappcorehttp.h +++ b/indra/newview/llappcorehttp.h @@ -233,7 +233,9 @@ private:  	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 2d4ce6c883..530eb685fa 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 aa440c06a6..4f08057477 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 c12c2cc24c..e4e63afa16 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 f2589c7f41..3a1c9c82b7 100755 --- a/indra/newview/llxmlrpctransaction.h +++ b/indra/newview/llxmlrpctransaction.h @@ -81,7 +81,7 @@ private:  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 @@ public:  		// only valid if StsatusComplete, otherwise 0.0  private: +	class Handler;  	class Impl; +  	Impl& impl;  }; | 
