PageRenderTime 70ms CodeModel.GetById 14ms app.highlight 48ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llmessage/lliohttpserver.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 998 lines | 739 code | 112 blank | 147 comment | 105 complexity | 4175039ee1b4a682e7d4d21c37fa7720 MD5 | raw file
  1/** 
  2 * @file lliohttpserver.cpp
  3 * @author Phoenix
  4 * @date 2005-10-05
  5 * @brief Implementation of the http server classes
  6 *
  7 * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29#include "linden_common.h"
 30
 31#include "lliohttpserver.h"
 32
 33#include "llapr.h"
 34#include "llbuffer.h"
 35#include "llbufferstream.h"
 36#include "llhttpnode.h"
 37#include "lliopipe.h"
 38#include "lliosocket.h"
 39#include "llioutil.h"
 40#include "llmemtype.h"
 41#include "llmemorystream.h"
 42#include "llpumpio.h"
 43#include "llsd.h"
 44#include "llsdserialize_xml.h"
 45#include "llstat.h"
 46#include "llstl.h"
 47#include "lltimer.h"
 48
 49#include <sstream>
 50
 51#include <boost/tokenizer.hpp>
 52
 53static const char HTTP_VERSION_STR[] = "HTTP/1.0";
 54const std::string CONTEXT_REQUEST("request");
 55const std::string CONTEXT_RESPONSE("response");
 56const std::string CONTEXT_VERB("verb");
 57const std::string CONTEXT_HEADERS("headers");
 58const std::string HTTP_VERB_GET("GET");
 59const std::string HTTP_VERB_PUT("PUT");
 60const std::string HTTP_VERB_POST("POST");
 61const std::string HTTP_VERB_DELETE("DELETE");
 62const std::string HTTP_VERB_OPTIONS("OPTIONS");
 63
 64static LLIOHTTPServer::timing_callback_t sTimingCallback = NULL;
 65static void* sTimingCallbackData = NULL;
 66
 67class LLHTTPPipe : public LLIOPipe
 68{
 69public:
 70	LLHTTPPipe(const LLHTTPNode& node)
 71		: mNode(node),
 72		  mResponse(NULL),
 73		  mState(STATE_INVOKE),
 74		  mChainLock(0),
 75		  mLockedPump(NULL),
 76		  mStatusCode(0)
 77		{ }
 78	virtual ~LLHTTPPipe()
 79	{
 80		if (mResponse.notNull())
 81		{
 82			mResponse->nullPipe();
 83		}
 84	}
 85
 86private:
 87	// LLIOPipe API implementation.
 88	virtual EStatus process_impl(
 89        const LLChannelDescriptors& channels,
 90        LLIOPipe::buffer_ptr_t& buffer,
 91        bool& eos,
 92        LLSD& context,
 93        LLPumpIO* pump);
 94
 95	const LLHTTPNode& mNode;
 96
 97	class Response : public LLHTTPNode::Response
 98	{
 99	public:
100
101		static LLPointer<Response> create(LLHTTPPipe* pipe);
102		virtual ~Response();
103
104		// from LLHTTPNode::Response
105		virtual void result(const LLSD&);
106		virtual void extendedResult(S32 code, const std::string& body, const LLSD& headers);
107		
108		virtual void status(S32 code, const std::string& message);
109
110		void nullPipe();
111
112	private:
113		Response() : mPipe(NULL) {} // Must be accessed through LLPointer.
114		LLHTTPPipe* mPipe;
115	};
116	friend class Response;
117
118	LLPointer<Response> mResponse;
119
120	enum State
121	{
122		STATE_INVOKE,
123		STATE_DELAYED,
124		STATE_LOCKED,
125		STATE_GOOD_RESULT,
126		STATE_STATUS_RESULT,
127		STATE_EXTENDED_RESULT
128	};
129	State mState;
130
131	S32 mChainLock;
132	LLPumpIO* mLockedPump;
133
134	void lockChain(LLPumpIO*);
135	void unlockChain();
136
137	LLSD mGoodResult;
138	S32 mStatusCode;
139	std::string mStatusMessage;	
140	LLSD mHeaders;
141};
142
143static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_PIPE("HTTP Pipe");
144LLIOPipe::EStatus LLHTTPPipe::process_impl(
145	const LLChannelDescriptors& channels,
146    buffer_ptr_t& buffer,
147    bool& eos,
148    LLSD& context,
149    LLPumpIO* pump)
150{
151	LLFastTimer t(FTM_PROCESS_HTTP_PIPE);
152	PUMP_DEBUG;
153    lldebugs << "LLSDHTTPServer::process_impl" << llendl;
154
155    // Once we have all the data, We need to read the sd on
156    // the the in channel, and respond on  the out channel
157
158    if(!eos) return STATUS_BREAK;
159    if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET;
160
161	PUMP_DEBUG;
162	if (mState == STATE_INVOKE)
163	{
164		PUMP_DEBUG;
165		mState = STATE_DELAYED;
166			// assume deferred unless mResponse does otherwise
167		mResponse = Response::create(this);
168
169		// *TODO: Babbage: Parameterize parser?
170		// *TODO: We should look at content-type and do the right
171		// thing. Phoenix 2007-12-31
172		LLBufferStream istr(channels, buffer.get());
173
174		static LLTimer timer;
175		timer.reset();
176
177		std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB];
178		if(verb == HTTP_VERB_GET)
179		{
180            LLPerfBlock getblock("http_get");   
181			mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
182		}
183		else if(verb == HTTP_VERB_PUT)
184		{
185            LLPerfBlock putblock("http_put");
186			LLSD input;
187			if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD)
188			{
189				LLSDSerialize::fromXML(input, istr);
190			}
191			else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT)
192			{
193				std::stringstream strstrm;
194				strstrm << istr.rdbuf();
195				input = strstrm.str();
196			}
197			mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input);
198		}
199		else if(verb == HTTP_VERB_POST)
200		{
201            LLPerfBlock postblock("http_post");
202			LLSD input;
203			if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD)
204			{
205				LLSDSerialize::fromXML(input, istr);
206			}
207			else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT)
208			{
209				std::stringstream strstrm;
210				strstrm << istr.rdbuf();
211				input = strstrm.str();
212			}
213			mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input);
214		}
215		else if(verb == HTTP_VERB_DELETE)
216		{
217            LLPerfBlock delblock("http_delete");
218			mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);
219		}		
220		else if(verb == HTTP_VERB_OPTIONS)
221		{
222			mNode.options(LLHTTPNode::ResponsePtr(mResponse), context);
223		}		
224		else 
225		{
226		    mResponse->methodNotAllowed();
227		}
228
229		F32 delta = timer.getElapsedTimeF32();
230		if (sTimingCallback)
231		{
232			LLHTTPNode::Description desc;
233			mNode.describe(desc);
234			LLSD info = desc.getInfo();
235			std::string timing_name = info["description"];
236			timing_name += " ";
237			timing_name += verb;
238			sTimingCallback(timing_name.c_str(), delta, sTimingCallbackData);
239		}
240
241		// Log all HTTP transactions.
242		// TODO: Add a way to log these to their own file instead of indra.log
243		// It is just too spammy to be in indra.log.
244		lldebugs << verb << " " << context[CONTEXT_REQUEST]["path"].asString()
245			<< " " << mStatusCode << " " <<  mStatusMessage << " " << delta
246			<< "s" << llendl;
247
248		// Log Internal Server Errors
249		//if(mStatusCode == 500)
250		//{
251		//	llwarns << "LLHTTPPipe::process_impl:500:Internal Server Error" 
252		//			<< llendl;
253		//}
254	}
255
256	PUMP_DEBUG;
257	switch (mState)
258	{
259		case STATE_DELAYED:
260			lockChain(pump);
261			mState = STATE_LOCKED;
262			return STATUS_BREAK;
263
264		case STATE_LOCKED:
265			// should never ever happen!
266			return STATUS_ERROR;
267
268		case STATE_GOOD_RESULT:
269		{
270			LLSD headers = mHeaders;
271			headers["Content-Type"] = "application/llsd+xml";
272			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
273			LLBufferStream ostr(channels, buffer.get());
274			LLSDSerialize::toXML(mGoodResult, ostr);
275
276			return STATUS_DONE;
277		}
278
279		case STATE_STATUS_RESULT:
280		{
281			LLSD headers = mHeaders;
282			headers["Content-Type"] = "text/plain";
283			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
284			context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
285			context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage;
286			LLBufferStream ostr(channels, buffer.get());
287			ostr << mStatusMessage;
288
289			return STATUS_DONE;
290		}
291		case STATE_EXTENDED_RESULT:
292		{
293			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = mHeaders;
294			context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
295			LLBufferStream ostr(channels, buffer.get());
296			ostr << mStatusMessage;
297
298			return STATUS_DONE;
299		}
300		default:
301			llwarns << "LLHTTPPipe::process_impl: unexpected state "
302				<< mState << llendl;
303
304			return STATUS_BREAK;
305	}
306// 	PUMP_DEBUG; // unreachable
307}
308
309LLPointer<LLHTTPPipe::Response> LLHTTPPipe::Response::create(LLHTTPPipe* pipe)
310{
311	LLPointer<Response> result = new Response();
312	result->mPipe = pipe;
313	return result;
314}
315
316// virtual
317LLHTTPPipe::Response::~Response()
318{
319}
320
321void LLHTTPPipe::Response::nullPipe()
322{
323	mPipe = NULL;
324}
325
326// virtual
327void LLHTTPPipe::Response::result(const LLSD& r)
328{
329	if(! mPipe)
330	{
331		llwarns << "LLHTTPPipe::Response::result: NULL pipe" << llendl;
332		return;
333	}
334
335	mPipe->mStatusCode = 200;
336	mPipe->mStatusMessage = "OK";
337	mPipe->mGoodResult = r;
338	mPipe->mState = STATE_GOOD_RESULT;
339	mPipe->mHeaders = mHeaders;
340	mPipe->unlockChain();	
341}
342
343void LLHTTPPipe::Response::extendedResult(S32 code, const std::string& body, const LLSD& headers)
344{
345	if(! mPipe)
346	{
347		llwarns << "LLHTTPPipe::Response::status: NULL pipe" << llendl;
348		return;
349	}
350
351	mPipe->mStatusCode = code;
352	mPipe->mStatusMessage = body;
353	mPipe->mHeaders = headers;
354	mPipe->mState = STATE_EXTENDED_RESULT;
355	mPipe->unlockChain();
356}
357
358// virtual
359void LLHTTPPipe::Response::status(S32 code, const std::string& message)
360{
361	if(! mPipe)
362	{
363		llwarns << "LLHTTPPipe::Response::status: NULL pipe" << llendl;
364		return;
365	}
366
367	mPipe->mStatusCode = code;
368	mPipe->mStatusMessage = message;
369	mPipe->mState = STATE_STATUS_RESULT;
370	mPipe->mHeaders = mHeaders;
371	mPipe->unlockChain();
372}
373
374void LLHTTPPipe::lockChain(LLPumpIO* pump)
375{
376	if (mChainLock != 0) { return; }
377
378	mLockedPump = pump;
379	mChainLock = pump->setLock();
380}
381
382void LLHTTPPipe::unlockChain()
383{
384	if (mChainLock == 0) { return; }
385
386	mLockedPump->clearLock(mChainLock);
387	mLockedPump = NULL;
388	mChainLock = 0;
389}
390
391
392
393/** 
394 * @class LLHTTPResponseHeader
395 * @brief Class which correctly builds HTTP headers on a pipe
396 * @see LLIOPipe
397 *
398 * An instance of this class can be placed in a chain where it will
399 * wait for an end of stream. Once it gets that, it will count the
400 * bytes on CHANNEL_OUT (or the size of the buffer in io pipe versions
401 * prior to 2) prepend that data to the request in an HTTP format, and
402 * supply all normal HTTP response headers.
403 */
404class LLHTTPResponseHeader : public LLIOPipe
405{
406public:
407	LLHTTPResponseHeader() : mCode(0) {}
408	virtual ~LLHTTPResponseHeader() {}
409
410protected:
411	/* @name LLIOPipe virtual implementations
412	 */
413	//@{
414	/** 
415	 * @brief Process the data in buffer
416	 */
417	EStatus process_impl(
418		const LLChannelDescriptors& channels,
419		buffer_ptr_t& buffer,
420		bool& eos,
421		LLSD& context,
422		LLPumpIO* pump);
423	//@}
424
425protected:
426	S32 mCode;
427};
428
429
430/**
431 * LLHTTPResponseHeader
432 */
433
434static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_HEADER("HTTP Header");
435
436// virtual
437LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
438	const LLChannelDescriptors& channels,
439	buffer_ptr_t& buffer,
440	bool& eos,
441	LLSD& context,
442	LLPumpIO* pump)
443{
444	LLFastTimer t(FTM_PROCESS_HTTP_HEADER);
445	PUMP_DEBUG;
446	LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
447	if(eos)
448	{
449		PUMP_DEBUG;
450		//mGotEOS = true;
451		std::ostringstream ostr;
452		std::string message = context[CONTEXT_RESPONSE]["statusMessage"];
453		
454		int code = context[CONTEXT_RESPONSE]["statusCode"];
455		if (code < 200)
456		{
457			code = 200;
458			message = "OK";
459		}
460		
461		ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n";
462
463		S32 content_length = buffer->countAfter(channels.in(), NULL);
464		if(0 < content_length)
465		{
466			ostr << "Content-Length: " << content_length << "\r\n";
467		}
468		// *NOTE: This guard can go away once the LLSD static map
469		// iterator is available. Phoenix. 2008-05-09
470		LLSD headers = context[CONTEXT_RESPONSE][CONTEXT_HEADERS];
471		if(headers.isDefined())
472		{
473			LLSD::map_iterator iter = headers.beginMap();
474			LLSD::map_iterator end = headers.endMap();
475			for(; iter != end; ++iter)
476			{
477				ostr << (*iter).first << ": " << (*iter).second.asString()
478					<< "\r\n";
479			}
480		}
481		ostr << "\r\n";
482
483		LLChangeChannel change(channels.in(), channels.out());
484		std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
485		std::string header = ostr.str();
486		buffer->prepend(channels.out(), (U8*)header.c_str(), header.size());
487		PUMP_DEBUG;
488		return STATUS_DONE;
489	}
490	PUMP_DEBUG;
491	return STATUS_OK;
492}
493
494
495
496/** 
497 * @class LLHTTPResponder
498 * @brief This class 
499 * @see LLIOPipe
500 *
501 * <b>NOTE:</b> You should not need to create or use one of these, the
502 * details are handled by the HTTPResponseFactory.
503 */
504class LLHTTPResponder : public LLIOPipe
505{
506public:
507	LLHTTPResponder(const LLHTTPNode& tree, const LLSD& ctx);
508	~LLHTTPResponder();
509
510protected:
511	/** 
512	 * @brief Read data off of CHANNEL_IN keeping track of last read position.
513	 *
514	 * This is a quick little hack to read headers. It is not IO
515	 * optimal, but it makes it easier for me to implement the header
516	 * parsing. Plus, there should never be more than a few headers.
517	 * This method will tend to read more than necessary, find the
518	 * newline, make the front part of dest look like a c string, and
519	 * move the read head back to where the newline was found. Thus,
520	 * the next read will pick up on the next line.
521	 * @param channel The channel to read in the buffer
522	 * @param buffer The heap array of processed data
523	 * @param dest Destination for the data to be read
524	 * @param[in,out] len <b>in</b> The size of the buffer. <b>out</b> how 
525	 * much was read. This value is not useful for determining where to 
526	 * seek orfor string assignment.
527	 * @returns Returns true if a line was found.
528	 */
529	bool readHeaderLine(
530		const LLChannelDescriptors& channels,
531		buffer_ptr_t buffer,
532		U8* dest,
533		S32& len);
534	
535	/** 
536	 * @brief Mark the request as bad, and handle appropriately
537	 *
538	 * @param channels The channels to use in the buffer.
539	 * @param buffer The heap array of processed data.
540	 */
541	void markBad(const LLChannelDescriptors& channels, buffer_ptr_t buffer);
542
543protected:
544	/* @name LLIOPipe virtual implementations
545	 */
546	//@{
547	/** 
548	 * @brief Process the data in buffer
549	 */
550	EStatus process_impl(
551		const LLChannelDescriptors& channels,
552		buffer_ptr_t& buffer,
553		bool& eos,
554		LLSD& context,
555		LLPumpIO* pump);
556	//@}
557
558protected:
559	enum EState
560	{
561		STATE_NOTHING,
562		STATE_READING_HEADERS,
563		STATE_LOOKING_FOR_EOS,
564		STATE_DONE,
565		STATE_SHORT_CIRCUIT
566	};
567
568	LLSD mBuildContext;
569	EState mState;
570	U8* mLastRead;
571	std::string mVerb;
572	std::string mAbsPathAndQuery;
573	std::string mPath;
574	std::string mQuery;
575	std::string mVersion;
576	S32 mContentLength;
577	LLSD mHeaders;
578
579	// handle the urls
580	const LLHTTPNode& mRootNode;
581};
582
583LLHTTPResponder::LLHTTPResponder(const LLHTTPNode& tree, const LLSD& ctx) :
584	mBuildContext(ctx),
585	mState(STATE_NOTHING),
586	mLastRead(NULL),
587	mContentLength(0),
588	mRootNode(tree)
589{
590	LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
591}
592
593// virtual
594LLHTTPResponder::~LLHTTPResponder()
595{
596	LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
597	//lldebugs << "destroying LLHTTPResponder" << llendl;
598}
599
600bool LLHTTPResponder::readHeaderLine(
601	const LLChannelDescriptors& channels,
602	buffer_ptr_t buffer,
603	U8* dest,
604	S32& len)
605{
606	LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
607	--len;
608	U8* last = buffer->readAfter(channels.in(), mLastRead, dest, len);
609	dest[len] = '\0';
610	U8* newline = (U8*)strchr((char*)dest, '\n');
611	if(!newline)
612	{
613		if(len)
614		{
615			lldebugs << "readLine failed - too long maybe?" << llendl;
616			markBad(channels, buffer);
617		}
618		return false;
619	}
620	S32 offset = -((len - 1) - (newline - dest));
621	++newline;
622	*newline = '\0';
623	mLastRead = buffer->seek(channels.in(), last, offset);
624	return true;
625}
626
627void LLHTTPResponder::markBad(
628	const LLChannelDescriptors& channels,
629	buffer_ptr_t buffer)
630{
631	LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
632	mState = STATE_SHORT_CIRCUIT;
633	LLBufferStream out(channels, buffer.get());
634	out << HTTP_VERSION_STR << " 400 Bad Request\r\n\r\n<html>\n"
635		<< "<title>Bad Request</title>\n<body>\nBad Request.\n"
636		<< "</body>\n</html>\n";
637}
638
639static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_RESPONDER("HTTP Responder");
640
641// virtual
642LLIOPipe::EStatus LLHTTPResponder::process_impl(
643	const LLChannelDescriptors& channels,
644	buffer_ptr_t& buffer,
645	bool& eos,
646	LLSD& context,
647	LLPumpIO* pump)
648{
649	LLFastTimer t(FTM_PROCESS_HTTP_RESPONDER);
650	PUMP_DEBUG;
651	LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
652	LLIOPipe::EStatus status = STATUS_OK;
653
654	// parsing headers
655	if((STATE_NOTHING == mState) || (STATE_READING_HEADERS == mState))
656	{
657		PUMP_DEBUG;
658		status = STATUS_BREAK;
659		mState = STATE_READING_HEADERS;
660		const S32 HEADER_BUFFER_SIZE = 1024;
661		char buf[HEADER_BUFFER_SIZE + 1];  /*Flawfinder: ignore*/
662		S32 len = HEADER_BUFFER_SIZE;
663
664#if 0
665		if(true)
666		{
667		LLBufferArray::segment_iterator_t seg_iter = buffer->beginSegment();
668		char buf[1024];	  /*Flawfinder: ignore*/
669		while(seg_iter != buffer->endSegment())
670		{
671			memcpy(buf, (*seg_iter).data(), (*seg_iter).size());	  /*Flawfinder: ignore*/
672			buf[(*seg_iter).size()] = '\0';
673			llinfos << (*seg_iter).getChannel() << ": " << buf
674					<< llendl;
675			++seg_iter;
676		}
677		}
678#endif
679		
680		PUMP_DEBUG;
681		if(readHeaderLine(channels, buffer, (U8*)buf, len))
682		{
683			bool read_next_line = false;
684			bool parse_all = true;
685			if(mVerb.empty())
686			{
687				read_next_line = true;
688				LLMemoryStream header((U8*)buf, len);
689				header >> mVerb;
690
691				if((HTTP_VERB_GET == mVerb)
692				   || (HTTP_VERB_POST == mVerb)
693				   || (HTTP_VERB_PUT == mVerb)
694				   || (HTTP_VERB_DELETE == mVerb)
695				   || (HTTP_VERB_OPTIONS == mVerb))
696				{
697					header >> mAbsPathAndQuery;
698					header >> mVersion;
699
700					lldebugs << "http request: "
701							 << mVerb
702							 << " " << mAbsPathAndQuery
703							 << " " << mVersion << llendl;
704
705					std::string::size_type delimiter
706						= mAbsPathAndQuery.find('?');
707					if (delimiter == std::string::npos)
708					{
709						mPath = mAbsPathAndQuery;
710						mQuery = "";
711					}
712					else
713					{
714						mPath = mAbsPathAndQuery.substr(0, delimiter);
715						mQuery = mAbsPathAndQuery.substr(delimiter+1);
716					}
717
718					if(!mAbsPathAndQuery.empty())
719					{
720						if(mVersion.empty())
721						{
722							// simple request.
723							parse_all = false;
724							mState = STATE_DONE;
725							mVersion.assign("HTTP/1.0");
726						}
727					}
728				}
729				else
730				{
731					read_next_line = false;
732					parse_all = false;
733					lldebugs << "unknown http verb: " << mVerb << llendl;
734					markBad(channels, buffer);
735				}
736			}
737			if(parse_all)
738			{
739				bool keep_parsing = true;
740				while(keep_parsing)
741				{
742					if(read_next_line)
743					{
744						len = HEADER_BUFFER_SIZE;	
745						if (!readHeaderLine(channels, buffer, (U8*)buf, len))
746						{
747							// Failed to read the header line, probably too long.
748							// readHeaderLine already marked the channel/buffer as bad.
749							keep_parsing = false;
750							break;
751						}
752					}
753					if(0 == len)
754					{
755						return status;
756					}
757					if(buf[0] == '\r' && buf[1] == '\n')
758					{
759						// end-o-headers
760						keep_parsing = false;
761						mState = STATE_LOOKING_FOR_EOS;
762						break;
763					}
764					char* pos_colon = strchr(buf, ':');
765					if(NULL == pos_colon)
766					{
767						keep_parsing = false;
768						lldebugs << "bad header: " << buf << llendl;
769						markBad(channels, buffer);
770						break;
771					}
772					// we've found a header
773					read_next_line = true;
774					std::string name(buf, pos_colon - buf);
775					std::string value(pos_colon + 2);
776					LLStringUtil::toLower(name);
777					if("content-length" == name)
778					{
779						lldebugs << "Content-Length: " << value << llendl;
780						mContentLength = atoi(value.c_str());
781					}
782					else
783					{
784						LLStringUtil::trimTail(value);
785						mHeaders[name] = value;
786					}
787				}
788			}
789		}
790	}
791
792	PUMP_DEBUG;
793	// look for the end of stream based on 
794	if(STATE_LOOKING_FOR_EOS == mState)
795	{
796		if(0 == mContentLength)
797		{
798			mState = STATE_DONE;
799		}
800		else if(buffer->countAfter(channels.in(), mLastRead) >= mContentLength)
801		{
802			mState = STATE_DONE;
803		}
804		// else more bytes should be coming.
805	}
806
807	PUMP_DEBUG;
808	if(STATE_DONE == mState)
809	{
810		// hey, hey, we should have everything now, so we pass it to
811		// a content handler.
812		context[CONTEXT_REQUEST][CONTEXT_VERB] = mVerb;
813		const LLHTTPNode* node = mRootNode.traverse(mPath, context);
814		if(node)
815		{
816 			//llinfos << "LLHTTPResponder::process_impl found node for "
817			//	<< mAbsPathAndQuery << llendl;
818
819  			// Copy everything after mLast read to the out.
820			LLBufferArray::segment_iterator_t seg_iter;
821
822			buffer->lock();
823			seg_iter = buffer->splitAfter(mLastRead);
824			if(seg_iter != buffer->endSegment())
825			{
826				LLChangeChannel change(channels.in(), channels.out());
827				++seg_iter;
828				std::for_each(seg_iter, buffer->endSegment(), change);
829
830#if 0
831				seg_iter = buffer->beginSegment();
832				char buf[1024];	  /*Flawfinder: ignore*/
833				while(seg_iter != buffer->endSegment())
834				{
835					memcpy(buf, (*seg_iter).data(), (*seg_iter).size());	  /*Flawfinder: ignore*/
836					buf[(*seg_iter).size()] = '\0';
837					llinfos << (*seg_iter).getChannel() << ": " << buf
838							<< llendl;
839					++seg_iter;
840				}
841#endif
842			}
843			buffer->unlock();
844			//
845			// *FIX: get rid of extra bytes off the end
846			//
847
848			// Set up a chain which will prepend a content length and
849			// HTTP headers.
850			LLPumpIO::chain_t chain;
851			chain.push_back(LLIOPipe::ptr_t(new LLIOFlush));
852			context[CONTEXT_REQUEST]["path"] = mPath;
853			context[CONTEXT_REQUEST]["query-string"] = mQuery;
854			context[CONTEXT_REQUEST]["remote-host"]
855				= mBuildContext["remote-host"];
856			context[CONTEXT_REQUEST]["remote-port"]
857				= mBuildContext["remote-port"];
858			context[CONTEXT_REQUEST][CONTEXT_HEADERS] = mHeaders;
859
860			const LLChainIOFactory* protocolHandler
861				= node->getProtocolHandler();
862			if (protocolHandler)
863			{
864				lldebugs << "HTTP context: " << context << llendl;
865				protocolHandler->build(chain, context);
866			}
867			else
868			{
869				// this is a simple LLHTTPNode, so use LLHTTPPipe
870				chain.push_back(LLIOPipe::ptr_t(new LLHTTPPipe(*node)));
871			}
872
873			// Add the header - which needs to have the same
874			// channel information as the link before it since it
875			// is part of the response.
876			LLIOPipe* header = new LLHTTPResponseHeader;
877			chain.push_back(LLIOPipe::ptr_t(header));
878
879			// We need to copy all of the pipes _after_ this so
880			// that the response goes out correctly.
881			LLPumpIO::links_t current_links;
882			pump->copyCurrentLinkInfo(current_links);
883			LLPumpIO::links_t::iterator link_iter = current_links.begin();
884			LLPumpIO::links_t::iterator links_end = current_links.end();
885			bool after_this = false;
886			for(; link_iter < links_end; ++link_iter)
887			{
888				if(after_this)
889				{
890					chain.push_back((*link_iter).mPipe);
891				}
892				else if(this == (*link_iter).mPipe.get())
893				{
894					after_this = true;
895				}
896			}
897			
898			// Do the final build of the chain, and send it on
899			// it's way.
900			LLChannelDescriptors chnl = channels;
901			LLPumpIO::LLLinkInfo link;
902			LLPumpIO::links_t links;
903			LLPumpIO::chain_t::iterator it = chain.begin();
904			LLPumpIO::chain_t::iterator end = chain.end();
905			while(it != end)
906			{
907				link.mPipe = *it;
908				link.mChannels = chnl;
909				links.push_back(link);
910				chnl = LLBufferArray::makeChannelConsumer(chnl);
911				++it;
912			}
913			pump->addChain(
914				links,
915				buffer,
916				context,
917				DEFAULT_CHAIN_EXPIRY_SECS);
918
919			status = STATUS_STOP;
920		}
921		else
922		{
923			llwarns << "LLHTTPResponder::process_impl didn't find a node for "
924				<< mAbsPathAndQuery << llendl;
925			LLBufferStream str(channels, buffer.get());
926			mState = STATE_SHORT_CIRCUIT;
927			str << HTTP_VERSION_STR << " 404 Not Found\r\n\r\n<html>\n"
928				<< "<title>Not Found</title>\n<body>\nNode '" << mAbsPathAndQuery
929				<< "' not found.\n</body>\n</html>\n";
930		}
931	}
932
933	if(STATE_SHORT_CIRCUIT == mState)
934	{
935		//status = mNext->process(buffer, true, pump, context);
936		status = STATUS_DONE;
937	}
938	PUMP_DEBUG;
939	return status;
940}
941
942
943// static 
944void LLIOHTTPServer::createPipe(LLPumpIO::chain_t& chain, 
945        const LLHTTPNode& root, const LLSD& ctx)
946{
947	chain.push_back(LLIOPipe::ptr_t(new LLHTTPResponder(root, ctx)));
948}
949
950
951class LLHTTPResponseFactory : public LLChainIOFactory
952{
953public:
954	bool build(LLPumpIO::chain_t& chain, LLSD ctx) const
955	{
956		LLIOHTTPServer::createPipe(chain, mTree, ctx);
957		return true;
958	}
959
960	LLHTTPNode& getRootNode() { return mTree; }
961
962private:
963	LLHTTPNode mTree;
964};
965
966
967// static
968LLHTTPNode& LLIOHTTPServer::create(
969	apr_pool_t* pool, LLPumpIO& pump, U16 port)
970{
971	LLSocket::ptr_t socket = LLSocket::create(
972        pool,
973        LLSocket::STREAM_TCP,
974        port);
975    if(!socket)
976    {
977        llerrs << "Unable to initialize socket" << llendl;
978    }
979
980    LLHTTPResponseFactory* factory = new LLHTTPResponseFactory;
981	boost::shared_ptr<LLChainIOFactory> factory_ptr(factory);
982
983    LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr);
984
985	LLPumpIO::chain_t chain;
986    chain.push_back(LLIOPipe::ptr_t(server));
987    pump.addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
988
989	return factory->getRootNode();
990}
991
992// static
993void LLIOHTTPServer::setTimingCallback(timing_callback_t callback,
994									   void* data)
995{
996	sTimingCallback = callback;
997	sTimingCallbackData = data;
998}