diff options
55 files changed, 2927 insertions, 1745 deletions
| diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index 5cfcdab41c..e5a913a6a9 100755 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -51,6 +51,7 @@  #include <cstdlib>  #include <ctime>  #include <iosfwd> +#include <memory>  // Linden only libs in alpha-order other than stdtypes.h  // *NOTE: Please keep includes here to a minimum, see above. diff --git a/indra/llcorehttp/_httpinternal.h b/indra/llcorehttp/_httpinternal.h index a2a60ca056..79c89d6c92 100755 --- a/indra/llcorehttp/_httpinternal.h +++ b/indra/llcorehttp/_httpinternal.h @@ -104,8 +104,9 @@ namespace LLCore  {  // Maxium number of policy classes that can be defined. -// *TODO:  Currently limited to the default class + 1, extend. -const int HTTP_POLICY_CLASS_LIMIT = 8; +// *TODO:  Currently limited to the default class + 1, extend.  +// (TSN: should this be more dynamically sized.  Is there a reason to hard limit the number of policies?) +const int HTTP_POLICY_CLASS_LIMIT = 32;  // Debug/informational tracing.  Used both  // as a global option and in per-request traces. diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index b9632a7921..7c2309b31d 100755 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -139,7 +139,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(). @@ -259,7 +260,9 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)  		response->setStatus(mStatus);  		response->setBody(mReplyBody);  		response->setHeaders(mReplyHeaders); -		if (mReplyOffset || mReplyLength) +        response->setRequestURL(mReqURL); + +        if (mReplyOffset || mReplyLength)  		{  			// Got an explicit offset/length in response  			response->setRange(mReplyOffset, mReplyLength, mReplyFullLength); @@ -267,6 +270,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 +463,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 +475,48 @@ 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(-1L); + +	if (mReqOptions) +	{ +		follow_redirect = mReqOptions->getFollowRedirects() ? 1L : 0L; +		sslPeerV = mReqOptions->getSSLVerifyPeer() ? 1L : 0L; +		sslHostV = mReqOptions->getSSLVerifyHost() ? 2L : 0L; +		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..e71d1d1edf 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" @@ -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,6 +165,8 @@ protected:  	static const unsigned int	PF_SAVE_HEADERS = 0x00000002U;  	static const unsigned int	PF_USE_RETRY_AFTER = 0x00000004U; +	HttpRequest::policyCallback_t	mCallbackSSLVerify; +  public:  	// Request data  	EMethod				mReqMethod; diff --git a/indra/llcorehttp/_httppolicyglobal.cpp b/indra/llcorehttp/_httppolicyglobal.cpp index 1dc95f3dce..3d0df96ade 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_t 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_t * 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..e02da4386a 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_t 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_t * value) const;  public:  	long				mConnectionLimit; @@ -70,6 +72,7 @@ public:  	std::string			mHttpProxy;  	long				mTrace;  	long				mUseLLProxy; +	HttpRequest::policyCallback_t	mSslCtxCallback;  };  // end class HttpPolicyGlobal  }  // end namespace LLCore diff --git a/indra/llcorehttp/_httpservice.cpp b/indra/llcorehttp/_httpservice.cpp index c673e1be1d..252db78c89 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_t * 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_t value, HttpRequest::policyCallback_t * 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..ac518a5de7 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_t * 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_t value,  +								HttpRequest::policyCallback_t * 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..076f341736 100755 --- a/indra/llcorehttp/bufferarray.h +++ b/indra/llcorehttp/bufferarray.h @@ -30,6 +30,7 @@  #include <cstdlib>  #include <vector> +#include "boost/intrusive_ptr.hpp"  #include "_refcounted.h" @@ -73,6 +74,8 @@ public:  	BufferArray(); +	typedef boost::intrusive_ptr<BufferArray> ptr_t; +  protected:  	virtual ~BufferArray();						// Use release() @@ -129,6 +132,7 @@ protected:  	container_t			mBlocks;  	size_t				mLen; +  };  // end class BufferArray diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index 7907e958a4..99238ea920 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,30 +131,34 @@ std::string HttpStatus::toString() const  	{  		return std::string("");  	} -	switch (mType) +	switch (getType())  	{  	case EXT_CURL_EASY: -		return std::string(curl_easy_strerror(CURLcode(mStatus))); +		return std::string(curl_easy_strerror(CURLcode(getStatus())));  	case EXT_CURL_MULTI: -		return std::string(curl_multi_strerror(CURLMcode(mStatus))); +		return std::string(curl_multi_strerror(CURLMcode(getStatus())));  	case LLCORE: -		if (mStatus >= 0 && mStatus < llcore_errors_count) +		if (getStatus() >= 0 && getStatus() < llcore_errors_count)  		{ -			return std::string(llcore_errors[mStatus]); +			return std::string(llcore_errors[getStatus()]);  		}  		break;  	default:  		if (isHttpStatus())  		{ +			// special handling for status 499 "Linden Catchall" +			if ((getType() == 499) && (!getMessage().empty())) +				return getMessage(); +  			// Binary search for the error code and string  			int bottom(0), top(http_errors_count);  			while (true)  			{  				int at((bottom + top) / 2); -				if (mType == http_errors[at].mCode) +				if (getType() == http_errors[at].mCode)  				{  					return std::string(http_errors[at].mText);  				} @@ -162,7 +166,7 @@ std::string HttpStatus::toString() const  				{  					break;  				} -				else if (mType < http_errors[at].mCode) +				else if (getType() < http_errors[at].mCode)  				{  					top = at;  				} @@ -182,9 +186,9 @@ std::string HttpStatus::toTerseString() const  {  	std::ostringstream result; -	unsigned int error_value((unsigned short) mStatus); +	unsigned int error_value((unsigned short)getStatus()); -	switch (mType) +	switch (getType())  	{  	case EXT_CURL_EASY:  		result << "Easy_"; @@ -202,7 +206,7 @@ std::string HttpStatus::toTerseString() const  		if (isHttpStatus())  		{  			result << "Http_"; -			error_value = mType; +			error_value = getType();  		}  		else  		{ @@ -244,7 +248,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() && getType() >= 499 && getType() <= 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..ada5c1bbe7 100755 --- a/indra/llcorehttp/httpcommon.h +++ b/indra/llcorehttp/httpcommon.h @@ -188,10 +188,11 @@  ///  #include "linden_common.h"		// Modifies curl/curl.h interfaces - +#include "boost/intrusive_ptr.hpp" +#include "boost/shared_ptr.hpp" +#include "boost/function.hpp"  #include <string> -  namespace LLCore  { @@ -286,52 +287,63 @@ enum HttpError  /// 5.  Construct an HTTP 301 status code to be treated as success:  ///				HttpStatus(301, HE_SUCCESS);  /// +/// 6.	Construct a failed status of HTTP Status 499 with a custom error message +///				HttpStatus(499, "Failed LLSD Response");  struct HttpStatus  {  	typedef unsigned short type_enum_t;  	HttpStatus() -		: mType(LLCORE), -		  mStatus(HE_SUCCESS) -		{} +	{ +		mDetails = boost::shared_ptr<Details>(new Details(LLCORE, HE_SUCCESS)); +    }  	HttpStatus(type_enum_t type, short status) -		: mType(type), -		  mStatus(status) -		{} +	{ +        mDetails = boost::shared_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) -		{ -			llassert(http_status >= 100 && http_status <= 999); -		} +	{ +        mDetails = boost::shared_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(int http_status, const std::string &message) +	{ +        mDetails = boost::shared_ptr<Details>(new Details(http_status, +			(http_status >= 200 && http_status <= 299) ? HE_SUCCESS : HE_REPLY_ERROR)); +		llassert(http_status >= 100 && http_status <= 999); +		mDetails->mMessage = message; +	}  	HttpStatus(const HttpStatus & rhs) -		: mType(rhs.mType), -		  mStatus(rhs.mStatus) -		{} +	{ +		mDetails = rhs.mDetails; +	} + +	~HttpStatus() +	{ +	}  	HttpStatus & operator=(const HttpStatus & rhs) -		{ -			// Don't care if lhs & rhs are the same object +	{ +        mDetails = rhs.mDetails; +		return *this; +	} -			mType = rhs.mType; -			mStatus = rhs.mStatus; -			return *this; -		} +    HttpStatus & clone(const HttpStatus &rhs) +    { +        mDetails = boost::shared_ptr<Details>(new Details(*rhs.mDetails)); +        return *this; +    }  	static const type_enum_t EXT_CURL_EASY = 0;			///< mStatus is an error from a curl_easy_*() call  	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 +351,7 @@ struct HttpStatus  	///  	operator bool() const  	{ -		return 0 == mStatus; +		return 0 == mDetails->mStatus;  	}  	/// Inverse of previous operator. @@ -347,14 +359,14 @@ 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 == *rhs.mDetails);   	}  	bool operator!=(const HttpStatus & rhs) const @@ -395,7 +407,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 +415,78 @@ 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; +	} + +	/// 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) +		{} + +        bool operator == (const Details &rhs) const +        { +            return (mType == rhs.mType) && (mStatus == rhs.mStatus); +        } + +		type_enum_t	mType; +		short		mStatus; +		std::string	mMessage; +		void *		mErrorData; +	}; + +    boost::shared_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.cpp b/indra/llcorehttp/httpheaders.cpp index 23ebea361c..73c92c8f10 100755 --- a/indra/llcorehttp/httpheaders.cpp +++ b/indra/llcorehttp/httpheaders.cpp @@ -105,7 +105,7 @@ void HttpHeaders::appendNormal(const char * header, size_t size)  // Find from end to simulate a tradition of using single-valued  // std::map for this in the past. -const std::string * HttpHeaders::find(const char * name) const +const std::string * HttpHeaders::find(const std::string &name) const  {  	const_reverse_iterator iend(rend());  	for (const_reverse_iterator iter(rbegin()); iend != iter; ++iter) diff --git a/indra/llcorehttp/httpheaders.h b/indra/llcorehttp/httpheaders.h index f70cd898f3..940f92183c 100755 --- a/indra/llcorehttp/httpheaders.h +++ b/indra/llcorehttp/httpheaders.h @@ -28,8 +28,8 @@  #define	_LLCORE_HTTP_HEADERS_H_ +#include "httpcommon.h"  #include <string> -  #include "_refcounted.h" @@ -92,6 +92,7 @@ public:  	/// the instance.  	HttpHeaders(); +	typedef boost::intrusive_ptr<HttpHeaders> ptr_t;  protected:  	virtual ~HttpHeaders();						// Use release() @@ -145,8 +146,12 @@ public:  	//					a pointer to a std::string in the container.  	//					Pointer is valid only for the lifetime of  	//					the container or until container is modifed. -	// -	const std::string * find(const char * name) const; +	 +	const std::string * find(const std::string &name) const; +	const std::string * find(const char * name) const +	{ +		return find(std::string(name)); +	}  	// Count of headers currently in the list.  	size_type size() const diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp index 5bf1ecb4a5..a4d08a80df 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(false), +    mDNSCacheTimeout(-1L)  {} @@ -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(bool verify) +{ +	mVerifyHost = verify; +} + +void HttpOptions::setDNSCacheTimeout(int timeout) +{ +	mDNSCacheTimeout = timeout; +}  }   // end namespace LLCore diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h index 4ab5ff18c4..765d2431bb 100755 --- a/indra/llcorehttp/httpoptions.h +++ b/indra/llcorehttp/httpoptions.h @@ -29,7 +29,6 @@  #include "httpcommon.h" -  #include "_refcounted.h" @@ -61,6 +60,8 @@ class HttpOptions : public LLCoreInt::RefCounted  public:  	HttpOptions(); +	typedef boost::intrusive_ptr<HttpOptions> ptr_t; +  protected:  	virtual ~HttpOptions();						// Use release() @@ -68,47 +69,86 @@ protected:  	void operator=(const HttpOptions &);		// Not defined  public: +  	// Default:   false  	void				setWantHeaders(bool wanted);  	bool				getWantHeaders() const -		{ -			return mWantHeaders; -		} +	{ +		return mWantHeaders; +	}  	// Default:  0  	void				setTrace(int long);  	int					getTrace() const -		{ -			return mTracing; -		} +	{ +		return mTracing; +	}  	// Default:  30  	void				setTimeout(unsigned int timeout);  	unsigned int		getTimeout() const -		{ -			return mTimeout; -		} +	{ +		return mTimeout; +	}  	// Default:  0  	void				setTransferTimeout(unsigned int timeout);  	unsigned int		getTransferTimeout() const -		{ -			return mTransferTimeout; -		} +	{ +		return mTransferTimeout; +	} +    /// Sets the number of retries on an LLCore::HTTPRequest before the  +    /// request fails.  	// Default:  8  	void				setRetries(unsigned int retries);  	unsigned int		getRetries() const -		{ -			return mRetries; -		} +	{ +		return mRetries; +	}  	// Default:  true  	void				setUseRetryAfter(bool use_retry);  	bool				getUseRetryAfter() const -		{ -			return mUseRetryAfter; -		} +	{ +		return mUseRetryAfter; +	} + +    /// Instructs the LLCore::HTTPRequest to follow redirects  +	/// Default: false +	void				setFollowRedirects(bool follow_redirect); +	bool				getFollowRedirects() const +	{ +		return mFollowRedirects; +	} + +    /// Instructs the LLCore::HTTPRequest to verify that the exchanged security +    /// certificate is authentic.  +    /// Default: false +    void				setSSLVerifyPeer(bool verify); +	bool				getSSLVerifyPeer() const +	{ +		return mVerifyPeer; +	} + +    /// Instructs the LLCore::HTTPRequest to verify that the name in the  +    /// security certificate matches the name of the host contacted. +    /// Default: false +    void				setSSLVerifyHost(bool verify); +	bool	        	getSSLVerifyHost() const +	{ +		return mVerifyHost; +	} + +    /// Sets the time for DNS name caching in seconds.  Setting this value +    /// to 0 will disable name caching.  Setting this value to -1 causes the  +    /// name cache to never time out. +    /// Default: -1 +	void				setDNSCacheTimeout(int timeout); +	int					getDNSCacheTimeout() const +	{ +		return mDNSCacheTimeout; +	}  protected:  	bool				mWantHeaders; @@ -117,6 +157,10 @@ protected:  	unsigned int		mTransferTimeout;  	unsigned int		mRetries;  	bool				mUseRetryAfter; +	bool				mFollowRedirects; +	bool				mVerifyPeer; +	bool        		mVerifyHost; +	int					mDNSCacheTimeout;  }; // end class HttpOptions diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp index 7b1888e3eb..df8502b947 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_t value, policyCallback_t * 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) diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h index 7f23723b0b..f7ce82d412 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 boost::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 boost::function<HttpStatus(const std::string &, HttpHandler const * const, void *)> policyCallback_t; +  	/// 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_t value, policyCallback_t * 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.cpp b/indra/llcorehttp/httpresponse.cpp index c974395b0a..7d88f02527 100755 --- a/indra/llcorehttp/httpresponse.cpp +++ b/indra/llcorehttp/httpresponse.cpp @@ -41,7 +41,8 @@ HttpResponse::HttpResponse()  	  mBufferArray(NULL),  	  mHeaders(NULL),  	  mRetries(0U), -	  m503Retries(0U) +	  m503Retries(0U), +      mRequestUrl()  {} @@ -89,5 +90,9 @@ void HttpResponse::setHeaders(HttpHeaders * headers)  	mHeaders = headers;  } +size_t HttpResponse::getBodySize() const +{ +	return (mBufferArray) ? mBufferArray->size() : 0; +}  }   // end namespace LLCore diff --git a/indra/llcorehttp/httpresponse.h b/indra/llcorehttp/httpresponse.h index aee64e2878..6c3b4da5e6 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 boost::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 @@ -92,6 +104,10 @@ public:  			return mBufferArray;  		} +	/// Safely get the size of the body buffer.  If the body buffer is missing +	/// return 0 as the size. +	size_t getBodySize() const; +  	/// Set the response data in the instance.  Will drop the reference  	/// count to any existing data and increment the count of that passed  	/// in.  It is legal to set the data to NULL. @@ -168,6 +184,27 @@ public:  			m503Retries = retries_503;  		} +	void setTransferStats(TransferStats::ptr_t &stats)  +		{ +			mStats = stats; +		} + +	TransferStats::ptr_t getTransferStats() +		{ +			return mStats; +		} + +    void setRequestURL(const std::string &url) +        { +            mRequestUrl = url; +        } + +    const std::string &getRequestURL() const +        { +            return mRequestUrl; +        } + +  protected:  	// Response data here  	HttpStatus			mStatus; @@ -179,6 +216,9 @@ protected:  	std::string			mContentType;  	unsigned int		mRetries;  	unsigned int		m503Retries; +    std::string         mRequestUrl; + +	TransferStats::ptr_t	mStats;  }; diff --git a/indra/llcorehttp/tests/test_httpstatus.hpp b/indra/llcorehttp/tests/test_httpstatus.hpp index 0b379836c9..4502d32fe1 100755 --- a/indra/llcorehttp/tests/test_httpstatus.hpp +++ b/indra/llcorehttp/tests/test_httpstatus.hpp @@ -55,77 +55,68 @@ void HttpStatusTestObjectType::test<1>()  	// auto allocation fine for this  	HttpStatus status; -	status.mType = HttpStatus::EXT_CURL_EASY; -	status.mStatus = 0; + +	status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0);  	ensure(bool(status));  	ensure(false == !(status)); -	status.mType = HttpStatus::EXT_CURL_MULTI; -	status.mStatus = 0; +	status = HttpStatus(HttpStatus::EXT_CURL_MULTI, 0);  	ensure(bool(status));  	ensure(false == !(status)); -	 -	status.mType = HttpStatus::LLCORE; -	status.mStatus = HE_SUCCESS; + +	status = HttpStatus(HttpStatus::LLCORE, HE_SUCCESS);  	ensure(bool(status));  	ensure(false == !(status)); -	status.mType = HttpStatus::EXT_CURL_MULTI; -	status.mStatus = -1; +	status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -1);  	ensure(false == bool(status));  	ensure(!(status)); -	status.mType = HttpStatus::EXT_CURL_EASY; -	status.mStatus = CURLE_BAD_DOWNLOAD_RESUME; +	status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_DOWNLOAD_RESUME);  	ensure(false == bool(status));  	ensure(!(status));  } -template <> template <> -void HttpStatusTestObjectType::test<2>() -{ -	set_test_name("HttpStatus memory structure"); - -	// Require that an HttpStatus object can be trivially -	// returned as a function return value in registers. -	// One should fit in an int on all platforms. - -	ensure(sizeof(HttpStatus) <= sizeof(int)); -} +// template <> template <> +// void HttpStatusTestObjectType::test<2>() +// { +// 	set_test_name("HttpStatus memory structure"); +//  +// 	// Require that an HttpStatus object can be trivially +// 	// returned as a function return value in registers. +// 	// One should fit in an int on all platforms. +//  +// 	//ensure(sizeof(HttpStatus) <= sizeof(int)); +// }  template <> template <> -void HttpStatusTestObjectType::test<3>() +void HttpStatusTestObjectType::test<2>()  {  	set_test_name("HttpStatus valid status string conversion"); -	HttpStatus status; -	status.mType = HttpStatus::EXT_CURL_EASY; -	status.mStatus = 0; +	HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 0);  	std::string msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(msg.empty()); -	 -	status.mType = HttpStatus::EXT_CURL_EASY; -	status.mStatus = CURLE_BAD_FUNCTION_ARGUMENT; + +	status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_BAD_FUNCTION_ARGUMENT);  	msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty()); -	status.mType = HttpStatus::EXT_CURL_MULTI; -	status.mStatus = CURLM_OUT_OF_MEMORY; +	status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY);  	msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty()); -	status.mType = HttpStatus::LLCORE; -	status.mStatus = HE_SHUTTING_DOWN; +	status = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN);  	msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty()); @@ -133,32 +124,28 @@ void HttpStatusTestObjectType::test<3>()  template <> template <> -void HttpStatusTestObjectType::test<4>() +void HttpStatusTestObjectType::test<3>()  {  	set_test_name("HttpStatus invalid status string conversion"); -	HttpStatus status; -	status.mType = HttpStatus::EXT_CURL_EASY; -	status.mStatus = 32726; +	HttpStatus status = HttpStatus(HttpStatus::EXT_CURL_EASY, 32726);  	std::string msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty()); -	 -	status.mType = HttpStatus::EXT_CURL_MULTI; -	status.mStatus = -470; + +	status = HttpStatus(HttpStatus::EXT_CURL_MULTI, -470);  	msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty()); -	status.mType = HttpStatus::LLCORE; -	status.mStatus = 923; +	status = HttpStatus(HttpStatus::LLCORE, 923);  	msg = status.toString();  	// std::cout << "Result:  " << msg << std::endl;  	ensure(! msg.empty());  }  template <> template <> -void HttpStatusTestObjectType::test<5>() +void HttpStatusTestObjectType::test<4>()  {  	set_test_name("HttpStatus equality/inequality testing"); @@ -170,62 +157,55 @@ void HttpStatusTestObjectType::test<5>()  	HttpStatus status2(HttpStatus::EXT_CURL_EASY, HE_SUCCESS);  	ensure(status1 != status2); -	status1.mType = HttpStatus::LLCORE; -	status1.mStatus = HE_REPLY_ERROR; -	status2.mType = HttpStatus::LLCORE; -	status2.mStatus= HE_SHUTTING_DOWN; +	status1 = HttpStatus(HttpStatus::LLCORE, HE_REPLY_ERROR); +	status1 = HttpStatus(HttpStatus::LLCORE, HE_SHUTTING_DOWN); +  	ensure(status1 != status2);  }  template <> template <> -void HttpStatusTestObjectType::test<6>() +void HttpStatusTestObjectType::test<5>()  {  	set_test_name("HttpStatus basic HTTP status encoding");  	HttpStatus status; -	status.mType = 200; -	status.mStatus = HE_SUCCESS; + +	status = HttpStatus(200, HE_SUCCESS);  	std::string msg = status.toString();  	ensure(msg.empty());  	ensure(bool(status));  	// Normally a success but application says error -	status.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(200, HE_REPLY_ERROR);  	msg = status.toString();  	ensure(! msg.empty());  	ensure(! bool(status));  	ensure(status.toULong() > 1UL);				// Biggish number, not a bool-to-ulong  	// Same statuses with distinct success/fail are distinct -	status.mType = 200; -	status.mStatus = HE_SUCCESS; +	status = HttpStatus(200, HE_SUCCESS);  	HttpStatus status2(200, HE_REPLY_ERROR);  	ensure(status != status2);  	// Normally an error but application says okay -	status.mType = 406; -	status.mStatus = HE_SUCCESS; +	status = HttpStatus(406, HE_SUCCESS);  	msg = status.toString();  	ensure(msg.empty());  	ensure(bool(status));  	// Different statuses but both successful are distinct -	status.mType = 200; -	status.mStatus = HE_SUCCESS; -	status2.mType = 201; -	status2.mStatus = HE_SUCCESS; +	status = HttpStatus(200, HE_SUCCESS); +	status2 = HttpStatus(201, HE_SUCCESS);  	ensure(status != status2);  	// Different statuses but both failed are distinct -	status.mType = 200; -	status.mStatus = HE_REPLY_ERROR; -	status2.mType = 201; -	status2.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(200, HE_REPLY_ERROR); +	status2 = HttpStatus(201, HE_REPLY_ERROR);  	ensure(status != status2);  }  template <> template <> -void HttpStatusTestObjectType::test<7>() +void HttpStatusTestObjectType::test<6>()  {  	set_test_name("HttpStatus HTTP status text strings"); @@ -234,34 +214,30 @@ void HttpStatusTestObjectType::test<7>()  	ensure(! msg.empty());				// Should be something  	ensure(msg == "Continue"); -	status.mStatus = HE_SUCCESS; +	status = HttpStatus(200, HE_SUCCESS);  	msg = status.toString();  	ensure(msg.empty());				// Success is empty -	status.mType = 199; -	status.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(199, HE_REPLY_ERROR);  	msg = status.toString();  	ensure(msg == "Unknown error"); -	status.mType = 505;					// Last defined string -	status.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(505, HE_REPLY_ERROR);  	msg = status.toString();  	ensure(msg == "HTTP Version not supported"); -	status.mType = 506;					// One beyond -	status.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(506, HE_REPLY_ERROR);  	msg = status.toString();  	ensure(msg == "Unknown error"); -	status.mType = 999;					// Last HTTP status -	status.mStatus = HE_REPLY_ERROR; +	status = HttpStatus(999, HE_REPLY_ERROR);  	msg = status.toString();  	ensure(msg == "Unknown error");  }  template <> template <> -void HttpStatusTestObjectType::test<8>() +void HttpStatusTestObjectType::test<7>()  {  	set_test_name("HttpStatus toHex() nominal function"); @@ -273,7 +249,7 @@ void HttpStatusTestObjectType::test<8>()  template <> template <> -void HttpStatusTestObjectType::test<9>() +void HttpStatusTestObjectType::test<8>()  {  	set_test_name("HttpStatus toTerseString() nominal function"); diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 40eddcb0ab..f6ca6a3634 100755 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -49,6 +49,7 @@ set(llmessage_SOURCE_FILES      llhttpclientadapter.cpp      llhttpconstants.cpp      llhttpnode.cpp +	llhttpsdhandler.cpp      llhttpsender.cpp      llinstantmessage.cpp      lliobuffer.cpp @@ -144,6 +145,7 @@ set(llmessage_HEADER_FILES      llhttpconstants.h      llhttpnode.h      llhttpnodeadapter.h +	llhttpsdhandler.h      llhttpsender.h      llinstantmessage.h      llinvite.h @@ -224,7 +226,7 @@ target_link_libraries(    llmessage    ${CURL_LIBRARIES}    ${LLCOMMON_LIBRARIES} -  ${LLVFS_LIBRARES} +  ${LLVFS_LIBRARIES}    ${LLMATH_LIBRARIES}    ${CARES_LIBRARIES}    ${OPENSSL_LIBRARIES} @@ -241,15 +243,20 @@ if (LL_TESTS)      )    LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}") +      #    set(TEST_DEBUG on) +      set(test_libs -    ${CURL_LIBRARIES} -    ${LLMESSAGE_LIBRARIES}      ${WINDOWS_LIBRARIES}      ${LLVFS_LIBRARIES}      ${LLMATH_LIBRARIES} +    ${CURL_LIBRARIES}      ${LLCOMMON_LIBRARIES} -      ${GOOGLEMOCK_LIBRARIES} +    ${LLMESSAGE_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES} +    ${BOOST_CONTEXT_LIBRARY} +    ${BOOST_COROUTINE_LIBRARY} +    ${GOOGLEMOCK_LIBRARIES}      )    LL_ADD_INTEGRATION_TEST( diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index d02a60b7b2..88859819e0 100755 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -33,9 +33,18 @@  #include "llhttpclient.h"  #include "llsd.h"  #include "llsdserialize.h" - +#include "httpresponse.h" +#include "llhttpsdhandler.h"  #include <boost/tokenizer.hpp> +#include "httpcommon.h" +#include "httprequest.h" +#include "httpheaders.h" +#include "httpoptions.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llcorehttputil.h" +  #include <map>  #include <set> @@ -90,6 +99,12 @@ namespace LLAvatarNameCache  	// Time-to-live for a temp cache entry.  	const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0; +    LLCore::HttpRequest::ptr_t		sHttpRequest; +    LLCore::HttpHeaders::ptr_t		sHttpHeaders; +    LLCore::HttpOptions::ptr_t		sHttpOptions; +    LLCore::HttpRequest::policy_t	sHttpPolicy; +    LLCore::HttpRequest::priority_t	sHttpPriority; +  	//-----------------------------------------------------------------------  	// Internal methods  	//----------------------------------------------------------------------- @@ -121,7 +136,13 @@ namespace LLAvatarNameCache  	// Erase expired names from cache  	void eraseUnrefreshed(); -	bool expirationFromCacheControl(const LLSD& headers, F64 *expires); +    //bool expirationFromCacheControl(LLCore::HttpHeaders *headers, F64 *expires); +    bool expirationFromCacheControl(const LLSD& headers, F64 *expires); + +    // This is a coroutine.  The only parameter that can be specified as a reference is the self +    void requestAvatarNameCache_(LLCoros::self& self, std::string url, std::vector<LLUUID> agentIds); + +    void handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult);  }  /* Sample response: @@ -163,94 +184,125 @@ namespace LLAvatarNameCache  </llsd>  */ -class LLAvatarNameResponder : public LLHTTPClient::Responder +// Coroutine for sending and processing avatar name cache requests.   +// Do not call directly.  See documentation in lleventcoro.h and llcoro.h for +// further explanation. +void LLAvatarNameCache::requestAvatarNameCache_(LLCoros::self& self, std::string url, std::vector<LLUUID> agentIds)  { -	LOG_CLASS(LLAvatarNameResponder); -private: -	// need to store agent ids that are part of this request in case of -	// an error, so we can flag them as unavailable -	std::vector<LLUUID> mAgentIDs; - -public: -	LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids) -	:	mAgentIDs(agent_ids) -	{ } -	 -protected: -	/*virtual*/ void httpSuccess() -	{ -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		// Pull expiration out of headers if available -		F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(getResponseHeaders()); -		F64 now = LLFrameTimer::getTotalSeconds(); +    LLEventStream  replyPump("NameCacheReply", true); +    LLCoreHttpUtil::HttpCoroHandler::ptr_t httpHandler =  +        LLCoreHttpUtil::HttpCoroHandler::ptr_t(new LLCoreHttpUtil::HttpCoroHandler(replyPump)); -		const LLSD& agents = content["agents"]; -		LLSD::array_const_iterator it = agents.beginArray(); -		for ( ; it != agents.endArray(); ++it) -		{ -			const LLSD& row = *it; -			LLUUID agent_id = row["id"].asUUID(); +    LL_DEBUGS("AvNameCache") << "Entering coroutine " << LLCoros::instance().getName(self) +        << " with url '" << url << "', requesting " << agentIds.size() << " Agent Ids" << LL_ENDL; -			LLAvatarName av_name; -			av_name.fromLLSD(row); +    try +    { +        bool success = true; -			// Use expiration time from header -			av_name.mExpires = expires; +        LLAvatarNameCache::sHttpRequest->requestGet( +            LLAvatarNameCache::sHttpPolicy, LLAvatarNameCache::sHttpPriority,  +            url, LLAvatarNameCache::sHttpOptions.get(),  +            LLAvatarNameCache::sHttpHeaders.get(), httpHandler.get()); -			LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL; -			av_name.dump(); -			 -			// cache it and fire signals -			LLAvatarNameCache::processName(agent_id, av_name); -		} +        LLSD results = waitForEventOn(self, replyPump); +        LLSD httpResults; -		// Same logic as error response case -		const LLSD& unresolved_agents = content["bad_ids"]; -		S32  num_unresolved = unresolved_agents.size(); -		if (num_unresolved > 0) -		{ -            LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; " -                                    << "expires in " << expires - now << " seconds" -                                    << LL_ENDL; -			it = unresolved_agents.beginArray(); -			for ( ; it != unresolved_agents.endArray(); ++it) -			{ -				const LLUUID& agent_id = *it; +        LL_DEBUGS() << results << LL_ENDL; -				LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " -                                        << "failed id " << agent_id -                                        << LL_ENDL; +        if (!results.isMap()) +        { +            LL_WARNS("AvNameCache") << " Invalid result returned from LLCoreHttpUtil::HttpCoroHandler." << LL_ENDL; +            success = false; +        } +        else +        { +            httpResults = results["http_result"]; +            success = httpResults["success"].asBoolean(); +            if (!success) +            { +                LL_WARNS("AvNameCache") << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code " +                    << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL; +            } +        } +        if (!success) +        {   // on any sort of failure add dummy records for any agent IDs  +            // in this request that we do not have cached already +            std::vector<LLUUID>::const_iterator it = agentIds.begin(); +            for ( ; it != agentIds.end(); ++it) +            { +                const LLUUID& agent_id = *it;                  LLAvatarNameCache::handleAgentError(agent_id); -			} -		} -        LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result "  -                                 << LLAvatarNameCache::sCache.size() << " cached names" -                                 << LL_ENDL; +            } +            return; +        } + +        LLAvatarNameCache::handleAvNameCacheSuccess(results, httpResults); +      } +    catch (std::exception e) +    { +        LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL; +    } +    catch (...) +    { +        LL_WARNS() << "Caught unknown exception." << LL_ENDL; +    } +} -	/*virtual*/ void httpFailure() -	{ -		// If there's an error, it might be caused by PeopleApi, -		// or when loading textures on startup and using a very slow  -		// network, this query may time out. -		// What we should do depends on whether or not we have a cached name -		LL_WARNS("AvNameCache") << dumpResponse() << LL_ENDL; - -		// Add dummy records for any agent IDs in this request that we do not have cached already -		std::vector<LLUUID>::const_iterator it = mAgentIDs.begin(); -		for ( ; it != mAgentIDs.end(); ++it) -		{ -			const LLUUID& agent_id = *it; -			LLAvatarNameCache::handleAgentError(agent_id); -		} -	} -}; +void LLAvatarNameCache::handleAvNameCacheSuccess(const LLSD &data, const LLSD &httpResult) +{ + +    LLSD headers = httpResult["headers"]; +    // Pull expiration out of headers if available +    F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(headers); +    F64 now = LLFrameTimer::getTotalSeconds(); + +    const LLSD& agents = data["agents"]; +    LLSD::array_const_iterator it = agents.beginArray(); +    for (; it != agents.endArray(); ++it) +    { +        const LLSD& row = *it; +        LLUUID agent_id = row["id"].asUUID(); + +        LLAvatarName av_name; +        av_name.fromLLSD(row); + +        // Use expiration time from header +        av_name.mExpires = expires; + +        LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL; +        av_name.dump(); + +        // cache it and fire signals +        LLAvatarNameCache::processName(agent_id, av_name); +    } + +    // Same logic as error response case +    const LLSD& unresolved_agents = data["bad_ids"]; +    S32  num_unresolved = unresolved_agents.size(); +    if (num_unresolved > 0) +    { +        LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " << num_unresolved << " unresolved ids; " +            << "expires in " << expires - now << " seconds" +            << LL_ENDL; +        it = unresolved_agents.beginArray(); +        for (; it != unresolved_agents.endArray(); ++it) +        { +            const LLUUID& agent_id = *it; + +            LL_WARNS("AvNameCache") << "LLAvatarNameResponder::result " +                << "failed id " << agent_id +                << LL_ENDL; + +            LLAvatarNameCache::handleAgentError(agent_id); +        } +    } +    LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result " +        << LLAvatarNameCache::sCache.size() << " cached names" +        << LL_ENDL; +}  // Provide some fallback for agents that return errors  void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) @@ -353,12 +405,17 @@ void LLAvatarNameCache::requestNamesViaCapability()  		}  	} -	if (!url.empty()) -	{ -		LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested " -								 << ids << " ids" -								 << LL_ENDL; -		LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); +    if (!url.empty()) +    { +        LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested " +            << ids << " ids" +            << LL_ENDL; + +        std::string coroname =  +            LLCoros::instance().launch("LLAvatarNameCache::requestAvatarNameCache_", +            boost::bind(&LLAvatarNameCache::requestAvatarNameCache_, _1, url, agent_ids)); +        LL_DEBUGS("AvNameCache") << coroname << " with  url '" << url << "', agent_ids.size()=" << agent_ids.size() << LL_ENDL; +  	}  } @@ -422,11 +479,20 @@ void LLAvatarNameCache::initClass(bool running, bool usePeopleAPI)  {  	sRunning = running;  	sUsePeopleAPI = usePeopleAPI; + +    sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); +    sHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false); +    sHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false); +    sHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID; +    sHttpPriority = 0;  }  void LLAvatarNameCache::cleanupClass()  { -	sCache.clear(); +    sHttpRequest.reset(); +    sHttpHeaders.reset(); +    sHttpOptions.reset(); +    sCache.clear();  }  void LLAvatarNameCache::importFile(std::istream& istr) @@ -498,6 +564,8 @@ void LLAvatarNameCache::idle()  	// By convention, start running at first idle() call  	sRunning = true; +    sHttpRequest->update(0L); +  	// *TODO: Possibly re-enabled this based on People API load measurements  	// 100 ms is the threshold for "user speed" operations, so we can  	// stall for about that long to batch up requests. @@ -697,6 +765,50 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na  	sCache[agent_id] = av_name;  } +#if 0 +F64 LLAvatarNameCache::nameExpirationFromHeaders(LLCore::HttpHeaders *headers) +{ +    F64 expires = 0.0; +    if (expirationFromCacheControl(headers, &expires)) +    { +        return expires; +    } +    else +    { +        // With no expiration info, default to an hour +        const F64 DEFAULT_EXPIRES = 60.0 * 60.0; +        F64 now = LLFrameTimer::getTotalSeconds(); +        return now + DEFAULT_EXPIRES; +    } +} + +bool LLAvatarNameCache::expirationFromCacheControl(LLCore::HttpHeaders *headers, F64 *expires) +{ +    bool fromCacheControl = false; +    F64 now = LLFrameTimer::getTotalSeconds(); + +    // Allow the header to override the default +    const std::string *cache_control; +     +    cache_control = headers->find(HTTP_IN_HEADER_CACHE_CONTROL); + +    if (cache_control && !cache_control->empty()) +    { +        S32 max_age = 0; +        if (max_age_from_cache_control(*cache_control, &max_age)) +        { +            *expires = now + (F64)max_age; +            fromCacheControl = true; +        } +    } +    LL_DEBUGS("AvNameCache") +        << ( fromCacheControl ? "expires based on cache control " : "default expiration " ) +        << "in " << *expires - now << " seconds" +        << LL_ENDL; + +    return fromCacheControl; +} +#else  F64 LLAvatarNameCache::nameExpirationFromHeaders(const LLSD& headers)  {  	F64 expires = 0.0; @@ -741,7 +853,7 @@ bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *exp  	return fromCacheControl;  } - +#endif  void LLAvatarNameCache::addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb)   {  diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index ea016b3125..17b948f799 100755 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -29,7 +29,6 @@  #define LLAVATARNAMECACHE_H  #include "llavatarname.h"	// for convenience -  #include <boost/signals2.hpp>  class LLSD; @@ -49,7 +48,7 @@ namespace LLAvatarNameCache  	void importFile(std::istream& istr);  	void exportFile(std::ostream& ostr); -	// On the viewer, usually a simulator capabilitity. +	// On the viewer, usually a simulator capabilities.  	// If empty, name cache will fall back to using legacy name lookup system.  	void setNameLookupURL(const std::string& name_lookup_url); @@ -90,7 +89,7 @@ namespace LLAvatarNameCache  	// Compute name expiration time from HTTP Cache-Control header,  	// or return default value, in seconds from epoch. -	F64 nameExpirationFromHeaders(const LLSD& headers); +    F64 nameExpirationFromHeaders(const LLSD& headers);  	void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);  } diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index ee80b0fd94..30f5f3d3ed 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -30,15 +30,17 @@  #include <sstream>  #include "llcorehttputil.h" +#include "llhttpconstants.h"  #include "llsdserialize.h" -  using namespace LLCore;  namespace LLCoreHttpUtil  { + +  // *TODO:  Currently converts only from XML content.  A mode  // to convert using fromBinary() might be useful as well.  Mesh  // headers could use it. @@ -88,6 +90,57 @@ HttpHandle requestPostWithLLSD(HttpRequest * request,  	return handle;  } +HttpHandle requestPostWithLLSD(HttpRequest::ptr_t & request, +	HttpRequest::policy_t policy_id, +	HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	HttpOptions::ptr_t & options, +	HttpHeaders::ptr_t & headers, +	HttpHandler * handler) +{ +	return requestPostWithLLSD(request.get(), policy_id, priority, +		url, body, options.get(), headers.get(), handler); +} + +HttpHandle requestPutWithLLSD(HttpRequest * request, +							   HttpRequest::policy_t policy_id, +							   HttpRequest::priority_t priority, +							   const std::string & url, +							   const LLSD & body, +							   HttpOptions * options, +							   HttpHeaders * headers, +							   HttpHandler * handler) +{ +	HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID); + +	BufferArray * ba = new BufferArray(); +	BufferArrayStream bas(ba); +	LLSDSerialize::toXML(body, bas); + +	handle = request->requestPut(policy_id, +		priority, +		url, +		ba, +		options, +		headers, +		handler); +	ba->release(); +	return handle; +} + +HttpHandle requestPutWithLLSD(HttpRequest::ptr_t & request, +	HttpRequest::policy_t policy_id, +	HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	HttpOptions::ptr_t & options, +	HttpHeaders::ptr_t & headers, +	HttpHandler * handler) +{ +	return requestPutWithLLSD(request.get(), policy_id, priority, +		url, body, options.get(), headers.get(), handler); +}  std::string responseToString(LLCore::HttpResponse * response)  { @@ -135,5 +188,118 @@ std::string responseToString(LLCore::HttpResponse * response)  } +HttpCoroHandler::HttpCoroHandler(LLEventStream &reply) : +    mReplyPump(reply) +{ +} + +void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) +{ +    LLSD result; + +    LLCore::HttpStatus status = response->getStatus(); + +    if (!status) +    { +        result = LLSD::emptyMap(); +        LL_WARNS() +            << "\n--------------------------------------------------------------------------\n" +            << " Error[" << status.toULong() << "] cannot access url '" << response->getRequestURL()  +            << "' because " << status.toString() +            << "\n--------------------------------------------------------------------------" +            << LL_ENDL; + +    } +    else +    { +        const bool emit_parse_errors = false; + +        bool parsed = !((response->getBodySize() == 0) || +            !LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, result)); + +        if (!parsed) +        { +            // Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' +            LLCore::HttpHeaders::ptr_t headers(response->getHeaders()); +            const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL; + +            if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType)) +            { +                std::string thebody = LLCoreHttpUtil::responseToString(response); +                LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] " +                    << " body: " << thebody << LL_ENDL; + +                // Replace the status with a new one indicating the failure. +                status = LLCore::HttpStatus(499, "Failed to deserialize LLSD."); +            } +        } + +        if (result.isUndefined()) +        { +            // If we've gotten to this point and the result LLSD is still undefined  +            // either there was an issue deserializing the body or the response was +            // blank.  Create an empty map to hold the result either way. +            result = LLSD::emptyMap(); +        } +    } + +    buildStatusEntry(response, status, result); +    mReplyPump.post(result); +} + +void HttpCoroHandler::buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result) +{ +    LLSD httpresults = LLSD::emptyMap(); + +    httpresults["success"] = static_cast<LLSD::Boolean>(status); +    httpresults["type"] = static_cast<LLSD::Integer>(status.getType()); +    httpresults["status"] = static_cast<LLSD::Integer>(status.getStatus()); +    httpresults["message"] = static_cast<LLSD::String>(status.getMessage()); +    httpresults["url"] = static_cast<LLSD::String>(response->getRequestURL()); + +    LLSD httpHeaders = LLSD::emptyMap(); +    LLCore::HttpHeaders * hdrs = response->getHeaders(); + +    if (hdrs) +    { +        for (LLCore::HttpHeaders::iterator it = hdrs->begin(); it != hdrs->end(); ++it) +        { +            if (!(*it).second.empty()) +            { +                httpHeaders[(*it).first] = (*it).second; +            } +            else +            { +                httpHeaders[(*it).first] = static_cast<LLSD::Boolean>(true); +            } +        } +    } + +    httpresults["headers"] = httpHeaders; +    result["http_result"] = httpresults; +} + +HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request): +    mHttpRequest(request) +{ +    mBoundListener = LLEventPumps::instance().obtain("mainloop"). +        listen(LLEventPump::inventName(), boost::bind(&HttpRequestPumper::pollRequest, this, _1)); +} + +HttpRequestPumper::~HttpRequestPumper() +{ +    if (mBoundListener.connected()) +    { +        mBoundListener.disconnect(); +    } +} + +bool HttpRequestPumper::pollRequest(const LLSD&) +{ +    mHttpRequest->update(0L); +    return false; +} + +  } // end namespace LLCoreHttpUtil diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h index d40172bc7a..4ae6e112b3 100644 --- a/indra/llmessage/llcorehttputil.h +++ b/indra/llmessage/llcorehttputil.h @@ -39,6 +39,7 @@  #include "bufferarray.h"  #include "bufferstream.h"  #include "llsd.h" +#include "llevents.h"  ///  /// The base llcorehttp library implements many HTTP idioms @@ -109,6 +110,92 @@ LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest * request,  									   LLCore::HttpHeaders * headers,  									   LLCore::HttpHandler * handler); +LLCore::HttpHandle requestPostWithLLSD(LLCore::HttpRequest::ptr_t & request, +	LLCore::HttpRequest::policy_t policy_id, +	LLCore::HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	LLCore::HttpOptions::ptr_t & options, +	LLCore::HttpHeaders::ptr_t & headers, +	LLCore::HttpHandler * handler); + +/// Issue a standard HttpRequest::requestPut() call but using +/// and LLSD object as the request body.  Conventions are the +/// same as with that method.  Caller is expected to provide +/// an HttpHeaders object with a correct 'Content-Type:' header. +/// One will not be provided by this call. +/// +/// @return				If request is successfully issued, the +///						HttpHandle representing the request. +///						On error, LLCORE_HTTP_HANDLE_INVALID +///						is returned and caller can fetch detailed +///						status with the getStatus() method on the +///						request object.  In case of error, no +///						request is queued and caller may need to +///						perform additional cleanup such as freeing +///						a now-useless HttpHandler object. +/// +LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest * request, +	LLCore::HttpRequest::policy_t policy_id, +	LLCore::HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	LLCore::HttpOptions * options, +	LLCore::HttpHeaders * headers, +	LLCore::HttpHandler * handler); + +LLCore::HttpHandle requestPutWithLLSD(LLCore::HttpRequest::ptr_t & request, +	LLCore::HttpRequest::policy_t policy_id, +	LLCore::HttpRequest::priority_t priority, +	const std::string & url, +	const LLSD & body, +	LLCore::HttpOptions::ptr_t & options, +	LLCore::HttpHeaders::ptr_t & headers, +	LLCore::HttpHandler * handler); + +/// The HttpCoroHandler is a specialization of the LLCore::HttpHandler for  +/// interacting with coroutines. When the request is completed the response  +/// will be posted onto the supplied Event Pump. +///  +/// The LLSD posted back to the coroutine will have the following additions: +/// llsd["http_result"] -+- ["message"] - An error message returned from the HTTP status +///                      +- ["status"]  - The status code associated with the HTTP call +///                      +- ["success"] - Success of failure of the HTTP call and LLSD parsing. +///                      +- ["type"]    - The LLCore::HttpStatus type associted with the HTTP call +///                      +- ["url"]     - The URL used to make the call. +///                      +- ["headers"] - A map of name name value pairs with the HTTP headers. +///                       +class HttpCoroHandler : public LLCore::HttpHandler +{ +public: +    HttpCoroHandler(LLEventStream &reply); + +    virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + +    typedef boost::shared_ptr<HttpCoroHandler> ptr_t; + +private: +    void buildStatusEntry(LLCore::HttpResponse *response, LLCore::HttpStatus status, LLSD &result); + +    LLEventStream &mReplyPump; +}; + +/// The HttpRequestPumper is a utility class. When constructed it will poll the  +/// supplied HttpRequest once per frame until it is destroyed. +///  +class HttpRequestPumper +{ +public: +    HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request); +    ~HttpRequestPumper(); + +private: +    bool                       pollRequest(const LLSD&); + +    LLTempBoundListener        mBoundListener; +    LLCore::HttpRequest::ptr_t mHttpRequest; +}; +  } // end namespace LLCoreHttpUtil diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 73df47b933..ef28a4d211 100755 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -69,13 +69,15 @@  	do this.   */ +// *TODO: TSN remove the commented code from this file  //////////////////////////////////////////////////////////////////////////////  static const U32 EASY_HANDLE_POOL_SIZE		= 5;  static const S32 MULTI_PERFORM_CALL_REPEAT	= 5;  static const S32 CURL_REQUEST_TIMEOUT = 120; // seconds per operation  static const S32 CURL_CONNECT_TIMEOUT = 30; //seconds to wait for a connection -static const S32 MAX_ACTIVE_REQUEST_COUNT = 100; + +//static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;  // DEBUG //  S32 gCurlEasyCount = 0; @@ -676,6 +678,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,  }  //////////////////////////////////////////////////////////////////////////// +#if 1  LLCurl::Multi::Multi(F32 idle_time_out)  	: mQueued(0),  	  mErrorCount(0), @@ -1056,6 +1059,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 +1180,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 +1992,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..06b3ce45e1 100755 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -418,100 +418,6 @@ private:  } ; -class LLCurlRequest -{ -public: -	typedef std::vector<std::string> headers_t; -	 -	LLCurlRequest(); -	~LLCurlRequest(); - -	void get(const std::string& url, LLCurl::ResponderPtr responder); -	bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder); -	bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder, S32 time_out = 0); -	bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder, S32 time_out = 0); -	 -	S32  process(); -	S32  getQueued(); - -private: -	void addMulti(); -	LLCurl::Easy* allocEasy(); -	bool addEasy(LLCurl::Easy* easy); -	 -private: -	typedef std::set<LLCurl::Multi*> curlmulti_set_t; -	curlmulti_set_t mMultiSet; -	LLCurl::Multi* mActiveMulti; -	S32 mActiveRequestCount; -	BOOL mProcessing; -}; - -//for texture fetch only -class LLCurlTextureRequest : public LLCurlRequest -{ -public: -	LLCurlTextureRequest(S32 concurrency); -	~LLCurlTextureRequest(); - -	U32 getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder, F32 delay_time = -1.f); -	void nextRequests(); -	void completeRequest(S32 received_bytes); - -	void updatePriority(U32 handle, U32 pri); -	void removeRequest(U32 handle); - -	U32 getTotalReceivedBits(); -	U32 getTotalIssuedRequests(); -	S32 getNumRequests(); -	bool isWaiting(U32 handle); -	 -private: -	LLMutex mMutex; -	S32 mConcurrency; -	S32 mInQueue; //request currently in queue. -	U32 mHandleCounter; -	U32 mTotalIssuedRequests; -	U32 mTotalReceivedBits; - -	typedef struct _request_t -	{ -		_request_t(U32 handle, const std::string& url, const headers_t& headers, S32 offset, S32 length, U32 pri, LLCurl::ResponderPtr responder) : -				mHandle(handle), mUrl(url), mHeaders(headers), mOffset(offset), mLength(length), mPriority(pri), mResponder(responder), mStartTime(0.f) -				{} - -		U32  mHandle; -		std::string mUrl; -		LLCurlRequest::headers_t mHeaders; -		S32 mOffset; -		S32 mLength; -		LLCurl::ResponderPtr mResponder; -		U32 mPriority; -		F32 mStartTime; //start time to issue this request -	} request_t; - -	struct request_compare -	{ -		bool operator()(const request_t* lhs, const request_t* rhs) const -		{ -			if(lhs->mPriority != rhs->mPriority) -			{ -				return lhs->mPriority > rhs->mPriority; // higher priority in front of queue (set) -			} -			else -			{ -				return (U32)lhs < (U32)rhs; -			} -		} -	}; - -	typedef std::set<request_t*, request_compare> req_queue_t; -	req_queue_t mCachedRequests; -	std::map<S32, request_t*> mRequestMap; - -	LLFrameTimer mGlobalTimer; -}; -  class LLCurlEasyRequest  {  public: @@ -550,7 +456,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..b4a76cb808 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> 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/llhttpsdhandler.cpp b/indra/llmessage/llhttpsdhandler.cpp new file mode 100644 index 0000000000..159d03b176 --- /dev/null +++ b/indra/llmessage/llhttpsdhandler.cpp @@ -0,0 +1,103 @@ +/** +* @file llhttpsdhandler.h +* @brief Public-facing declarations for the HttpHandler class +* +* $LicenseInfo:firstyear=2012&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2012, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#include "linden_common.h" +#include "llhttpconstants.h" + +#include "llhttpsdhandler.h" +#include "httpresponse.h" +#include "httpheaders.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "bufferstream.h" +#include "llcorehttputil.h" + +//======================================================================== +LLHttpSDHandler::LLHttpSDHandler() +{ +} + +void LLHttpSDHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) +{ +	LLCore::HttpStatus status = response->getStatus(); + +	if (!status) +	{ +		this->onFailure(response, status); +	} +	else +	{ +		LLSD resplsd; +		const bool emit_parse_errors = false; + +		bool parsed = !((response->getBodySize() == 0) || +			!LLCoreHttpUtil::responseToLLSD(response, emit_parse_errors, resplsd)); + +		if (!parsed)  +		{ +			// Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' +			LLCore::HttpHeaders::ptr_t headers(response->getHeaders()); +			const std::string *contentType = (headers) ? headers->find(HTTP_IN_HEADER_CONTENT_TYPE) : NULL; + +			if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType)) +			{ +				std::string thebody = LLCoreHttpUtil::responseToString(response); + +				LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] " +					<< " body: " << thebody << LL_ENDL; +			} +		} + +		this->onSuccess(response, resplsd); +	} + +	// The handler must destroy itself when it is done.  +	// *TODO: I'm not fond of this pattern. A class shooting itself in the head  +	// outside of a smart pointer always makes me nervous. +	delete this; +} + +//======================================================================== +LLHttpSDGenericHandler::LLHttpSDGenericHandler(const std::string &caps) : +	LLHttpSDHandler(), +	mCaps(caps) +{ +} + +void LLHttpSDGenericHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content) +{ +	LL_DEBUGS() << mCaps << " Success." << LL_ENDL; +} + +void LLHttpSDGenericHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) +{ +	LL_WARNS() +		<< "\n--------------------------------------------------------------------------\n" +		<< mCaps << " Error[" << status.toULong() << "] cannot access cap with url '"  +		<< response->getRequestURL() << "' because " << status.toString() +		<< "\n--------------------------------------------------------------------------" +		<< LL_ENDL; +} diff --git a/indra/llmessage/llhttpsdhandler.h b/indra/llmessage/llhttpsdhandler.h new file mode 100644 index 0000000000..7c28dbcab6 --- /dev/null +++ b/indra/llmessage/llhttpsdhandler.h @@ -0,0 +1,67 @@ +/** +* @file llhttpsdhandler.h +* @brief Public-facing declarations for the HttpHandler class +* +* $LicenseInfo:firstyear=2012&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2012, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#ifndef	_LLHTTPSDHANDLER_H_ +#define	_LLHTTPSDHANDLER_H_ +#include "httpcommon.h" +#include "httphandler.h" +#include "lluri.h" + +/// Handler class LLCore's HTTP library. Splitting with separate success and  +/// failure routines and parsing the result body into LLSD on success.  It  +/// is intended to be subclassed for specific capability handling. +///  +// *TODO: This class self deletes at the end of onCompleted method.  This is  +// less than ideal and should be revisited. +class LLHttpSDHandler : public LLCore::HttpHandler +{ +public: +	LLHttpSDHandler(); + +	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); +	 +protected: +	virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content) = 0; +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) = 0; + +}; + +/// A trivial implementation of LLHttpSDHandler. This success and failure  +/// methods log the action taken, the URI accessed and the status code retuned  +/// in the response. +class LLHttpSDGenericHandler : public LLHttpSDHandler +{ +public:  +	LLHttpSDGenericHandler(const std::string &action); + +protected: +	virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); + +private: +	std::string mCaps; +}; +#endif
\ No newline at end of file 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/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp index e9ce116bb3..e0a82e237b 100755 --- a/indra/llmessage/tests/llhttpclientadapter_test.cpp +++ b/indra/llmessage/tests/llhttpclientadapter_test.cpp @@ -23,7 +23,7 @@   * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA   * $/LicenseInfo$   */ - +#if 0  #include "llhttpclientadapter.h"  #include "../test/lltut.h" @@ -219,3 +219,4 @@ namespace tut  	}  } +#endif
\ No newline at end of file diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 13040ea423..3858383e39 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2330,16 +2330,26 @@ if (LL_TESTS)      "${CMAKE_SOURCE_DIR}/llmessage/tests/test_llsdmessage_peer.py"      ) +  if (LINUX)	 +    # llcommon uses `clock_gettime' which is provided by librt on linux. +    set(LIBRT_LIBRARY +	  rt +	  ) +  endif (LINUX) +    set(test_libs -    ${LLMESSAGE_LIBRARIES} -    ${LLCOREHTTP_LIBRARIES}      ${WINDOWS_LIBRARIES}      ${LLVFS_LIBRARIES}      ${LLMATH_LIBRARIES}      ${LLCOMMON_LIBRARIES} +    ${LLMESSAGE_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES}      ${GOOGLEMOCK_LIBRARIES}      ${OPENSSL_LIBRARIES}      ${CRYPTO_LIBRARIES} +	${LIBRT_LIBRARY} +    ${BOOST_CONTEXT_LIBRARY} +    ${BOOST_COROUTINE_LIBRARY}    )      LL_ADD_INTEGRATION_TEST(llsechandler_basic diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index a42286a9e4..c52e6e1172 100755 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -27,90 +27,171 @@  #include "llviewerprecompiledheaders.h"  #include "llaccountingcostmanager.h"  #include "llagent.h" -#include "llcurl.h" -#include "llhttpclient.h" +#include "httpcommon.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llcorehttputil.h" +  //=============================================================================== -LLAccountingCostManager::LLAccountingCostManager() +LLAccountingCostManager::LLAccountingCostManager(): +    mHttpRequest(), +    mHttpHeaders(), +    mHttpOptions(), +    mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), +    mHttpPriority(0)  {	 +    mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); +    mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false); +    mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false); +    //mHttpPolicy = LLCore::HttpRequest::DEFAULT_POLICY_ID; +  } -//=============================================================================== -class LLAccountingCostResponder : public LLCurl::Responder + +// Coroutine for sending and processing avatar name cache requests.   +// Do not call directly.  See documentation in lleventcoro.h and llcoro.h for +// further explanation. +void LLAccountingCostManager::accountingCostCoro(LLCoros::self& self, std::string url, +    eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle)  { -	LOG_CLASS(LLAccountingCostResponder); -public: -	LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle<LLAccountingCostObserver>& observer_handle ) -	: mObjectIDs( objectIDs ), -	  mObserverHandle( observer_handle ) -	{ -		LLAccountingCostObserver* observer = mObserverHandle.get(); -		if (observer) -		{ -			mTransactionID = observer->getTransactionID(); -		} -	} +    LLEventStream  replyPump("AccountingCostReply", true); +    LLCoreHttpUtil::HttpCoroHandler::ptr_t httpHandler =  +        LLCoreHttpUtil::HttpCoroHandler::ptr_t(new LLCoreHttpUtil::HttpCoroHandler(replyPump)); -	void clearPendingRequests ( void ) -	{ -		for ( LLSD::array_iterator iter = mObjectIDs.beginArray(); iter != mObjectIDs.endArray(); ++iter ) -		{ -			LLAccountingCostManager::getInstance()->removePendingObject( iter->asUUID() ); -		} -	} -	 -protected: -	void httpFailure() -	{ -		LL_WARNS() << dumpResponse() << LL_ENDL; -		clearPendingRequests(); - -		LLAccountingCostObserver* observer = mObserverHandle.get(); -		if (observer && observer->getTransactionID() == mTransactionID) -		{ -			observer->setErrorStatus(getStatus(), getReason()); -		} -	} -	 -	void httpSuccess() -	{ -		const LLSD& content = getContent(); -		//Check for error -		if ( !content.isMap() || content.has("error") ) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Error on fetched data", content); -			return; -		} -		else if (content.has("selected")) -		{ -			F32 physicsCost		= 0.0f; -			F32 networkCost		= 0.0f; -			F32 simulationCost	= 0.0f; - -			physicsCost		= content["selected"]["physics"].asReal(); -			networkCost		= content["selected"]["streaming"].asReal(); -			simulationCost	= content["selected"]["simulation"].asReal(); -				 -			SelectionCost selectionCost( /*transactionID,*/ physicsCost, networkCost, simulationCost ); - -			LLAccountingCostObserver* observer = mObserverHandle.get(); -			if (observer && observer->getTransactionID() == mTransactionID) -			{ -				observer->onWeightsUpdate(selectionCost); -			} -		} - -		clearPendingRequests(); -	} -	 -private: -	//List of posted objects -	LLSD mObjectIDs; +    LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::instance().getName(self) +        << " with url '" << url << LL_ENDL; + +    try +    { +        LLSD objectList; +        U32  objectIndex = 0; + +        IDIt IDIter = mObjectList.begin(); +        IDIt IDIterEnd = mObjectList.end(); + +        for (; IDIter != IDIterEnd; ++IDIter) +        { +            // Check to see if a request for this object has already been made. +            if (mPendingObjectQuota.find(*IDIter) == mPendingObjectQuota.end()) +            { +                mPendingObjectQuota.insert(*IDIter); +                objectList[objectIndex++] = *IDIter; +            } +        } + +        mObjectList.clear(); + +        //Post results +        if (objectList.size() == 0) +            return; + +        std::string keystr; +        if (selectionType == Roots) +        { +            keystr = "selected_roots"; +        } +        else if (selectionType == Prims) +        { +            keystr = "selected_prims"; +        } +        else +        { +            LL_INFOS() << "Invalid selection type " << LL_ENDL; +            mObjectList.clear(); +            mPendingObjectQuota.clear(); +            return; +        } -	// Current request ID -	LLUUID mTransactionID; +        LLSD dataToPost = LLSD::emptyMap(); +        dataToPost[keystr.c_str()] = objectList; + +        LLAccountingCostObserver* observer = observerHandle.get(); +        LLUUID transactionId = observer->getTransactionID(); +        observer = NULL; + +        LLSD results; +        {   // Scoping block for pumper object +            LL_INFOS() << "Requesting transaction " << transactionId << LL_ENDL; +            LLCoreHttpUtil::HttpRequestPumper pumper(mHttpRequest); +            LLCore::HttpHandle hhandle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest, +                mHttpPolicy, mHttpPriority, url, dataToPost, mHttpOptions, mHttpHeaders, +                httpHandler.get()); + +            if (hhandle == LLCORE_HTTP_HANDLE_INVALID) +            { +                LLCore::HttpStatus status = mHttpRequest->getStatus(); +                LL_WARNS() << "Error posting to " << url << " Status=" << status.getStatus() << +                    " message = " << status.getMessage() << LL_ENDL; +                mPendingObjectQuota.clear(); +                return; +            } + +            results = waitForEventOn(self, replyPump); +            LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL; +        } +        LLSD httpResults; +        httpResults = results["http_result"]; + +        do  +        { +            observer = observerHandle.get(); +            if ((!observer) || (observer->getTransactionID() != transactionId)) +            { +                if (!observer) +                    break; +                LL_WARNS() << "Request transaction Id(" << transactionId +                    << ") does not match observer's transaction Id(" +                    << observer->getTransactionID() << ")." << LL_ENDL; +                break; +            } + +            if (!httpResults["success"].asBoolean()) +            { +                LL_WARNS() << "Error result from LLCoreHttpUtil::HttpCoroHandler. Code " +                    << httpResults["status"] << ": '" << httpResults["message"] << "'" << LL_ENDL; +                if (observer) +                { +                    observer->setErrorStatus(httpResults["status"].asInteger(), httpResults["message"].asStringRef()); +                } +                break; +            } + +            if (!results.isMap() || results.has("error")) +            { +                LL_WARNS() << "Error on fetched data" << LL_ENDL; +                observer->setErrorStatus(499, "Error on fetched data"); +                break; +            } + +            if (results.has("selected")) +            { +                F32 physicsCost = 0.0f; +                F32 networkCost = 0.0f; +                F32 simulationCost = 0.0f; + +                physicsCost = results["selected"]["physics"].asReal(); +                networkCost = results["selected"]["streaming"].asReal(); +                simulationCost = results["selected"]["simulation"].asReal(); + +                SelectionCost selectionCost( physicsCost, networkCost, simulationCost); + +                observer->onWeightsUpdate(selectionCost); +            } + +        } while (false); + +    } +    catch (std::exception e) +    { +        LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL; +    } +    catch (...) +    { +        LL_WARNS() << "Caught unknown exception." << LL_ENDL; +    } + +    mPendingObjectQuota.clear(); +} -	// Cost update observer handle -	LLHandle<LLAccountingCostObserver> mObserverHandle; -};  //===============================================================================  void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,  										  const std::string& url, @@ -119,50 +200,11 @@ void LLAccountingCostManager::fetchCosts( eSelectionType selectionType,  	// Invoking system must have already determined capability availability  	if ( !url.empty() )  	{ -		LLSD objectList; -		U32  objectIndex = 0; -		 -		IDIt IDIter = mObjectList.begin(); -		IDIt IDIterEnd = mObjectList.end(); -		 -		for ( ; IDIter != IDIterEnd; ++IDIter ) -		{ -			// Check to see if a request for this object has already been made. -			if ( mPendingObjectQuota.find( *IDIter ) ==	mPendingObjectQuota.end() ) -			{ -				mPendingObjectQuota.insert( *IDIter ); -				objectList[objectIndex++] = *IDIter; -			} -		} -	 -		mObjectList.clear(); -		 -		//Post results -		if ( objectList.size() > 0 ) -		{ -			std::string keystr; -			if ( selectionType == Roots )  -			{  -				keystr="selected_roots";  -			} -			else -			if ( selectionType == Prims )  -			{  -				keystr="selected_prims"; -			} -			else  -			{ -				LL_INFOS()<<"Invalid selection type "<<LL_ENDL; -				mObjectList.clear(); -				mPendingObjectQuota.clear(); -				return; -			} -			 -			LLSD dataToPost = LLSD::emptyMap();		 -			dataToPost[keystr.c_str()] = objectList; - -			LLHTTPClient::post( url, dataToPost, new LLAccountingCostResponder( objectList, observer_handle )); -		} +        std::string coroname =  +            LLCoros::instance().launch("LLAccountingCostManager::accountingCostCoro", +            boost::bind(&LLAccountingCostManager::accountingCostCoro, this, _1, url, selectionType, observer_handle)); +        LL_DEBUGS() << coroname << " with  url '" << url << LL_ENDL; +  	}  	else  	{ diff --git a/indra/newview/llaccountingcostmanager.h b/indra/newview/llaccountingcostmanager.h index 3ade34c81d..7d544b15e8 100755 --- a/indra/newview/llaccountingcostmanager.h +++ b/indra/newview/llaccountingcostmanager.h @@ -30,6 +30,13 @@  #include "llhandle.h"  #include "llaccountingcost.h" +#include "httpcommon.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "httprequest.h" +#include "httpheaders.h" +#include "httpoptions.h" +  //===============================================================================  // An interface class for panels which display the parcel accounting information.  class LLAccountingCostObserver @@ -69,6 +76,14 @@ private:  	//a fetch has been instigated.  	std::set<LLUUID> mPendingObjectQuota;  	typedef std::set<LLUUID>::iterator IDIt; + +    void accountingCostCoro(LLCoros::self& self, std::string url, eSelectionType selectionType, const LLHandle<LLAccountingCostObserver> observerHandle); + +    LLCore::HttpRequest::ptr_t		mHttpRequest; +    LLCore::HttpHeaders::ptr_t		mHttpHeaders; +    LLCore::HttpOptions::ptr_t		mHttpOptions; +    LLCore::HttpRequest::policy_t	mHttpPolicy; +    LLCore::HttpRequest::priority_t	mHttpPriority;  };  //=============================================================================== diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index f151b15e29..eeedda5c6d 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -95,6 +95,8 @@  #include "lscript_byteformat.h"  #include "stringize.h"  #include "boost/foreach.hpp" +#include "llhttpsdhandler.h" +#include "llcorehttputil.h"  using namespace LLAvatarAppearanceDefines; @@ -361,7 +363,12 @@ LLAgent::LLAgent() :  	mMaturityPreferenceNumRetries(0U),  	mLastKnownRequestMaturity(SIM_ACCESS_MIN),  	mLastKnownResponseMaturity(SIM_ACCESS_MIN), -	mTeleportState( TELEPORT_NONE ), +	mHttpRequest(), +	mHttpHeaders(), +	mHttpOptions(), +	mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), +	mHttpPriority(0), +	mTeleportState(TELEPORT_NONE),  	mRegionp(NULL),  	mAgentOriginGlobal(), @@ -459,6 +466,17 @@ void LLAgent::init()  		mTeleportFailedSlot = LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&LLAgent::handleTeleportFailed, this));  	} +	LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + +	mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); +	mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false); +	mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false); +	mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_AGENT); + +    // Now ensure that we get regular callbacks to poll for completion. +    mBoundListener = LLEventPumps::instance().obtain("mainloop"). +        listen(LLEventPump::inventName(), boost::bind(&LLAgent::pollHttp, this, _1)); +  	mInitialized = TRUE;  } @@ -476,6 +494,10 @@ void LLAgent::cleanup()  	{  		mTeleportFailedSlot.disconnect();  	} +    if (mBoundListener.connected()) +    { +        mBoundListener.disconnect(); +    }  }  //----------------------------------------------------------------------------- @@ -498,6 +520,17 @@ LLAgent::~LLAgent()  	mTeleportSourceSLURL = NULL;  } +//----------------------------------------------------------------------------- +// pollHttp +//  Polling done once per frame on the "mainloop" to support HTTP processing. +//----------------------------------------------------------------------------- +bool LLAgent::pollHttp(const LLSD&) +{ +    mHttpRequest->update(0L); +    return false; +} + +  // Handle any actions that need to be performed when the main app gains focus  // (such as through alt-tab).  //----------------------------------------------------------------------------- @@ -2515,66 +2548,61 @@ int LLAgent::convertTextToMaturity(char text)  	return LLAgentAccess::convertTextToMaturity(text);  } -class LLMaturityPreferencesResponder : public LLHTTPClient::Responder +//========================================================================= +class LLMaturityHttpHandler : public LLHttpSDHandler  { -	LOG_CLASS(LLMaturityPreferencesResponder);  public: -	LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity); -	virtual ~LLMaturityPreferencesResponder(); +	LLMaturityHttpHandler(LLAgent *agent, U8 preferred, U8 previous): +		LLHttpSDHandler(), +		mAgent(agent), +		mPreferredMaturity(preferred), +		mPreviousMaturity(previous) +	{ } -protected: -	virtual void httpSuccess(); -	virtual void httpFailure(); +	virtual ~LLMaturityHttpHandler() +	{ }  protected: +	virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);  private: -	U8 parseMaturityFromServerResponse(const LLSD &pContent) const; +	U8			parseMaturityFromServerResponse(const LLSD &pContent) const; -	LLAgent                                  *mAgent; -	U8                                       mPreferredMaturity; -	U8                                       mPreviousMaturity; -}; - -LLMaturityPreferencesResponder::LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity) -	: LLHTTPClient::Responder(), -	mAgent(pAgent), -	mPreferredMaturity(pPreferredMaturity), -	mPreviousMaturity(pPreviousMaturity) -{ -} +	LLAgent *	mAgent; +	U8			mPreferredMaturity; +	U8          mPreviousMaturity; -LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder() -{ -} +}; -void LLMaturityPreferencesResponder::httpSuccess() +//------------------------------------------------------------------------- +void LLMaturityHttpHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)  { -	U8 actualMaturity = parseMaturityFromServerResponse(getContent()); +	U8 actualMaturity = parseMaturityFromServerResponse(content);  	if (actualMaturity != mPreferredMaturity)  	{  		LL_WARNS() << "while attempting to change maturity preference from '" -				   << LLViewerRegion::accessToString(mPreviousMaturity) -				   << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  -				   << "', the server responded with '" -				   << LLViewerRegion::accessToString(actualMaturity)  -				   << "' [value:" << static_cast<U32>(actualMaturity)  -				   << "], " << dumpResponse() << LL_ENDL; +			<< LLViewerRegion::accessToString(mPreviousMaturity) +			<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) +			<< "', the server responded with '" +			<< LLViewerRegion::accessToString(actualMaturity) +			<< "' [value:" << static_cast<U32>(actualMaturity) +			<< "], " << LL_ENDL;  	}  	mAgent->handlePreferredMaturityResult(actualMaturity);  } -void LLMaturityPreferencesResponder::httpFailure() +void LLMaturityHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)  { -	LL_WARNS() << "while attempting to change maturity preference from '"  -			   << LLViewerRegion::accessToString(mPreviousMaturity) -			   << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  -			<< "', " << dumpResponse() << LL_ENDL; +	LL_WARNS() << "while attempting to change maturity preference from '" +		<< LLViewerRegion::accessToString(mPreviousMaturity) +		<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) +		<< "', " << LL_ENDL;  	mAgent->handlePreferredMaturityError();  } -U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const +U8 LLMaturityHttpHandler::parseMaturityFromServerResponse(const LLSD &pContent) const  {  	U8 maturity = SIM_ACCESS_MIN; @@ -2595,6 +2623,7 @@ U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &p  	return maturity;  } +//=========================================================================  void LLAgent::handlePreferredMaturityResult(U8 pServerMaturity)  { @@ -2724,42 +2753,82 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity)  		// Update the last know maturity request  		mLastKnownRequestMaturity = pPreferredMaturity; -		// Create a response handler -		LLHTTPClient::ResponderPtr responderPtr = LLHTTPClient::ResponderPtr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity)); -  		// If we don't have a region, report it as an error  		if (getRegion() == NULL)  		{ -			responderPtr->failureResult(0U, "region is not defined", LLSD()); +			LL_WARNS("Agent") << "Region is not defined, can not change Maturity setting." << LL_ENDL; +			return;  		} -		else +		std::string url = getRegion()->getCapability("UpdateAgentInformation"); + +		// If the capability is not defined, report it as an error +		if (url.empty())  		{ -			// Find the capability to send maturity preference -			std::string url = getRegion()->getCapability("UpdateAgentInformation"); +			LL_WARNS("Agent") << "'UpdateAgentInformation' is not defined for region" << LL_ENDL; +			return; +		} -			// If the capability is not defined, report it as an error -			if (url.empty()) -			{ -				responderPtr->failureResult(0U,  -							"capability 'UpdateAgentInformation' is not defined for region", LLSD()); -			} -			else -			{ -				// Set new access preference -				LLSD access_prefs = LLSD::emptyMap(); -				access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity); - -				LLSD body = LLSD::emptyMap(); -				body["access_prefs"] = access_prefs; -				LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) -					<< "' via capability to: " << url << LL_ENDL; -				LLSD headers; -				LLHTTPClient::post(url, body, responderPtr, headers, 30.0f); -			} +		LLMaturityHttpHandler * handler = new LLMaturityHttpHandler(this, pPreferredMaturity, mLastKnownResponseMaturity); + +		LLSD access_prefs = LLSD::emptyMap(); +		access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity); + +		LLSD postData = LLSD::emptyMap(); +		postData["access_prefs"] = access_prefs; +		LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) +			<< "' via capability to: " << url << LL_ENDL; + +		LLCore::HttpHandle handle = requestPostCapability("UpdateAgentInformation", url, postData, handler); + +		if (handle == LLCORE_HTTP_HANDLE_INVALID) +		{ +			delete handler; +			LL_WARNS("Agent") << "Maturity request post failed." << LL_ENDL;  		}  	}  } +LLCore::HttpHandle LLAgent::requestPostCapability(const std::string &cap, const std::string &url, LLSD &postData, LLHttpSDHandler *usrhndlr) +{ +	LLHttpSDHandler * handler = (usrhndlr) ? usrhndlr : new LLHttpSDGenericHandler(cap); +	LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest, +		mHttpPolicy, mHttpPriority, url, +		postData, mHttpOptions, mHttpHeaders, handler); + +	if (handle == LLCORE_HTTP_HANDLE_INVALID) +	{ +        // If no handler was passed in we delete the handler default handler allocated  +        // at the start of this function. +        // *TODO: Change this metaphore to use boost::shared_ptr<> for handlers.  Requires change in LLCore::HTTP +		if (!usrhndlr) +			delete handler; +		LLCore::HttpStatus status = mHttpRequest->getStatus(); +		LL_WARNS("Agent") << "'" << cap << "' request POST failed. Reason "  +			<< status.toTerseString() << " \"" << status.toString() << "\"" << LL_ENDL; +	} +	return handle; +} + +LLCore::HttpHandle LLAgent::requestGetCapability(const std::string &cap, const std::string &url, LLHttpSDHandler *usrhndlr) +{ +    LLHttpSDHandler * handler = (usrhndlr) ? usrhndlr : new LLHttpSDGenericHandler(cap); +    LLCore::HttpHandle handle = mHttpRequest->requestGet(mHttpPolicy, mHttpPriority,  +            url, mHttpOptions.get(), mHttpHeaders.get(), handler); + +    if (handle == LLCORE_HTTP_HANDLE_INVALID) +    { +        // If no handler was passed in we delete the handler default handler allocated  +        // at the start of this function. +        // *TODO: Change this metaphore to use boost::shared_ptr<> for handlers.  Requires change in LLCore::HTTP +        if (!usrhndlr) +            delete handler; +        LLCore::HttpStatus status = mHttpRequest->getStatus(); +        LL_WARNS("Agent") << "'" << cap << "' request GET failed. Reason " +            << status.toTerseString() << " \"" << status.toString() << "\"" << LL_ENDL; +    } +    return handle; +} +  BOOL LLAgent::getAdminOverride() const	  {   	return mAgentAccess->getAdminOverride();  diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 56bd1428ce..9ffc9b9a7a 100755 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -34,7 +34,11 @@  #include "llcoordframe.h"			// for mFrameAgent  #include "llavatarappearancedefines.h"  #include "llpermissionsflags.h" +#include "llevents.h"  #include "v3dmath.h" +#include "httprequest.h" +#include "httpheaders.h" +#include "httpoptions.h"  #include <boost/function.hpp>  #include <boost/shared_ptr.hpp> @@ -60,6 +64,7 @@ class LLSLURL;  class LLPauseRequestHandle;  class LLUIColor;  class LLTeleportRequest; +class LLHttpSDHandler;  typedef boost::shared_ptr<LLTeleportRequest> LLTeleportRequestPtr; @@ -112,6 +117,8 @@ public:  	void			init();  	void			cleanup(); +private: +  	//--------------------------------------------------------------------  	// Login  	//-------------------------------------------------------------------- @@ -754,11 +761,17 @@ private:  	unsigned int                    mMaturityPreferenceNumRetries;  	U8                              mLastKnownRequestMaturity;  	U8                              mLastKnownResponseMaturity; +	LLCore::HttpRequest::ptr_t		mHttpRequest; +	LLCore::HttpHeaders::ptr_t		mHttpHeaders; +	LLCore::HttpOptions::ptr_t		mHttpOptions; +	LLCore::HttpRequest::policy_t	mHttpPolicy; +	LLCore::HttpRequest::priority_t	mHttpPriority; +    LLTempBoundListener             mBoundListener;  	bool            isMaturityPreferenceSyncedWithServer() const;  	void 			sendMaturityPreferenceToServer(U8 pPreferredMaturity); -	friend class LLMaturityPreferencesResponder; +	friend class	LLMaturityHttpHandler;  	void            handlePreferredMaturityResult(U8 pServerMaturity);  	void            handlePreferredMaturityError();  	void            reportPreferredMaturitySuccess(); @@ -768,6 +781,8 @@ private:  	void 			handleMaturity(const LLSD &pNewValue);  	bool 			validateMaturity(const LLSD& newvalue); +    bool            pollHttp(const LLSD &); +  /**                    Access   **                                                                            ** @@ -907,6 +922,20 @@ public:  /********************************************************************************   **                                                                            ** + **                    UTILITY + **/ +public: +	/// Utilities for allowing the the agent sub managers to post and get via +	/// HTTP using the agent's policy settings and headers.   +	LLCore::HttpHandle	requestPostCapability(const std::string &cap, const std::string &url, LLSD &postData, LLHttpSDHandler *usrhndlr = NULL); +    LLCore::HttpHandle	requestGetCapability(const std::string &cap, const std::string &url, LLHttpSDHandler *usrhndlr = NULL); + +/**                    Utility + **                                                                            ** + *******************************************************************************/ + +/******************************************************************************** + **                                                                            **   **                    DEBUGGING   **/ diff --git a/indra/newview/llagentlanguage.cpp b/indra/newview/llagentlanguage.cpp index fe6236a32a..f2ac323578 100755 --- a/indra/newview/llagentlanguage.cpp +++ b/indra/newview/llagentlanguage.cpp @@ -32,6 +32,7 @@  #include "llviewerregion.h"  // library includes  #include "llui.h"					// getLanguage() +#include "httpcommon.h"  // static  void LLAgentLanguage::init() @@ -69,7 +70,12 @@ bool LLAgentLanguage::update()  		body["language"] = language;  		body["language_is_public"] = gSavedSettings.getBOOL("LanguageIsPublic"); -		LLHTTPClient::post(url, body, new LLHTTPClient::Responder); +		//LLHTTPClient::post(url, body, new LLHTTPClient::Responder); +		LLCore::HttpHandle handle = gAgent.requestPostCapability("UpdateAgentLanguage", url, body); +		if (handle == LLCORE_HTTP_HANDLE_INVALID) +		{ +			LL_WARNS() << "Unable to change language." << LL_ENDL; +		}  	}      return true;  } diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index f5f224b83e..51cca273d8 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 @@ -93,6 +97,16 @@ static const struct  		4,		1,		4,		0,		false,  		"",  		"inventory" +	}, +	{ // AP_MATERIALS +		2,		1,		8,		0,		false, +		"RenderMaterials", +		"material manager requests" +	}, +	{ // AP_AGENT +		2,		1,		32,		0,		true, +		"Agent", +		"Agent requests"  	}  }; @@ -151,6 +165,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 @@ -182,6 +205,8 @@ void LLAppCoreHttp::init()  		}  		mHttpClasses[app_policy].mPolicy = LLCore::HttpRequest::createPolicyClass(); +		// We have run out of available HTTP policies. Adjust HTTP_POLICY_CLASS_LIMIT in _httpinternal.h +		llassert(mHttpClasses[app_policy].mPolicy != LLCore::HttpRequest::INVALID_POLICY_ID);  		if (! mHttpClasses[app_policy].mPolicy)  		{  			// Use default policy (but don't accidentally modify default) @@ -457,6 +482,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..410d7c6b07 100755 --- a/indra/newview/llappcorehttp.h +++ b/indra/newview/llappcorehttp.h @@ -164,7 +164,29 @@ public:  		/// Pipelined:       no  		AP_INVENTORY,  		AP_REPORTING = AP_INVENTORY,	// Piggy-back on inventory -		 + +		/// Material resource requests and puts.   +		/// +		/// Destination:     simhost:12043 +		/// Protocol:        https: +		/// Transfer size:   KB +		/// Long poll:       no +		/// Concurrency:     low +		/// Request rate:    low +		/// Pipelined:       no +		AP_MATERIALS, + +		/// Appearance resource requests and puts.   +		/// +		/// Destination:     simhost:12043 +		/// Protocol:        https: +		/// Transfer size:   KB +		/// Long poll:       no +		/// Concurrency:     mid +		/// Request rate:    low +		/// Pipelined:       yes +		AP_AGENT, +  		AP_COUNT						// Must be last  	}; @@ -233,7 +255,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/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index a64d5b50b3..4fbcd90baa 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -23,7 +23,7 @@   * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA   * $/LicenseInfo$   */ - +   #include "llviewerprecompiledheaders.h"  #include <boost/lexical_cast.hpp> @@ -54,6 +54,9 @@  #include "llsdserialize.h"  #include "llhttpretrypolicy.h"  #include "llaisapi.h" +#include "llhttpsdhandler.h" +#include "llcorehttputil.h" +#include "llappviewer.h"  #if LL_MSVC  // disable boost::lexical_cast warning @@ -1242,6 +1245,165 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items)  	items = new_items;  } +//========================================================================= +class LLAppearanceMgrHttpHandler : public LLHttpSDHandler +{ +public: +	LLAppearanceMgrHttpHandler(LLAppearanceMgr *mgr) : +		LLHttpSDHandler(), +		mManager(mgr) +	{ } + +	virtual ~LLAppearanceMgrHttpHandler() +	{ } + +	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); + +protected: +	virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); + +private: +	static void debugCOF(const LLSD& content); + +	LLAppearanceMgr *mManager; + +}; + +//------------------------------------------------------------------------- +void LLAppearanceMgrHttpHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) +{ +	mManager->decrementInFlightCounter(); + +	LLHttpSDHandler::onCompleted(handle, response); +} + +void LLAppearanceMgrHttpHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content) +{ +	if (!content.isMap()) +	{ +		LLCore::HttpStatus status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents"); +		response->setStatus(status); +		onFailure(response, status); +		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +		{ +			debugCOF(content); +		} +		return; +	} +	if (content["success"].asBoolean()) +	{ +		LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; +		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +		{ +			dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); +		} +	} +	else +	{ +		LLCore::HttpStatus status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Non-success response"); +		response->setStatus(status); +		onFailure(response, status); +		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +		{ +			debugCOF(content); +		} +		return; +	} +} + +void LLAppearanceMgrHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) +{ +	LL_WARNS("Avatar") << "Appearance Mgr request failed to " << response->getRequestURL() +		<< ". Reason code: (" << status.toTerseString() << ") " +		<< status.toString() << LL_ENDL; +} + +void LLAppearanceMgrHttpHandler::debugCOF(const LLSD& content) +{ +	dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); + +	LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() +		<< " ================================= " << LL_ENDL; +	std::set<LLUUID> ais_items, local_items; +	const LLSD& cof_raw = content["cof_raw"]; +	for (LLSD::array_const_iterator it = cof_raw.beginArray(); +		it != cof_raw.endArray(); ++it) +	{ +		const LLSD& item = *it; +		if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) +		{ +			ais_items.insert(item["item_id"].asUUID()); +			if (item["type"].asInteger() == 24) // link +			{ +				LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() +					<< " linked_item_id: " << item["asset_id"].asUUID() +					<< " name: " << item["name"].asString() +					<< LL_ENDL; +			} +			else if (item["type"].asInteger() == 25) // folder link +			{ +				LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() +					<< " linked_item_id: " << item["asset_id"].asUUID() +					<< " name: " << item["name"].asString() +					<< LL_ENDL; +			} +			else +			{ +				LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() +					<< " linked_item_id: " << item["asset_id"].asUUID() +					<< " name: " << item["name"].asString() +					<< " type: " << item["type"].asInteger() +					<< LL_ENDL; +			} +		} +	} +	LL_INFOS("Avatar") << LL_ENDL; +	LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() +		<< " ================================= " << LL_ENDL; +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t item_array; +	gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), +		cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH); +	for (S32 i = 0; i < item_array.size(); i++) +	{ +		const LLViewerInventoryItem* inv_item = item_array.at(i).get(); +		local_items.insert(inv_item->getUUID()); +		LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() +			<< " linked_item_id: " << inv_item->getLinkedUUID() +			<< " name: " << inv_item->getName() +			<< " parent: " << inv_item->getParentUUID() +			<< LL_ENDL; +	} +	LL_INFOS("Avatar") << " ================================= " << LL_ENDL; +	S32 local_only = 0, ais_only = 0; +	for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) +	{ +		if (ais_items.find(*it) == ais_items.end()) +		{ +			LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; +			local_only++; +		} +	} +	for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) +	{ +		if (local_items.find(*it) == local_items.end()) +		{ +			LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; +			ais_only++; +		} +	} +	if (local_only == 0 && ais_only == 0) +	{ +		LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " +			<< content["observed"].asInteger() +			<< " rcv " << content["expected"].asInteger() +			<< ")" << LL_ENDL; +	} +} + +//========================================================================= +  const LLUUID LLAppearanceMgr::getCOF() const  {  	return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); @@ -3154,276 +3316,6 @@ void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id,  } -class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::Responder -{ -	LOG_CLASS(RequestAgentUpdateAppearanceResponder); - -	friend class LLAppearanceMgr; -	 -public: -	RequestAgentUpdateAppearanceResponder(); - -	virtual ~RequestAgentUpdateAppearanceResponder(); - -private: -	// Called when sendServerAppearanceUpdate called. May or may not -	// trigger a request depending on various bits of state. -	void onRequestRequested(); - -	// Post the actual appearance request to cap. -	void sendRequest(); - -	void debugCOF(const LLSD& content); - -protected: -	// Successful completion. -	/* virtual */ void httpSuccess(); - -	// Error -	/*virtual*/ void httpFailure(); - -	void onFailure(); -	void onSuccess(); - -	S32 mInFlightCounter; -	LLTimer mInFlightTimer; -	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -}; - -RequestAgentUpdateAppearanceResponder::RequestAgentUpdateAppearanceResponder() -{ -	bool retry_on_4xx = true; -	mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx); -	mInFlightCounter = 0; -} - -RequestAgentUpdateAppearanceResponder::~RequestAgentUpdateAppearanceResponder() -{ -} - -void RequestAgentUpdateAppearanceResponder::onRequestRequested() -{ -	// If we have already received an update for this or higher cof version, ignore. -	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); -	S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; -	S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; -	LL_DEBUGS("Avatar") << "cof_version " << cof_version -						<< " last_rcv " << last_rcv -						<< " last_req " << last_req -						<< " in flight " << mInFlightCounter << LL_ENDL; -	if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired())) -	{ -		LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; -		mInFlightCounter = 0; -	} -	if (cof_version < last_rcv) -	{ -		LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv -							<< " will not request for " << cof_version << LL_ENDL; -		return; -	} -	if (mInFlightCounter>0 && last_req >= cof_version) -	{ -		LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req  -							<< " will not request for " << cof_version << LL_ENDL; -		return; -	} - -	// Actually send the request. -	LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL; -	mRetryPolicy->reset(); -	sendRequest(); -} -	 -void RequestAgentUpdateAppearanceResponder::sendRequest() -{ -	if (gAgentAvatarp->isEditingAppearance())  -	{ -		// don't send out appearance updates if in appearance editing mode -		return; -	} - -	if (!gAgent.getRegion()) -	{ -		LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; -		return; -	} -	if (gAgent.getRegion()->getCentralBakeVersion()==0) -	{ -		LL_WARNS() << "Region does not support baking" << LL_ENDL; -	} -	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");	 -	if (url.empty()) -	{ -		LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; -		return; -	} -	 -	LLSD body; -	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); -	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) -	{ -		body = LLAppearanceMgr::instance().dumpCOF(); -	} -	else -	{ -		body["cof_version"] = cof_version; -		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) -		{ -			body["cof_version"] = cof_version+999; -		} -	} -	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; - -	mInFlightCounter++; -	mInFlightTimer.setTimerExpirySec(60.0); -	LLHTTPClient::post(url, body, this); -	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); -	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; -} - -void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content) -{ -	LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() -					   << " ================================= " << LL_ENDL; -	std::set<LLUUID> ais_items, local_items; -	const LLSD& cof_raw = content["cof_raw"]; -	for (LLSD::array_const_iterator it = cof_raw.beginArray(); -		 it != cof_raw.endArray(); ++it) -	{ -		const LLSD& item = *it; -		if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) -		{ -			ais_items.insert(item["item_id"].asUUID()); -			if (item["type"].asInteger() == 24) // link -			{ -				LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() -								   << " linked_item_id: " << item["asset_id"].asUUID() -								   << " name: " << item["name"].asString() -								   << LL_ENDL;  -			} -			else if (item["type"].asInteger() == 25) // folder link -			{ -				LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() -								   << " linked_item_id: " << item["asset_id"].asUUID() -								   << " name: " << item["name"].asString() -								   << LL_ENDL;  -			} -			else -			{ -				LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() -								   << " linked_item_id: " << item["asset_id"].asUUID() -								   << " name: " << item["name"].asString() -								   << " type: " << item["type"].asInteger() -								   << LL_ENDL;  -			} -		} -	} -	LL_INFOS("Avatar") << LL_ENDL; -	LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger()  -					   << " ================================= " << LL_ENDL; -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), -								  cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); -	for (S32 i=0; i<item_array.size(); i++) -	{ -		const LLViewerInventoryItem* inv_item = item_array.at(i).get(); -		local_items.insert(inv_item->getUUID()); -		LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() -						   << " linked_item_id: " << inv_item->getLinkedUUID() -						   << " name: " << inv_item->getName() -						   << " parent: " << inv_item->getParentUUID() -						   << LL_ENDL; -	} -	LL_INFOS("Avatar") << " ================================= " << LL_ENDL; -	S32 local_only = 0, ais_only = 0; -	for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) -	{ -		if (ais_items.find(*it) == ais_items.end()) -		{ -			LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; -			local_only++; -		} -	} -	for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) -	{ -		if (local_items.find(*it) == local_items.end()) -		{ -			LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; -			ais_only++; -		} -	} -	if (local_only==0 && ais_only==0) -	{ -		LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " -						   << content["observed"].asInteger() -						   << " rcv " << content["expected"].asInteger() -						   << ")" << LL_ENDL; -	} -} - -/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess() -{ -	const LLSD& content = getContent(); -	if (!content.isMap()) -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -		return; -	} -	if (content["success"].asBoolean()) -	{ -		LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; -		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) -		{ -			dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); -		} - -		onSuccess(); -	} -	else -	{ -		failureResult(HTTP_INTERNAL_ERROR, "Non-success response", content); -	} -} - -void RequestAgentUpdateAppearanceResponder::onSuccess() -{ -	mInFlightCounter = llmax(mInFlightCounter-1,0); -} - -/*virtual*/ void RequestAgentUpdateAppearanceResponder::httpFailure() -{ -	LL_WARNS("Avatar") << "appearance update request failed, status " -					   << getStatus() << " reason " << getReason() << LL_ENDL; - -	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) -	{ -		const LLSD& content = getContent(); -		dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); -		debugCOF(content); -	} -	onFailure(); -} - -void RequestAgentUpdateAppearanceResponder::onFailure() -{ -	mInFlightCounter = llmax(mInFlightCounter-1,0); - -	F32 seconds_to_wait; -	mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); -	if (mRetryPolicy->shouldRetry(seconds_to_wait)) -	{ -		LL_INFOS() << "retrying" << LL_ENDL; -		doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this), -						seconds_to_wait); -	} -	else -	{ -		LL_WARNS() << "giving up after too many retries" << LL_ENDL; -	} -}	 -  LLSD LLAppearanceMgr::dumpCOF() const  { @@ -3490,101 +3382,104 @@ LLSD LLAppearanceMgr::dumpCOF() const  void LLAppearanceMgr::requestServerAppearanceUpdate()  { -	mAppearanceResponder->onRequestRequested(); -} -class LLIncrementCofVersionResponder : public LLHTTPClient::Responder -{ -	LOG_CLASS(LLIncrementCofVersionResponder); -public: -	LLIncrementCofVersionResponder() : LLHTTPClient::Responder() +	if (!testCOFRequestVersion())  	{ -		mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 16.0, 2.0, 5); +		// *TODO: LL_LOG message here +		return;  	} -	virtual ~LLIncrementCofVersionResponder() +	if ((mInFlightCounter > 0) && (mInFlightTimer.hasExpired()))  	{ +		LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; +		mInFlightCounter = 0;  	} -protected: -	virtual void httpSuccess() +	if (gAgentAvatarp->isEditingAppearance())  	{ -		LL_INFOS() << "Successfully incremented agent's COF." << LL_ENDL; -		const LLSD& content = getContent(); -		if (!content.isMap()) -		{ -			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); -			return; -		} -		S32 new_version = content["category"]["version"].asInteger(); - -		// cof_version should have increased -		llassert(new_version > gAgentAvatarp->mLastUpdateRequestCOFVersion); - -		gAgentAvatarp->mLastUpdateRequestCOFVersion = new_version; +		LL_WARNS("Avatar") << "Avatar editing appeance, not sending request." << LL_ENDL; +		// don't send out appearance updates if in appearance editing mode +		return;  	} -	virtual void httpFailure() +	if (!gAgent.getRegion())  	{ -		LL_WARNS("Avatar") << "While attempting to increment the agent's cof we got an error " -						   << dumpResponse() << LL_ENDL; -		F32 seconds_to_wait; -		mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); -		if (mRetryPolicy->shouldRetry(seconds_to_wait)) -		{ -			LL_INFOS() << "retrying" << LL_ENDL; -			doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion, -										LLAppearanceMgr::getInstance(), -										LLHTTPClient::ResponderPtr(this)), -										seconds_to_wait); -		} -		else -		{ -			LL_WARNS() << "giving up after too many retries" << LL_ENDL; -		} +		LL_WARNS("Avatar") << "Region not set, cannot request server appearance update" << LL_ENDL; +		return;  	} - -private: -	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -}; - -void LLAppearanceMgr::incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr) -{ -	// If we don't have a region, report it as an error -	if (gAgent.getRegion() == NULL) +	if (gAgent.getRegion()->getCentralBakeVersion() == 0)  	{ -		LL_WARNS() << "Region not set, cannot request cof_version increment" << LL_ENDL; -		return; +		LL_WARNS("Avatar") << "Region does not support baking" << LL_ENDL;  	} - -	std::string url = gAgent.getRegion()->getCapability("IncrementCofVersion"); +	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");  	if (url.empty())  	{ -		LL_WARNS() << "No cap for IncrementCofVersion." << LL_ENDL; +		LL_WARNS("Avatar") << "No cap for UpdateAvatarAppearance." << LL_ENDL;  		return;  	} -	LL_INFOS() << "Requesting cof_version be incremented via capability to: " -			<< url << LL_ENDL; -	LLSD headers; -	LLSD body = LLSD::emptyMap(); - -	if (!responder_ptr.get()) +	LLSD postData; +	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); +	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))  	{ -		responder_ptr = LLHTTPClient::ResponderPtr(new LLIncrementCofVersionResponder()); +		postData = LLAppearanceMgr::instance().dumpCOF();  	} +	else +	{ +		postData["cof_version"] = cof_version; +		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure")) +		{ +			postData["cof_version"] = cof_version + 999; +		} +	} +	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; + +	LLAppearanceMgrHttpHandler * handler = new LLAppearanceMgrHttpHandler(this); -	LLHTTPClient::get(url, body, responder_ptr, headers, 30.0f); +	mInFlightCounter++; +	mInFlightTimer.setTimerExpirySec(60.0); + +	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); +	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; + + +	LLCore::HttpHandle handle = gAgent.requestPostCapability("UpdateAvatarAppearance", url, postData, handler); + +	if (handle == LLCORE_HTTP_HANDLE_INVALID) +	{ +		delete handler; +	}  } -U32 LLAppearanceMgr::getNumAttachmentsInCOF() +bool LLAppearanceMgr::testCOFRequestVersion() const  { -	const LLUUID cof = getCOF(); -	LLInventoryModel::item_array_t obj_items; -	getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); -	return obj_items.size(); -} +	// If we have already received an update for this or higher cof version, ignore. +	S32 cof_version = getCOFVersion(); +	S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; +	S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; +	LL_DEBUGS("Avatar") << "cof_version " << cof_version +		<< " last_rcv " << last_rcv +		<< " last_req " << last_req +		<< " in flight " << mInFlightCounter  +		<< LL_ENDL; +	if (cof_version < last_rcv) +	{ +		LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv +			<< " will not request for " << cof_version << LL_ENDL; +		return false; +	} +	if (/*mInFlightCounter > 0 &&*/ last_req >= cof_version) +	{ +		LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req +			<< " will not request for " << cof_version << LL_ENDL; +		return false; +	} + +	// Actually send the request. +	LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL; +	return true; +}  std::string LLAppearanceMgr::getAppearanceServiceURL() const  { @@ -3850,15 +3745,17 @@ void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items,  	}  } +bool LLAppearanceMgr::mActive = true; +  LLAppearanceMgr::LLAppearanceMgr():  	mAttachmentInvLinkEnabled(false),  	mOutfitIsDirty(false),  	mOutfitLocked(false), -	mIsInUpdateAppearanceFromCOF(false), -	mAppearanceResponder(new RequestAgentUpdateAppearanceResponder) +	mInFlightCounter(0), +	mInFlightTimer(), +	mIsInUpdateAppearanceFromCOF(false)  {  	LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); -  	// unlock outfit on save operation completed  	outfit_observer.addCOFSavedCallback(boost::bind(  			&LLAppearanceMgr::setOutfitLocked, this, false)); @@ -3866,11 +3763,12 @@ LLAppearanceMgr::LLAppearanceMgr():  	mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32(  			"OutfitOperationsTimeout"))); -	gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle,NULL); +	gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle, NULL);  }  LLAppearanceMgr::~LLAppearanceMgr()  { +	mActive = false;  }  void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val) diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 7742a19c07..760a0bc6ef 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -34,12 +34,10 @@  #include "llinventorymodel.h"  #include "llinventoryobserver.h"  #include "llviewerinventory.h" -#include "llhttpclient.h"  class LLWearableHoldingPattern;  class LLInventoryCallback;  class LLOutfitUnLockTimer; -class RequestAgentUpdateAppearanceResponder;  class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>  { @@ -54,7 +52,6 @@ public:  	void updateAppearanceFromCOF(bool enforce_item_restrictions = true,  								 bool enforce_ordering = true,  								 nullary_func_t post_update_func = no_op); -	bool needToSaveCOF();  	void updateCOF(const LLUUID& category, bool append = false);  	void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append);  	void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); @@ -215,20 +212,20 @@ public:  	void requestServerAppearanceUpdate(); -	void incrementCofVersion(LLHTTPClient::ResponderPtr responder_ptr = NULL); +	void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; } +	std::string getAppearanceServiceURL() const; -	U32 getNumAttachmentsInCOF(); -	// *HACK Remove this after server side texture baking is deployed on all sims. -	void incrementCofVersionLegacy(); +	bool testCOFRequestVersion() const; +	void decrementInFlightCounter() +	{ +		mInFlightCounter = llmax(mInFlightCounter - 1, 0); +	} -	void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; } -	std::string getAppearanceServiceURL() const;  private:  	std::string		mAppearanceServiceURL; -  protected:  	LLAppearanceMgr();  	~LLAppearanceMgr(); @@ -252,13 +249,14 @@ private:  	bool mOutfitIsDirty;  	bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. -	LLPointer<RequestAgentUpdateAppearanceResponder> mAppearanceResponder; -  	/**  	 * Lock for blocking operations on outfit until server reply or timeout exceed  	 * to avoid unsynchronized outfit state or performing duplicate operations.  	 */  	bool mOutfitLocked; +	S32  mInFlightCounter; +	LLTimer mInFlightTimer; +	static bool mActive;  	std::auto_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer; diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp index 38e153137c..aeaa832bc7 100644 --- a/indra/newview/llavatarrenderinfoaccountant.cpp +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -43,7 +43,9 @@  #include "llviewerregion.h"  #include "llvoavatar.h"  #include "llworld.h" - +#include "llhttpsdhandler.h" +#include "httpheaders.h" +#include "httpoptions.h"  static	const std::string KEY_AGENTS = "agents";			// map  static 	const std::string KEY_WEIGHT = "weight";			// integer @@ -55,8 +57,113 @@ static	const std::string KEY_ERROR = "error";  // Send data updates about once per minute, only need per-frame resolution  LLFrameTimer LLAvatarRenderInfoAccountant::sRenderInfoReportTimer; +//LLCore::HttpRequest::ptr_t LLAvatarRenderInfoAccountant::sHttpRequest; + +#if 0 +//========================================================================= +class LLAvatarRenderInfoHandler : public LLHttpSDHandler +{ +public: +	LLAvatarRenderInfoHandler(const LLURI &uri, U64 regionHandle); + +protected: +	virtual void onSuccess(LLCore::HttpResponse * response, LLSD &content); +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status); + +private: +	U64	mRegionHandle; +}; + +LLAvatarRenderInfoHandler::LLAvatarRenderInfoHandler(const LLURI &uri, U64 regionHandle) : +	LLHttpSDHandler(uri), +	mRegionHandle(regionHandle) +{ +} + +void LLAvatarRenderInfoHandler::onSuccess(LLCore::HttpResponse * response, LLSD &content) +{ +	LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); +	if (regionp) +	{ +		if (LLAvatarRenderInfoAccountant::logRenderInfo()) +		{ +			LL_INFOS() << "LRI: Result for avatar weights request for region " << regionp->getName() << ":" << LL_ENDL; +		} + +		if (content.isMap()) +		{ +			if (content.has(KEY_AGENTS)) +			{ +				const LLSD & agents = content[KEY_AGENTS]; +				if (agents.isMap()) +				{ +					LLSD::map_const_iterator	report_iter = agents.beginMap(); +					while (report_iter != agents.endMap()) +					{ +						LLUUID target_agent_id = LLUUID(report_iter->first); +						const LLSD & agent_info_map = report_iter->second; +						LLViewerObject* avatarp = gObjectList.findObject(target_agent_id); +						if (avatarp && +							avatarp->isAvatar() && +							agent_info_map.isMap()) +						{	// Extract the data for this avatar + +							if (LLAvatarRenderInfoAccountant::logRenderInfo()) +							{ +								LL_INFOS() << "LRI:  Agent " << target_agent_id +									<< ": " << agent_info_map << LL_ENDL; +							} + +							if (agent_info_map.has(KEY_WEIGHT)) +							{ +								((LLVOAvatar *)avatarp)->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); +							} +						} +						report_iter++; +					} +				} +			}	// has "agents" +			else if (content.has(KEY_ERROR)) +			{ +				const LLSD & error = content[KEY_ERROR]; +				LL_WARNS() << "Avatar render info GET error: " +					<< error[KEY_IDENTIFIER] +					<< ": " << error[KEY_MESSAGE] +					<< " from region " << regionp->getName() +					<< LL_ENDL; +			} +		} +	} +	else +	{ +		LL_INFOS() << "Avatar render weight info received but region not found for " +			<< mRegionHandle << LL_ENDL; +	} +} +void LLAvatarRenderInfoHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status) +{ +	LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); +	if (regionp) +	{ +		LL_WARNS() << "HTTP error result for avatar weight GET: " << status.toULong() +			<< ", " << status.toString() +			<< " returned by region " << regionp->getName() +			<< LL_ENDL; +	} +	else +	{ +		LL_WARNS() << "Avatar render weight GET error received but region not found for "  +			<< mRegionHandle  +			<< ", error " << status.toULong() +			<< ", " << status.toString() +			<< LL_ENDL; +	} +} + +//------------------------------------------------------------------------- +#else  // HTTP responder class for GET request for avatar render weight information  class LLAvatarRenderInfoGetResponder : public LLHTTPClient::Responder  { @@ -142,7 +249,7 @@ public:  		}  		else  		{ -			LL_INFOS() << "Avatar render weight info recieved but region not found for "  +			LL_INFOS() << "Avatar render weight info received but region not found for "   				<< mRegionHandle << LL_ENDL;  		}  	} @@ -150,7 +257,7 @@ public:  private:  	U64		mRegionHandle;  }; - +#endif  // HTTP responder class for POST request for avatar render weight information  class LLAvatarRenderInfoPostResponder : public LLHTTPClient::Responder @@ -172,7 +279,7 @@ public:  		}  		else  		{ -			LL_WARNS() << "Avatar render weight POST error recieved but region not found for "  +			LL_WARNS() << "Avatar render weight POST error received but region not found for "   				<< mRegionHandle   				<< ", error " << statusNum   				<< ", " << reason @@ -215,7 +322,6 @@ private:  	U64		mRegionHandle;  }; -  // static   // Send request for one region, no timer checks  void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regionp) @@ -292,7 +398,19 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi  		}  		// First send a request to get the latest data +#if 0 +		if (!LLAvatarRenderInfoAccountant::sHttpRequest) +			sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); +		LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + +		LLCore::HttpHeaders::ptr_t httpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false); +		LLCore::HttpOptions::ptr_t httpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false); +		LLCore::HttpRequest::policy_t httpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_AGENT); + +		LLCore::HttpHandle handle = sHttpRequest-> +#else  		LLHTTPClient::get(url, new LLAvatarRenderInfoGetResponder(regionp->getHandle())); +#endif  	}  } @@ -301,6 +419,9 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi  // Called every frame - send render weight requests to every region  void LLAvatarRenderInfoAccountant::idle()  { +//	if (!LLAvatarRenderInfoAccountant::sHttpRequest) +//		sHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); +  	if (sRenderInfoReportTimer.hasExpired())  	{  		const F32 SECS_BETWEEN_REGION_SCANS   =  5.f;		// Scan the region list every 5 seconds diff --git a/indra/newview/llavatarrenderinfoaccountant.h b/indra/newview/llavatarrenderinfoaccountant.h index d68f2dccfb..13054f5e2f 100644 --- a/indra/newview/llavatarrenderinfoaccountant.h +++ b/indra/newview/llavatarrenderinfoaccountant.h @@ -29,6 +29,8 @@  #if ! defined(LL_llavatarrenderinfoaccountant_H)  #define LL_llavatarrenderinfoaccountant_H +#include "httpcommon.h" +  class LLViewerRegion;  // Class to gather avatar rendering information  @@ -36,8 +38,6 @@ class LLViewerRegion;  class LLAvatarRenderInfoAccountant  {  public: -	LLAvatarRenderInfoAccountant()	{}; -	~LLAvatarRenderInfoAccountant()	{};  	static void sendRenderInfoToRegion(LLViewerRegion * regionp);  	static void getRenderInfoFromRegion(LLViewerRegion * regionp); @@ -49,8 +49,14 @@ public:  	static bool logRenderInfo();  private: +	LLAvatarRenderInfoAccountant() {}; +	~LLAvatarRenderInfoAccountant()	{}; +  	// Send data updates about once per minute, only need per-frame resolution  	static LLFrameTimer sRenderInfoReportTimer; + +//	static LLCore::HttpRequest::ptr_t	sHttpRequest; +  };  #endif /* ! defined(LL_llavatarrenderinfoaccountant_H) */ 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/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index a1f6a01aa0..8a726ec7c9 100755 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -36,6 +36,9 @@  #include "llviewerobjectlist.h"  #include "llviewerregion.h"  #include "llworld.h" +#include "llhttpsdhandler.h" +#include "httpcommon.h" +#include "llcorehttputil.h"  /**   * Materials cap parameters @@ -59,56 +62,51 @@  #define MATERIALS_PUT_THROTTLE_SECS               1.f  #define MATERIALS_PUT_MAX_ENTRIES                 50 -/** - * LLMaterialsResponder helper class - */ -class LLMaterialsResponder : public LLHTTPClient::Responder + +class LLMaterialHttpHandler : public LLHttpSDHandler  { -public: -	typedef boost::function<void (bool, const LLSD&)> CallbackFunction; +public:  +	typedef boost::function<void(bool, const LLSD&)> CallbackFunction; +	typedef boost::shared_ptr<LLMaterialHttpHandler> ptr_t; + +	LLMaterialHttpHandler(const std::string& method, CallbackFunction cback); -	LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback); -	virtual ~LLMaterialsResponder(); +	virtual ~LLMaterialHttpHandler(); -	virtual void httpSuccess(); -	virtual void httpFailure(); +protected: +	virtual void onSuccess(LLCore::HttpResponse * response, const LLSD &content); +	virtual void onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status);  private:  	std::string      mMethod; -	std::string      mCapabilityURL;  	CallbackFunction mCallback;  }; -LLMaterialsResponder::LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback) -	: LLHTTPClient::Responder() -	, mMethod(pMethod) -	, mCapabilityURL(pCapabilityURL) -	, mCallback(pCallback) +LLMaterialHttpHandler::LLMaterialHttpHandler(const std::string& method, CallbackFunction cback): +	LLHttpSDHandler(), +	mMethod(method), +	mCallback(cback)  { +  } -LLMaterialsResponder::~LLMaterialsResponder() +LLMaterialHttpHandler::~LLMaterialHttpHandler()  {  } -void LLMaterialsResponder::httpSuccess() +void LLMaterialHttpHandler::onSuccess(LLCore::HttpResponse * response, const LLSD &content)  { -	const LLSD& pContent = getContent(); -  	LL_DEBUGS("Materials") << LL_ENDL; -	mCallback(true, pContent); +	mCallback(true, content);  } -void LLMaterialsResponder::httpFailure() +void LLMaterialHttpHandler::onFailure(LLCore::HttpResponse * response, LLCore::HttpStatus status)  { -	U32 pStatus = (U32) getStatus(); -	const std::string& pReason = getReason(); -	  	LL_WARNS("Materials")  		<< "\n--------------------------------------------------------------------------\n" -		<< mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME -		<< "'\n  with url '" << mCapabilityURL	<< "' because " << pReason  +		<< mMethod << " Error[" << status.toULong() << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME +		<< "'\n  with url '" << response->getRequestURL() << "' because " << status.toString()  		<< "\n--------------------------------------------------------------------------"  		<< LL_ENDL; @@ -116,12 +114,35 @@ void LLMaterialsResponder::httpFailure()  	mCallback(false, emptyResult);  } + +  /**   * LLMaterialMgr class   */ - -LLMaterialMgr::LLMaterialMgr() +LLMaterialMgr::LLMaterialMgr(): +	mGetQueue(), +	mGetPending(), +	mGetCallbacks(), +	mGetTECallbacks(), +	mGetAllQueue(), +	mGetAllRequested(), +	mGetAllPending(), +	mGetAllCallbacks(), +	mPutQueue(), +	mMaterials(), +	mHttpRequest(), +	mHttpHeaders(), +	mHttpOptions(), +	mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), +	mHttpPriority(0)  { +	LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); + +	mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest()); +	mHttpHeaders = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders(), false); +	mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions(), false); +	mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_MATERIALS); +  	mMaterials.insert(std::pair<LLMaterialID, LLMaterialPtr>(LLMaterialID::null, LLMaterialPtr(NULL)));  	gIdleCallbacks.addFunction(&LLMaterialMgr::onIdle, NULL);  	LLWorld::instance().setRegionRemovedCallback(boost::bind(&LLMaterialMgr::onRegionRemoved, this, _1)); @@ -554,6 +575,8 @@ void LLMaterialMgr::onIdle(void*)  	{  		instancep->processPutQueue();  	} + +	instancep->mHttpRequest->update(0L);  }  void LLMaterialMgr::processGetQueue() @@ -629,10 +652,26 @@ void LLMaterialMgr::processGetQueue()  		LLSD postData = LLSD::emptyMap();  		postData[MATERIALS_CAP_ZIP_FIELD] = materialBinary; -		LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("POST", capURL, boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id)); -		LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialsData.size() << " materials."  +		LLMaterialHttpHandler * handler =  +				new LLMaterialHttpHandler("POST", +				boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id) +				); + +		LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '" << capURL << " for " << materialsData.size() << " materials."  			<< "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL; -		LLHTTPClient::post(capURL, postData, materialsResponder); + +		LLCore::HttpHandle handle = LLCoreHttpUtil::requestPostWithLLSD(mHttpRequest,  +				mHttpPolicy, mHttpPriority, capURL,  +				postData, mHttpOptions, mHttpHeaders, handler); + +		if (handle == LLCORE_HTTP_HANDLE_INVALID) +		{ +			delete handler; +			LLCore::HttpStatus status = mHttpRequest->getStatus(); +			LL_ERRS("Meterials") << "Failed to execute material POST. Status = " << +				status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL; +		} +  		regionp->resetMaterialsCapThrottle();  	}  } @@ -667,8 +706,22 @@ void LLMaterialMgr::processGetAllQueue()  		}  		LL_DEBUGS("Materials") << "GET all for region " << region_id << "url " << capURL << LL_ENDL; -		LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("GET", capURL, boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion)); -		LLHTTPClient::get(capURL, materialsResponder); +		LLMaterialHttpHandler *handler =  +			new LLMaterialHttpHandler("GET", +			boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion) +			); + +		LLCore::HttpHandle handle = mHttpRequest->requestGet(mHttpPolicy, mHttpPriority, capURL, +				mHttpOptions.get(), mHttpHeaders.get(), handler); + +		if (handle == LLCORE_HTTP_HANDLE_INVALID) +		{ +			delete handler; +			LLCore::HttpStatus status = mHttpRequest->getStatus(); +			LL_ERRS("Meterials") << "Failed to execute material GET. Status = " << +				status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL; +		} +  		regionp->resetMaterialsCapThrottle();  		mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds()));  		mGetAllQueue.erase(itRegion);	// Invalidates region_id @@ -755,8 +808,24 @@ void LLMaterialMgr::processPutQueue()  			putData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;  			LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL; -			LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2)); -			LLHTTPClient::put(capURL, putData, materialsResponder); + +			LLMaterialHttpHandler * handler = +					new LLMaterialHttpHandler("PUT", +					boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2) +					); + +			LLCore::HttpHandle handle = LLCoreHttpUtil::requestPutWithLLSD( +				mHttpRequest, mHttpPolicy, mHttpPriority, capURL, +				putData, mHttpOptions, mHttpHeaders, handler); + +			if (handle == LLCORE_HTTP_HANDLE_INVALID) +			{ +				delete handler; +				LLCore::HttpStatus status = mHttpRequest->getStatus(); +				LL_ERRS("Meterials") << "Failed to execute material PUT. Status = " <<  +					status.toULong() << "\"" << status.toString() << "\"" << LL_ENDL; +			} +  			regionp->resetMaterialsCapThrottle();  		}  		else diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h index e83f1f4e01..ef202d24ba 100644 --- a/indra/newview/llmaterialmgr.h +++ b/indra/newview/llmaterialmgr.h @@ -30,6 +30,9 @@  #include "llmaterial.h"  #include "llmaterialid.h"  #include "llsingleton.h" +#include "httprequest.h" +#include "httpheaders.h" +#include "httpoptions.h"  class LLViewerRegion; @@ -56,7 +59,7 @@ public:  	void put(const LLUUID& object_id, const U8 te, const LLMaterial& material);  	void remove(const LLUUID& object_id, const U8 te); -protected: +private:  	void clearGetQueues(const LLUUID& region_id);  	bool isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const;  	bool isGetAllPending(const LLUUID& region_id) const; @@ -72,16 +75,7 @@ protected:  	void onPutResponse(bool success, const LLSD& content);  	void onRegionRemoved(LLViewerRegion* regionp); -protected: -	typedef std::set<LLMaterialID> material_queue_t; -	typedef std::map<LLUUID, material_queue_t> get_queue_t; -	get_queue_t        mGetQueue; -	typedef std::pair<const LLUUID, LLMaterialID> pending_material_t; -	typedef std::map<const pending_material_t, F64> get_pending_map_t; -	get_pending_map_t  mGetPending; -	typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t; -	get_callback_map_t mGetCallbacks; - +private:  	// struct for TE-specific material ID query  	class TEMaterialPair  	{ @@ -108,22 +102,37 @@ protected:  		bool   operator()(const TEMaterialPair& left, const TEMaterialPair& right) const { return left < right; }  	}; -	typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t; -	get_callback_te_map_t mGetTECallbacks; +	typedef std::set<LLMaterialID> material_queue_t; +	typedef std::map<LLUUID, material_queue_t> get_queue_t; +	typedef std::pair<const LLUUID, LLMaterialID> pending_material_t; +	typedef std::map<const pending_material_t, F64> get_pending_map_t; +	typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t; + +	typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t;  	typedef std::set<LLUUID> getall_queue_t; -	getall_queue_t        mGetAllQueue; -	getall_queue_t        mGetAllRequested;  	typedef std::map<LLUUID, F64> getall_pending_map_t; -	getall_pending_map_t  mGetAllPending;  	typedef std::map<LLUUID, getall_callback_t*> getall_callback_map_t; -	getall_callback_map_t mGetAllCallbacks; -  	typedef std::map<U8, LLMaterial> facematerial_map_t;  	typedef std::map<LLUUID, facematerial_map_t> put_queue_t; -	put_queue_t mPutQueue; -	material_map_t mMaterials; +	get_queue_t				mGetQueue; +	get_pending_map_t		mGetPending; +	get_callback_map_t		mGetCallbacks; + +	get_callback_te_map_t	mGetTECallbacks; +	getall_queue_t			mGetAllQueue; +	getall_queue_t			mGetAllRequested; +	getall_pending_map_t	mGetAllPending; +	getall_callback_map_t	mGetAllCallbacks; +	put_queue_t				mPutQueue; +	material_map_t			mMaterials; + +	LLCore::HttpRequest::ptr_t		mHttpRequest; +	LLCore::HttpHeaders::ptr_t		mHttpHeaders; +	LLCore::HttpOptions::ptr_t		mHttpOptions; +	LLCore::HttpRequest::policy_t	mHttpPolicy; +	LLCore::HttpRequest::priority_t	mHttpPriority;  	U32 getMaxEntries(const LLViewerRegion* regionp);  }; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 1e9945b514..f9160b6d60 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -2362,7 +2362,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..702d0c3a29 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! @@ -43,6 +48,13 @@  #include "llappviewer.h"  #include "lltrans.h" +#include "boost/move/unique_ptr.hpp" + +namespace boost +{ +	using ::boost::movelib::unique_ptr; // move unique_ptr into the boost namespace. +} +  // Static instance of LLXMLRPCListener declared here so that every time we  // bring in this code, we instantiate a listener. If we put the static  // instance of LLXMLRPCListener into llxmlrpclistener.cpp, the linker would @@ -155,55 +167,158 @@ 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 boost::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(),  	  mStatus(LLXMLRPCTransaction::StatusNotStarted),  	  mURI(uri), -	  mRequestText(0),   	  mResponse(0)  {  	init(request, useGzip); @@ -212,10 +327,9 @@ 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(),  	  mStatus(LLXMLRPCTransaction::StatusNotStarted),  	  mURI(uri), -	  mRequestText(0),   	  mResponse(0)  {  	XMLRPC_REQUEST request = XMLRPC_RequestNew(); @@ -231,127 +345,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);  } @@ -361,28 +401,17 @@ LLXMLRPCTransaction::Impl::~Impl()  	{  		XMLRPC_RequestFree(mResponse, 1);  	} -	 -	if (mRequestText) -	{ -		XMLRPC_Free(mRequestText); -	} -	 -	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 +420,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); +	LLCore::HttpStatus status = mHttpRequest->update(0); -			mResponse = XMLRPC_REQUEST_FromXML( -					mResponseText.data(), mResponseText.size(), NULL); - -			bool		hasError = false; -			bool		hasFault = false; -			int			faultCode = 0; -			std::string	faultString; - -			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 +477,51 @@ 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"; -	 +	LLURI failuri(mURI); + +  	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 = +			std::string("DNS could not resolve the host name(") + failuri.hostName() + ").\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 +593,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;  }; | 
