aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llmessage/lliohttpserver.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmessage/lliohttpserver.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llmessage/lliohttpserver.cpp')
-rw-r--r--linden/indra/llmessage/lliohttpserver.cpp852
1 files changed, 852 insertions, 0 deletions
diff --git a/linden/indra/llmessage/lliohttpserver.cpp b/linden/indra/llmessage/lliohttpserver.cpp
new file mode 100644
index 0000000..25c1aef
--- /dev/null
+++ b/linden/indra/llmessage/lliohttpserver.cpp
@@ -0,0 +1,852 @@
1/**
2 * @file lliohttpserver.cpp
3 * @author Phoenix
4 * @date 2005-10-05
5 * @brief Implementation of the http server classes
6 *
7 * Copyright (c) 2005-2007, Linden Research, Inc.
8 *
9 * The source code in this file ("Source Code") is provided by Linden Lab
10 * to you under the terms of the GNU General Public License, version 2.0
11 * ("GPL"), unless you have obtained a separate licensing agreement
12 * ("Other License"), formally executed by you and Linden Lab. Terms of
13 * the GPL can be found in doc/GPL-license.txt in this distribution, or
14 * online at http://secondlife.com/developers/opensource/gplv2
15 *
16 * There are special exceptions to the terms and conditions of the GPL as
17 * it is applied to this Source Code. View the full text of the exception
18 * in the file doc/FLOSS-exception.txt in this software distribution, or
19 * online at http://secondlife.com/developers/opensource/flossexception
20 *
21 * By copying, modifying or distributing this software, you acknowledge
22 * that you have read and understood your obligations described above,
23 * and agree to abide by those obligations.
24 *
25 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
26 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
27 * COMPLETENESS OR PERFORMANCE.
28 */
29
30#include "linden_common.h"
31#include "lliohttpserver.h"
32
33#include "boost/tokenizer.hpp"
34
35#include "llapr.h"
36#include "llbuffer.h"
37#include "llbufferstream.h"
38#include "llhttpnode.h"
39#include "lliopipe.h"
40#include "lliosocket.h"
41#include "llioutil.h"
42#include "llmemtype.h"
43#include "llmemorystream.h"
44#include "llpumpio.h"
45#include "llsd.h"
46#include "llsdserialize_xml.h"
47#include "llstl.h"
48
49static const char HTTP_VERSION_STR[] = "HTTP/1.0";
50static const std::string CONTEXT_REQUEST("request");
51static const std::string HTTP_VERB_GET("GET");
52static const std::string HTTP_VERB_PUT("PUT");
53static const std::string HTTP_VERB_POST("POST");
54static const std::string HTTP_VERB_DELETE("DELETE");
55
56
57class LLHTTPPipe : public LLIOPipe
58{
59public:
60 LLHTTPPipe(const LLHTTPNode& node)
61 : mNode(node), mResponse(NULL), mState(STATE_INVOKE), mChainLock(0), mStatusCode(0)
62 { }
63 virtual ~LLHTTPPipe()
64 {
65 if (mResponse.notNull())
66 {
67 mResponse->nullPipe();
68 }
69 }
70
71private:
72 // LLIOPipe API implementation.
73 virtual EStatus process_impl(
74 const LLChannelDescriptors& channels,
75 LLIOPipe::buffer_ptr_t& buffer,
76 bool& eos,
77 LLSD& context,
78 LLPumpIO* pump);
79
80 const LLHTTPNode& mNode;
81
82 class Response : public LLHTTPNode::Response
83 {
84 public:
85
86 static LLPointer<Response> create(LLHTTPPipe* pipe);
87 virtual ~Response();
88
89 // from LLHTTPNode::Response
90 virtual void result(const LLSD&);
91 virtual void status(S32 code, const std::string& message);
92
93 void nullPipe();
94
95 private:
96 Response() {;} // Must be accessed through LLPointer.
97 LLHTTPPipe* mPipe;
98 };
99 friend class Response;
100
101 LLPointer<Response> mResponse;
102
103 enum State
104 {
105 STATE_INVOKE,
106 STATE_DELAYED,
107 STATE_LOCKED,
108 STATE_GOOD_RESULT,
109 STATE_STATUS_RESULT
110 };
111 State mState;
112
113 S32 mChainLock;
114 LLPumpIO* mLockedPump;
115
116 void lockChain(LLPumpIO*);
117 void unlockChain();
118
119 LLSD mGoodResult;
120 S32 mStatusCode;
121 std::string mStatusMessage;
122};
123
124LLIOPipe::EStatus LLHTTPPipe::process_impl(
125 const LLChannelDescriptors& channels,
126 buffer_ptr_t& buffer,
127 bool& eos,
128 LLSD& context,
129 LLPumpIO* pump)
130{
131 PUMP_DEBUG;
132 lldebugs << "LLSDHTTPServer::process_impl" << llendl;
133
134 // Once we have all the data, We need to read the sd on
135 // the the in channel, and respond on the out channel
136
137 if(!eos) return STATUS_BREAK;
138 if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET;
139
140 PUMP_DEBUG;
141 if (mState == STATE_INVOKE)
142 {
143 PUMP_DEBUG;
144 mState = STATE_DELAYED;
145 // assume deferred unless mResponse does otherwise
146 mResponse = Response::create(this);
147
148 // TODO: Babbage: Parameterize parser?
149 LLBufferStream istr(channels, buffer.get());
150
151 std::string verb = context[CONTEXT_REQUEST]["verb"];
152 if(verb == HTTP_VERB_GET)
153 {
154 mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
155 }
156 else if(verb == HTTP_VERB_PUT)
157 {
158 LLSD input;
159 LLSDSerialize::fromXML(input, istr);
160
161 mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input);
162 }
163 else if(verb == HTTP_VERB_POST)
164 {
165 LLSD input;
166 LLSDSerialize::fromXML(input, istr);
167
168 mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input);
169 }
170 else if(verb == HTTP_VERB_DELETE)
171 {
172 mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);
173 }
174 else
175 {
176 mResponse->methodNotAllowed();
177 }
178
179 // Log Internal Server Errors
180 if(mStatusCode == 500)
181 {
182 llwarns << "LLHTTPPipe::process_impl:500:Internal Server Error"
183 << llendl;
184 }
185 }
186
187 PUMP_DEBUG;
188 switch (mState)
189 {
190 case STATE_DELAYED:
191 lockChain(pump);
192 mState = STATE_LOCKED;
193 return STATUS_BREAK;
194
195 case STATE_LOCKED:
196 // should never ever happen!
197 return STATUS_ERROR;
198
199 case STATE_GOOD_RESULT:
200 {
201 context["response"]["contentType"] = "application/xml";
202 LLBufferStream ostr(channels, buffer.get());
203 LLSDSerialize::toXML(mGoodResult, ostr);
204
205 return STATUS_DONE;
206 }
207
208 case STATE_STATUS_RESULT:
209 {
210 context["response"]["contentType"] = "text/plain";
211 context["response"]["statusCode"] = mStatusCode;
212 context["response"]["statusMessage"] = mStatusMessage;
213 LLBufferStream ostr(channels, buffer.get());
214 ostr << mStatusMessage << std::ends;
215
216 return STATUS_DONE;
217 }
218 default:
219 llwarns << "LLHTTPPipe::process_impl: unexpected state "
220 << mState << llendl;
221
222 return STATUS_BREAK;
223 }
224// PUMP_DEBUG; // unreachable
225}
226
227LLPointer<LLHTTPPipe::Response> LLHTTPPipe::Response::create(LLHTTPPipe* pipe)
228{
229 LLPointer<Response> result = new Response();
230 result->mPipe = pipe;
231 return result;
232}
233
234// virtual
235LLHTTPPipe::Response::~Response()
236{
237}
238
239void LLHTTPPipe::Response::nullPipe()
240{
241 mPipe = NULL;
242}
243
244// virtual
245void LLHTTPPipe::Response::result(const LLSD& r)
246{
247 if(! mPipe)
248 {
249 llwarns << "LLHTTPPipe::Response::result: NULL pipe" << llendl;
250 return;
251 }
252
253 mPipe->mStatusCode = 200;
254 mPipe->mStatusMessage = "OK";
255 mPipe->mGoodResult = r;
256 mPipe->mState = STATE_GOOD_RESULT;
257 mPipe->unlockChain();
258}
259
260// virtual
261void LLHTTPPipe::Response::status(S32 code, const std::string& message)
262{
263 if(! mPipe)
264 {
265 llwarns << "LLHTTPPipe::Response::status: NULL pipe" << llendl;
266 return;
267 }
268
269 mPipe->mStatusCode = code;
270 mPipe->mStatusMessage = message;
271 mPipe->mState = STATE_STATUS_RESULT;
272 mPipe->unlockChain();
273}
274
275void LLHTTPPipe::lockChain(LLPumpIO* pump)
276{
277 if (mChainLock != 0) { return; }
278
279 mLockedPump = pump;
280 mChainLock = pump->setLock();
281}
282
283void LLHTTPPipe::unlockChain()
284{
285 if (mChainLock == 0) { return; }
286
287 mLockedPump->clearLock(mChainLock);
288 mLockedPump = NULL;
289 mChainLock = 0;
290}
291
292
293
294/**
295 * @class LLHTTPResponseHeader
296 * @brief Class which correctly builds HTTP headers on a pipe
297 * @see LLIOPipe
298 *
299 * An instance of this class can be placed in a chain where it will
300 * wait for an end of stream. Once it gets that, it will count the
301 * bytes on CHANNEL_OUT (or the size of the buffer in io pipe versions
302 * prior to 2) prepend that data to the request in an HTTP format, and
303 * supply all normal HTTP response headers.
304 */
305class LLHTTPResponseHeader : public LLIOPipe
306{
307public:
308 LLHTTPResponseHeader() {}
309 virtual ~LLHTTPResponseHeader() {}
310
311protected:
312 /* @name LLIOPipe virtual implementations
313 */
314 //@{
315 /**
316 * @brief Process the data in buffer
317 */
318 EStatus process_impl(
319 const LLChannelDescriptors& channels,
320 buffer_ptr_t& buffer,
321 bool& eos,
322 LLSD& context,
323 LLPumpIO* pump);
324 //@}
325
326protected:
327 S32 mCode;
328};
329
330
331/**
332 * LLHTTPResponseHeader
333 */
334// virtual
335LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
336 const LLChannelDescriptors& channels,
337 buffer_ptr_t& buffer,
338 bool& eos,
339 LLSD& context,
340 LLPumpIO* pump)
341{
342 PUMP_DEBUG;
343 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
344 if(eos)
345 {
346 PUMP_DEBUG;
347 //mGotEOS = true;
348 std::ostringstream ostr;
349 std::string message = context["response"]["statusMessage"];
350
351 int code = context["response"]["statusCode"];
352 if (code < 200)
353 {
354 code = 200;
355 message = "OK";
356 }
357
358 ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n";
359
360 std::string type = context["response"]["contentType"].asString();
361 if (!type.empty())
362 {
363 ostr << "Content-Type: " << type << "\r\n";
364 }
365 S32 content_length = buffer->countAfter(channels.in(), NULL);
366 if(0 < content_length)
367 {
368 ostr << "Content-Length: " << content_length << "\r\n";
369 }
370 ostr << "\r\n";
371
372 LLChangeChannel change(channels.in(), channels.out());
373 std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
374 std::string header = ostr.str();
375 buffer->prepend(channels.out(), (U8*)header.c_str(), header.size());
376 PUMP_DEBUG;
377 return STATUS_DONE;
378 }
379 PUMP_DEBUG;
380 return STATUS_OK;
381}
382
383
384
385/**
386 * @class LLHTTPResponder
387 * @brief This class
388 * @see LLIOPipe
389 *
390 * <b>NOTE:</b> You should not need to create or use one of these, the
391 * details are handled by the HTTPResponseFactory.
392 */
393class LLHTTPResponder : public LLIOPipe
394{
395public:
396 LLHTTPResponder(const LLHTTPNode& tree);
397 ~LLHTTPResponder();
398
399protected:
400 /**
401 * @brief Read data off of CHANNEL_IN keeping track of last read position.
402 *
403 * This is a quick little hack to read headers. It is not IO
404 * optimal, but it makes it easier for me to implement the header
405 * parsing. Plus, there should never be more than a few headers.
406 * This method will tend to read more than necessary, find the
407 * newline, make the front part of dest look like a c string, and
408 * move the read head back to where the newline was found. Thus,
409 * the next read will pick up on the next line.
410 * @param channel The channel to read in the buffer
411 * @param buffer The heap array of processed data
412 * @param dest Destination for the data to be read
413 * @param[in,out] len <b>in</b> The size of the buffer. <b>out</b> how
414 * much was read. This value is not useful for determining where to
415 * seek orfor string assignment.
416 * @returns Returns true if a line was found.
417 */
418 bool readLine(
419 const LLChannelDescriptors& channels,
420 buffer_ptr_t buffer,
421 U8* dest,
422 S32& len);
423
424 /**
425 * @brief Mark the request as bad, and handle appropriately
426 *
427 * @param channels The channels to use in the buffer.
428 * @param buffer The heap array of processed data.
429 */
430 void markBad(const LLChannelDescriptors& channels, buffer_ptr_t buffer);
431
432protected:
433 /* @name LLIOPipe virtual implementations
434 */
435 //@{
436 /**
437 * @brief Process the data in buffer
438 */
439 EStatus process_impl(
440 const LLChannelDescriptors& channels,
441 buffer_ptr_t& buffer,
442 bool& eos,
443 LLSD& context,
444 LLPumpIO* pump);
445 //@}
446
447protected:
448 enum EState
449 {
450 STATE_NOTHING,
451 STATE_READING_HEADERS,
452 STATE_LOOKING_FOR_EOS,
453 STATE_DONE,
454 STATE_SHORT_CIRCUIT
455 };
456
457 EState mState;
458 U8* mLastRead;
459 std::string mVerb;
460 std::string mAbsPathAndQuery;
461 std::string mPath;
462 std::string mQuery;
463 std::string mVersion;
464 S32 mContentLength;
465
466 // handle the urls
467 const LLHTTPNode& mRootNode;
468};
469
470LLHTTPResponder::LLHTTPResponder(const LLHTTPNode& tree) :
471 mState(STATE_NOTHING),
472 mLastRead(NULL),
473 mContentLength(0),
474 mRootNode(tree)
475{
476 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
477}
478
479// virtual
480LLHTTPResponder::~LLHTTPResponder()
481{
482 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
483 //lldebugs << "destroying LLHTTPResponder" << llendl;
484}
485
486bool LLHTTPResponder::readLine(
487 const LLChannelDescriptors& channels,
488 buffer_ptr_t buffer,
489 U8* dest,
490 S32& len)
491{
492 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
493 --len;
494 U8* last = buffer->readAfter(channels.in(), mLastRead, dest, len);
495 dest[len] = '\0';
496 U8* newline = (U8*)strchr((char*)dest, '\n');
497 if(!newline)
498 {
499 if(len)
500 {
501 lldebugs << "readLine failed - too long maybe?" << llendl;
502 markBad(channels, buffer);
503 }
504 return false;
505 }
506 S32 offset = -((len - 1) - (newline - dest));
507 ++newline;
508 *newline = '\0';
509 mLastRead = buffer->seek(channels.in(), last, offset);
510 return true;
511}
512
513void LLHTTPResponder::markBad(
514 const LLChannelDescriptors& channels,
515 buffer_ptr_t buffer)
516{
517 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
518 mState = STATE_SHORT_CIRCUIT;
519 LLBufferStream out(channels, buffer.get());
520 out << HTTP_VERSION_STR << " 400 Bad Request\r\n\r\n<html>\n"
521 << "<title>Bad Request</title>\n<body>\nBad Request.\n"
522 << "</body>\n</html>\n";
523}
524
525// virtual
526LLIOPipe::EStatus LLHTTPResponder::process_impl(
527 const LLChannelDescriptors& channels,
528 buffer_ptr_t& buffer,
529 bool& eos,
530 LLSD& context,
531 LLPumpIO* pump)
532{
533 PUMP_DEBUG;
534 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
535 LLIOPipe::EStatus status = STATUS_OK;
536
537 // parsing headers
538 if((STATE_NOTHING == mState) || (STATE_READING_HEADERS == mState))
539 {
540 PUMP_DEBUG;
541 status = STATUS_BREAK;
542 mState = STATE_READING_HEADERS;
543 const S32 HEADER_BUFFER_SIZE = 1024;
544 char buf[HEADER_BUFFER_SIZE + 1]; /*Flawfinder: ignore*/
545 S32 len = HEADER_BUFFER_SIZE;
546
547#if 0
548 if(true)
549 {
550 LLBufferArray::segment_iterator_t seg_iter = buffer->beginSegment();
551 char buf[1024]; /*Flawfinder: ignore*/
552 while(seg_iter != buffer->endSegment())
553 {
554 memcpy(buf, (*seg_iter).data(), (*seg_iter).size()); /*Flawfinder: ignore*/
555 buf[(*seg_iter).size()] = '\0';
556 llinfos << (*seg_iter).getChannel() << ": " << buf
557 << llendl;
558 ++seg_iter;
559 }
560 }
561#endif
562
563 PUMP_DEBUG;
564 if(readLine(channels, buffer, (U8*)buf, len))
565 {
566 bool read_next_line = false;
567 bool parse_all = true;
568 if(mVerb.empty())
569 {
570 read_next_line = true;
571 LLMemoryStream header((U8*)buf, len);
572 header >> mVerb;
573
574 if((HTTP_VERB_GET == mVerb)
575 || (HTTP_VERB_POST == mVerb)
576 || (HTTP_VERB_PUT == mVerb)
577 || (HTTP_VERB_DELETE == mVerb))
578 {
579 header >> mAbsPathAndQuery;
580 header >> mVersion;
581
582 lldebugs << "http request: "
583 << mVerb
584 << " " << mAbsPathAndQuery
585 << " " << mVersion << llendl;
586
587 std::string::size_type delimiter
588 = mAbsPathAndQuery.find('?');
589 if (delimiter == std::string::npos)
590 {
591 mPath = mAbsPathAndQuery;
592 mQuery = "";
593 }
594 else
595 {
596 mPath = mAbsPathAndQuery.substr(0, delimiter);
597 mQuery = mAbsPathAndQuery.substr(delimiter+1);
598 }
599
600 if(!mAbsPathAndQuery.empty())
601 {
602 if(mVersion.empty())
603 {
604 // simple request.
605 parse_all = false;
606 mState = STATE_DONE;
607 mVersion.assign("HTTP/1.0");
608 }
609 }
610 }
611 else
612 {
613 read_next_line = false;
614 parse_all = false;
615 lldebugs << "unknown http verb: " << mVerb << llendl;
616 markBad(channels, buffer);
617 }
618 }
619 if(parse_all)
620 {
621 bool keep_parsing = true;
622 while(keep_parsing)
623 {
624 if(read_next_line)
625 {
626 len = HEADER_BUFFER_SIZE;
627 readLine(channels, buffer, (U8*)buf, len);
628 }
629 if(0 == len)
630 {
631 return status;
632 }
633 if(buf[0] == '\r' && buf[1] == '\n')
634 {
635 // end-o-headers
636 keep_parsing = false;
637 mState = STATE_LOOKING_FOR_EOS;
638 break;
639 }
640 char* pos_colon = strchr(buf, ':');
641 if(NULL == pos_colon)
642 {
643 keep_parsing = false;
644 lldebugs << "bad header: " << buf << llendl;
645 markBad(channels, buffer);
646 break;
647 }
648 // we've found a header
649 read_next_line = true;
650 std::string name(buf, pos_colon - buf);
651 std::string value(pos_colon + 2);
652 LLString::toLower(name);
653 if("content-length" == name)
654 {
655 lldebugs << "Content-Length: " << value << llendl;
656 mContentLength = atoi(value.c_str());
657 }
658 }
659 }
660 }
661 }
662
663 PUMP_DEBUG;
664 // look for the end of stream based on
665 if(STATE_LOOKING_FOR_EOS == mState)
666 {
667 if(0 == mContentLength)
668 {
669 mState = STATE_DONE;
670 }
671 else if(buffer->countAfter(channels.in(), mLastRead) >= mContentLength)
672 {
673 mState = STATE_DONE;
674 }
675 // else more bytes should be coming.
676 }
677
678 PUMP_DEBUG;
679 if(STATE_DONE == mState)
680 {
681 // hey, hey, we should have everything now, so we pass it to
682 // a content handler.
683 context[CONTEXT_REQUEST]["verb"] = mVerb;
684 const LLHTTPNode* node = mRootNode.traverse(mPath, context);
685 if(node)
686 {
687 llinfos << "LLHTTPResponder::process_impl found node for "
688 << mAbsPathAndQuery << llendl;
689
690 // Copy everything after mLast read to the out.
691 LLBufferArray::segment_iterator_t seg_iter;
692 seg_iter = buffer->splitAfter(mLastRead);
693 if(seg_iter != buffer->endSegment())
694 {
695 LLChangeChannel change(channels.in(), channels.out());
696 ++seg_iter;
697 std::for_each(seg_iter, buffer->endSegment(), change);
698
699#if 0
700 seg_iter = buffer->beginSegment();
701 char buf[1024]; /*Flawfinder: ignore*/
702 while(seg_iter != buffer->endSegment())
703 {
704 memcpy(buf, (*seg_iter).data(), (*seg_iter).size()); /*Flawfinder: ignore*/
705 buf[(*seg_iter).size()] = '\0';
706 llinfos << (*seg_iter).getChannel() << ": " << buf
707 << llendl;
708 ++seg_iter;
709 }
710#endif
711 }
712
713 //
714 // *FIX: get rid of extra bytes off the end
715 //
716
717 // Set up a chain which will prepend a content length and
718 // HTTP headers.
719 LLPumpIO::chain_t chain;
720 chain.push_back(LLIOPipe::ptr_t(new LLIOFlush));
721 context[CONTEXT_REQUEST]["path"] = mPath;
722 context[CONTEXT_REQUEST]["query-string"] = mQuery;
723
724 const LLChainIOFactory* protocolHandler
725 = node->getProtocolHandler();
726 if (protocolHandler)
727 {
728 protocolHandler->build(chain, context);
729 }
730 else
731 {
732 // this is a simple LLHTTPNode, so use LLHTTPPipe
733 chain.push_back(LLIOPipe::ptr_t(new LLHTTPPipe(*node)));
734 }
735
736 // Add the header - which needs to have the same
737 // channel information as the link before it since it
738 // is part of the response.
739 LLIOPipe* header = new LLHTTPResponseHeader;
740 chain.push_back(LLIOPipe::ptr_t(header));
741
742 // We need to copy all of the pipes _after_ this so
743 // that the response goes out correctly.
744 LLPumpIO::links_t current_links;
745 pump->copyCurrentLinkInfo(current_links);
746 LLPumpIO::links_t::iterator link_iter = current_links.begin();
747 LLPumpIO::links_t::iterator links_end = current_links.end();
748 bool after_this = false;
749 for(; link_iter < links_end; ++link_iter)
750 {
751 if(after_this)
752 {
753 chain.push_back((*link_iter).mPipe);
754 }
755 else if(this == (*link_iter).mPipe.get())
756 {
757 after_this = true;
758 }
759 }
760
761 // Do the final build of the chain, and send it on
762 // it's way.
763 LLChannelDescriptors chnl = channels;
764 LLPumpIO::LLLinkInfo link;
765 LLPumpIO::links_t links;
766 LLPumpIO::chain_t::iterator it = chain.begin();
767 LLPumpIO::chain_t::iterator end = chain.end();
768 while(it != end)
769 {
770 link.mPipe = *it;
771 link.mChannels = chnl;
772 links.push_back(link);
773 chnl = LLBufferArray::makeChannelConsumer(chnl);
774 ++it;
775 }
776 pump->addChain(
777 links,
778 buffer,
779 context,
780 DEFAULT_CHAIN_EXPIRY_SECS);
781
782 status = STATUS_STOP;
783 }
784 else
785 {
786 llinfos << "LLHTTPResponder::process_impl didn't find a node for "
787 << mAbsPathAndQuery << llendl;
788 LLBufferStream str(channels, buffer.get());
789 mState = STATE_SHORT_CIRCUIT;
790 str << HTTP_VERSION_STR << " 404 Not Found\r\n\r\n<html>\n"
791 << "<title>Not Found</title>\n<body>\nNode '" << mAbsPathAndQuery
792 << "' not found.\n</body>\n</html>\n";
793 }
794 }
795
796 if(STATE_SHORT_CIRCUIT == mState)
797 {
798 //status = mNext->process(buffer, true, pump, context);
799 status = STATUS_DONE;
800 }
801 PUMP_DEBUG;
802 return status;
803}
804
805
806
807void LLCreateHTTPPipe(LLPumpIO::chain_t& chain, const LLHTTPNode& root)
808{
809 chain.push_back(LLIOPipe::ptr_t(new LLHTTPResponder(root)));
810}
811
812
813class LLHTTPResponseFactory : public LLChainIOFactory
814{
815public:
816 bool build(LLPumpIO::chain_t& chain, LLSD ctx) const
817 {
818 LLCreateHTTPPipe(chain, mTree);
819 return true;
820 }
821
822 LLHTTPNode& getRootNode() { return mTree; }
823
824private:
825 LLHTTPNode mTree;
826};
827
828
829LLHTTPNode& LLCreateHTTPServer(
830 apr_pool_t* pool, LLPumpIO& pump, U16 port)
831{
832 LLSocket::ptr_t socket = LLSocket::create(
833 pool,
834 LLSocket::STREAM_TCP,
835 port);
836 if(!socket)
837 {
838 llerrs << "Unable to initialize socket" << llendl;
839 }
840
841 LLHTTPResponseFactory* factory = new LLHTTPResponseFactory;
842 boost::shared_ptr<LLChainIOFactory> factory_ptr(factory);
843
844 LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr);
845
846 LLPumpIO::chain_t chain;
847 chain.push_back(LLIOPipe::ptr_t(server));
848 pump.addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
849
850 return factory->getRootNode();
851}
852