// virtual
LLIOPipe::EStatus LLURLRequest::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	PUMP_DEBUG;
	LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
	//llinfos << "LLURLRequest::process_impl()" << llendl;
	if(!buffer) return STATUS_ERROR;
	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.get();
		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;
		mDetail->mCurlRequest->perform();
		while(1)
		{
			CURLcode result;
			bool newmsg = mDetail->mCurlRequest->getResult(&result);
			if (!newmsg)
			{
				break;
			}

			mState = STATE_HAVE_RESPONSE;
			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);
						pump->respond(chain, buffer, context);
						mCompletionCallback = NULL;
					}
					break;
				case CURLE_FAILED_INIT:
				case CURLE_COULDNT_CONNECT:
					status = STATUS_NO_CONNECTION;
					break;
				default:
					llwarns << "URLRequest Error: " << result
							<< ", "
							<< LLCurl::strerror(result)
							<< ", "
							<< (mDetail->mURL.empty() ? "<EMPTY URL>" : mDetail->mURL)
							<< llendl;
					status = STATUS_ERROR;
					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;
		return STATUS_DONE;

	default:
		PUMP_DEBUG;
		return STATUS_ERROR;
	}
}
Exemple #2
0
// virtual
LLIOPipe::EStatus LLSDRPCServer::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	LLFastTimer t(FTM_PROCESS_SDRPC_SERVER);
	PUMP_DEBUG;
	LLMemType m1(LLMemType::MTYPE_IO_SD_SERVER);
//	lldebugs << "LLSDRPCServer::process_impl" << llendl;
	// 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:
//		lldebugs << "STATE_DONE" << llendl;
		break;
	case STATE_CALLBACK:
//		lldebugs << "STATE_CALLBACK" << llendl;
		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:
//		lldebugs << "STATE_NONE" << llendl;
	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
LLIOPipe::EStatus LLURLRequest::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	PUMP_DEBUG;
	LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
	//llinfos << "LLURLRequest::process_impl()" << llendl;
	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))
	{
		 // 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);
		 lldebugs << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << llendl;
		 if (mState == STATE_INITIALIZED)
		 {
			  llinfos << "LLURLRequest adjustTimeoutSeconds called during upload" << llendl;
		 }
	}

	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.get();
		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;
		mDetail->mCurlRequest->perform();
		while(1)
		{
			CURLcode result;
			bool 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;
			lldebugs << this << "Setting context to " << context << llendl;
			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);
						pump->respond(chain, buffer, context);
						mCompletionCallback = NULL;
					}
					break;
				case CURLE_FAILED_INIT:
				case CURLE_COULDNT_CONNECT:
					status = STATUS_NO_CONNECTION;
					break;
				default:
					llwarns << "URLRequest Error: " << result
							<< ", "
							<< LLCurl::strerror(result)
							<< ", "
							<< (mDetail->mURL.empty() ? "<EMPTY URL>" : mDetail->mURL)
							<< llendl;
					status = STATUS_ERROR;
					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;
		lldebugs << this << "Setting context to " << context << llendl;
		return STATUS_DONE;

	default:
		PUMP_DEBUG;
		context[CONTEXT_REQUEST][CONTEXT_TRANSFERED_BYTES] = mRequestTransferedBytes;
		context[CONTEXT_RESPONSE][CONTEXT_TRANSFERED_BYTES] = mResponseTransferedBytes;
		lldebugs << this << "Setting context to " << context << llendl;
		return STATUS_ERROR;
	}
}