Example #1
0
bool LLHTTPResponder::readLine(
	const LLChannelDescriptors& channels,
	buffer_ptr_t buffer,
	U8* dest,
	S32& len)
{
	LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
	--len;
	U8* last = buffer->readAfter(channels.in(), mLastRead, dest, len);
	dest[len] = '\0';
	U8* newline = (U8*)strchr((char*)dest, '\n');
	if(!newline)
	{
		if(len)
		{
			lldebugs << "readLine failed - too long maybe?" << llendl;
			markBad(channels, buffer);
		}
		return false;
	}
	S32 offset = -((len - 1) - (newline - dest));
	++newline;
	*newline = '\0';
	mLastRead = buffer->seek(channels.in(), last, offset);
	return true;
}
Example #2
0
// virtual
LLIOPipe::EStatus LLContextURLExtractor::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	PUMP_DEBUG;
	LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
	// 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;
}
Example #3
0
	void buffer_object_t::test<1>()
	{
		LLChannelDescriptors channelDescriptors;
		ensure("in() and out() functions Failed", (0 == channelDescriptors.in() && 1 == channelDescriptors.out()));
	
		S32 val = 50;
		LLChannelDescriptors channelDescriptors1(val);
		ensure("LLChannelDescriptors in() and out() functions Failed", (50 == channelDescriptors1.in() && 51 == channelDescriptors1.out()));
	}	
Example #4
0
	void buffer_object_t::test<6>()
	{
		LLBufferArray bufferArray;
		const char array[] = "SecondLife";
		S32 len = strlen(array);
		LLChannelDescriptors channelDescriptors = bufferArray.nextChannel();
		bufferArray.append(channelDescriptors.in(), (U8*)array, len);
		S32 count = bufferArray.countAfter(channelDescriptors.in(), NULL);
		ensure_equals("Appended size is:", count, len);
	}
Example #5
0
// virtual
LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	PUMP_DEBUG;
	LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
	if(eos)
	{
		PUMP_DEBUG;
		//mGotEOS = true;
		std::ostringstream ostr;
		std::string message = context[CONTEXT_RESPONSE]["statusMessage"];
		
		int code = context[CONTEXT_RESPONSE]["statusCode"];
		if (code < 200)
		{
			code = 200;
			message = "OK";
		}
		
		ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n";
		S32 content_length = buffer->countAfter(channels.in(), NULL);
		if(0 < content_length)
		{
			ostr << "Content-Length: " << content_length << "\r\n";
		}
		// *NOTE: This guard can go away once the LLSD static map
		// iterator is available. Phoenix. 2008-05-09
		LLSD headers = context[CONTEXT_RESPONSE][CONTEXT_HEADERS];
		if(headers.isDefined())
		{
			LLSD::map_iterator iter = headers.beginMap();
			LLSD::map_iterator end = headers.endMap();
			for(; iter != end; ++iter)
			{
				ostr << (*iter).first << ": " << (*iter).second.asString()
					<< "\r\n";
			}
		}
		ostr << "\r\n";

		LLChangeChannel change(channels.in(), channels.out());
		std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
		std::string header = ostr.str();
		buffer->prepend(channels.out(), (U8*)header.c_str(), header.size());
		PUMP_DEBUG;
		return STATUS_DONE;
	}
	PUMP_DEBUG;
	return STATUS_OK;
}
	void completedRaw(
		const LLChannelDescriptors& channels,
		const LLIOPipe::buffer_ptr_t& buffer)
	{
		completedHeader();

		if (!isGoodStatus())
		{
			if (getStatus() == HTTP_NOT_MODIFIED)
			{
				LL_INFOS("fsdata") << "Got [304] not modified for " << mURL << LL_ENDL;
			}
			else
			{
				LL_WARNS("fsdata") << "Error fetching " << mURL << " Status: [" << getStatus() << "]" << LL_ENDL;
			}
			return;
		}

		S32 data_size = buffer->countAfter(channels.in(), NULL);
		if (data_size <= 0)
		{
			LL_WARNS("fsdata") << "Received zero data for " << mURL << LL_ENDL;
			return;
		}

		U8* data = new U8[data_size];
		buffer->readAfter(channels.in(), NULL, data, data_size);

		// basic check for valid data received
		LLXMLNodePtr xml_root;
		if ( (!LLXMLNode::parseBuffer(data, data_size, xml_root, NULL)) || (xml_root.isNull()) || (!xml_root->hasName("script_library")) )
		{
			LL_WARNS("fsdata") << "Could not read the script library data from "<< mURL << LL_ENDL;
			delete[] data;
			data = NULL;
			return;
		}
		
		LLAPRFile outfile ;
		outfile.open(mFilename, LL_APR_WB);
		if (!outfile.getFileHandle())
		{
			LL_WARNS("fsdata") << "Unable to open file for writing: " << mFilename << LL_ENDL;
		}
		else
		{
			LL_INFOS("fsdata") << "Saving " << mFilename << LL_ENDL;
			outfile.write(data, data_size);
			outfile.close() ;
		}
		delete[] data;
		data = NULL;
	}
Example #7
0
	void buffer_object_t::test<12>()
	{
		LLBufferArray bufferArray;
		LLChannelDescriptors channelDescriptors;
		LLBufferArray::segment_iterator_t it;
		S32 length = 1000;
		it = bufferArray.makeSegment(channelDescriptors.out(), length);
		ensure("makeSegment() function failed", (it != bufferArray.endSegment()));
		ensure("eraseSegment() function failed", bufferArray.eraseSegment(it));
		ensure("eraseSegment() begin/end should now be same", bufferArray.beginSegment() == bufferArray.endSegment());
	}
Example #8
0
	void buffer_object_t::test<9>()
	{
		LLBufferArray bufferArray;
		const char array[] = "SecondLife";
		S32 len = strlen(array) + 1;
		std::string str(array);
		LLChannelDescriptors channelDescriptors = bufferArray.nextChannel();
		bufferArray.append(channelDescriptors.in(), (U8*)array, len);
		LLBufferArray bufferArray1;
		ensure("Contents are not copied and the source buffer is not empty", (1 == bufferArray1.takeContents(bufferArray)));
		
		char buf[100];
		S32 len2 = len;
		bufferArray1.readAfter(channelDescriptors.in(), NULL, (U8*)buf, len2);	
		ensure_equals("takeContents failed to copy", buf, str);
	}
Example #9
0
// virtual
LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	PUMP_DEBUG;
	LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
	if(eos)
	{
		PUMP_DEBUG;
		//mGotEOS = true;
		std::ostringstream ostr;
		std::string message = context["response"]["statusMessage"];
		
		int code = context["response"]["statusCode"];
		if (code < 200)
		{
			code = 200;
			message = "OK";
		}
		
		ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n";
		
		std::string type = context["response"]["contentType"].asString();
		if (!type.empty())
		{
			ostr << "Content-Type: " << type << "\r\n";
		}
		S32 content_length = buffer->countAfter(channels.in(), NULL);
		if(0 < content_length)
		{
			ostr << "Content-Length: " << content_length << "\r\n";
		}
		ostr << "\r\n";

		LLChangeChannel change(channels.in(), channels.out());
		std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
		std::string header = ostr.str();
		buffer->prepend(channels.out(), (U8*)header.c_str(), header.size());
		PUMP_DEBUG;
		return STATUS_DONE;
	}
	PUMP_DEBUG;
	return STATUS_OK;
}
// virtual
LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	LLFastTimer t(FTM_PROCESS_SD2XMLRPC_RESPONSE);

	PUMP_DEBUG;
	// This pipe does not work if it does not have everyting. This
	// could be addressed by making a stream parser for llsd which
	// handled partial information.
	if(!eos)
	{
		return STATUS_BREAK;
	}

	PUMP_DEBUG;
	// we have everyting in the buffer, so turn the structure data rpc
	// response into an xml rpc response.
	LLBufferStream stream(channels, buffer.get());
	stream << XML_HEADER << XMLRPC_METHOD_RESPONSE_HEADER << std::flush;	// Flush, or buffer->count() returns too much!
	LLSD sd;
	LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in()));

	PUMP_DEBUG;
	LLIOPipe::EStatus rv = STATUS_ERROR;
	if(sd.has("response"))
	{
		PUMP_DEBUG;
		// it is a normal response. pack it up and ship it out.
		stream.precision(DEFAULT_PRECISION);
		stream << XMLRPC_RESPONSE_HEADER;
		streamOut(stream, sd["response"]);
		stream << XMLRPC_RESPONSE_FOOTER << XMLRPC_METHOD_RESPONSE_FOOTER;
		rv = STATUS_DONE;
	}
	else if(sd.has("fault"))
	{
		PUMP_DEBUG;
		// it is a fault.
		stream << XMLRPC_FAULT_1 << sd["fault"]["code"].asInteger()
			<< XMLRPC_FAULT_2
			<< xml_escape_string(sd["fault"]["description"].asString())
			<< XMLRPC_FAULT_3 << XMLRPC_METHOD_RESPONSE_FOOTER;
		rv = STATUS_DONE;
	}
	else
	{
		llwarns << "Unable to determine the type of LLSD response." << llendl;
	}
	PUMP_DEBUG;
	return rv;
}
//virtual 
LLIOPipe::EStatus LLPipeStringInjector::process_impl(
		const LLChannelDescriptors& channels,
		buffer_ptr_t& buffer,
		bool& eos,
		LLSD& context,
		LLPumpIO* pump)
{
	buffer->append(channels.out(), (U8*) mString.data(), mString.size());
	eos = true;
	return STATUS_DONE;
}
void XMLRPCResponder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
{
	if (mCode == CURLE_OK && !is_internal_http_error(status))
	{
		mBufferSize = buffer->count(channels.in());
		if (200 <= status && status < 400)
		{
			char* ptr = NULL;
			char* buf = NULL;
			LLMutexLock lock(buffer->getMutex());
			LLBufferArray::const_segment_iterator_t const end = buffer->endSegment();
			for (LLBufferArray::const_segment_iterator_t iter = buffer->beginSegment(); iter != end; ++iter)
			{
				LLSegment const& segment = *iter;
				if (segment.isOnChannel(channels.in()))
				{
					S32 const segment_size = segment.size();
					if (!buf)
					{
						if (segment_size == mBufferSize)
						{
							// It's contiguous, no need for copying.
							mResponse = XMLRPC_REQUEST_FromXML((char const*)segment.data(), mBufferSize, NULL);
							break;
						}
						ptr = buf = new char [mBufferSize];
					}
					llassert(ptr + segment_size <= buf + mBufferSize);
					memcpy(ptr, segment.data(), segment_size);
					ptr += segment_size;
				}
			}
			if (buf)
			{
				mResponse = XMLRPC_REQUEST_FromXML(buf, mBufferSize, NULL);
				delete [] buf;
			}
		}
	}
}
Example #13
0
	void buffer_object_t::test<8>()
	{
		LLBufferArray bufferArray;
		const char array[] = "SecondLife";
		S32 len = strlen(array);
		const char array1[] = "LindenLabs";
		S32 len1 = strlen(array1);
		
		std::string str(array);
		str.append(array1);
		
		LLChannelDescriptors channelDescriptors = bufferArray.nextChannel();
		bufferArray.append(channelDescriptors.in(), (U8*)array, len);		
		bufferArray.append(channelDescriptors.in(), (U8*)array1, len1);
		char buf[100];
		S32 len2 = 20;
		bufferArray.readAfter(channelDescriptors.in(), NULL, (U8*)buf, len2);
		ensure_equals("readAfter length failed", len2, 20);
		
		buf[len2] = '\0';
		ensure_equals("readAfter/append/append failed", buf, str);
	}
Example #14
0
void HippoRestHandlerRaw::handle(int status, const std::string &reason,
								 const LLChannelDescriptors &channels,
								 const boost::shared_ptr<LLBufferArray> &body)
{
	if (status == 200) {
		std::string data;
		LLBufferArray *buffer = body.get();
		LLBufferArray::segment_iterator_t it, end = buffer->endSegment();
		for (it=buffer->beginSegment(); it!=end; ++it)
			if (it->isOnChannel(channels.in()))
				data.append((char*)it->data(), it->size());
		result(data);
	} else {
		llwarns << "Rest request error " << status << ": " << reason << llendl;
	}
}
Example #15
0
void HippoRestHandlerXml::handle(int status, const std::string &reason,
								 const LLChannelDescriptors &channels,
								 const boost::shared_ptr<LLBufferArray> &body)
{
	if (status == 200) {
		LLXmlTree *tree = new LLXmlTree();
		bool success = tree->parseBufferStart();
		LLBufferArray *buffer = body.get();
		LLBufferArray::segment_iterator_t it, end = buffer->endSegment();
		for (it=buffer->beginSegment(); success && (it!=end); ++it)
			if (it->isOnChannel(channels.in()))
				success = success && tree->parseBuffer((char*)it->data(), it->size());
		success = success && tree->parseBufferFinalize();
		if (success) result(tree);
		delete tree;
	} else {
		llwarns << "Rest request error " << status << ": " << reason << llendl;
	}
}
// virtual
LLIOPipe::EStatus LLIOASCIIFuzz::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	while(mByteCount)
	{
		std::vector<U8> data;
		data.reserve(10000);
		int size = llmin(10000, mByteCount);
		std::generate_n(
			std::back_insert_iterator< std::vector<U8> >(data),
			size,
			random_ascii_generator());
		buffer->append(channels.out(), &data[0], size);
		mByteCount -= size;
	}
	return STATUS_OK;
}
Example #17
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 LLIOSocketWriter::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_WRITER);
	PUMP_DEBUG;
	if(!mDestination) return STATUS_PRECONDITION_NOT_MET;
	if(!mInitialized)
	{
		PUMP_DEBUG;
		// Since the write will not block, it's ok to initialize and
		// attempt to write immediately.
		mInitialized = true;
		if(pump)
		{
			PUMP_DEBUG;
			LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketWriter."
					 << LL_ENDL;
			apr_pollfd_t poll_fd;
			poll_fd.p = NULL;
			poll_fd.desc_type = APR_POLL_SOCKET;
			poll_fd.reqevents = APR_POLLOUT;
			poll_fd.rtnevents = 0x0;
			poll_fd.desc.s = mDestination->getSocket();
			poll_fd.client_data = NULL;
			pump->setConditional(this, &poll_fd);
		}
	}

	PUMP_DEBUG;
	// *FIX: Some sort of writev implementation would be much more
	// efficient - not only because writev() is better, but also
	// because we won't have to do as much work to find the start
	// address.
	buffer->lock();
	LLBufferArray::segment_iterator_t it;
	LLBufferArray::segment_iterator_t end = buffer->endSegment();
	LLSegment segment;
	it = buffer->constructSegmentAfter(mLastWritten, segment);
	/*
	if(NULL == mLastWritten)
	{
		it = buffer->beginSegment();
		segment = (*it);
	}
	else
	{
		it = buffer->getSegment(mLastWritten);
		segment = (*it);
		S32 size = segment.size();
		U8* data = segment.data();
		if((data + size) == mLastWritten)
		{
			++it;
			segment = (*it);
		}
		else
		{
			// *FIX: check the math on this one
			segment = LLSegment(
				(*it).getChannelMask(),
				mLastWritten + 1,
				size - (mLastWritten - data));
		}
	}
	*/

	PUMP_DEBUG;
	apr_size_t len;
	bool done = false;
	apr_status_t status = APR_SUCCESS;
	while(it != end)
	{

		PUMP_DEBUG;
		if((*it).isOnChannel(channels.in()))
		{
			PUMP_DEBUG;
			len = (apr_size_t)segment.size();
			status = apr_socket_send(
				mDestination->getSocket(),
				(const char*)segment.data(),
				&len);
			// We sometimes get a 'non-blocking socket operation could not be 
			// completed immediately' error from apr_socket_send.  In this
			// case we break and the data will be sent the next time the chain
			// is pumped.
			if(APR_STATUS_IS_EAGAIN(status))
			{
				ll_apr_warn_status(status);
				break;
			}

			mLastWritten = segment.data() + len - 1;

			PUMP_DEBUG;
			if((S32)len < segment.size())
			{
				break;
			}
			
		}

		++it;
		if(it != end)
		{
			segment = (*it);
		}
		else
		{
			done = true;
		}

	}
	buffer->unlock();

	PUMP_DEBUG;
	if(done && eos)
	{
		return STATUS_DONE;
	}
	return STATUS_OK;
}
// virtual
LLIOPipe::EStatus LLIOSocketReader::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_READER);
	PUMP_DEBUG;
	if(!mSource) return STATUS_PRECONDITION_NOT_MET;
	if(!mInitialized)
	{
		PUMP_DEBUG;
		// Since the read will not block, it's ok to initialize and
		// attempt to read off the descriptor immediately.
		mInitialized = true;
		if(pump)
		{
			PUMP_DEBUG;
			LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketReader."
					 << LL_ENDL;
			apr_pollfd_t poll_fd;
			poll_fd.p = NULL;
			poll_fd.desc_type = APR_POLL_SOCKET;
			poll_fd.reqevents = APR_POLLIN;
			poll_fd.rtnevents = 0x0;
			poll_fd.desc.s = mSource->getSocket();
			poll_fd.client_data = NULL;
			pump->setConditional(this, &poll_fd);
		}
	}
	//if(!buffer)
	//{
	//	buffer = new LLBufferArray;
	//}
	PUMP_DEBUG;
	const apr_size_t READ_BUFFER_SIZE = 1024;
	char read_buf[READ_BUFFER_SIZE]; /*Flawfinder: ignore*/
	apr_size_t len;
	apr_status_t status = APR_SUCCESS;
	do
	{
		PUMP_DEBUG;
		len = READ_BUFFER_SIZE;
		status = apr_socket_recv(mSource->getSocket(), read_buf, &len);
		buffer->append(channels.out(), (U8*)read_buf, len);
	} while((APR_SUCCESS == status) && (READ_BUFFER_SIZE == len));
	LL_DEBUGS() << "socket read status: " << status << LL_ENDL;
	LLIOPipe::EStatus rv = STATUS_OK;

	PUMP_DEBUG;
	// *FIX: Also need to check for broken pipe
	if(APR_STATUS_IS_EOF(status))
	{
		// *FIX: Should we shut down the socket read?
		if(pump)
		{
			pump->setConditional(this, NULL);
		}
		rv = STATUS_DONE;
		eos = true;
	}
	else if(APR_STATUS_IS_EAGAIN(status))
	{
/*Commented out by Aura 9-9-8 for DEV-19961.
		// everything is fine, but we can terminate this process pump.
	
		rv = STATUS_BREAK;
*/
	}
	else
	{
		if(ll_apr_warn_status(status))
		{
			rv = STATUS_ERROR;
		}
	}
	PUMP_DEBUG;
	return rv;
}
LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_REQUEST);
	PUMP_DEBUG;
	if(!eos) return STATUS_BREAK;
	if(!buffer) return STATUS_ERROR;

	PUMP_DEBUG;
	// *FIX: This technique for reading data is far from optimal. We
	// need to have some kind of istream interface into the xml
	// parser...
	S32 bytes = buffer->countAfter(channels.in(), NULL);
	if(!bytes) return STATUS_ERROR;
	char* buf = new char[bytes + 1];
	buf[bytes] = '\0';
	buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes);

	//lldebugs << "xmlrpc request: " << buf << llendl;
	
	// Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if 
	// values that are less than 0x20 are passed to it, except
	// 0x09: Horizontal tab; 0x0a: New Line; 0x0d: Carriage
	U8* cur_pBuf = (U8*)buf;
    U8 cur_char;
	for (S32 i=0; i<bytes; i++) 
	{
        cur_char = *cur_pBuf;
		if (   cur_char < 0x20
            && 0x09 != cur_char
            && 0x0a != cur_char
            && 0x0d != cur_char )
        {
			*cur_pBuf = '?';
        }
		++cur_pBuf;
	}

	PUMP_DEBUG;
	XMLRPC_REQUEST request = XMLRPC_REQUEST_FromXML(
		buf,
		bytes,
		NULL);
	if(!request)
	{
		llwarns << "XML -> SD Request process parse error." << llendl;
		delete[] buf;
		return STATUS_ERROR;
	}

	PUMP_DEBUG;
	LLBufferStream stream(channels, buffer.get());
	stream.precision(DEFAULT_PRECISION);
	const char* name = XMLRPC_RequestGetMethodName(request);
	stream << LLSDRPC_REQUEST_HEADER_1 << (name ? name : "")
		   << LLSDRPC_REQUEST_HEADER_2;
	XMLRPC_VALUE param = XMLRPC_RequestGetData(request);
	if(param)
	{
		PUMP_DEBUG;
		S32 size = XMLRPC_VectorSize(param);
		if(size > 1)
		{
			// if there are multiple parameters, stuff the values into
			// an array so that the next step in the chain can read them.
			stream << "[";
		}
 		XMLRPC_VALUE current = XMLRPC_VectorRewind(param);
		bool needs_comma = false;
 		while(current)
 		{
			if(needs_comma)
			{
				stream << ",";
			}
			needs_comma = true;
 			stream_out(stream, current);
 			current = XMLRPC_VectorNext(param);
 		}
		if(size > 1)
		{
			// close the array
			stream << "]";
		}
	}
	stream << LLSDRPC_REQUEST_FOOTER << std::flush;
	XMLRPC_RequestFree(request, 1);
	delete[] buf;
	PUMP_DEBUG;
	return STATUS_DONE;
}
LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_RESPONSE);

	PUMP_DEBUG;
	if(!eos) return STATUS_BREAK;
	if(!buffer) return STATUS_ERROR;

	PUMP_DEBUG;
	// *FIX: This technique for reading data is far from optimal. We
	// need to have some kind of istream interface into the xml
	// parser...
	S32 bytes = buffer->countAfter(channels.in(), NULL);
	if(!bytes) return STATUS_ERROR;
	char* buf = new char[bytes + 1];
	buf[bytes] = '\0';
	buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes);

	//lldebugs << "xmlrpc response: " << buf << llendl;

	PUMP_DEBUG;
	XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML(
		buf,
		bytes,
		NULL);
	if(!response)
	{
		llwarns << "XML -> SD Response unable to parse xml." << llendl;
		delete[] buf;
		return STATUS_ERROR;
	}

	PUMP_DEBUG;
	LLBufferStream stream(channels, buffer.get());
	stream.precision(DEFAULT_PRECISION);
	if(XMLRPC_ResponseIsFault(response))
	{
		PUMP_DEBUG;
		stream << LLSDRPC_FAULT_HADER_1
			   << XMLRPC_GetResponseFaultCode(response)
			   << LLSDRPC_FAULT_HADER_2;
		const char* fault_str = XMLRPC_GetResponseFaultString(response);
		std::string fault_string;
		if(fault_str)
		{
			fault_string.assign(fault_str);
		}
		stream << "'" << LLSDNotationFormatter::escapeString(fault_string)
		   << "'" <<LLSDRPC_FAULT_FOOTER << std::flush;
	}
	else
	{
		PUMP_DEBUG;
		stream << LLSDRPC_RESPONSE_HEADER;
		XMLRPC_VALUE param = XMLRPC_RequestGetData(response);
		if(param)
		{
			stream_out(stream, param);
		}
		stream << LLSDRPC_RESPONSE_FOOTER << std::flush;
	}
	PUMP_DEBUG;
	XMLRPC_RequestFree(response, 1);
	delete[] buf;
	PUMP_DEBUG;
	return STATUS_DONE;
}
// virtual
LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	LLFastTimer t(FTM_PROCESS_SD2XMLRPC_REQUEST);
	// This pipe does not work if it does not have everyting. This
	// could be addressed by making a stream parser for llsd which
	// handled partial information.
	PUMP_DEBUG;
	if(!eos)
	{
		llinfos << "!eos" << llendl;
		return STATUS_BREAK;
	}

	// See if we can parse it
	LLBufferStream stream(channels, buffer.get());
	LLSD sd;
	LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in()));
	if(stream.fail())
	{
		llinfos << "STREAM FAILURE reading structure data." << llendl;
	}

	PUMP_DEBUG;
	// We can get the method and parameters from either the member
	// function or passed in via the buffer. We prefer the buffer if
	// we found a parameter and a method, or fall back to using
	// mMethod and putting everyting in the buffer into the parameter.
	std::string method;
	LLSD param_sd;
	if(sd.has("method") && sd.has("parameter"))
	{
		method = sd["method"].asString();
		param_sd = sd["parameter"];
	}
	else
	{
		method = mMethod;
		param_sd = sd;
	}
	if(method.empty())
	{
		llwarns << "SD -> XML Request no method found." << llendl;
		return STATUS_ERROR;
	}

	PUMP_DEBUG;
	// We have a method, and some kind of parameter, so package it up
	// and send it out.
	LLBufferStream ostream(channels, buffer.get());
	ostream.precision(DEFAULT_PRECISION);
	if(ostream.fail())
	{
		llinfos << "STREAM FAILURE setting precision" << llendl;
	}
	ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1
		<< xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2;
	if(ostream.fail())
	{
		llinfos << "STREAM FAILURE writing method headers" << llendl;
	}
	switch(param_sd.type())
	{
	case LLSD::TypeMap:
		// If the params are a map, then we do not want to iterate
		// through them since the iterators returned will be map
		// ordered un-named values, which will lose the names, and
		// only stream the values, turning it into an array.
		ostream << "<param>";
		streamOut(ostream, param_sd);
		ostream << "</param>";
		break;
	case LLSD::TypeArray:
	{

		LLSD::array_iterator it = param_sd.beginArray();
		LLSD::array_iterator end = param_sd.endArray();
		for(; it != end; ++it)
		{
			ostream << "<param>";
			streamOut(ostream, *it);
			ostream << "</param>";
		}
		break;
	}
	default:
		ostream << "<param>";
		streamOut(ostream, param_sd);
		ostream << "</param>";
		break;
	}

	stream << XMLRPC_REQUEST_FOOTER << std::flush;
	return STATUS_DONE;
}
// static
LLChannelDescriptors LLBufferArray::makeChannelConsumer(
	const LLChannelDescriptors& channels)
{
	LLChannelDescriptors rv(channels.out());
	return rv;
}
Example #24
0
	void buffer_object_t::test<5>()
	{
		LLChannelDescriptors inchannelDescriptors(20);
		LLChannelDescriptors outchannelDescriptors = LLBufferArray::makeChannelConsumer(inchannelDescriptors);	
		ensure("LLBufferArray::makeChannelConsumer() function Failed", (21 == outchannelDescriptors.in()));
	}
// virtual
LLIOPipe::EStatus LLSDRPCClient::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	PUMP_DEBUG;
	LLMemType m1(LLMemType::MTYPE_IO_SD_CLIENT);
	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;
//		lldebugs << "LLSDRPCClient::process_impl STATE_READY" << llendl;
		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.
		//lldebugs << "LLSDRPCClient::process_impl STATE_WAITING_FOR_RESPONSE"
		//		 << llendl;
		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;
		llinfos << "invalid state to process" << llendl;
		rv = STATUS_ERROR;
		break;
	}
	return rv;
}