diff options
| -rwxr-xr-x | indra/llmessage/llcurl.cpp | 1707 | ||||
| -rwxr-xr-x | indra/llmessage/llcurl.h | 341 | ||||
| -rwxr-xr-x | indra/llmessage/llproxy.cpp | 10 | ||||
| -rwxr-xr-x | indra/llmessage/llproxy.h | 14 | ||||
| -rwxr-xr-x | indra/llmessage/llsdrpcclient.cpp | 249 | ||||
| -rwxr-xr-x | indra/llmessage/llsdrpcclient.h | 226 | ||||
| -rwxr-xr-x | indra/llmessage/llsdrpcserver.cpp | 341 | ||||
| -rwxr-xr-x | indra/llmessage/llsdrpcserver.h | 361 | ||||
| -rwxr-xr-x | indra/llmessage/llurlrequest.cpp | 785 | ||||
| -rwxr-xr-x | indra/llmessage/llurlrequest.h | 357 | ||||
| -rwxr-xr-x | indra/newview/llappviewer.cpp | 12 | ||||
| -rwxr-xr-x | indra/test/io.cpp | 422 | 
12 files changed, 22 insertions, 4803 deletions
| diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 630e5ebe71..61b7a52c76 100755 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -89,7 +89,7 @@ S32 gCurlMultiCount = 0;  std::vector<LLMutex*> LLCurl::sSSLMutex;  std::string LLCurl::sCAPath;  std::string LLCurl::sCAFile; -LLCurlThread* LLCurl::sCurlThread = NULL ; +//LLCurlThread* LLCurl::sCurlThread = NULL ;  LLMutex* LLCurl::sHandleMutexp = NULL ;  S32      LLCurl::sTotalHandles = 0 ;  bool     LLCurl::sNotQuitting = true; @@ -135,1042 +135,6 @@ std::string LLCurl::getVersionString()  	return std::string(curl_version());  } -////////////////////////////////////////////////////////////////////////////// - -LLCurl::Responder::Responder() -	: mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR) -{ -} - -LLCurl::Responder::~Responder() -{ -	LL_CHECK_MEMORY -} - -// virtual -void LLCurl::Responder::httpFailure() -{ -	LL_WARNS("curl") << dumpResponse() << LL_ENDL; -} - -std::string LLCurl::Responder::dumpResponse() const  -{ -	std::ostringstream s; -	s << "[" << httpMethodAsVerb(mHTTPMethod) << ":" << mURL << "] " -	  << "[status:" << mStatus << "] " -	  << "[reason:" << mReason << "] "; - -	if (mResponseHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE)) -	{ -		s << "[content-type:" << mResponseHeaders[HTTP_IN_HEADER_CONTENT_TYPE] << "] "; -	} - -	s << "[content:" << mContent << "]"; - -	return s.str(); -} - -// virtual -void LLCurl::Responder::httpSuccess() -{ -} - -void LLCurl::Responder::setURL(const std::string& url) -{ -	mURL = url; -} - -void LLCurl::Responder::successResult(const LLSD& content) -{ -	setResult(HTTP_OK, "", content); -	httpSuccess(); -} - -void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) -{ -	setResult(status, reason, content); -	httpFailure(); -} - -void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) -{ -	setResult(status, reason, content); -	httpCompleted(); -} - -void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) -{ -	mStatus = status; -	mReason = reason; -	mContent = content; -} - -void LLCurl::Responder::setHTTPMethod(EHTTPMethod method) -{ -	mHTTPMethod = method; -} - -void LLCurl::Responder::setResponseHeader(const std::string& header, const std::string& value) -{ -	mResponseHeaders[header] = value; -} - -const std::string& LLCurl::Responder::getResponseHeader(const std::string& header) const -{ -	if (mResponseHeaders.has(header)) -	{ -		return mResponseHeaders[header].asStringRef(); -	} -	static const std::string empty; -	return empty; -} - -bool LLCurl::Responder::hasResponseHeader(const std::string& header) const -{ -	if (mResponseHeaders.has(header)) return true; -	return false; -} - -// virtual -void LLCurl::Responder::completedRaw( -	const LLChannelDescriptors& channels, -	const LLIOPipe::buffer_ptr_t& buffer) -{ -	LLBufferStream istr(channels, buffer.get()); -	const bool emit_parse_errors = false; - -	std::string debug_body("(empty)"); -	bool parsed=true; -	if (EOF == istr.peek()) -	{ -		parsed=false; -	} -	// Try to parse body as llsd, no matter what 'content-type' says. -	else if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(mContent, istr, emit_parse_errors)) -	{ -		parsed=false; -		char body[1025];  -		body[1024] = '\0'; -		istr.seekg(0, std::ios::beg); -		istr.get(body,1024); -		if (strlen(body) > 0) -		{ -			mContent = body; -			debug_body = body; -		} -	} - -	// Only emit a warning if we failed to parse when 'content-type' == 'application/llsd+xml' -	if (!parsed && (HTTP_CONTENT_LLSD_XML == getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE))) -	{ -		LL_WARNS() << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] "  -			<< "(" << mReason << ") body: " << debug_body << LL_ENDL; -	} - -	httpCompleted(); -} - -// virtual -void LLCurl::Responder::httpCompleted() -{ -	if (isGoodStatus()) -	{ -		httpSuccess(); -	} -	else -	{ -		httpFailure(); -	} -} - -////////////////////////////////////////////////////////////////////////////// - -std::set<CURL*> LLCurl::Easy::sFreeHandles; -std::set<CURL*> LLCurl::Easy::sActiveHandles; -LLMutex* LLCurl::Easy::sHandleMutexp = NULL ; - -//static -CURL* LLCurl::Easy::allocEasyHandle() -{ -	llassert(LLCurl::getCurlThread()) ; - -	CURL* ret = NULL; - -	LLMutexLock lock(sHandleMutexp) ; - -	if (sFreeHandles.empty()) -	{ -		ret = LLCurl::newEasyHandle(); -	} -	else -	{ -		ret = *(sFreeHandles.begin()); -		sFreeHandles.erase(ret); -		curl_easy_reset(ret); -	} - -	if (ret) -	{ -		sActiveHandles.insert(ret); -	} - -	return ret; -} - -//static -void LLCurl::Easy::releaseEasyHandle(CURL* handle) -{ -	static const S32 MAX_NUM_FREE_HANDLES = 32 ; - -	if (!handle) -	{ -		return ; //handle allocation failed. -		//LL_ERRS() << "handle cannot be NULL!" << LL_ENDL; -	} - -	LLMutexLock lock(sHandleMutexp) ; -	if (sActiveHandles.find(handle) != sActiveHandles.end()) -	{ -		LL_CHECK_MEMORY -		sActiveHandles.erase(handle); -		LL_CHECK_MEMORY -		if(sFreeHandles.size() < MAX_NUM_FREE_HANDLES) -		{ -			sFreeHandles.insert(handle); -			LL_CHECK_MEMORY -		} -		else -		{ -			LLCurl::deleteEasyHandle(handle) ; -			LL_CHECK_MEMORY -		} -	} -	else -	{ -		LL_ERRS() << "Invalid handle." << LL_ENDL; -	} -} - -//static -void LLCurl::Easy::deleteAllActiveHandles() -{ -	LLMutexLock lock(sHandleMutexp) ; -	LL_CHECK_MEMORY -	for (std::set<CURL*>::iterator activeHandle = sActiveHandles.begin(); activeHandle != sActiveHandles.end(); ++activeHandle) -	{ -		CURL* curlHandle = *activeHandle; -		LLCurl::deleteEasyHandle(curlHandle); -		LL_CHECK_MEMORY -	} - -	sFreeHandles.clear(); -} - -//static -void LLCurl::Easy::deleteAllFreeHandles() -{ -	LLMutexLock lock(sHandleMutexp) ; -	LL_CHECK_MEMORY -	for (std::set<CURL*>::iterator freeHandle = sFreeHandles.begin(); freeHandle != sFreeHandles.end(); ++freeHandle) -	{ -		CURL* curlHandle = *freeHandle; -		LLCurl::deleteEasyHandle(curlHandle); -		LL_CHECK_MEMORY -	} - -	sFreeHandles.clear(); -} - -LLCurl::Easy::Easy() -	: mHeaders(NULL), -	  mCurlEasyHandle(NULL) -{ -	mErrorBuffer[0] = 0; -} - -LLCurl::Easy* LLCurl::Easy::getEasy() -{ -	Easy* easy = new Easy(); -	easy->mCurlEasyHandle = allocEasyHandle();  -	 -	if (!easy->mCurlEasyHandle) -	{ -		// this can happen if we have too many open files (fails in c-ares/ares_init.c) -		LL_WARNS("curl") << "allocEasyHandle() returned NULL! Easy handles: "  -			<< gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL; -		delete easy; -		return NULL; -	} -	 -	// Enable a brief cache period for now.  This was zero for the longest time -	// which caused some routers grief and generated unneeded traffic.  For the -	// threaded resolver, we're using system resolution libraries and non-zero values -	// are preferred.  The c-ares resolver is another matter and it might not -	// track server changes as well. -	CURLcode result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 15); -	check_curl_code(result); -	result = curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); -	check_curl_code(result); -	 -	++gCurlEasyCount; -	return easy; -} - -LLCurl::Easy::~Easy() -{ -	releaseEasyHandle(mCurlEasyHandle); -	--gCurlEasyCount; -	curl_slist_free_all(mHeaders); -	LL_CHECK_MEMORY -	for_each(mStrings.begin(), mStrings.end(), DeletePointerArray()); -	LL_CHECK_MEMORY -	if (mResponder && LLCurl::sNotQuitting) //aborted -	{ -		// HTTP_REQUEST_TIME_OUT, timeout, abort -		// *TODO: This looks like improper use of the 408 status code. -		// See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.9 -		// This status code should be returned by the *server* when: -		// "The client did not produce a request within the time that the server was prepared to wait." -		mResponder->setResult(HTTP_REQUEST_TIME_OUT, "Request timeout, aborted."); -		mResponder->completedRaw(mChannels, mOutput); -		LL_CHECK_MEMORY -	} -	mResponder = NULL; -} - -void LLCurl::Easy::resetState() -{ - 	curl_easy_reset(mCurlEasyHandle); - -	if (mHeaders) -	{ -		curl_slist_free_all(mHeaders); -		mHeaders = NULL; -	} - -	mRequest.str(""); -	mRequest.clear(); - -	mOutput.reset(); -	 -	mInput.str(""); -	mInput.clear(); -	 -	mErrorBuffer[0] = 0; -	 -	mHeaderOutput.str(""); -	mHeaderOutput.clear(); -} - -void LLCurl::Easy::setErrorBuffer() -{ -	setopt(CURLOPT_ERRORBUFFER, &mErrorBuffer); -} - -const char* LLCurl::Easy::getErrorBuffer() -{ -	return mErrorBuffer; -} - -void LLCurl::Easy::setCA() -{ -	if (!sCAPath.empty()) -	{ -		setoptString(CURLOPT_CAPATH, sCAPath); -	} -	if (!sCAFile.empty()) -	{ -		setoptString(CURLOPT_CAINFO, sCAFile); -	} -} - -void LLCurl::Easy::setHeaders() -{ -	setopt(CURLOPT_HTTPHEADER, mHeaders); -} - -void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info) -{ -	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload)); -	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime)); -	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload)); -} - -S32 LLCurl::Easy::report(CURLcode code) -{ -	S32 responseCode = 0; -	std::string responseReason; -	 -	if (code == CURLE_OK) -	{ -		check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode)); -		//*TODO: get reason from first line of mHeaderOutput -	} -	else -	{ -		responseCode = HTTP_INTERNAL_ERROR; -		responseReason = strerror(code) + " : " + mErrorBuffer; -		setopt(CURLOPT_FRESH_CONNECT, TRUE); -	} - -	if (mResponder) -	{	 -		mResponder->setResult(responseCode, responseReason); -		mResponder->completedRaw(mChannels, mOutput); -		mResponder = NULL; -	} -	 -	resetState(); -	return responseCode; -} - -// Note: these all assume the caller tracks the value (i.e. keeps it persistant) -void LLCurl::Easy::setopt(CURLoption option, S32 value) -{ -	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value); -	check_curl_code(result); -} - -void LLCurl::Easy::setopt(CURLoption option, void* value) -{ -	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value); -	check_curl_code(result); -} - -void LLCurl::Easy::setopt(CURLoption option, char* value) -{ -	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, value); -	check_curl_code(result); -} - -// Note: this copies the string so that the caller does not have to keep it around -void LLCurl::Easy::setoptString(CURLoption option, const std::string& value) -{ -	char* tstring = new char[value.length()+1]; -	strcpy(tstring, value.c_str()); -	mStrings.push_back(tstring); -	CURLcode result = curl_easy_setopt(mCurlEasyHandle, option, tstring); -	check_curl_code(result); -} - -void LLCurl::Easy::slist_append(const std::string& header, const std::string& value) -{ -	std::string pair(header); -	if (value.empty()) -	{ -		pair += ":"; -	} -	else -	{ -		pair += ": "; -		pair += value; -	} -	slist_append(pair.c_str()); -} - -void LLCurl::Easy::slist_append(const char* str) -{ -	if (str) -	{ -		mHeaders = curl_slist_append(mHeaders, str); -		if (!mHeaders) -		{ -			LL_WARNS() << "curl_slist_append() call returned NULL appending " << str << LL_ENDL; -		} -	} -} - -size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data) -{ -	LLCurl::Easy* easy = (LLCurl::Easy*)user_data; -	 -	S32 n = size * nmemb; -	S32 startpos = (S32)easy->getInput().tellg(); -	easy->getInput().seekg(0, std::ios::end); -	S32 endpos = (S32)easy->getInput().tellg(); -	easy->getInput().seekg(startpos, std::ios::beg); -	S32 maxn = endpos - startpos; -	n = llmin(n, maxn); -	easy->getInput().read((char*)data, n); - -	return n; -} - -size_t curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data) -{ -	LLCurl::Easy* easy = (LLCurl::Easy*)user_data; -	 -	S32 n = size * nmemb; -	easy->getOutput()->append(easy->getChannels().in(), (const U8*)data, n); - -	return n; -} - -size_t curlHeaderCallback(void* data, size_t size, size_t nmemb, void* user_data) -{ -	LLCurl::Easy* easy = (LLCurl::Easy*)user_data; -	 -	size_t n = size * nmemb; -	easy->getHeaderOutput().write((const char*)data, n); - -	return n; -} - -void LLCurl::Easy::prepRequest(const std::string& url, -							   const std::vector<std::string>& headers, -							   ResponderPtr responder, S32 time_out, bool post) -{ -	resetState(); -	 -	if (post) setoptString(CURLOPT_ENCODING, ""); - -	//setopt(CURLOPT_VERBOSE, 1); // useful for debugging -	setopt(CURLOPT_NOSIGNAL, 1); -	setopt(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); -	 -	// Set the CURL options for either Socks or HTTP proxy -	LLProxy::getInstance()->applyProxySettings(this); - -	mOutput.reset(new LLBufferArray); -	mOutput->setThreaded(true); -	setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback); -	setopt(CURLOPT_WRITEDATA, (void*)this); - -	setopt(CURLOPT_READFUNCTION, (void*)&curlReadCallback); -	setopt(CURLOPT_READDATA, (void*)this); -	 -	setopt(CURLOPT_HEADERFUNCTION, (void*)&curlHeaderCallback); -	setopt(CURLOPT_HEADERDATA, (void*)this); - -	// Allow up to five redirects -	if (responder && responder->followRedir()) -	{ -		setopt(CURLOPT_FOLLOWLOCATION, 1); -		setopt(CURLOPT_MAXREDIRS, MAX_REDIRECTS); -	} - -	setErrorBuffer(); -	setCA(); - -	setopt(CURLOPT_SSL_VERIFYPEER, true); -	 -	//don't verify host name so urls with scrubbed host names will work (improves DNS performance) -	setopt(CURLOPT_SSL_VERIFYHOST, 0); -	setopt(CURLOPT_TIMEOUT, llmax(time_out, CURL_REQUEST_TIMEOUT)); -	setopt(CURLOPT_CONNECTTIMEOUT, CURL_CONNECT_TIMEOUT); - -	setoptString(CURLOPT_URL, url); - -	mResponder = responder; - -	if (!post) -	{ -		// *TODO: Should this be set to 'Keep-Alive' ? -		slist_append(HTTP_OUT_HEADER_CONNECTION, "keep-alive"); -		slist_append(HTTP_OUT_HEADER_KEEP_ALIVE, "300"); -		// Accept and other headers -		for (std::vector<std::string>::const_iterator iter = headers.begin(); -			 iter != headers.end(); ++iter) -		{ -			slist_append((*iter).c_str()); -		} -	} -} - -//////////////////////////////////////////////////////////////////////////// -#if 1 -LLCurl::Multi::Multi(F32 idle_time_out) -	: mQueued(0), -	  mErrorCount(0), -	  mState(STATE_READY), -	  mDead(FALSE), -	  mValid(TRUE), -	  mMutexp(NULL), -	  mDeletionMutexp(NULL), -	  mEasyMutexp(NULL) -{ -	mCurlMultiHandle = LLCurl::newMultiHandle(); -	if (!mCurlMultiHandle) -	{ -		LL_WARNS() << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL; -		mCurlMultiHandle = LLCurl::newMultiHandle(); -	} -	 -	//llassert_always(mCurlMultiHandle);	 - -	if(mCurlMultiHandle) -	{ -	if(LLCurl::getCurlThread()->getThreaded()) -	{ -		mMutexp = new LLMutex(NULL) ; -		mDeletionMutexp = new LLMutex(NULL) ; -		mEasyMutexp = new LLMutex(NULL) ; -	} -	LLCurl::getCurlThread()->addMulti(this) ; - -		mIdleTimeOut = idle_time_out ; -		if(mIdleTimeOut < LLCurl::sCurlRequestTimeOut) -		{ -			mIdleTimeOut = LLCurl::sCurlRequestTimeOut ; -		} - -	++gCurlMultiCount; -} -} - -LLCurl::Multi::~Multi() -{ -	cleanup(true) ;	 -	 -	delete mDeletionMutexp ; -	mDeletionMutexp = NULL ;	 -} - -void LLCurl::Multi::cleanup(bool deleted) -{ -	if(!mCurlMultiHandle) -	{ -		return ; //nothing to clean. -	} -	llassert_always(deleted || !mValid) ; - -	LLMutexLock lock(mDeletionMutexp); - - -	// Clean up active -	for(easy_active_list_t::iterator iter = mEasyActiveList.begin(); -		iter != mEasyActiveList.end(); ++iter) -	{ -		Easy* easy = *iter; -		LL_CHECK_MEMORY -		check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle())); -		LL_CHECK_MEMORY -		if(deleted) -		{ -			easy->mResponder = NULL ; //avoid triggering mResponder. -			LL_CHECK_MEMORY -		} -		delete easy; -		LL_CHECK_MEMORY -	} -	mEasyActiveList.clear(); -	mEasyActiveMap.clear(); -	 -	LL_CHECK_MEMORY -	 -		// Clean up freed -	for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());	 -	mEasyFreeList.clear(); -	 -	LL_CHECK_MEMORY -		 -	check_curl_multi_code(LLCurl::deleteMultiHandle(mCurlMultiHandle)); -	mCurlMultiHandle = NULL ; - -	LL_CHECK_MEMORY -	 -	delete mMutexp ; -	mMutexp = NULL ; - -	LL_CHECK_MEMORY - -	delete mEasyMutexp ; -	mEasyMutexp = NULL ; - -	LL_CHECK_MEMORY - -	mQueued = 0 ; -	mState = STATE_COMPLETED; -	 -	--gCurlMultiCount; - -	return ; -} - -void LLCurl::Multi::lock() -{ -	if(mMutexp) -	{ -		mMutexp->lock() ; -	} -} - -void LLCurl::Multi::unlock() -{ -	if(mMutexp) -	{ -		mMutexp->unlock() ; -	} -} - -void LLCurl::Multi::markDead() -{ -	{ -		LLMutexLock lock(mDeletionMutexp) ; -	 -		if(mCurlMultiHandle != NULL) -		{ -			mDead = TRUE ; -			LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_URGENT) ;  - -			return; -		} -	} -	 -	//not valid, delete it. -	delete this;	 -} - -void LLCurl::Multi::setState(LLCurl::Multi::ePerformState state) -{ -	lock() ; -	mState = state ; -	unlock() ; - -	if(mState == STATE_READY) -	{ -		LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_NORMAL) ; -	}	 -} - -LLCurl::Multi::ePerformState LLCurl::Multi::getState() -{ -	return mState; -} -	 -bool LLCurl::Multi::isCompleted()  -{ -	return STATE_COMPLETED == getState() ; -} - -bool LLCurl::Multi::waitToComplete() -{ -	if(!isValid()) -	{ -		return true ; -	} - -	if(!mMutexp) //not threaded -	{ -		doPerform() ; -		return true ; -	} - -	bool completed = (STATE_COMPLETED == mState) ; -	if(!completed) -	{ -		LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_HIGH) ; -	} -	 -	return completed; -} - -CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue) -{ -	LLMutexLock lock(mMutexp) ; - -	CURLMsg* curlmsg = curl_multi_info_read(mCurlMultiHandle, msgs_in_queue); -	return curlmsg; -} - -//return true if dead -bool LLCurl::Multi::doPerform() -{ -	LLMutexLock lock(mDeletionMutexp) ; -	 -	bool dead = mDead ; - -	if(mDead) -	{ -		setState(STATE_COMPLETED); -		mQueued = 0 ; -	} -	else if(getState() != STATE_COMPLETED) -	{		 -		setState(STATE_PERFORMING); - -		S32 q = 0; -		for (S32 call_count = 0; -				call_count < MULTI_PERFORM_CALL_REPEAT; -				call_count++) -		{ -			LLMutexLock lock(mMutexp) ; - -			//WARNING: curl_multi_perform will block for many hundreds of milliseconds -			// NEVER call this from the main thread, and NEVER allow the main thread to  -			// wait on a mutex held by this thread while curl_multi_perform is executing -			CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q); -			if (CURLM_CALL_MULTI_PERFORM != code || q == 0) -			{ -				check_curl_multi_code(code); -			 -				break; -			} -		} - -		mQueued = q;	 -		setState(STATE_COMPLETED) ; -		mIdleTimer.reset() ; -	} -	else if(!mValid && mIdleTimer.getElapsedTimeF32() > mIdleTimeOut) //idle for too long, remove it. -	{ -		dead = true ; -	} -	else if(mValid && mIdleTimer.getElapsedTimeF32() > mIdleTimeOut - 1.f) //idle for too long, mark it invalid. -	{ -		mValid = FALSE ; -	} - -	return dead ; -} - -S32 LLCurl::Multi::process() -{ -	if(!isValid()) -	{ -		return 0 ; -	} - -	waitToComplete() ; - -	if (getState() != STATE_COMPLETED) -	{ -		return 0; -	} - -	CURLMsg* msg; -	int msgs_in_queue; - -	S32 processed = 0; -	while ((msg = info_read(&msgs_in_queue))) -	{ -		++processed; -		if (msg->msg == CURLMSG_DONE) -		{ -			S32 response = 0; -			Easy* easy = NULL ; - -			{ -				LLMutexLock lock(mEasyMutexp) ; -				easy_active_map_t::iterator iter = mEasyActiveMap.find(msg->easy_handle); -				if (iter != mEasyActiveMap.end()) -				{ -					easy = iter->second; -				} -			} - -			if(easy) -			{ -				response = easy->report(msg->data.result); -				removeEasy(easy); -			} -			else -			{ -				response = HTTP_INTERNAL_ERROR; -				//*TODO: change to LL_WARNS() -				LL_ERRS() << "cleaned up curl request completed!" << LL_ENDL; -			} -			if (response >= 400) -			{ -				// failure of some sort, inc mErrorCount for debugging and flagging multi for destruction -				++mErrorCount; -			} -		} -	} - -	setState(STATE_READY); - -	return processed; -} - -LLCurl::Easy* LLCurl::Multi::allocEasy() -{ -	Easy* easy = 0;	 - -	if (mEasyFreeList.empty()) -	{		 -		easy = Easy::getEasy(); -	} -	else -	{ -		LLMutexLock lock(mEasyMutexp) ; -		easy = *(mEasyFreeList.begin()); -		mEasyFreeList.erase(easy); -	} -	if (easy) -	{ -		LLMutexLock lock(mEasyMutexp) ; -		mEasyActiveList.insert(easy); -		mEasyActiveMap[easy->getCurlHandle()] = easy; -	} -	return easy; -} - -bool LLCurl::Multi::addEasy(Easy* easy) -{ -	LLMutexLock lock(mMutexp) ; -	CURLMcode mcode = curl_multi_add_handle(mCurlMultiHandle, easy->getCurlHandle()); -	check_curl_multi_code(mcode); -	//if (mcode != CURLM_OK) -	//{ -	//	LL_WARNS() << "Curl Error: " << curl_multi_strerror(mcode) << LL_ENDL; -	//	return false; -	//} -	return true; -} - -void LLCurl::Multi::easyFree(Easy* easy) -{ -	if(mEasyMutexp) -	{ -		mEasyMutexp->lock() ; -	} - -	mEasyActiveList.erase(easy); -	mEasyActiveMap.erase(easy->getCurlHandle()); - -	if (mEasyFreeList.size() < EASY_HANDLE_POOL_SIZE) -	{		 -		mEasyFreeList.insert(easy); -		 -		if(mEasyMutexp) -		{ -			mEasyMutexp->unlock() ; -		} - -		easy->resetState(); -	} -	else -	{ -		if(mEasyMutexp) -		{ -			mEasyMutexp->unlock() ; -		} -		delete easy; -	} -} - -void LLCurl::Multi::removeEasy(Easy* easy) -{ -	{ -		LLMutexLock lock(mMutexp) ; -		check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle())); -	} -	easyFree(easy); -} - -#endif - -#if 1 -//------------------------------------------------------------ -//LLCurlThread -LLCurlThread::CurlRequest::CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread) : -	LLQueuedThread::QueuedRequest(handle, LLQueuedThread::PRIORITY_NORMAL, FLAG_AUTO_COMPLETE), -	mMulti(multi), -	mCurlThread(curl_thread) -{	 -} - -LLCurlThread::CurlRequest::~CurlRequest() -{	 -	if(mMulti) -	{ -		mCurlThread->deleteMulti(mMulti) ; -		mMulti = NULL ; -	} -} - -bool LLCurlThread::CurlRequest::processRequest() -{ -	bool completed = true ; -	if(mMulti) -	{ -		completed = mCurlThread->doMultiPerform(mMulti) ; - -		if(!completed) -		{ -			setPriority(LLQueuedThread::PRIORITY_LOW) ; -		} -	} - -	return completed ; -} - -void LLCurlThread::CurlRequest::finishRequest(bool completed) -{ -	if(mMulti->isDead()) -	{ -		mCurlThread->deleteMulti(mMulti) ; -	} -	else -	{ -		mCurlThread->cleanupMulti(mMulti) ; //being idle too long, remove the request. -	} - -	mMulti = NULL ; -} -	 -LLCurlThread::LLCurlThread(bool threaded) : -	LLQueuedThread("curlthread", threaded) -{ -} -	 -//virtual  -LLCurlThread::~LLCurlThread()  -{ -} - -S32 LLCurlThread::update(F32 max_time_ms) -{	 -	return LLQueuedThread::update(max_time_ms); -} - -void LLCurlThread::addMulti(LLCurl::Multi* multi) -{ -	multi->mHandle = generateHandle() ; - -	CurlRequest* req = new CurlRequest(multi->mHandle, multi, this) ; - -	if (!addRequest(req)) -	{ -		LL_WARNS() << "curl request added when the thread is quitted" << LL_ENDL; -	} -} -	 -void LLCurlThread::killMulti(LLCurl::Multi* multi) -{ -	if(!multi) -	{ -		return ; -	} - - -	multi->markDead() ; -} - -//private -bool LLCurlThread::doMultiPerform(LLCurl::Multi* multi)  -{ -	return multi->doPerform() ; -} - -//private -void LLCurlThread::deleteMulti(LLCurl::Multi* multi)  -{ -	delete multi ; -} - -//private -void LLCurlThread::cleanupMulti(LLCurl::Multi* multi)  -{ -	multi->cleanup() ; -	if(multi->isDead()) //check if marked dead during cleaning up. -	{ -		deleteMulti(multi) ; -	} -} -#endif -//------------------------------------------------------------  //static  std::string LLCurl::strerror(CURLcode errorcode) @@ -1178,641 +142,6 @@ std::string LLCurl::strerror(CURLcode errorcode)  	return std::string(curl_easy_strerror(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; -// } - -//////////////////////////////////////////////////////////////////////////// -// For generating one easy request -// associated with a single multi request - -LLCurlEasyRequest::LLCurlEasyRequest() -	: mRequestSent(false), -	  mResultReturned(false) -{ -	mMulti = new LLCurl::Multi(); -	 -	if(mMulti->isValid()) -	{ -	mEasy = mMulti->allocEasy(); -	if (mEasy) -	{ -		mEasy->setErrorBuffer(); -		mEasy->setCA(); -		// Set proxy settings if configured to do so. -		LLProxy::getInstance()->applyProxySettings(mEasy); -	} -} -	else -	{ -		LLCurl::getCurlThread()->killMulti(mMulti) ; -		mEasy = NULL ; -		mMulti = NULL ; -	} -} - -LLCurlEasyRequest::~LLCurlEasyRequest() -{ -	LLCurl::getCurlThread()->killMulti(mMulti) ; -} -	 -void LLCurlEasyRequest::setopt(CURLoption option, S32 value) -{ -	if (isValid() && mEasy) -	{ -		mEasy->setopt(option, value); -	} -} - -void LLCurlEasyRequest::setoptString(CURLoption option, const std::string& value) -{ -	if (isValid() && mEasy) -	{ -		mEasy->setoptString(option, value); -	} -} - -void LLCurlEasyRequest::setPost(char* postdata, S32 size) -{ -	if (isValid() && mEasy) -	{ -		mEasy->setopt(CURLOPT_POST, 1); -		mEasy->setopt(CURLOPT_POSTFIELDS, postdata); -		mEasy->setopt(CURLOPT_POSTFIELDSIZE, size); -	} -} - -void LLCurlEasyRequest::setHeaderCallback(curl_header_callback callback, void* userdata) -{ -	if (isValid() && mEasy) -	{ -		mEasy->setopt(CURLOPT_HEADERFUNCTION, (void*)callback); -		mEasy->setopt(CURLOPT_HEADERDATA, userdata); // aka CURLOPT_WRITEHEADER -	} -} - -void LLCurlEasyRequest::setWriteCallback(curl_write_callback callback, void* userdata) -{ -	if (isValid() && mEasy) -	{ -		mEasy->setopt(CURLOPT_WRITEFUNCTION, (void*)callback); -		mEasy->setopt(CURLOPT_WRITEDATA, userdata); -	} -} - -void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userdata) -{ -	if (isValid() && mEasy) -	{ -		mEasy->setopt(CURLOPT_READFUNCTION, (void*)callback); -		mEasy->setopt(CURLOPT_READDATA, userdata); -	} -} - -void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata) -{ -	if (isValid() && mEasy) -	{ -		mEasy->setopt(CURLOPT_SSL_CTX_FUNCTION, (void*)callback); -		mEasy->setopt(CURLOPT_SSL_CTX_DATA, userdata); -	} -} - -void LLCurlEasyRequest::slist_append(const std::string& header, const std::string& value) -{ -	if (isValid() && mEasy) -	{ -		mEasy->slist_append(header, value); -	} -} - -void LLCurlEasyRequest::slist_append(const char* str) -{ -	if (isValid() && mEasy) -	{ -		mEasy->slist_append(str); -	} -} - -void LLCurlEasyRequest::sendRequest(const std::string& url) -{ -	llassert_always(!mRequestSent); -	mRequestSent = true; -	LL_DEBUGS() << url << LL_ENDL; -	if (isValid() && mEasy) -	{ -		mEasy->setHeaders(); -		mEasy->setoptString(CURLOPT_URL, url); -		mMulti->addEasy(mEasy); -	} -} - -void LLCurlEasyRequest::requestComplete() -{ -	llassert_always(mRequestSent); -	mRequestSent = false; -	if (isValid() && mEasy) -	{ -		mMulti->removeEasy(mEasy); -	} -} - -// Usage: Call getRestult until it returns false (no more messages) -bool LLCurlEasyRequest::getResult(CURLcode* result, LLCurl::TransferInfo* info) -{ -	if(!isValid()) -	{ -		return false ; -	} -	if (!mMulti->isCompleted()) -	{ //we're busy, try again later -		return false; -	} -	mMulti->setState(LLCurl::Multi::STATE_READY) ; - -	if (!mEasy) -	{ -		// Special case - we failed to initialize a curl_easy (can happen if too many open files) -		//  Act as though the request failed to connect -		if (mResultReturned) -		{ -			return false; -		} -		else -		{ -			*result = CURLE_FAILED_INIT; -			mResultReturned = true; -			return true; -		} -	} -	// In theory, info_read might return a message with a status other than CURLMSG_DONE -	// In practice for all messages returned, msg == CURLMSG_DONE -	// Ignore other messages just in case -	while(1) -	{ -		S32 q; -		CURLMsg* curlmsg = info_read(&q, info); -		if (curlmsg) -		{ -			if (curlmsg->msg == CURLMSG_DONE) -			{ -				*result = curlmsg->data.result;			 -				return true; -			} -			// else continue -		} -		else -		{ -			return false; -		} -	} -} - -// private -CURLMsg* LLCurlEasyRequest::info_read(S32* q, LLCurl::TransferInfo* info) -{ -	if (mEasy) -	{ -		CURLMsg* curlmsg = mMulti->info_read(q); -		if (curlmsg && curlmsg->msg == CURLMSG_DONE) -		{ -			if (info) -			{ -				mEasy->getTransferInfo(info); -			} -		} -		return curlmsg; -	} -	return NULL; -} - -std::string LLCurlEasyRequest::getErrorString() -{ -	return isValid() &&  mEasy ? std::string(mEasy->getErrorBuffer()) : std::string(); -}  //////////////////////////////////////////////////////////////////////////// @@ -1859,11 +188,11 @@ void LLCurl::initClass(F32 curl_reuest_timeout, S32 max_number_handles, bool mul  	CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);  #endif -	sCurlThread = new LLCurlThread(multi_threaded) ; +//	sCurlThread = new LLCurlThread(multi_threaded) ;  	if(multi_threaded)  	{  		sHandleMutexp = new LLMutex(NULL) ; -		Easy::sHandleMutexp = new LLMutex(NULL) ; +//		Easy::sHandleMutexp = new LLMutex(NULL) ;  	}  } @@ -1872,18 +201,18 @@ void LLCurl::cleanupClass()  	sNotQuitting = false; //set quitting  	//shut down curl thread -	while(1) -	{ -		if(!sCurlThread->update(1)) //finish all tasks -		{ -			break ; -		} -	} +// 	while(1) +// 	{ +// 		if(!sCurlThread->update(1)) //finish all tasks +// 		{ +// 			break ; +// 		} +// 	}  	LL_CHECK_MEMORY -	sCurlThread->shutdown() ; +//	sCurlThread->shutdown() ;  	LL_CHECK_MEMORY -	delete sCurlThread ; -	sCurlThread = NULL ; +//	delete sCurlThread ; +//	sCurlThread = NULL ;  	LL_CHECK_MEMORY  #if SAFE_SSL @@ -1892,21 +221,13 @@ void LLCurl::cleanupClass()  	sSSLMutex.clear();  #endif -	LL_CHECK_MEMORY -	Easy::deleteAllFreeHandles(); -	LL_CHECK_MEMORY -	Easy::deleteAllActiveHandles(); -	LL_CHECK_MEMORY +    LL_CHECK_MEMORY  	// Free the template easy handle  	curl_easy_cleanup(sCurlTemplateStandardHandle);  	sCurlTemplateStandardHandle = NULL;  	LL_CHECK_MEMORY -	delete Easy::sHandleMutexp ; -	Easy::sHandleMutexp = NULL ; - -	LL_CHECK_MEMORY  	delete sHandleMutexp ;  	sHandleMutexp = NULL ; diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index ca70462d0e..289e4bfd22 100755 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -48,7 +48,7 @@  #include "llsingleton.h"  class LLMutex; -class LLCurlThread; +//class LLCurlThread;  // For whatever reason, this is not typedef'd in curl.h  typedef size_t (*curl_header_callback)(void *ptr, size_t size, size_t nmemb, void *stream); @@ -58,114 +58,6 @@ class LLCurl  	LOG_CLASS(LLCurl);  public: -	class Easy; -	class Multi; - -	struct TransferInfo -	{ -		TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {} -		F64 mSizeDownload; -		F64 mTotalTime; -		F64 mSpeedDownload; -	}; -	 -	class Responder : public LLThreadSafeRefCount -	{ -	//LOG_CLASS(Responder); -	public: - -		Responder(); -		virtual ~Responder(); - -		virtual bool followRedir()  -		{ -			return false; -		} - -		/** -		 * @brief return true if the status code indicates success. -		 */ -		bool isGoodStatus() const { return isHttpGoodStatus(mStatus); } - -		S32 getStatus() const { return mStatus; } -		const std::string& getReason() const { return mReason; } -		const LLSD& getContent() const { return mContent; } -		bool hasResponseHeader(const std::string& header) const; -		const std::string& getResponseHeader(const std::string& header) const; -		const LLSD& getResponseHeaders() const { return mResponseHeaders; } -		const std::string& getURL() const { return mURL; } -		EHTTPMethod getHTTPMethod() const { return mHTTPMethod; } - -		// This formats response information for use in log spam.  Includes content spam. -		std::string dumpResponse() const; - -		// Allows direct triggering of success/error with different results. -		void completeResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); -		void successResult(const LLSD& content); -		void failureResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); - -		// The default implementation will try to parse body content as an LLSD, however -		// it should not spam about parsing failures unless the server sent a -		// Content-Type: application/llsd+xml header. -		virtual void completedRaw( -			const LLChannelDescriptors& channels, -			const LLIOPipe::buffer_ptr_t& buffer); -			/**< Override point for clients that may want to use this -			   class when the response is some other format besides LLSD -			*/ -			 - -		// The http* methods are not public since these should be triggered internally -		// after status, reason, content, etc have been set. -		// If you need to trigger a completion method, use the *Result methods, above. -	protected: -		// These methods are the preferred way to process final results. -		// By default, when one of these is called the following information will be resolved: -		// * HTTP status code - getStatus() -		// * Reason string - getReason() -		// * Content - getContent() -		// * Response Headers - getResponseHeaders() - -		// By default, httpSuccess is triggered whenever httpCompleted is called with a 2xx status code. -		virtual void httpSuccess(); -			//< called by completed for good status codes. - -		// By default, httpFailure is triggered whenever httpCompleted is called with a non-2xx status code. -		virtual void httpFailure(); -			//< called by httpCompleted() on bad status  - -		// httpCompleted does not generally need to be overridden, unless -		// you don't care about the status code (which determine httpFailure or httpSuccess) -		// or if you want to re-interpret what a 'good' vs' bad' status code is. -		virtual void httpCompleted(); -			/**< The default implementation calls -				either: -				* httpSuccess(), or -				* httpFailure()  -			*/ - -	public: -		void setHTTPMethod(EHTTPMethod method); -		void setURL(const std::string& url); -		void setResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); -		void setResponseHeader(const std::string& header, const std::string& value); - -	private: -		// These can be accessed by the get* methods.  Treated as 'read-only' during completion handlers. -		EHTTPMethod mHTTPMethod; -		std::string mURL; -		LLSD mResponseHeaders; - -	protected: -		// These should also generally be treated as 'read-only' during completion handlers -		// and should be accessed by the get* methods.  The exception to this rule would -		// be when overriding the completedRaw method in preparation for calling httpCompleted(). -		S32 mStatus; -		std::string mReason; -		LLSD mContent; -	}; -	typedef LLPointer<Responder>	ResponderPtr; -  	/**  	 * @ brief Set certificate authority file used to verify HTTPS certs. @@ -214,7 +106,7 @@ public:  	static void ssl_locking_callback(int mode, int type, const char *file, int line);  	static unsigned long ssl_thread_id(void); -	static LLCurlThread* getCurlThread() { return sCurlThread ;} +//	static LLCurlThread* getCurlThread() { return sCurlThread ;}  	static CURLM* newMultiHandle() ;  	static CURLMcode deleteMultiHandle(CURLM* handle) ; @@ -227,7 +119,8 @@ private:  	static std::string sCAPath;  	static std::string sCAFile;  	static const unsigned int MAX_REDIRECTS; -	static LLCurlThread* sCurlThread; +    //	static LLCurlThread* sCurlThread; +//    static LLCurlThread* sCurlThread;  	static LLMutex* sHandleMutexp ;  	static S32      sTotalHandles ; @@ -238,232 +131,6 @@ public:  	static F32      sCurlRequestTimeOut;	  }; -class LLCurl::Easy -{ -	LOG_CLASS(Easy); - -private: -	Easy(); - -public: -	static Easy* getEasy(); -	~Easy(); - -	CURL* getCurlHandle() const { return mCurlEasyHandle; } - -	void setErrorBuffer(); -	void setCA(); - -	void setopt(CURLoption option, S32 value); -	// These assume the setter does not free value! -	void setopt(CURLoption option, void* value); -	void setopt(CURLoption option, char* value); -	// Copies the string so that it is guaranteed to stick around -	void setoptString(CURLoption option, const std::string& value); - -	void slist_append(const std::string& header, const std::string& value); -	void slist_append(const char* str); -	void setHeaders(); - -	S32 report(CURLcode); -	void getTransferInfo(LLCurl::TransferInfo* info); - -	void prepRequest(const std::string& url, const std::vector<std::string>& headers, LLCurl::ResponderPtr, S32 time_out = 0, bool post = false); - -	const char* getErrorBuffer(); - -	std::stringstream& getInput() { return mInput; } -	std::stringstream& getHeaderOutput() { return mHeaderOutput; } -	LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; } -	const LLChannelDescriptors& getChannels() { return mChannels; } - -	void resetState(); - -	static CURL* allocEasyHandle(); -	static void releaseEasyHandle(CURL* handle); - -private: -	friend class LLCurl; -#if 1 -	friend class LLCurl::Multi; -#endif - -	CURL*				mCurlEasyHandle; -	struct curl_slist*	mHeaders; - -	std::stringstream	mRequest; -	LLChannelDescriptors mChannels; -	LLIOPipe::buffer_ptr_t mOutput; -	std::stringstream	mInput; -	std::stringstream	mHeaderOutput; -	char				mErrorBuffer[CURL_ERROR_SIZE]; - -	// Note: char*'s not strings since we pass pointers to curl -	std::vector<char*>	mStrings; - -	LLCurl::ResponderPtr		mResponder; - -	static std::set<CURL*> sFreeHandles; -	static std::set<CURL*> sActiveHandles; -	static LLMutex*        sHandleMutexp ; - -	static void deleteAllActiveHandles(); -	static void deleteAllFreeHandles(); -}; - -#if 1 -class LLCurl::Multi -{ -	LOG_CLASS(Multi); - -	friend class LLCurlThread ; - -private: -	~Multi(); - -	void markDead() ; -	bool doPerform(); - -public: - -	typedef enum -	{ -		STATE_READY=0, -		STATE_PERFORMING=1, -		STATE_COMPLETED=2 -	} ePerformState; - -	Multi(F32 idle_time_out = 0.f);	 - -	LLCurl::Easy* allocEasy(); -	bool addEasy(LLCurl::Easy* easy);	 -	void removeEasy(LLCurl::Easy* easy); -	 -	void lock() ; -	void unlock() ; - -	void setState(ePerformState state) ; -	ePerformState getState() ; -	 -	bool isCompleted() ; -	bool isValid() {return mCurlMultiHandle != NULL && mValid;} -	bool isDead() {return mDead;} - -	bool waitToComplete() ; - -	S32 process(); -	 -	CURLMsg* info_read(S32* msgs_in_queue); - -	S32 mQueued; -	S32 mErrorCount; -	 -private: -	void easyFree(LLCurl::Easy*); -	void cleanup(bool deleted = false) ; -	 -	CURLM* mCurlMultiHandle; - -	typedef std::set<LLCurl::Easy*> easy_active_list_t; -	easy_active_list_t mEasyActiveList; -	typedef std::map<CURL*, LLCurl::Easy*> easy_active_map_t; -	easy_active_map_t mEasyActiveMap; -	typedef std::set<LLCurl::Easy*> easy_free_list_t; -	easy_free_list_t mEasyFreeList; - -	LLQueuedThread::handle_t mHandle ; -	ePerformState mState; - -	BOOL mDead ; -	BOOL mValid ; -	LLMutex* mMutexp ; -	LLMutex* mDeletionMutexp ; -	LLMutex* mEasyMutexp ; -	LLFrameTimer mIdleTimer ; -	F32 mIdleTimeOut; -}; -#endif - -#if 1 -class LLCurlThread : public LLQueuedThread -{ -public: - -	class CurlRequest : public LLQueuedThread::QueuedRequest -	{ -	protected: -		virtual ~CurlRequest(); // use deleteRequest() -		 -	public: -		CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread); - -		/*virtual*/ bool processRequest(); -		/*virtual*/ void finishRequest(bool completed); - -	private: -		// input -		LLCurl::Multi* mMulti; -		LLCurlThread*  mCurlThread; -	}; -	friend class CurlRequest; - -public: -	LLCurlThread(bool threaded = true) ; -	virtual ~LLCurlThread() ; - -	S32 update(F32 max_time_ms); - -	void addMulti(LLCurl::Multi* multi) ; -	void killMulti(LLCurl::Multi* multi) ; - -private: -	bool doMultiPerform(LLCurl::Multi* multi) ; -	void deleteMulti(LLCurl::Multi* multi) ; -	void cleanupMulti(LLCurl::Multi* multi) ; -} ; -#endif - - -class LLCurlEasyRequest -{ -public: -	LLCurlEasyRequest(); -	~LLCurlEasyRequest(); -	void setopt(CURLoption option, S32 value); -	void setoptString(CURLoption option, const std::string& value); -	void setPost(char* postdata, S32 size); -	void setHeaderCallback(curl_header_callback callback, void* userdata); -	void setWriteCallback(curl_write_callback callback, void* userdata); -	void setReadCallback(curl_read_callback callback, void* userdata); -	void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata); -	void slist_append(const std::string& header, const std::string& value); -	void slist_append(const char* str); -	void sendRequest(const std::string& url); -	void requestComplete(); -	bool getResult(CURLcode* result, LLCurl::TransferInfo* info = NULL); -	std::string getErrorString(); -#if 0 -    bool isCompleted() { return false; } -    bool wait() { return false; } -    bool isValid() { return false; } -#else -	bool isCompleted() {return mMulti->isCompleted() ;} -	bool wait() { return mMulti->waitToComplete(); } -	bool isValid() {return mMulti && mMulti->isValid(); } -#endif -	LLCurl::Easy* getEasy() const { return mEasy; } - -private: -	CURLMsg* info_read(S32* queue, LLCurl::TransferInfo* info); -	 -private: -#if 1 -	LLCurl::Multi* mMulti; -#endif -	LLCurl::Easy* mEasy; -	bool mRequestSent; -	bool mResultReturned; -};  // Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.  namespace LLCurlFF diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp index 9b8d19cc3e..c25f1ec5e5 100755 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -408,16 +408,6 @@ void LLProxy::cleanupClass()  	deleteSingleton();  } -void LLProxy::applyProxySettings(LLCurlEasyRequest* handle) -{ -	applyProxySettings(handle->getEasy()); -} - -void LLProxy::applyProxySettings(LLCurl::Easy* handle) -{ -	applyProxySettings(handle->getCurlHandle()); -} -  /**   * @brief Apply proxy settings to a CuRL request if an HTTP proxy is enabled.   * diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h index a919370540..da965219fa 100755 --- a/indra/llmessage/llproxy.h +++ b/indra/llmessage/llproxy.h @@ -208,16 +208,13 @@ enum LLSocks5AuthType   * thread-safe method to apply those options to a curl request   * (LLProxy::applyProxySettings()). This method is overloaded   * to accommodate the various abstraction libcurl layers that exist - * throughout the viewer (LLCurlEasyRequest, LLCurl::Easy, and CURL). - * - * If you are working with LLCurl or LLCurlEasyRequest objects, - * the configured proxy settings will be applied in the constructors - * of those request handles.  If you are working with CURL objects - * directly, you will need to pass the handle of the request to - * applyProxySettings() before issuing the request. + * throughout the viewer (CURL).   *   * To ensure thread safety, all LLProxy members that relate to the HTTP   * proxy require the LLProxyMutex to be locked before accessing. + *  + * *TODO$: This should be moved into the LLCore::Http space. + *    */  class LLProxy: public LLSingleton<LLProxy>  { @@ -252,9 +249,6 @@ public:  	// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.  	// Safe to call from any thread.  	void applyProxySettings(CURL* handle); -	void applyProxySettings(LLCurl::Easy* handle); -	void applyProxySettings(LLCurlEasyRequest* handle); -  	// Start a connection to the SOCKS 5 proxy. Call from main thread only.  	S32 startSOCKSProxy(LLHost host); diff --git a/indra/llmessage/llsdrpcclient.cpp b/indra/llmessage/llsdrpcclient.cpp deleted file mode 100755 index bb4739f733..0000000000 --- a/indra/llmessage/llsdrpcclient.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/**  - * @file llsdrpcclient.cpp - * @author Phoenix - * @date 2005-11-05 - * @brief Implementation of the llsd client classes. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 "llsdrpcclient.h" - -#include "llbufferstream.h" -#include "llfasttimer.h" -#include "llfiltersd2xmlrpc.h" -#include "llpumpio.h" -#include "llsd.h" -#include "llsdserialize.h" -#include "llurlrequest.h" - -/** - * String constants - */ -static std::string LLSDRPC_RESPONSE_NAME("response"); -static std::string LLSDRPC_FAULT_NAME("fault"); - -#if 0 -/**  - * LLSDRPCResponse - */ -LLSDRPCResponse::LLSDRPCResponse() : -	mIsError(false), -	mIsFault(false) -{ -} - -// virtual -LLSDRPCResponse::~LLSDRPCResponse() -{ -} - -bool LLSDRPCResponse::extractResponse(const LLSD& sd) -{ -	bool rv = true; -	if(sd.has(LLSDRPC_RESPONSE_NAME)) -	{ -		mReturnValue = sd[LLSDRPC_RESPONSE_NAME]; -		mIsFault = false; -	} -	else if(sd.has(LLSDRPC_FAULT_NAME)) -	{ -		mReturnValue = sd[LLSDRPC_FAULT_NAME]; -		mIsFault = true; -	} -	else -	{ -		mReturnValue.clear(); -		mIsError = true; -		rv = false; -	} -	return rv; -} - -static LLTrace::BlockTimerStatHandle FTM_SDRPC_RESPONSE("SDRPC Response"); - -// virtual -LLIOPipe::EStatus LLSDRPCResponse::process_impl( -	const LLChannelDescriptors& channels, -	buffer_ptr_t& buffer, -	bool& eos, -	LLSD& context, -	LLPumpIO* pump) -{ -	LL_RECORD_BLOCK_TIME(FTM_SDRPC_RESPONSE); -	PUMP_DEBUG; -	if(mIsError) -	{ -		error(pump); -	} -	else if(mIsFault) -	{ -		fault(pump); -	} -	else -	{ -		response(pump); -	} -	PUMP_DEBUG; -	return STATUS_DONE; -} -#endif - -#if 0 -/**  - * LLSDRPCClient - */ - -LLSDRPCClient::LLSDRPCClient() : -	mState(STATE_NONE), -	mQueue(EPBQ_PROCESS) -{ -} - -// virtual -LLSDRPCClient::~LLSDRPCClient() -{ -} - -bool LLSDRPCClient::call( -	const std::string& uri, -	const std::string& method, -	const LLSD& parameter, -	LLSDRPCResponse* response, -	EPassBackQueue queue) -{ -	//LL_INFOS() << "RPC: " << uri << "." << method << "(" << *parameter << ")" -	//		<< LL_ENDL; -	if(method.empty() || !response) -	{ -		return false; -	} -	mState = STATE_READY; -	mURI.assign(uri); -	std::stringstream req; -	req << LLSDRPC_REQUEST_HEADER_1 << method -		<< LLSDRPC_REQUEST_HEADER_2; -	LLSDSerialize::toNotation(parameter, req); -	req << LLSDRPC_REQUEST_FOOTER; -	mRequest = req.str(); -	mQueue = queue; -	mResponse = response; -	return true; -} - -bool LLSDRPCClient::call( -	const std::string& uri, -	const std::string& method, -	const std::string& parameter, -	LLSDRPCResponse* response, -	EPassBackQueue queue) -{ -	//LL_INFOS() << "RPC: " << uri << "." << method << "(" << parameter << ")" -	//		<< LL_ENDL; -	if(method.empty() || parameter.empty() || !response) -	{ -		return false; -	} -	mState = STATE_READY; -	mURI.assign(uri); -	std::stringstream req; -	req << LLSDRPC_REQUEST_HEADER_1 << method -		<< LLSDRPC_REQUEST_HEADER_2 << parameter -		<< LLSDRPC_REQUEST_FOOTER; -	mRequest = req.str(); -	mQueue = queue; -	mResponse = response; -	return true; -} - -static LLTrace::BlockTimerStatHandle FTM_PROCESS_SDRPC_CLIENT("SDRPC Client"); - -// virtual -LLIOPipe::EStatus LLSDRPCClient::process_impl( -	const LLChannelDescriptors& channels, -	buffer_ptr_t& buffer, -	bool& eos, -	LLSD& context, -	LLPumpIO* pump) -{ -	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SDRPC_CLIENT); -	PUMP_DEBUG; -	if((STATE_NONE == mState) || (!pump)) -	{ -		// You should have called the call() method already. -		return STATUS_PRECONDITION_NOT_MET; -	} -	EStatus rv = STATUS_DONE; -	switch(mState) -	{ -	case STATE_READY: -	{ -		PUMP_DEBUG; -//		LL_DEBUGS() << "LLSDRPCClient::process_impl STATE_READY" << LL_ENDL; -		buffer->append( -			channels.out(), -			(U8*)mRequest.c_str(), -			mRequest.length()); -		context[CONTEXT_DEST_URI_SD_LABEL] = mURI; -		mState = STATE_WAITING_FOR_RESPONSE; -		break; -	} -	case STATE_WAITING_FOR_RESPONSE: -	{ -		PUMP_DEBUG; -		// The input channel has the sd response in it. -		//LL_DEBUGS() << "LLSDRPCClient::process_impl STATE_WAITING_FOR_RESPONSE" -		//		 << LL_ENDL; -		LLBufferStream resp(channels, buffer.get()); -		LLSD sd; -		LLSDSerialize::fromNotation(sd, resp, buffer->count(channels.in())); -		LLSDRPCResponse* response = (LLSDRPCResponse*)mResponse.get(); -		if (!response) -		{ -			mState = STATE_DONE; -			break; -		} -		response->extractResponse(sd); -		if(EPBQ_PROCESS == mQueue) -		{ -			LLPumpIO::chain_t chain; -			chain.push_back(mResponse); -			pump->addChain(chain, DEFAULT_CHAIN_EXPIRY_SECS); -		} -		else -		{ -			pump->respond(mResponse.get()); -		} -		mState = STATE_DONE; -		break; -	} -	case STATE_DONE: -	default: -		PUMP_DEBUG; -		LL_INFOS() << "invalid state to process" << LL_ENDL; -		rv = STATUS_ERROR; -		break; -	} -	return rv; -} -#endif diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h deleted file mode 100755 index c22051094d..0000000000 --- a/indra/llmessage/llsdrpcclient.h +++ /dev/null @@ -1,226 +0,0 @@ -/**  - * @file llsdrpcclient.h - * @author Phoenix - * @date 2005-11-05 - * @brief Implementation and helpers for structure data RPC clients. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 LL_LLSDRPCCLIENT_H -#define LL_LLSDRPCCLIENT_H - -/**  - * This file declares classes to encapsulate a basic structured data - * remote procedure client. - */ - -#include "llchainio.h" -#include "llfiltersd2xmlrpc.h" -#include "lliopipe.h" -#if 0 -//#include "llurlrequest.h" -#endif - -#if 0 -/**  - * @class LLSDRPCClientResponse - * @brief Abstract base class to represent a response from an SD server. - * - * This is used as a base class for callbacks generated from an - * structured data remote procedure call. The - * <code>extractResponse</code> method will deal with the llsdrpc method - * call overhead, and keep track of what to call during the next call - * into <code>process</code>. If you use this as a base class, you - * need to implement <code>response</code>, <code>fault</code>, and - * <code>error</code> to do something useful. When in those methods, - * you can parse and utilize the mReturnValue member data. - */ -class LLSDRPCResponse : public LLIOPipe -{ -public: -	LLSDRPCResponse(); -	virtual ~LLSDRPCResponse(); - -	/**  -	 * @brief This method extracts the response out of the sd passed in -	 * -	 * Any appropriate data found in the sd passed in will be -	 * extracted and managed by this object - not copied or cloned. It -	 * will still be up to the caller to delete the pointer passed in. -	 * @param sd The raw structured data response from the remote server. -	 * @return Returns true if this was able to parse the structured data. -	 */ -	bool extractResponse(const LLSD& sd); - -protected: -	/**  -	 * @brief Method called when the response is ready. -	 */ -	virtual bool response(LLPumpIO* pump) = 0; - -	/**  -	 * @brief Method called when a fault is generated by the remote server. -	 */ -	virtual bool fault(LLPumpIO* pump) = 0; - -	/**  -	 * @brief Method called when there was an error -	 */ -	virtual bool error(LLPumpIO* pump) = 0; - -protected: -	/* @name LLIOPipe virtual implementations -	 */ -	//@{ -	/**  -	 * @brief Process the data in buffer -	 */ -	virtual EStatus process_impl( -		const LLChannelDescriptors& channels, -		buffer_ptr_t& buffer, -		bool& eos, -		LLSD& context, -		LLPumpIO* pump); -	//@} -	 -protected: -	LLSD mReturnValue; -	bool mIsError; -	bool mIsFault; -}; -#endif - -#if 0 -/**  - * @class LLSDRPCClient - * @brief Client class for a structured data remote procedure call. - * - * This class helps deal with making structured data calls to a remote - * server. You can visualize the calls as: - * <code> - * response = uri.method(parameter) - * </code> - * where you pass in everything to <code>call</code> and this class - * takes care of the rest of the details. - * In typical usage, you will derive a class from this class and - * provide an API more useful for the specific application at - * hand. For example, if you were writing a service to send an instant - * message, you could create an API for it to send the messsage, and - * that class would do the work of translating it into the method and - * parameter, find the destination, and invoke <code>call</call> with - * a useful implementation of LLSDRPCResponse passed in to handle the - * response from the network. - */ -class LLSDRPCClient : public LLIOPipe -{ -public: -	LLSDRPCClient(); -	virtual ~LLSDRPCClient(); - -	/**  -	 * @brief Enumeration for tracking which queue to process the -	 * response. -	 */ -	enum EPassBackQueue -	{ -		EPBQ_PROCESS, -		EPBQ_CALLBACK, -	}; - -	/**  -	 * @brief Call a method on a remote LLSDRPCServer -	 * -	 * @param uri The remote object to call, eg, -	 * http://localhost/usher. If you are using a factory with a fixed -	 * url, the uri passed in will probably be ignored. -	 * @param method The method to call on the remote object -	 * @param parameter The parameter to pass into the remote -	 * object. It is up to the caller to delete the value passed in. -	 * @param response The object which gets the response. -	 * @param queue Specifies to call the response on the process or -	 * callback queue. -	 * @return Returns true if this object will be able to make the RPC call. -	 */ -	bool call( -		const std::string& uri, -		const std::string& method, -		const LLSD& parameter, -		LLSDRPCResponse* response, -		EPassBackQueue queue); - -	/**  -	 * @brief Call a method on a remote LLSDRPCServer -	 * -	 * @param uri The remote object to call, eg, -	 * http://localhost/usher. If you are using a factory with a fixed -	 * url, the uri passed in will probably be ignored. -	 * @param method The method to call on the remote object -	 * @param parameter The seriailized parameter to pass into the -	 * remote object. -	 * @param response The object which gets the response. -	 * @param queue Specifies to call the response on the process or -	 * callback queue. -	 * @return Returns true if this object will be able to make the RPC call. -	 */ -	bool call( -		const std::string& uri, -		const std::string& method, -		const std::string& parameter, -		LLSDRPCResponse* response, -		EPassBackQueue queue); - -protected: -	/**  -	 * @brief Enumeration for tracking client state. -	 */ -	enum EState -	{ -		STATE_NONE, -		STATE_READY, -		STATE_WAITING_FOR_RESPONSE, -		STATE_DONE -	}; -	 -	/* @name LLIOPipe virtual implementations -	 */ -	//@{ -	/**  -	 * @brief Process the data in buffer -	 */ -	virtual EStatus process_impl( -		const LLChannelDescriptors& channels, -		buffer_ptr_t& buffer, -		bool& eos, -		LLSD& context, -		LLPumpIO* pump); -	//@} - -protected: -	EState mState; -	std::string mURI; -	std::string mRequest; -	EPassBackQueue mQueue; -	LLIOPipe::ptr_t mResponse; -}; -#endif -#endif // LL_LLSDRPCCLIENT_H diff --git a/indra/llmessage/llsdrpcserver.cpp b/indra/llmessage/llsdrpcserver.cpp deleted file mode 100755 index ac3f341d0f..0000000000 --- a/indra/llmessage/llsdrpcserver.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/**  - * @file llsdrpcserver.cpp - * @author Phoenix - * @date 2005-10-11 - * @brief Implementation of the LLSDRPCServer and related classes. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 "llsdrpcserver.h" - -#include "llbuffer.h" -#include "llbufferstream.h" -#include "llfasttimer.h" -#include "llpumpio.h" -#include "llsdserialize.h" -#include "llstl.h" - -#if 0 -static const char FAULT_PART_1[] = "{'fault':{'code':i"; -static const char FAULT_PART_2[] = ", 'description':'"; -static const char FAULT_PART_3[] = "'}}"; - -static const char RESPONSE_PART_1[] = "{'response':"; -static const char RESPONSE_PART_2[] = "}"; - -static const S32 FAULT_GENERIC = 1000; -static const S32 FAULT_METHOD_NOT_FOUND = 1001; - -static const std::string LLSDRPC_METHOD_SD_NAME("method"); -static const std::string LLSDRPC_PARAMETER_SD_NAME("parameter"); - - -/** - * LLSDRPCServer - */ -LLSDRPCServer::LLSDRPCServer() : -	mState(LLSDRPCServer::STATE_NONE), -	mPump(NULL), -	mLock(0) -{ -} - -LLSDRPCServer::~LLSDRPCServer() -{ -	std::for_each( -		mMethods.begin(), -		mMethods.end(), -		llcompose1( -			DeletePointerFunctor<LLSDRPCMethodCallBase>(), -			llselect2nd<method_map_t::value_type>())); -	std::for_each( -		mCallbackMethods.begin(), -		mCallbackMethods.end(), -		llcompose1( -			DeletePointerFunctor<LLSDRPCMethodCallBase>(), -			llselect2nd<method_map_t::value_type>())); -} - - -// virtual -ESDRPCSStatus LLSDRPCServer::deferredResponse( -        const LLChannelDescriptors& channels, -	LLBufferArray* data) { -    // subclass should provide a sane implementation -    return ESDRPCS_DONE; -} - -void LLSDRPCServer::clearLock() -{ -	if(mLock && mPump) -	{ -		mPump->clearLock(mLock); -		mPump = NULL; -		mLock = 0; -	} -} - -static LLTrace::BlockTimerStatHandle FTM_PROCESS_SDRPC_SERVER("SDRPC Server"); - -// virtual -LLIOPipe::EStatus LLSDRPCServer::process_impl( -	const LLChannelDescriptors& channels, -	buffer_ptr_t& buffer, -	bool& eos, -	LLSD& context, -	LLPumpIO* pump) -{ -	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SDRPC_SERVER); -	PUMP_DEBUG; -//	LL_DEBUGS() << "LLSDRPCServer::process_impl" << LL_ENDL; -	// Once we have all the data, We need to read the sd on -	// the the in channel, and respond on  the out channel -	if(!eos) return STATUS_BREAK; -	if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET; - -	std::string method_name; -	LLIOPipe::EStatus status = STATUS_DONE; - -	switch(mState) -	{ -	case STATE_DEFERRED: -		PUMP_DEBUG; -		if(ESDRPCS_DONE != deferredResponse(channels, buffer.get())) -		{ -			buildFault( -				channels, -				buffer.get(), -				FAULT_GENERIC, -				"deferred response failed."); -		} -		mState = STATE_DONE; -		return STATUS_DONE; - -	case STATE_DONE: -//		LL_DEBUGS() << "STATE_DONE" << LL_ENDL; -		break; -	case STATE_CALLBACK: -//		LL_DEBUGS() << "STATE_CALLBACK" << LL_ENDL; -		PUMP_DEBUG; -		method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString(); -		if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME)) -		{ -			if(ESDRPCS_DONE != callbackMethod( -				   method_name, -				   mRequest[LLSDRPC_PARAMETER_SD_NAME], -				   channels, -				   buffer.get())) -			{ -				buildFault( -					channels, -					buffer.get(), -					FAULT_GENERIC, -					"Callback method call failed."); -			} -		} -		else -		{ -			// this should never happen, since we should not be in -			// this state unless we originally found a method and -			// params during the first call to process. -			buildFault( -				channels, -				buffer.get(), -				FAULT_GENERIC, -				"Invalid LLSDRPC sever state - callback without method."); -		} -		pump->clearLock(mLock); -		mLock = 0; -		mState = STATE_DONE; -		break; -	case STATE_NONE: -//		LL_DEBUGS() << "STATE_NONE" << LL_ENDL; -	default: -	{ -		// First time we got here - process the SD request, and call -		// the method. -		PUMP_DEBUG; -		LLBufferStream istr(channels, buffer.get()); -		mRequest.clear(); -		LLSDSerialize::fromNotation( -			mRequest, -			istr, -			buffer->count(channels.in())); - -		// { 'method':'...', 'parameter': ... } -		method_name = mRequest[LLSDRPC_METHOD_SD_NAME].asString(); -		if(!method_name.empty() && mRequest.has(LLSDRPC_PARAMETER_SD_NAME)) -		{ -			ESDRPCSStatus rv = callMethod( -				method_name, -				mRequest[LLSDRPC_PARAMETER_SD_NAME], -				channels, -				buffer.get()); -			switch(rv) -			{ -			case ESDRPCS_DEFERRED: -				mPump = pump; -				mLock = pump->setLock(); -				mState = STATE_DEFERRED; -				status = STATUS_BREAK; -				break; - -			case ESDRPCS_CALLBACK: -			{ -				mState = STATE_CALLBACK; -				LLPumpIO::LLLinkInfo link; -				link.mPipe = LLIOPipe::ptr_t(this); -				link.mChannels = channels; -				LLPumpIO::links_t links; -				links.push_back(link); -				pump->respond(links, buffer, context); -				mLock = pump->setLock(); -				status = STATUS_BREAK; -				break; -			} -			case ESDRPCS_DONE: -				mState = STATE_DONE; -				break; -			case ESDRPCS_ERROR: -			default: -				buildFault( -					channels, -					buffer.get(), -					FAULT_GENERIC, -					"Method call failed."); -				break; -			} -		} -		else -		{ -			// send a fault -			buildFault( -				channels, -				buffer.get(), -				FAULT_GENERIC, -				"Unable to find method and parameter in request."); -		} -		break; -	} -	} - -	PUMP_DEBUG; -	return status; -} - -// virtual -ESDRPCSStatus LLSDRPCServer::callMethod( -	const std::string& method, -	const LLSD& params, -	const LLChannelDescriptors& channels, -	LLBufferArray* response) -{ -	// Try to find the method in the method table. -	ESDRPCSStatus rv = ESDRPCS_DONE; -	method_map_t::iterator it = mMethods.find(method); -	if(it != mMethods.end()) -	{ -		rv = (*it).second->call(params, channels, response); -	} -	else -	{ -		it = mCallbackMethods.find(method); -		if(it == mCallbackMethods.end()) -		{ -			// method not found. -			std::ostringstream message; -			message << "rpc server unable to find method: " << method; -			buildFault( -				channels, -				response, -				FAULT_METHOD_NOT_FOUND, -				message.str()); -		} -		else -		{ -			// we found it in the callback methods - tell the process -			// to coordinate calling on the pump callback. -			return ESDRPCS_CALLBACK; -		} -	} -	return rv; -} - -// virtual -ESDRPCSStatus LLSDRPCServer::callbackMethod( -	const std::string& method, -	const LLSD& params, -	const LLChannelDescriptors& channels, -	LLBufferArray* response) -{ -	// Try to find the method in the callback method table. -	ESDRPCSStatus rv = ESDRPCS_DONE; -	method_map_t::iterator it = mCallbackMethods.find(method); -	if(it != mCallbackMethods.end()) -	{ -		rv = (*it).second->call(params, channels, response); -	} -	else -	{ -		std::ostringstream message; -		message << "pcserver unable to find callback method: " << method; -		buildFault( -			channels, -			response, -			FAULT_METHOD_NOT_FOUND, -			message.str()); -	} -	return rv; -} - -// static -void LLSDRPCServer::buildFault( -	const LLChannelDescriptors& channels, -	LLBufferArray* data, -	S32 code, -	const std::string& msg) -{ -	LLBufferStream ostr(channels, data); -	ostr << FAULT_PART_1 << code << FAULT_PART_2 << msg << FAULT_PART_3; -	LL_INFOS() << "LLSDRPCServer::buildFault: " << code << ", " << msg << LL_ENDL; -} - -// static -void LLSDRPCServer::buildResponse( -	const LLChannelDescriptors& channels, -	LLBufferArray* data, -	const LLSD& response) -{ -	LLBufferStream ostr(channels, data); -	ostr << RESPONSE_PART_1; -	LLSDSerialize::toNotation(response, ostr); -	ostr << RESPONSE_PART_2; -#if LL_DEBUG -	std::ostringstream debug_ostr; -	debug_ostr << "LLSDRPCServer::buildResponse: "; -	LLSDSerialize::toNotation(response, debug_ostr); -	LL_INFOS() << debug_ostr.str() << LL_ENDL; -#endif -} -#endif diff --git a/indra/llmessage/llsdrpcserver.h b/indra/llmessage/llsdrpcserver.h deleted file mode 100755 index 07d7b58b31..0000000000 --- a/indra/llmessage/llsdrpcserver.h +++ /dev/null @@ -1,361 +0,0 @@ -/**  - * @file llsdrpcserver.h - * @author Phoenix - * @date 2005-10-11 - * @brief Declaration of the structured data remote procedure call server. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 LL_LLSDRPCSERVER_H -#define LL_LLSDRPCSERVER_H - -#if 0 -/**  - * I've set this up to be pretty easy to use when you want to make a - * structured data rpc server which responds to methods by - * name. Derive a class from the LLSDRPCServer, and during - * construction (or initialization if you have the luxury) map method - * names to pointers to member functions. This will look a lot like: - * - * <code> - *  class LLMessageAgents : public LLSDRPCServer {<br> - *  public:<br> - *    typedef LLSDRPCServer<LLUsher> mem_fn_t;<br> - *    LLMessageAgents() {<br> - *      mMethods["message"] = new mem_fn_t(this, &LLMessageAgents::rpc_IM);<br> - *      mMethods["alert"] = new mem_fn_t(this, &LLMessageAgents::rpc_Alrt);<br> - *    }<br> - *  protected:<br> - *    rpc_IM(const LLSD& params, - *		const LLChannelDescriptors& channels, - *		LLBufferArray* data) - *		{...}<br> - *    rpc_Alert(const LLSD& params, - *		const LLChannelDescriptors& channels, - *		LLBufferArray* data) - *		{...}<br> - *  };<br> - * </code> - * - * The params are an array where each element in the array is a single - * parameter in the call. - * - * It is up to you to pack a valid serialized llsd response into the - * data object passed into the method, but you can use the helper - * methods below to help. - */ - -#include <map> -#include "lliopipe.h" -#include "lliohttpserver.h" -#include "llfiltersd2xmlrpc.h" - -class LLSD; - -/**  - * @brief Enumeration for specifying server method call status. This - * enumeration controls how the server class will manage the pump - * process/callback mechanism. - */ -enum ESDRPCSStatus -{ - 	// The call went ok, but the response is not yet ready. The - 	// method will arrange for the clearLock() call to be made at - 	// a later date, after which, once the chain is being pumped -	// again, deferredResponse() will be called to gather the result - 	ESDRPCS_DEFERRED, - -	// The LLSDRPCServer would like to handle the method on the -	// callback queue of the pump. -	ESDRPCS_CALLBACK, - -	// The method call finished and generated output. -	ESDRPCS_DONE, - -	// Method failed for some unspecified reason - you should avoid -	// this. A generic fault will be sent to the output. -	ESDRPCS_ERROR, - -	ESDRPCS_COUNT, -}; - -/**  - * @class LLSDRPCMethodCallBase - * @brief Base class for calling a member function in an sd rpcserver - * implementation. - */ -class LLSDRPCMethodCallBase -{ -public: -	LLSDRPCMethodCallBase() {} -	virtual ~LLSDRPCMethodCallBase() {} - -	virtual ESDRPCSStatus call( -		const LLSD& params, -		const LLChannelDescriptors& channels, -		LLBufferArray* response) = 0; -protected: -}; - -/**  - * @class LLSDRPCMethodCall - * @brief Class which implements member function calls. - */ -template<class Server> -class LLSDRPCMethodCall : public LLSDRPCMethodCallBase -{ -public: -	typedef ESDRPCSStatus (Server::*mem_fn)( -		const LLSD& params, -		const LLChannelDescriptors& channels, -		LLBufferArray* data); -	LLSDRPCMethodCall(Server* s, mem_fn fn) : -		mServer(s), -		mMemFn(fn) -	{ -	} -	virtual ~LLSDRPCMethodCall() {} -	virtual ESDRPCSStatus call( -		const LLSD& params, -		const LLChannelDescriptors& channels, -		LLBufferArray* data) -	{ -		return (*mServer.*mMemFn)(params, channels, data); -	} - -protected: -	Server* mServer; -	mem_fn mMemFn; -	//bool (Server::*mMemFn)(const LLSD& params, LLBufferArray& data); -}; - - -/**  - * @class LLSDRPCServer - * @brief Basic implementation of a structure data rpc server - * - * The rpc server is also designed to appropriately straddle the pump - * <code>process()</code> and <code>callback()</code> to specify which - * thread you want to work on when handling a method call. The - * <code>mMethods</code> methods are called from - * <code>process()</code>, while the <code>mCallbackMethods</code> are - * called when a pump is in a <code>callback()</code> cycle. - */ -class LLSDRPCServer : public LLIOPipe -{ -public: -	LLSDRPCServer(); -	virtual ~LLSDRPCServer(); - -	/** -	 * enumeration for generic fault codes -	 */ -	enum -	{ -		FAULT_BAD_REQUEST = 2000, -		FAULT_NO_RESPONSE = 2001, -	}; - -	/**  -	 * @brief Call this method to return an rpc fault. -	 * -	 * @param channel The channel for output on the data buffer -	 * @param data buffer which will recieve the final output  -	 * @param code The fault code  -	 * @param msg The fault message  -	 */ -	static void buildFault( -		const LLChannelDescriptors& channels, -		LLBufferArray* data, -		S32 code, -		const std::string& msg); - -	/**  -	 * @brief Call this method to build an rpc response. -	 * -	 * @param channel The channel for output on the data buffer -	 * @param data buffer which will recieve the final output  -	 * @param response The return value from the method call -	 */ -	static void buildResponse( -		const LLChannelDescriptors& channels, -		LLBufferArray* data, -		const LLSD& response); - -protected: -	/* @name LLIOPipe virtual implementations -	 */ -	//@{ -	/**  -	 * @brief Process the data in buffer -	 */ -	virtual EStatus process_impl( -		const LLChannelDescriptors& channels, -		buffer_ptr_t& buffer, -		bool& eos, -		LLSD& context, -		LLPumpIO* pump); -	//@} - -protected: - -	/**  -	 * @brief Enumeration to track the state of the rpc server instance -	 */ -	enum EState -	{ -		STATE_NONE, -		STATE_CALLBACK, -		STATE_DEFERRED, -		STATE_DONE -	}; - -	/**  -	 * @brief This method is called when an http post comes in. -	 * -	 * The default behavior is to look at the method name, look up the -	 * method in the method table, and call it. If the method is not -	 * found, this function will build a fault response.  You can -	 * implement your own version of this function if you want to hard -	 * wire some behavior or optimize things a bit. -	 * @param method The method name being called -	 * @param params The parameters -	 * @param channel The channel for output on the data buffer -	 * @param data The http data -	 * @return Returns the status of the method call, done/deferred/etc -	 */ -	virtual ESDRPCSStatus callMethod( -		const std::string& method, -		const LLSD& params, -		const LLChannelDescriptors& channels, -		LLBufferArray* data); - -	/**  -	 * @brief This method is called when a pump callback is processed. -	 * -	 * The default behavior is to look at the method name, look up the -	 * method in the callback method table, and call it. If the method -	 * is not found, this function will build a fault response.  You -	 * can implement your own version of this function if you want to -	 * hard wire some behavior or optimize things a bit. -	 * @param method The method name being called -	 * @param params The parameters -	 * @param channel The channel for output on the data buffer -	 * @param data The http data -	 * @return Returns the status of the method call, done/deferred/etc -	 */ -	virtual ESDRPCSStatus callbackMethod( -		const std::string& method, -		const LLSD& params, -		const LLChannelDescriptors& channels, -		LLBufferArray* data); - -	/** -	 * @brief Called after a deferred service is unlocked -	 * -	 * If a method returns ESDRPCS_DEFERRED, then the service chain -	 * will be locked and not processed until some other system calls -	 * clearLock() on the service instance again.  At that point, -	 * once the pump starts processing the chain again, this method -	 * will be called so the service can output the final result -	 * into the buffers. -	 */ -	virtual ESDRPCSStatus deferredResponse( -		const LLChannelDescriptors& channels, -		LLBufferArray* data); - -	// donovan put this public here 7/27/06 -public: -	/** -	 * @brief unlock a service that as ESDRPCS_DEFERRED -	 */ -	void clearLock(); - -protected: -	EState mState; -	LLSD mRequest; -	LLPumpIO* mPump; -	S32 mLock; -	typedef std::map<std::string, LLSDRPCMethodCallBase*> method_map_t; -	method_map_t mMethods; -	method_map_t mCallbackMethods; -}; - -/**  - * @name Helper Templates for making LLHTTPNodes - * - * These templates help in creating nodes for handing a service from - * either SDRPC or XMLRPC, given a single implementation of LLSDRPCServer. - * - * To use it: - * \code - *  class LLUsefulServer : public LLSDRPCServer { ... } - * - *  LLHTTPNode& root = LLCreateHTTPWireServer(...); - *  root.addNode("llsdrpc/useful", new LLSDRPCNode<LLUsefulServer>); - *  root.addNode("xmlrpc/useful", new LLXMLRPCNode<LLUsefulServer>); - * \endcode - */ -//@{ - -template<class Server> -class LLSDRPCServerFactory : public LLChainIOFactory -{ -public: -	virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const -	{ -		LL_DEBUGS() << "LLXMLSDRPCServerFactory::build" << LL_ENDL; -		chain.push_back(LLIOPipe::ptr_t(new Server)); -		return true; -	} -}; - -template<class Server> -class LLSDRPCNode : public LLHTTPNodeForFactory< -								LLSDRPCServerFactory<Server> > -{ -}; - -template<class Server> -class LLXMLRPCServerFactory : public LLChainIOFactory -{ -public: -	virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const -	{ -		LL_DEBUGS() << "LLXMLSDRPCServerFactory::build" << LL_ENDL; -		chain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD)); -		chain.push_back(LLIOPipe::ptr_t(new Server)); -		chain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse)); -		return true; -	} -}; - -template<class Server> -class LLXMLRPCNode : public LLHTTPNodeForFactory< -					 			LLXMLRPCServerFactory<Server> > -{ -}; - -//@} -#endif -#endif // LL_LLSDRPCSERVER_H diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp deleted file mode 100755 index 1bd9c8940e..0000000000 --- a/indra/llmessage/llurlrequest.cpp +++ /dev/null @@ -1,785 +0,0 @@ -/**  - * @file llurlrequest.cpp - * @author Phoenix - * @date 2005-04-28 - * @brief Implementation of the URLRequest class and related classes. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 "llurlrequest.h" - -#include <algorithm> -#include <openssl/x509_vfy.h> -#include <openssl/ssl.h> -#include "llcurl.h" -#include "llfasttimer.h" -#include "llioutil.h" -#include "llproxy.h" -#include "llpumpio.h" -#include "llsd.h" -#include "llstring.h" -#include "apr_env.h" -#include "llapr.h" - -#if 0 -/** - * String constants - */ -const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri"); -const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes"); - -// These are defined in llhttpnode.h/llhttpnode.cpp -extern const std::string CONTEXT_REQUEST; -extern const std::string CONTEXT_RESPONSE; - -static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user); - -/** - * class LLURLRequestDetail - */ -class LLURLRequestDetail -{ -public: -	LLURLRequestDetail(); -	~LLURLRequestDetail(); -	std::string mURL; -	LLCurlEasyRequest* mCurlRequest; -	LLIOPipe::buffer_ptr_t mResponseBuffer; -	LLChannelDescriptors mChannels; -	U8* mLastRead; -	U32 mBodyLimit; -	S32 mByteAccumulator; -	bool mIsBodyLimitSet; -	LLURLRequest::SSLCertVerifyCallback mSSLVerifyCallback; -}; - -LLURLRequestDetail::LLURLRequestDetail() : -	mCurlRequest(NULL), -	mLastRead(NULL), -	mBodyLimit(0), -	mByteAccumulator(0), -	mIsBodyLimitSet(false), -    mSSLVerifyCallback(NULL) -{ -	mCurlRequest = new LLCurlEasyRequest(); -	 -	if(!mCurlRequest->isValid()) //failed. -	{ -		delete mCurlRequest ; -		mCurlRequest = NULL ; -	} -} - -LLURLRequestDetail::~LLURLRequestDetail() -{ -	delete mCurlRequest; -	mLastRead = NULL; -} - -void LLURLRequest::setSSLVerifyCallback(SSLCertVerifyCallback callback, void *param) -{ -	mDetail->mSSLVerifyCallback = callback; -	mDetail->mCurlRequest->setSSLCtxCallback(LLURLRequest::_sslCtxCallback, (void *)this); -	mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYPEER, true); -	mDetail->mCurlRequest->setopt(CURLOPT_SSL_VERIFYHOST, 2);	 -} - - -// _sslCtxFunction -// Callback function called when an SSL Context is created via CURL -// used to configure the context for custom cert validation - -CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param) -{	 -	LLURLRequest *req = (LLURLRequest *)param; -	if(req == NULL || req->mDetail->mSSLVerifyCallback == NULL) -	{ -		SSL_CTX_set_cert_verify_callback((SSL_CTX *)sslctx, NULL, NULL); -		return CURLE_OK; -	} -	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, req->mDetail->mSSLVerifyCallback, (void *)req); -	// the calls are void -	return CURLE_OK; -	 -} - -/** - * class LLURLRequest - */ - - -LLURLRequest::LLURLRequest(EHTTPMethod action, bool follow_redirects /* = true */) : -	mAction(action), -	mFollowRedirects(follow_redirects) -{ -	initialize(); -} - -LLURLRequest::LLURLRequest( -	EHTTPMethod action, -	const std::string& url, -	bool follow_redirects /* = true */) : -	mAction(action), -	mFollowRedirects(follow_redirects) -{ -	initialize(); -	setURL(url); -} - -LLURLRequest::~LLURLRequest() -{ -	delete mDetail; -	mDetail = NULL ; -} - -void LLURLRequest::setURL(const std::string& url) -{ -	mDetail->mURL = url; -	if (url.empty()) -	{ -		LL_WARNS() << "empty URL specified" << LL_ENDL; -	} -} - -const std::string& LLURLRequest::getURL() const -{ -	return mDetail->mURL; -} - -void LLURLRequest::addHeader(const std::string& header, const std::string& value /* = "" */) -{ -	mDetail->mCurlRequest->slist_append(header, value); -} - -void LLURLRequest::addHeaderRaw(const char* header) -{ -	mDetail->mCurlRequest->slist_append(header); -} - -void LLURLRequest::setBodyLimit(U32 size) -{ -	mDetail->mBodyLimit = size; -	mDetail->mIsBodyLimitSet = true; -} - -void LLURLRequest::setCallback(LLURLRequestComplete* callback) -{ -	mCompletionCallback = callback; -	mDetail->mCurlRequest->setHeaderCallback(&headerCallback, (void*)callback); -} - -// Added to mitigate the effect of libcurl looking -// for the ALL_PROXY and http_proxy env variables -// and deciding to insert a Pragma: no-cache -// header! The only usage of this method at the -// time of this writing is in llhttpclient.cpp -// in the request() method, where this method -// is called with use_proxy = FALSE -void LLURLRequest::useProxy(bool use_proxy) -{ -    static char *env_proxy; - -    if (use_proxy && (env_proxy == NULL)) -    { -        apr_status_t status; -        LLAPRPool pool; -		status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool()); -        if (status != APR_SUCCESS) -        { -			status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool()); -        } -        if (status != APR_SUCCESS) -        { -           use_proxy = FALSE; -        } -    } - - -    LL_DEBUGS() << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << LL_ENDL; - -    if (env_proxy && use_proxy) -    { -		mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy); -    } -    else -    { -        mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, ""); -    } -} - -void LLURLRequest::useProxy(const std::string &proxy) -{ -    mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, proxy); -} - -void LLURLRequest::allowCookies() -{ -	mDetail->mCurlRequest->setoptString(CURLOPT_COOKIEFILE, ""); -} - -//virtual  -bool LLURLRequest::isValid()  -{ -	return mDetail->mCurlRequest && mDetail->mCurlRequest->isValid();  -} - -// virtual -LLIOPipe::EStatus LLURLRequest::handleError( -	LLIOPipe::EStatus status, -	LLPumpIO* pump) -{ -	if(!isValid()) -	{ -		return STATUS_EXPIRED ; -	} - -	if(mCompletionCallback && pump) -	{ -		LLURLRequestComplete* complete = NULL; -		complete = (LLURLRequestComplete*)mCompletionCallback.get(); -		complete->httpStatus( -			HTTP_INTERNAL_ERROR, -			LLIOPipe::lookupStatusString(status)); -		complete->responseStatus(status); -		pump->respond(complete); -		mCompletionCallback = NULL; -	} -	return status; -} - -static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_REQUEST("URL Request"); -static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_REQUEST_GET_RESULT("Get Result"); -static LLTrace::BlockTimerStatHandle FTM_URL_PERFORM("Perform"); -static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_PUMP_RESPOND("Pump Respond"); -static LLTrace::BlockTimerStatHandle FTM_URL_ADJUST_TIMEOUT("Adjust Timeout"); - -// virtual -LLIOPipe::EStatus LLURLRequest::process_impl( -	const LLChannelDescriptors& channels, -	buffer_ptr_t& buffer, -	bool& eos, -	LLSD& context, -	LLPumpIO* pump) -{ -	LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_REQUEST); -	PUMP_DEBUG; -	//LL_INFOS() << "LLURLRequest::process_impl()" << LL_ENDL; -	if (!buffer) return STATUS_ERROR; -	 -	// we're still waiting or prcessing, check how many -	// bytes we have accumulated. -	const S32 MIN_ACCUMULATION = 100000; -	if(pump && (mDetail->mByteAccumulator > MIN_ACCUMULATION)) -	{ -		LL_RECORD_BLOCK_TIME(FTM_URL_ADJUST_TIMEOUT); -		 // This is a pretty sloppy calculation, but this -		 // tries to make the gross assumption that if data -		 // is coming in at 56kb/s, then this transfer will -		 // probably succeed. So, if we're accumlated -		 // 100,000 bytes (MIN_ACCUMULATION) then let's -		 // give this client another 2s to complete. -		 const F32 TIMEOUT_ADJUSTMENT = 2.0f; -		 mDetail->mByteAccumulator = 0; -		 pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT); -		 LL_DEBUGS() << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << LL_ENDL; -		 if (mState == STATE_INITIALIZED) -		 { -			  LL_INFOS() << "LLURLRequest adjustTimeoutSeconds called during upload" << LL_ENDL; -		 } -	} - -	switch(mState) -	{ -	case STATE_INITIALIZED: -	{ -		PUMP_DEBUG; -		// We only need to wait for input if we are uploading -		// something. -		if(((HTTP_PUT == mAction) || (HTTP_POST == mAction)) && !eos) -		{ -			// we're waiting to get all of the information -			return STATUS_BREAK; -		} - -		// *FIX: bit of a hack, but it should work. The configure and -		// callback method expect this information to be ready. -		mDetail->mResponseBuffer = buffer; -		mDetail->mChannels = channels; -		if(!configure()) -		{ -			return STATUS_ERROR; -		} -		mState = STATE_WAITING_FOR_RESPONSE; - -		// *FIX: Maybe we should just go to the next state now... -		return STATUS_BREAK; -	} -	case STATE_WAITING_FOR_RESPONSE: -	case STATE_PROCESSING_RESPONSE: -	{ -		PUMP_DEBUG; -		LLIOPipe::EStatus status = STATUS_BREAK; -		{ -			LL_RECORD_BLOCK_TIME(FTM_URL_PERFORM); -			if(!mDetail->mCurlRequest->wait()) -			{ -				return status ; -			} -		} - -		bool keep_looping = true; -		while(keep_looping) -		{ -			CURLcode result; - -			bool newmsg = false; -			{ -				LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_REQUEST_GET_RESULT); -				newmsg = mDetail->mCurlRequest->getResult(&result); -			} -		 -			if(!newmsg) -			{ -				// keep processing -				break; -			} -		 - -			mState = STATE_HAVE_RESPONSE; -			context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; -			context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; -			LL_DEBUGS() << this << "Setting context to " << context << LL_ENDL; -			switch(result) -			{ -				case CURLE_OK: -				case CURLE_WRITE_ERROR: -					// NB: The error indication means that we stopped the -					// writing due the body limit being reached -					if(mCompletionCallback && pump) -					{ -						LLURLRequestComplete* complete = NULL; -						complete = (LLURLRequestComplete*) -							mCompletionCallback.get(); -						complete->responseStatus( -								result == CURLE_OK -									? STATUS_OK : STATUS_STOP); -						LLPumpIO::links_t chain; -						LLPumpIO::LLLinkInfo link; -						link.mPipe = mCompletionCallback; -						link.mChannels = LLBufferArray::makeChannelConsumer( -							channels); -						chain.push_back(link); -						{ -							LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_PUMP_RESPOND); -							pump->respond(chain, buffer, context); -						} -						mCompletionCallback = NULL; -					} -					break; -				case CURLE_FAILED_INIT: -				case CURLE_COULDNT_CONNECT: -					status = STATUS_NO_CONNECTION; -					keep_looping = false; -					break; -				default:			// CURLE_URL_MALFORMAT -					LL_WARNS() << "URLRequest Error: " << result -							<< ", " -							<< LLCurl::strerror(result) -							<< ", " -							<< (mDetail->mURL.empty() ? "<EMPTY URL>" : mDetail->mURL) -							<< LL_ENDL; -					status = STATUS_ERROR; -					keep_looping = false; -					break; -			} -		} -		return status; -	} -	case STATE_HAVE_RESPONSE: -		PUMP_DEBUG; -		// we already stuffed everything into channel in in the curl -		// callback, so we are done. -		eos = true; -		context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; -		context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; -		LL_DEBUGS() << this << "Setting context to " << context << LL_ENDL; -		return STATUS_DONE; - -	default: -		PUMP_DEBUG; -		context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes; -		context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes; -		LL_DEBUGS() << this << "Setting context to " << context << LL_ENDL; -		return STATUS_ERROR; -	} -} - -void LLURLRequest::initialize() -{ -	mState = STATE_INITIALIZED; -	mDetail = new LLURLRequestDetail; - -	if(!isValid()) -	{ -		return ; -	} - -	mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1); -	mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this); -	mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this); -	mRequestTransferedBytes = 0; -	mResponseTransferedBytes = 0; -} - -static LLTrace::BlockTimerStatHandle FTM_URL_REQUEST_CONFIGURE("URL Configure"); -bool LLURLRequest::configure() -{ -	LL_RECORD_BLOCK_TIME(FTM_URL_REQUEST_CONFIGURE); -	 -	bool rv = false; -	S32 bytes = mDetail->mResponseBuffer->countAfter( -   		mDetail->mChannels.in(), -		NULL); -	switch(mAction) -	{ -	case HTTP_HEAD: -		mDetail->mCurlRequest->setopt(CURLOPT_HEADER, 1); -		mDetail->mCurlRequest->setopt(CURLOPT_NOBODY, 1); -		if (mFollowRedirects) -		{ -			mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1); -		} -		rv = true; -		break; -	case HTTP_GET: -		mDetail->mCurlRequest->setopt(CURLOPT_HTTPGET, 1); -		if (mFollowRedirects) -		{ -			mDetail->mCurlRequest->setopt(CURLOPT_FOLLOWLOCATION, 1); -		} - -		// Set Accept-Encoding to allow response compression -		mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, ""); -		rv = true; -		break; - -	case HTTP_PUT: -		// Disable the expect http 1.1 extension. POST and PUT default -		// to turning this on, and I am not too sure what it means. -		addHeader(HTTP_OUT_HEADER_EXPECT); - -		mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1); -		mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes); -		rv = true; -		break; - -	case HTTP_PATCH: -		// Disable the expect http 1.1 extension. POST and PUT default -		// to turning this on, and I am not too sure what it means. -		addHeader(HTTP_OUT_HEADER_EXPECT); - -		mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1); -		mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes); -		mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "PATCH"); -		rv = true; -		break; - -	case HTTP_POST: -		// Disable the expect http 1.1 extension. POST and PUT default -		// to turning this on, and I am not too sure what it means. -		addHeader(HTTP_OUT_HEADER_EXPECT); - -		// Disable the content type http header. -		// *FIX: what should it be? -		addHeader(HTTP_OUT_HEADER_CONTENT_TYPE); - -		// Set the handle for an http post -		mDetail->mCurlRequest->setPost(NULL, bytes); - -		// Set Accept-Encoding to allow response compression -		mDetail->mCurlRequest->setoptString(CURLOPT_ENCODING, ""); -		rv = true; -		break; - -	case HTTP_DELETE: -		// Set the handle for an http delete -		mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE"); -		rv = true; -		break; - -	case HTTP_COPY: -		// Set the handle for an http copy -		mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "COPY"); -		rv = true; -		break; - -	case HTTP_MOVE: -		// Set the handle for an http move -		mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE"); -		// *NOTE: should we check for the Destination header? -		rv = true; -		break; - -	default: -		LL_WARNS() << "Unhandled URLRequest action: " << mAction << LL_ENDL; -		break; -	} -	if(rv) -	{ -		mDetail->mCurlRequest->sendRequest(mDetail->mURL); -	} -	return rv; -} - -// static -size_t LLURLRequest::downCallback( -	char* data, -	size_t size, -	size_t nmemb, -	void* user) -{ -	LLURLRequest* req = (LLURLRequest*)user; -	if(STATE_WAITING_FOR_RESPONSE == req->mState) -	{ -		req->mState = STATE_PROCESSING_RESPONSE; -	} -	U32 bytes = size * nmemb; -	if (req->mDetail->mIsBodyLimitSet) -	{ -		if (bytes > req->mDetail->mBodyLimit) -		{ -			bytes = req->mDetail->mBodyLimit; -			req->mDetail->mBodyLimit = 0; -		} -		else -		{ -			req->mDetail->mBodyLimit -= bytes; -		} -	} - -	req->mDetail->mResponseBuffer->append( -		req->mDetail->mChannels.out(), -		(U8*)data, -		bytes); -	req->mResponseTransferedBytes += bytes; -	req->mDetail->mByteAccumulator += bytes; -	return bytes; -} - -// static -size_t LLURLRequest::upCallback( -	char* data, -	size_t size, -	size_t nmemb, -	void* user) -{ -	LLURLRequest* req = (LLURLRequest*)user; -	S32 bytes = llmin( -		(S32)(size * nmemb), -		req->mDetail->mResponseBuffer->countAfter( -			req->mDetail->mChannels.in(), -			req->mDetail->mLastRead)); -	req->mDetail->mLastRead =  req->mDetail->mResponseBuffer->readAfter( -		req->mDetail->mChannels.in(), -		req->mDetail->mLastRead, -		(U8*)data, -		bytes); -	req->mRequestTransferedBytes += bytes; -	return bytes; -} - -static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user) -{ -	const char* header_line = (const char*)data; -	size_t header_len = size * nmemb; -	LLURLRequestComplete* complete = (LLURLRequestComplete*)user; - -	if (!complete || !header_line) -	{ -		return header_len; -	} - -	// *TODO: This should be a utility in llstring.h: isascii() -	for (size_t i = 0; i < header_len; ++i) -	{ -		if (header_line[i] < 0) -		{ -			return header_len; -		} -	} - -	std::string header(header_line, header_len); - -	// Per HTTP spec the first header line must be the status line. -	if (header.substr(0,5) == "HTTP/") -	{ -		std::string::iterator end = header.end(); -		std::string::iterator pos1 = std::find(header.begin(), end, ' '); -		if (pos1 != end) ++pos1; -		std::string::iterator pos2 = std::find(pos1, end, ' '); -		if (pos2 != end) ++pos2; -		std::string::iterator pos3 = std::find(pos2, end, '\r'); - -		std::string version(header.begin(), pos1); -		std::string status(pos1, pos2); -		std::string reason(pos2, pos3); - -		S32 status_code = atoi(status.c_str()); -		if (status_code > 0) -		{ -			complete->httpStatus(status_code, reason); -			return header_len; -		} -	} - -	std::string::iterator sep = std::find(header.begin(),header.end(),':'); - -	if (sep != header.end()) -	{ -		std::string key(header.begin(), sep); -		std::string value(sep + 1, header.end()); - -		key = utf8str_tolower(utf8str_trim(key)); -		value = utf8str_trim(value); - -		complete->header(key, value); -	} -	else -	{ -		LLStringUtil::trim(header); -		if (!header.empty()) -		{ -			LL_WARNS() << "Unable to parse header: " << header << LL_ENDL; -		} -	} - -	return header_len; -} - -static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_EXTRACTOR("URL Extractor"); -/** - * LLContextURLExtractor - */ -// virtual -LLIOPipe::EStatus LLContextURLExtractor::process_impl( -	const LLChannelDescriptors& channels, -	buffer_ptr_t& buffer, -	bool& eos, -	LLSD& context, -	LLPumpIO* pump) -{ -	LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_EXTRACTOR); -	PUMP_DEBUG; -	// The destination host is in the context. -	if(context.isUndefined() || !mRequest) -	{ -		return STATUS_PRECONDITION_NOT_MET; -	} - -	// copy in to out, since this just extract the URL and does not -	// actually change the data. -	LLChangeChannel change(channels.in(), channels.out()); -	std::for_each(buffer->beginSegment(), buffer->endSegment(), change); - -	// find the context url -	if(context.has(CONTEXT_DEST_URI_SD_LABEL)) -	{ -		mRequest->setURL(context[CONTEXT_DEST_URI_SD_LABEL].asString()); -		return STATUS_DONE; -	} -	return STATUS_ERROR; -} - - -/** - * LLURLRequestComplete - */ -LLURLRequestComplete::LLURLRequestComplete() : -	mRequestStatus(LLIOPipe::STATUS_ERROR) -{ -} - -// virtual -LLURLRequestComplete::~LLURLRequestComplete() -{ -} - -//virtual  -void LLURLRequestComplete::header(const std::string& header, const std::string& value) -{ -} - -//virtual  -void LLURLRequestComplete::complete(const LLChannelDescriptors& channels, -		const buffer_ptr_t& buffer) -{ -	if(STATUS_OK == mRequestStatus) -	{ -		response(channels, buffer); -	} -	else -	{ -		noResponse(); -	} -} - -//virtual  -void LLURLRequestComplete::response(const LLChannelDescriptors& channels, -		const buffer_ptr_t& buffer) -{ -	LL_WARNS() << "LLURLRequestComplete::response default implementation called" -		<< LL_ENDL; -} - -//virtual  -void LLURLRequestComplete::noResponse() -{ -	LL_WARNS() << "LLURLRequestComplete::noResponse default implementation called" -		<< LL_ENDL; -} - -void LLURLRequestComplete::responseStatus(LLIOPipe::EStatus status) -{ -	mRequestStatus = status; -} - -static LLTrace::BlockTimerStatHandle FTM_PROCESS_URL_COMPLETE("URL Complete"); -// virtual -LLIOPipe::EStatus LLURLRequestComplete::process_impl( -	const LLChannelDescriptors& channels, -	buffer_ptr_t& buffer, -	bool& eos, -	LLSD& context, -	LLPumpIO* pump) -{ -	LL_RECORD_BLOCK_TIME(FTM_PROCESS_URL_COMPLETE); -	PUMP_DEBUG; -	complete(channels, buffer); -	return STATUS_OK; -} -#endif diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h deleted file mode 100755 index e71a4c1d01..0000000000 --- a/indra/llmessage/llurlrequest.h +++ /dev/null @@ -1,357 +0,0 @@ -/**  - * @file llurlrequest.h - * @author Phoenix - * @date 2005-04-21 - * @brief Declaration of url based requests on pipes. - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 LL_LLURLREQUEST_H -#define LL_LLURLREQUEST_H - -/**  - * This file holds the declaration of useful classes for dealing with - * url based client requests.  - */ - -#include <string> -#include "lliopipe.h" -#include "llchainio.h" -#include "llerror.h" -#include <openssl/x509_vfy.h> -#include "llcurl.h" - -#if 0 -/** - * External constants - */ -extern const std::string CONTEXT_DEST_URI_SD_LABEL; -extern const std::string CONTEXT_TRANSFERED_BYTES; - -class LLURLRequestDetail; - -class LLURLRequestComplete; - -/**  - * @class LLURLRequest - * @brief Class to handle url based requests. - * @see LLIOPipe - * - * Currently, this class is implemented on top of curl. From the - * vantage of a programmer using this class, you do not care so much, - * but it's useful to know since in order to accomplish 'non-blocking' - * behavior, we have to use a more expensive curl interface which can - * still block if the server enters a half-accepted state. It would be - * worth the time and effort to eventually port this to a raw client - * socket. - */ -class LLURLRequest : public LLIOPipe -{ -	LOG_CLASS(LLURLRequest); -public: -	typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param); - -	/**  -	 * @brief Constructor. -	 * -	 * @param action One of the EHTTPMethod enumerations. -	 */ -	LLURLRequest(EHTTPMethod action, bool follow_redirects = true); - -	/**  -	 * @brief Constructor. -	 * -	 * @param action One of the EHTTPMethod enumerations. -	 * @param url The url of the request. It should already be encoded. -	 */ -	LLURLRequest(EHTTPMethod action, const std::string& url, bool follow_redirects = true); - -	/**  -	 * @brief Destructor. -	 */ -	virtual ~LLURLRequest(); - -	/* @name Instance methods -	 */ -	//@{ -	/**  -	 * @brief Set the url for the request -	 * -	 * This method assumes the url is encoded appropriately for the -	 * request.  -	 * The url must be set somehow before the first call to process(), -	 * or the url will not be set correctly. -	 *  -	 */ -	void setURL(const std::string& url); -	const std::string& getURL() const; -	/**  -	 * @brief Add a header to the http post. -	 * -	 * This provides a raw interface if you know what kind of request you -	 * will be making during construction of this instance. All -	 * required headers will be automatically constructed, so this is -	 * usually useful for encoding parameters. -	 */ -	void addHeader(const std::string& header, const std::string& value = ""); -	void addHeaderRaw(const char* header); - -	/** -	 * @brief Check remote server certificate signed by a known root CA. -	 * -	 * Set whether request will check that remote server -	 * certificates are signed by a known root CA when using HTTPS. -	 */ -	void setSSLVerifyCallback(SSLCertVerifyCallback callback, void * param); - -	 -	/** -	 * @brief Return at most size bytes of body. -	 * -	 * If the body had more bytes than this limit, they will not be -	 * returned and the connection closed.  In this case, STATUS_STOP -	 * will be passed to responseStatus(); -	 */ -	void setBodyLimit(U32 size); - -	/**  -	 * @brief Set a completion callback for this URLRequest. -	 * -	 * The callback is added to this URLRequet's pump when either the -	 * entire buffer is known or an error like timeout or connection -	 * refused has happened. In the case of a complete transfer, this -	 * object builds a response chain such that the callback and the -	 * next process consumer get to read the output. -	 * -	 * This setup is a little fragile since the url request consumer -	 * might not just read the data - it may do a channel change, -	 * which invalidates the input to the callback, but it works well -	 * in practice. -	 */ -	void setCallback(LLURLRequestComplete* callback); -	//@} - -	/* @name LLIOPipe virtual implementations -	 */ - -    /** -     * @ brief Turn off (or on) the CURLOPT_PROXY header. -     */ -    void useProxy(bool use_proxy); - -    /** -     * @ brief Set the CURLOPT_PROXY header to the given value. -     */ -	void useProxy(const std::string& proxy); - -	/** -	 * @brief Turn on cookie handling for this request with CURLOPT_COOKIEFILE. -	 */ -	void allowCookies(); - -	/*virtual*/ bool isValid() ; - -public: -	/**  -	 * @brief Give this pipe a chance to handle a generated error -	 */ -	virtual EStatus handleError(EStatus status, LLPumpIO* pump); - -	 -protected: -	/**  -	 * @brief Process the data in buffer -	 */ -	virtual EStatus process_impl( -		const LLChannelDescriptors& channels, -		buffer_ptr_t& buffer, -		bool& eos, -		LLSD& context, -		LLPumpIO* pump); -	//@} - -protected: -	enum EState -	{ -		STATE_INITIALIZED, -		STATE_WAITING_FOR_RESPONSE, -		STATE_PROCESSING_RESPONSE, -		STATE_HAVE_RESPONSE, -	}; -	EState mState; -	EHTTPMethod mAction; -	bool mFollowRedirects; -	LLURLRequestDetail* mDetail; -	LLIOPipe::ptr_t mCompletionCallback; -	S32 mRequestTransferedBytes; -	S32 mResponseTransferedBytes; - -	static CURLcode _sslCtxCallback(CURL * curl, void *sslctx, void *param); -	 -private: -	/**  -	 * @brief Initialize the object. Called during construction. -	 */ -	void initialize(); - -	/**  -	 * @brief Handle action specific url request configuration. -	 * -	 * @return Returns true if this is configured. -	 */ -	bool configure(); - -	/**  -	 * @brief Download callback method. -	 */ - 	static size_t downCallback( -		char* data, -		size_t size, -		size_t nmemb, -		void* user); - -	/**  -	 * @brief Upload callback method. -	 */ - 	static size_t upCallback( -		char* data, -		size_t size, -		size_t nmemb, -		void* user); - -	/**  -	 * @brief Declaration of unimplemented method to prevent copy -	 * construction. -	 */ -	LLURLRequest(const LLURLRequest&); -}; - - -/**  - * @class LLContextURLExtractor - * @brief This class unpacks the url out of a agent usher service so - * it can be packed into a LLURLRequest object. - * @see LLIOPipe - * - * This class assumes that the context is a map that contains an entry - * named CONTEXT_DEST_URI_SD_LABEL. - */ -class LLContextURLExtractor : public LLIOPipe -{ -public: -	LLContextURLExtractor(LLURLRequest* req) : mRequest(req) {} -	~LLContextURLExtractor() {} - -protected: -	/* @name LLIOPipe virtual implementations -	 */ -	//@{ -	/**  -	 * @brief Process the data in buffer -	 */ -	virtual EStatus process_impl( -		const LLChannelDescriptors& channels, -		buffer_ptr_t& buffer, -		bool& eos, -		LLSD& context, -		LLPumpIO* pump); -	//@} - -protected: -	LLURLRequest* mRequest; -}; - - -/**  - * @class LLURLRequestComplete - * @brief Class which can optionally be used with an LLURLRequest to - * get notification when the url request is complete. - */ -class LLURLRequestComplete : public LLIOPipe -{ -public: -	 -	// Called once for each header received, except status lines -	virtual void header(const std::string& header, const std::string& value); - -	// May be called more than once, particularly for redirects and proxy madness. -	// Ex. a 200 for a connection to https through a proxy, followed by the "real" status -	//     a 3xx for a redirect followed by a "real" status, or more redirects. -	virtual void httpStatus(S32 status, const std::string& reason) { } - -	virtual void complete( -		const LLChannelDescriptors& channels, -		const buffer_ptr_t& buffer); - -	/**  -	 * @brief This method is called when we got a valid response. -	 * -	 * It is up to class implementers to do something useful here. -	 */ -	virtual void response( -		const LLChannelDescriptors& channels, -		const buffer_ptr_t& buffer); - -	/**  -	 * @brief This method is called if there was no response. -	 * -	 * It is up to class implementers to do something useful here. -	 */ -	virtual void noResponse(); - -	/**  -	 * @brief This method will be called by the LLURLRequest object. -	 * -	 * If this is set to STATUS_OK or STATUS_STOP, then the transfer -	 * is asssumed to have worked. This will lead to calling response() -	 * on the next call to process(). Otherwise, this object will call -	 * noResponse() on the next call to process. -	 * @param status The status of the URLRequest. -	 */ -	void responseStatus(EStatus status); - -	// constructor & destructor. -	LLURLRequestComplete(); -	virtual ~LLURLRequestComplete(); - -protected: -	/* @name LLIOPipe virtual implementations -	 */ -	//@{ -	/**  -	 * @brief Process the data in buffer -	 */ -	virtual EStatus process_impl( -		const LLChannelDescriptors& channels, -		buffer_ptr_t& buffer, -		bool& eos, -		LLSD& context, -		LLPumpIO* pump); -	//@} - -	// value to note if we actually got the response. This value -	// depends on correct usage from the LLURLRequest instance. -	EStatus mRequestStatus; -}; -#endif -#endif // LL_LLURLREQUEST_H diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 16dac4a9e5..45e21d9129 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1556,11 +1556,6 @@ bool LLAppViewer::mainLoop()  				}  				gMeshRepo.update() ; -				if(!LLCurl::getCurlThread()->update(1)) -				{ -					LLCurl::getCurlThread()->pause() ; //nothing in the curl thread. -				} -  				if(!total_work_pending) //pause texture fetching threads if nothing to process.  				{  					LLAppViewer::getTextureCache()->pause(); @@ -1998,7 +1993,6 @@ bool LLAppViewer::cleanup()  		pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread  		pending += LLVFSThread::updateClass(0);  		pending += LLLFSThread::updateClass(0); -		pending += LLCurl::getCurlThread()->update(1) ;  		F64 idle_time = idleTimer.getElapsedTimeF64();  		if(!pending)  		{ @@ -2010,7 +2004,6 @@ bool LLAppViewer::cleanup()  			break;  		}  	} -	LLCurl::getCurlThread()->pause() ;  	// Delete workers first  	// shotdown all worker threads before deleting them in case of co-dependencies @@ -2025,11 +2018,6 @@ bool LLAppViewer::cleanup()  	LL_INFOS() << "Shutting down message system" << LL_ENDL;  	end_messaging_system(); -	// *NOTE:Mani - The following call is not thread safe.  -	LL_CHECK_MEMORY -	LLCurl::cleanupClass(); -	LL_CHECK_MEMORY -  	// Non-LLCurl libcurl library  	mAppCoreHttp.cleanup(); diff --git a/indra/test/io.cpp b/indra/test/io.cpp index 099331b727..ff900ab96b 100755 --- a/indra/test/io.cpp +++ b/indra/test/io.cpp @@ -41,8 +41,6 @@  #include "llpipeutil.h"  #include "llpumpio.h"  #include "llsd.h" -#include "llsdrpcclient.h" -#include "llsdrpcserver.h"  #include "llsdserialize.h"  #include "llcommon.h"  #include "lluuid.h" @@ -1177,426 +1175,6 @@ namespace tut  	}  } -#if 0 -namespace tut -{ -	struct rpc_server_data -	{ -		class LLSimpleRPCResponse : public LLSDRPCResponse -		{ -		public: -			LLSimpleRPCResponse(LLSD* response) : -				mResponsePtr(response) -			{ -			} -			~LLSimpleRPCResponse()  -			{ -			} -			virtual bool response(LLPumpIO* pump) -			{ -				*mResponsePtr = mReturnValue; -				return true; -			} -			virtual bool fault(LLPumpIO* pump) -			{ -				*mResponsePtr = mReturnValue; -				return false; -			} -			virtual bool error(LLPumpIO* pump) -			{ -				ensure("LLSimpleRPCResponse::error()", false); -				return false; -			} -		public: -			LLSD* mResponsePtr; -		}; - -		class LLSimpleRPCClient : public LLSDRPCClient -		{ -		public: -			LLSimpleRPCClient(LLSD* response) : -				mResponsePtr(response) -			{ -			} -			~LLSimpleRPCClient() {} -			void echo(const LLSD& parameter) -			{ -				LLSimpleRPCResponse* resp; -				resp = new LLSimpleRPCResponse(mResponsePtr); -				static const std::string URI_NONE; -				static const std::string METHOD_ECHO("echo"); -				call(URI_NONE, METHOD_ECHO, parameter, resp, EPBQ_CALLBACK); -			} -		public: -			LLSD* mResponsePtr; -		}; - -		class LLSimpleRPCServer : public LLSDRPCServer -		{ -		public: -			LLSimpleRPCServer() -			{ -				mMethods["echo"] = new mem_fn_t( -					this, -					&LLSimpleRPCServer::rpc_Echo); -			} -			~LLSimpleRPCServer() {} -		protected: -			typedef LLSDRPCMethodCall<LLSimpleRPCServer> mem_fn_t; -			ESDRPCSStatus rpc_Echo( -				const LLSD& parameter, -				const LLChannelDescriptors& channels, -				LLBufferArray* data) -			{ -				buildResponse(channels, data, parameter); -				return ESDRPCS_DONE; -			} -		}; - -		apr_pool_t* mPool; -		LLPumpIO* mPump; -		LLPumpIO::chain_t mChain; -		LLSimpleRPCClient* mClient; -		LLSD mResponse; - -		rpc_server_data() : -			mPool(NULL), -			mPump(NULL), -			mClient(NULL) -		{ -			apr_pool_create(&mPool, NULL); -			mPump = new LLPumpIO(mPool); -			mClient = new LLSimpleRPCClient(&mResponse); -			mChain.push_back(LLIOPipe::ptr_t(mClient)); -			mChain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCRequest)); -			mChain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCRequest2LLSD)); -			mChain.push_back(LLIOPipe::ptr_t(new LLSimpleRPCServer)); -			mChain.push_back(LLIOPipe::ptr_t(new LLFilterSD2XMLRPCResponse)); -			mChain.push_back(LLIOPipe::ptr_t(new LLFilterXMLRPCResponse2LLSD)); -			mChain.push_back(LLIOPipe::ptr_t(mClient)); -		} -		~rpc_server_data() -		{ -			mChain.clear(); -			delete mPump; -			mPump = NULL; -			apr_pool_destroy(mPool); -			mPool = NULL; -		} -		void pump_loop(const LLSD& request) -		{ -			LLTimer timer; -			timer.setTimerExpirySec(1.0f); -			mClient->echo(request); -			mPump->addChain(mChain, DEFAULT_CHAIN_EXPIRY_SECS); -			while(mResponse.isUndefined() && !timer.hasExpired()) -			{ -				mPump->pump(); -				mPump->callback(); -			} -		} -	}; -	typedef test_group<rpc_server_data> rpc_server_test; -	typedef rpc_server_test::object rpc_server_object; -	tut::rpc_server_test rpc("rpc_server"); - -	template<> template<> -	void rpc_server_object::test<1>() -	{ -		LLSD request; -		request = 1; -		pump_loop(request); -		//LL_INFOS() << "request: " << *request << LL_ENDL; -		//LL_INFOS() << "response: " << *mResponse << LL_ENDL; -		ensure_equals("integer request response", mResponse.asInteger(), 1); -	} - -	template<> template<> -	void rpc_server_object::test<2>() -	{ -//#if LL_WINDOWS && _MSC_VER >= 1400 -//        skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser."); -//#endif -		std::string uri("sl-am:66.150.244.180:12035/location?start=region&px=70.9247&py=254.378&pz=38.7304&lx=-0.043753&ly=-0.999042&lz=0"); -		std::stringstream stream; -		stream << "{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n}"; -		std::vector<U8> expected_binary; -		expected_binary.resize(stream.str().size()); -		memcpy(&expected_binary[0], stream.str().c_str(), stream.str().size());		/* Flawfinder: ignore */ -		stream.str(""); -		stream << "[{'uri':'" << uri << "'}, {'version':i1}, " -				  << "{'agent_id':'3c115e51-04f4-523c-9fa6-98aff1034730', 'session_id':'2c585cec-038c-40b0-b42e-a25ebab4d132', 'circuit_code':i1075, 'start':'region', 'limited_to_estate':i1 'first_name':'Phoenix', 'last_name':'Linden', 'group_title':'', 'group_id':u00000000-0000-0000-0000-000000000000, 'position':[r70.9247,r254.378,r38.7304], 'look_at':[r-0.043753,r-0.999042,r0], 'granters':[ua2e76fcd-9360-4f6d-a924-000000000003], 'texture_data':['5e481e8a-58a6-fc34-6e61-c7a36095c07f', 'c39675f5-ca90-a304-bb31-42cdb803a132', '5c989edf-88d1-b2ac-b00b-5ed4bab8e368', '6522e74d-1660-4e7f-b601-6f48c1659a77', '7ca39b4c-bd19-4699-aff7-f93fd03d3e7b', '41c58177-5eb6-5aeb-029d-bc4093f3c130', '97b75473-8b93-9b25-2a11-035b9ae93195', '1c2d8d9b-90eb-89d4-dea8-c1ed83990614', '69ec543f-e27b-c07c-9094-a8be6300f274', 'c9f8b80f-c629-4633-04ee-c566ce9fea4b', '989cddba-7ab6-01ed-67aa-74accd2a2a65', '45e319b2-6a8c-fa5c-895b-1a7149b88aef', '5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', '406f98fd-9c89-1d52-5f39-e67d508c5ee5', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97'], " -				  << "'attachment_data':[" -				  << "{'attachment_point':i2, 'item_id':'d6852c11-a74e-309a-0462-50533f1ef9b3', 'asset_id':'c69b29b1-8944-58ae-a7c5-2ca7b23e22fb'}," -				  << "{'attachment_point':i10, 'item_id':'ff852c22-a74e-309a-0462-50533f1ef900', 'asset_data':b(" << expected_binary.size() << ")\""; -		stream.write((const char*)&expected_binary[0], expected_binary.size()); -		stream << "\"}" -				  << "]" -				  << "}]"; - -		LLSD request; -		S32 count = LLSDSerialize::fromNotation( -			request, -			stream, -			stream.str().size()); -		ensure("parsed something", (count > 0)); - -		pump_loop(request); -		ensure_equals("return type", mResponse.type(), LLSD::TypeArray); -		ensure_equals("return size", mResponse.size(), 3); - -		ensure_equals( -			"uri parameter type", -			mResponse[0].type(), -			LLSD::TypeMap); -		ensure_equals( -			"uri type", -			mResponse[0]["uri"].type(), -			LLSD::TypeString); -		ensure_equals("uri value", mResponse[0]["uri"].asString(), uri); - -		ensure_equals( -			"version parameter type", -			mResponse[1].type(), -			LLSD::TypeMap); -		ensure_equals( -			"version type", -			mResponse[1]["version"].type(), -			LLSD::TypeInteger); -		ensure_equals( -			"version value", -			mResponse[1]["version"].asInteger(), -			1); - -		ensure_equals("agent params type", mResponse[2].type(), LLSD::TypeMap); -		LLSD attachment_data = mResponse[2]["attachment_data"]; -		ensure("attachment data exists", attachment_data.isDefined()); -		ensure_equals( -			"attachment type", -			attachment_data.type(), -			LLSD::TypeArray); -		ensure_equals( -			"attachment type 0", -			attachment_data[0].type(), -			LLSD::TypeMap); -		ensure_equals( -			"attachment type 1", -			attachment_data[1].type(), -			LLSD::TypeMap); -		ensure_equals("attachment size 1", attachment_data[1].size(), 3); -		ensure_equals( -			"asset data type", -			attachment_data[1]["asset_data"].type(), -			LLSD::TypeBinary); -		std::vector<U8> actual_binary; -		actual_binary = attachment_data[1]["asset_data"].asBinary(); -		ensure_equals( -			"binary data size", -			actual_binary.size(), -			expected_binary.size()); -		ensure( -			"binary data", -			(0 == memcmp( -				&actual_binary[0], -				&expected_binary[0], -				expected_binary.size()))); -	} - -	template<> template<> -	void rpc_server_object::test<3>() -	{ -//#if LL_WINDOWS && _MSC_VER >= 1400 -//        skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser."); -//#endif -		std::string uri("sl-am:66.150.244.180:12035/location?start=region&px=70.9247&py=254.378&pz=38.7304&lx=-0.043753&ly=-0.999042&lz=0"); - -		LLBufferArray buffer; -		LLChannelDescriptors buffer_channels = buffer.nextChannel(); -		LLBufferStream stream(buffer_channels, &buffer); -		stream << "[{'uri':'" << uri << "'}, {'version':i1}, " -				  << "{'agent_id':'3c115e51-04f4-523c-9fa6-98aff1034730', 'session_id':'2c585cec-038c-40b0-b42e-a25ebab4d132', 'circuit_code':i1075, 'start':'region', 'limited_to_estate':i1 'first_name':'Phoenix', 'last_name':'Linden', 'group_title':'', 'group_id':u00000000-0000-0000-0000-000000000000, 'position':[r70.9247,r254.378,r38.7304], 'look_at':[r-0.043753,r-0.999042,r0], 'granters':[ua2e76fcd-9360-4f6d-a924-000000000003], 'texture_data':['5e481e8a-58a6-fc34-6e61-c7a36095c07f', 'c39675f5-ca90-a304-bb31-42cdb803a132', '5c989edf-88d1-b2ac-b00b-5ed4bab8e368', '6522e74d-1660-4e7f-b601-6f48c1659a77', '7ca39b4c-bd19-4699-aff7-f93fd03d3e7b', '41c58177-5eb6-5aeb-029d-bc4093f3c130', '97b75473-8b93-9b25-2a11-035b9ae93195', '1c2d8d9b-90eb-89d4-dea8-c1ed83990614', '69ec543f-e27b-c07c-9094-a8be6300f274', 'c9f8b80f-c629-4633-04ee-c566ce9fea4b', '989cddba-7ab6-01ed-67aa-74accd2a2a65', '45e319b2-6a8c-fa5c-895b-1a7149b88aef', '5748decc-f629-461c-9a36-a35a221fe21f', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', '406f98fd-9c89-1d52-5f39-e67d508c5ee5', '685fbe10-ab40-f065-0aec-726cc6dfd7a1', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97', 'c228d1cf-4b5d-4ba8-84f4-899a0796aa97'], " -				  << "'attachment_data':[" -				  << "{'attachment_point':i2, 'item_id':'d6852c11-a74e-309a-0462-50533f1ef9b3', 'asset_id':'c69b29b1-8944-58ae-a7c5-2ca7b23e22fb'},"; - -		std::stringstream tmp_str; -		tmp_str << "{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n}"; -		std::vector<U8> expected_binary; -		expected_binary.resize(tmp_str.str().size()); -		memcpy(		/* Flawfinder: ignore */ -			&expected_binary[0], -			tmp_str.str().c_str(), -			tmp_str.str().size()); - -		LLBufferArray attachment_buffer; -		LLChannelDescriptors attach_channels = attachment_buffer.nextChannel(); -		LLBufferStream attach_stream(attach_channels, &attachment_buffer); -		attach_stream.write((const char*)&expected_binary[0], expected_binary.size()); -		attach_stream.flush(); -		S32 len = attachment_buffer.countAfter(attach_channels.out(), NULL); -		stream << "{'attachment_point':i10, 'item_id':'ff852c22-a74e-309a-0462-50533f1ef900', 'asset_data':b(" << len << ")\""; -		stream.flush(); -		buffer.takeContents(attachment_buffer); -		stream << "\"}]}]"; -		stream.flush(); - -		LLChannelDescriptors read_channel = buffer.nextChannel(); -		LLBufferStream read_stream(read_channel, &buffer); -		LLSD request; -		S32 count = LLSDSerialize::fromNotation( -			request, -			read_stream, -			buffer.count(read_channel.in())); -		ensure("parsed something", (count > 0)); -		ensure("deserialized", request.isDefined()); - -		// do the rpc round trip -		pump_loop(request); - -		ensure_equals("return type", mResponse.type(), LLSD::TypeArray); -		ensure_equals("return size", mResponse.size(), 3); - -		LLSD child = mResponse[0]; -		ensure("uri map exists", child.isDefined()); -		ensure_equals("uri parameter type", child.type(), LLSD::TypeMap); -		ensure("uri string exists", child.has("uri")); -		ensure_equals("uri type", child["uri"].type(), LLSD::TypeString); -		ensure_equals("uri value", child["uri"].asString(), uri); - -		child = mResponse[1]; -		ensure("version map exists",	child.isDefined()); -		ensure_equals("version param type", child.type(), LLSD::TypeMap); -		ensure_equals( -			"version type", -			child["version"].type(), -			LLSD::TypeInteger); -		ensure_equals("version value", child["version"].asInteger(), 1); - -		child = mResponse[2]; -		ensure("agent params map exists", child.isDefined()); -		ensure_equals("agent params type", child.type(), LLSD::TypeMap); -		child = child["attachment_data"]; -		ensure("attachment data exists", child.isDefined()); -		ensure_equals("attachment type", child.type(), LLSD::TypeArray); -		LLSD attachment = child[0]; -		ensure_equals("attachment type 0", attachment.type(), LLSD::TypeMap); -		attachment = child[1]; -		ensure_equals("attachment type 1", attachment.type(), LLSD::TypeMap); -		ensure_equals("attachment size 1", attachment.size(), 3); -		ensure_equals( -			"asset data type", -			attachment["asset_data"].type(), -			LLSD::TypeBinary); -		std::vector<U8> actual_binary = attachment["asset_data"].asBinary(); -		ensure_equals( -			"binary data size", -			actual_binary.size(), -			expected_binary.size()); -		ensure( -			"binary data", -			(0 == memcmp( -				&actual_binary[0], -				&expected_binary[0], -				expected_binary.size()))); -	} - -	template<> template<> -	void rpc_server_object::test<4>() -	{ -		std::string message("parcel '' is naughty."); -		std::stringstream str; -		str << "{'message':'" << LLSDNotationFormatter::escapeString(message) -			<< "'}"; -		LLSD request; -		S32 count = LLSDSerialize::fromNotation( -			request, -			str, -			str.str().size()); -		ensure_equals("parse count", count, 2); -		ensure_equals("request type", request.type(), LLSD::TypeMap); -		pump_loop(request); -		ensure("valid response", mResponse.isDefined()); -		ensure_equals("response type", mResponse.type(), LLSD::TypeMap); -		std::string actual = mResponse["message"].asString(); -		ensure_equals("message contents", actual, message); -	} - -	template<> template<> -	void rpc_server_object::test<5>() -	{ -		// test some of the problem cases with llsdrpc over xmlrpc - -		// for example: -		// * arrays are auto-converted to parameter lists, thus, this -		// becomes one parameter. -		// * undef goes over the wire as false (this might not be a good idea) -		// * uuids are converted to string. -		std::string val = "[{'failures':!,'successfuls':[u3c115e51-04f4-523c-9fa6-98aff1034730]}]"; -		std::istringstream istr; -		istr.str(val); -		LLSD sd; -		LLSDSerialize::fromNotation(sd, istr, val.size()); -		pump_loop(sd); -		ensure("valid response", mResponse.isDefined()); -		ensure_equals("parsed type", mResponse.type(), LLSD::TypeMap); -		ensure_equals("parsed size", mResponse.size(), 2); -		LLSD failures = mResponse["failures"]; -		ensure_equals("no failures.", failures.asBoolean(), false); -		LLSD success = mResponse["successfuls"]; -		ensure_equals("success type", success.type(), LLSD::TypeArray); -		ensure_equals("success size", success.size(), 1); -		ensure_equals( -			"success instance type", -			success[0].type(), -			LLSD::TypeString); -	} - -/* -	template<> template<> -	void rpc_server_object::test<5>() -	{ -		std::string expected("\xf3");//\xffsomething"); -		LLSD* request = LLSD::createString(expected); -		pump_loop(request); -		std::string actual; -		mResponse->getString(actual); -		if(actual != expected) -		{ -			//LL_WARNS() << "iteration " << i << LL_ENDL; -			std::ostringstream e_str; -			std::string::iterator iter = expected.begin(); -			std::string::iterator end = expected.end(); -			for(; iter != end; ++iter) -			{ -				e_str << (S32)((U8)(*iter)) << " "; -			} -			e_str << std::endl; -			llsd_serialize_string(e_str, expected); -			LL_WARNS() << "expected size: " << expected.size() << LL_ENDL; -			LL_WARNS() << "expected:	  " << e_str.str() << LL_ENDL; - -			std::ostringstream a_str; -			iter = actual.begin(); -			end = actual.end(); -			for(; iter != end; ++iter) -			{ -				a_str << (S32)((U8)(*iter)) << " "; -			} -			a_str << std::endl; -			llsd_serialize_string(a_str, actual); -			LL_WARNS() << "actual size:	  " << actual.size() << LL_ENDL; -			LL_WARNS() << "actual:		" << a_str.str() << LL_ENDL; -		} -		ensure_equals("binary string request response", actual, expected); -		delete request; -	} - -	template<> template<> -	void rpc_server_object::test<5>() -	{ -	} -*/ -} -#endif -  /*  'asset_data':b(12100)"{'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061088050622956\n\treztime\t1094866329019785\n\tparceltime\t1133568981980596\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':u61fa7364-e151-0597-774c-523312dae31b}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444922\n\ttotal_crc\t324\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.367110789\t0.00780026987\t-0.566269755\n\toldpos\t150.115005\t25.8479004\t8.18669987\n\trotation\t0.47332942485809326171875\t-0.380102097988128662109375\t-0.5734078884124755859375\t0.550168216228485107421875\n\tchildpos\t-0.00499999989\t-0.0370000005\t0.305000007\n\tchildrot\t-0.736649334430694580078125\t-0.03042060509324073791503906\t-0.02784589119255542755126953\t0.67501628398895263671875\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087839248891\n\treztime\t1094866329020800\n\tparceltime\t1133568981981983\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ub8d68643-7dd8-57af-0d24-8790032aed0c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444923\n\ttotal_crc\t235\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.120029509\t-0.00284469454\t-0.0302077383\n\toldpos\t150.710999\t25.8584995\t8.19172001\n\trotation\t0.145459949970245361328125\t-0.1646589934825897216796875\t0.659558117389678955078125\t-0.718826770782470703125\n\tchildpos\t0\t-0.182999998\t-0.26699999\n\tchildrot\t0.991444766521453857421875\t3.271923924330621957778931e-05\t-0.0002416197530692443251609802\t0.1305266767740249633789062\n\tscale\t0.0382982\t0.205957\t0.368276\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087534454174\n\treztime\t1094866329021741\n\tparceltime\t1133568981982889\n\ttax_rate\t1.00326\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ue4b19200-9d33-962f-c8c5-6f25be3a3fd0}\n{\n\tname\tApotheosis_Immolaine_tail|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444924\n\ttotal_crc\t675\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.34780401\t-0.00968400016\t-0.260098994\n\toldpos\t0\t0\t0\n\trotation\t0.73164522647857666015625\t-0.67541944980621337890625\t-0.07733880728483200073242188\t0.05022468417882919311523438\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.0382982\t0.32228\t0.383834\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087463950186\n\treztime\t1094866329022555\n\tparceltime\t1133568981984359\n\tdescription\t(No Description)|\n\ttax_rate\t1.01736\n\tnamevalue\tAttachPt U32 RW S 10\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.110088, -0.182018, 1.493795\n\tnamevalue\tAttachmentOffset VEC3 RW DS -0.347804, -0.009684, -0.260099\n\tnamevalue\tAttachItemID STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n"  */ | 
