示例#1
0
	/*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer)
	{
		llifstream fstream(mFilename, std::ios::binary);
		if (!fstream.is_open())
		  throw AICurlNoBody(llformat("Failed to open \"%s\".", mFilename.c_str()));
		LLBufferStream ostream(channels, buffer.get());
		char tmpbuf[4096];
#ifdef SHOW_ASSERT
		size_t total_len = 0;
		fstream.seekg(0, std::ios::end);
		size_t file_size = fstream.tellg();
		fstream.seekg(0, std::ios::beg);
#endif
		while (fstream)
		{
			fstream.read(tmpbuf, sizeof(tmpbuf));
			std::streamsize len = fstream.gcount();
			if (len > 0)
			{
				ostream.write(tmpbuf, len);
#ifdef SHOW_ASSERT
				total_len += len;
#endif
			}
		}
		if (fstream.bad())
		  throw AICurlNoBody(llformat("An error occured while reading \"%s\".", mFilename.c_str()));
		fstream.close();
		ostream << std::flush;
		llassert(total_len == file_size && total_len == ostream.count_out());
		return ostream.count_out();
	}
void EmeraldDicDownloader::completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, const buffer_ptr_t& buffer)
{
	if (status < 200 || status >= 300)
	{
		return;
	}
	LLBufferStream istr(channels, buffer.get());
	std::string dicpath(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "dictionaries", name.c_str()));

	llofstream ostr(dicpath, std::ios::binary);

	while (istr.good() && ostr.good())
	{
		ostr << istr.rdbuf();
	}
	ostr.close();
	if (panel)
	{
        if (panel->empanel)
        {
    		panel->empanel->refresh();
        }
        else
        {
            llinfos << "completedRaw(): No empanel to refresh()!" << llendl;
        }

		panel->close();
	}
}
示例#3
0
	/*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer)
	{
		LLBufferStream ostream(channels, buffer.get());
		ostream.write(mData, mSize);
		ostream << std::flush;			// Always flush a LLBufferStream when done writing to it.
		return mSize;
	}
示例#4
0
	/*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer)
	{
		LLBufferStream ostream(channels, buffer.get());
		LLSDSerialize::toXML(mSD, ostream);
		// Need to flush the LLBufferStream or count_out() returns more than the written data.
		ostream << std::flush;
		return ostream.count_out();
	}
示例#5
0
		/*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer)
		{
			std::string data;
			mTree->write(data);
			LLBufferStream ostream(channels, buffer.get());
			ostream.write(data.data(), data.size());
			ostream << std::flush;          // Always flush a LLBufferStream when done writing to it.
			return data.size();
		}
示例#6
0
		EStatus process_impl(const LLChannelDescriptors &channels,
							 buffer_ptr_t &buffer, bool &eos,
							 LLSD &context, LLPumpIO *pump)
		{
			LLBufferStream ostream(channels, buffer.get());
			ostream.write(mData.data(), mData.size());
			eos = true;
			return STATUS_DONE;
		}
// 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;
}
示例#8
0
	/*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer)
	{
		int requestTextSize;
		mRequestText = XMLRPC_REQUEST_ToXML(mRequest, &requestTextSize);
		if (!mRequestText)
			throw AICurlNoBody("XMLRPC_REQUEST_ToXML returned NULL.");
		LLBufferStream ostream(channels, buffer.get());
		ostream.write(mRequestText, requestTextSize);
		ostream << std::flush;          // Always flush a LLBufferStream when done writing to it.
		return requestTextSize;
	}
示例#9
0
void LLHTTPResponder::markBad(
	const LLChannelDescriptors& channels,
	buffer_ptr_t buffer)
{
	LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
	mState = STATE_SHORT_CIRCUIT;
	LLBufferStream out(channels, buffer.get());
	out << HTTP_VERSION_STR << " 400 Bad Request\r\n\r\n<html>\n"
		<< "<title>Bad Request</title>\n<body>\nBad Request.\n"
		<< "</body>\n</html>\n";
}
示例#10
0
	/*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer)
	{
		LLBufferStream ostream(channels, buffer.get());
		
		LLVFile vfile(gVFS, mUUID, mAssetType, LLVFile::READ);
		S32 fileSize = vfile.getSize();
		std::vector<U8> fileBuffer(fileSize);
		vfile.read(&fileBuffer[0], fileSize);
		ostream.write((char*)&fileBuffer[0], fileSize);
		ostream << std::flush;
		
		return fileSize;
	}
示例#11
0
			virtual EStatus process_impl(
				const LLChannelDescriptors& channels,
				buffer_ptr_t& buffer,
				bool& eos,
				LLSD& context,
				LLPumpIO* pump)
			{
				if(!eos) return STATUS_BREAK;
				LLSD sd = "yo!";
				LLBufferStream ostr(channels, buffer.get());
				ostr << LLSDXMLStreamer(sd);
				return STATUS_DONE;
			}
示例#12
0
	/*virtual*/ void completedRaw(
		U32 status,
		const std::string& reason,
		const LLChannelDescriptors& channels,
		const buffer_ptr_t& buffer)
	{
		LLBufferStream istr(channels, buffer.get());
		std::stringstream strstrm;
		strstrm << istr.rdbuf();
		const std::string body = strstrm.str();

		if (status != 200)
		{
			llwarns << "Failed to get upload config (" << status << ")" << llendl;
			LLWebProfile::reportImageUploadStatus(false);
			return;
		}

		Json::Value root;
		Json::Reader reader;
		if (!reader.parse(body, root))
		{
			llwarns << "Failed to parse upload config: " << reader.getFormatedErrorMessages() << llendl;
			LLWebProfile::reportImageUploadStatus(false);
			return;
		}

		// *TODO: 404 = not supported by the grid
		// *TODO: increase timeout or handle 499 Expired

		// Convert config to LLSD.
		const Json::Value data = root["data"];
		const std::string upload_url = root["url"].asString();
		LLSD config;
		config["acl"]						= data["acl"].asString();
		config["AWSAccessKeyId"]			= data["AWSAccessKeyId"].asString();
		config["Content-Type"]				= data["Content-Type"].asString();
		config["key"]						= data["key"].asString();
		config["policy"]					= data["policy"].asString();
		config["success_action_redirect"]	= data["success_action_redirect"].asString();
		config["signature"]					= data["signature"].asString();
		config["add_loc"]					= data.get("add_loc", "0").asString();
		config["caption"]					= data.get("caption", "").asString();

		// Do the actual image upload using the configuration.
		LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << "]" << LL_ENDL;
		LLWebProfile::post(mImagep, config, upload_url);
	}
	/*virtual*/ void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer)
	{
		if (mStatus != HTTP_OK)
		{
			LL_WARNS() << "Failed to upload image: " << mStatus << " " << mReason << LL_ENDL;
			LLWebProfile::reportImageUploadStatus(false);
			return;
		}

		LLBufferStream istr(channels, buffer.get());
		std::stringstream strstrm;
		strstrm << istr.rdbuf();
		const std::string body = strstrm.str();
		LL_INFOS() << "Image uploaded." << LL_ENDL;
		LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << LL_ENDL;
		LLWebProfile::reportImageUploadStatus(true);
	}
// virtual
LLIOPipe::EStatus LLIOSleeper::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	if(!mRespond)
	{
		LL_DEBUGS() << "LLIOSleeper::process_impl() sleeping." << LL_ENDL;
		mRespond = true;
		static const F64 SLEEP_TIME = 2.0;
		pump->sleepChain(SLEEP_TIME);
		return STATUS_BREAK;
	}
	LL_DEBUGS() << "LLIOSleeper::process_impl() responding." << LL_ENDL;
	LLBufferStream ostr(channels, buffer.get());
	ostr << "huh? sorry, I was sleeping." << std::endl;
	return STATUS_DONE;
}
示例#15
0
	/*virtual*/ void completedRaw(
		U32 status,
		const std::string& reason,
		const LLChannelDescriptors& channels,
		const buffer_ptr_t& buffer)
	{
		if (status != 200)
		{
			llwarns << "Failed to upload image: " << status << " " << reason << llendl;
			LLWebProfile::reportImageUploadStatus(false);
			return;
		}

		LLBufferStream istr(channels, buffer.get());
		std::stringstream strstrm;
		strstrm << istr.rdbuf();
		const std::string body = strstrm.str();
		llinfos << "Image uploaded." << llendl;
		LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << LL_ENDL;
		LLWebProfile::reportImageUploadStatus(true);
	}
LLIOPipe::EStatus LLPipeStringExtractor::process_impl(
	const LLChannelDescriptors& channels,
    buffer_ptr_t& buffer,
    bool& eos,
    LLSD& context,
    LLPumpIO* pump)
{
    if(!eos) return STATUS_BREAK;
    if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET;

	LLBufferStream istr(channels, buffer.get());
	std::ostringstream ostr;
	while (istr.good())
	{
		char buf[1024];		/* Flawfinder: ignore */
		istr.read(buf, sizeof(buf));	/* Flawfinder: ignore */
		ostr.write(buf, istr.gcount());
	}
	mString = ostr.str();
	mDone = true;
	
	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;
}
示例#19
0
LLIOPipe::EStatus LLHTTPPipe::process_impl(
	const LLChannelDescriptors& channels,
    buffer_ptr_t& buffer,
    bool& eos,
    LLSD& context,
    LLPumpIO* pump)
{
	PUMP_DEBUG;
    lldebugs << "LLSDHTTPServer::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;

	PUMP_DEBUG;
	if (mState == STATE_INVOKE)
	{
		PUMP_DEBUG;
		mState = STATE_DELAYED;
			// assume deferred unless mResponse does otherwise
		mResponse = Response::create(this);

		// *TODO: Babbage: Parameterize parser?
		// *TODO: We should look at content-type and do the right
		// thing. Phoenix 2007-12-31
		LLBufferStream istr(channels, buffer.get());

		static LLTimer timer;
		timer.reset();

		std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB];
		if(verb == HTTP_VERB_GET)
		{
            LLPerfBlock getblock("http_get");   
			mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
		}
		else if(verb == HTTP_VERB_PUT)
		{
            LLPerfBlock putblock("http_put");
			LLSD input;
			LLSDSerialize::fromXML(input, istr);
			mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input);
		}
		else if(verb == HTTP_VERB_POST)
		{
            LLPerfBlock postblock("http_post");
			LLSD input;
			LLSDSerialize::fromXML(input, istr);
			mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input);
		}
		else if(verb == HTTP_VERB_DELETE)
		{
            LLPerfBlock delblock("http_delete");
			mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);
		}		
		else if(verb == HTTP_VERB_OPTIONS)
		{
			mNode.options(LLHTTPNode::ResponsePtr(mResponse), context);
		}		
		else 
		{
		    mResponse->methodNotAllowed();
		}

		F32 delta = timer.getElapsedTimeF32();
		if (sTimingCallback)
		{
			LLHTTPNode::Description desc;
			mNode.describe(desc);
			LLSD info = desc.getInfo();
			std::string timing_name = info["description"];
			timing_name += " ";
			timing_name += verb;
			sTimingCallback(timing_name.c_str(), delta, sTimingCallbackData);
		}

		// Log all HTTP transactions.
		// TODO: Add a way to log these to their own file instead of indra.log
		// It is just too spammy to be in indra.log.
		lldebugs << verb << " " << context[CONTEXT_REQUEST]["path"].asString()
			<< " " << mStatusCode << " " <<  mStatusMessage << " " << delta
			<< "s" << llendl;

		// Log Internal Server Errors
		//if(mStatusCode == 500)
		//{
		//	llwarns << "LLHTTPPipe::process_impl:500:Internal Server Error" 
		//			<< llendl;
		//}
	}

	PUMP_DEBUG;
	switch (mState)
	{
		case STATE_DELAYED:
			lockChain(pump);
			mState = STATE_LOCKED;
			return STATUS_BREAK;

		case STATE_LOCKED:
			// should never ever happen!
			return STATUS_ERROR;

		case STATE_GOOD_RESULT:
		{
			LLSD headers = mHeaders;
			headers["Content-Type"] = "application/llsd+xml";
			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
			LLBufferStream ostr(channels, buffer.get());
			LLSDSerialize::toXML(mGoodResult, ostr);

			return STATUS_DONE;
		}

		case STATE_STATUS_RESULT:
		{
			LLSD headers = mHeaders;
			headers["Content-Type"] = "text/plain";
			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
			context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
			context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage;
			LLBufferStream ostr(channels, buffer.get());
			ostr << mStatusMessage << std::ends;

			return STATUS_DONE;
		}
		default:
			llwarns << "LLHTTPPipe::process_impl: unexpected state "
				<< mState << llendl;

			return STATUS_BREAK;
	}
// 	PUMP_DEBUG; // unreachable
}
示例#20
0
// 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;
	}
}
// 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;
}
示例#22
0
LLIOPipe::EStatus LLHTTPPipe::process_impl(
	const LLChannelDescriptors& channels,
    buffer_ptr_t& buffer,
    bool& eos,
    LLSD& context,
    LLPumpIO* pump)
{
	PUMP_DEBUG;
    lldebugs << "LLSDHTTPServer::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;

	PUMP_DEBUG;
	if (mState == STATE_INVOKE)
	{
		PUMP_DEBUG;
		mState = STATE_DELAYED;
			// assume deferred unless mResponse does otherwise
		mResponse = Response::create(this);

		// TODO: Babbage: Parameterize parser?
		LLBufferStream istr(channels, buffer.get());

		static LLTimer timer;
		if (sTimingCallback)
		{
			timer.reset();
		}

		std::string verb = context[CONTEXT_REQUEST]["verb"];
		if(verb == HTTP_VERB_GET)
		{
			mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
		}
		else if(verb == HTTP_VERB_PUT)
		{
			LLSD input;
			LLSDSerialize::fromXML(input, istr);

			mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input);
		}
		else if(verb == HTTP_VERB_POST)
		{
			LLSD input;
			LLSDSerialize::fromXML(input, istr);

			mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input);
		}
		else if(verb == HTTP_VERB_DELETE)
		{
			mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);
		}		
		else 
		{
		    mResponse->methodNotAllowed();
		}

		if (sTimingCallback)
		{
			LLHTTPNode::Description desc;
			mNode.describe(desc);
			LLSD info = desc.getInfo();
			std::string timing_name = info["description"];
			timing_name += " ";
			timing_name += verb;
			F32 delta = timer.getElapsedTimeF32();
			sTimingCallback(timing_name.c_str(), delta, sTimingCallbackData);
		}

		// Log Internal Server Errors
		if(mStatusCode == 500)
		{
			llwarns << "LLHTTPPipe::process_impl:500:Internal Server Error" 
					<< llendl;
		}
	}

	PUMP_DEBUG;
	switch (mState)
	{
		case STATE_DELAYED:
			lockChain(pump);
			mState = STATE_LOCKED;
			return STATUS_BREAK;

		case STATE_LOCKED:
			// should never ever happen!
			return STATUS_ERROR;

		case STATE_GOOD_RESULT:
		{
			context["response"]["contentType"] = "application/xml";
			LLBufferStream ostr(channels, buffer.get());
			LLSDSerialize::toXML(mGoodResult, ostr);

			return STATUS_DONE;
		}

		case STATE_STATUS_RESULT:
		{
			context["response"]["contentType"] = "text/plain";
			context["response"]["statusCode"] = mStatusCode;
			context["response"]["statusMessage"] = mStatusMessage;
			LLBufferStream ostr(channels, buffer.get());
			ostr << mStatusMessage << std::ends;

			return STATUS_DONE;
		}
		default:
			llwarns << "LLHTTPPipe::process_impl: unexpected state "
				<< mState << llendl;

			return STATUS_BREAK;
	}
// 	PUMP_DEBUG; // unreachable
}
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;
}
示例#24
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;
}
示例#25
0
// 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;
	}
}