00001
00034 #include "linden_common.h"
00035
00036 #include "lliohttpserver.h"
00037
00038 #include "llapr.h"
00039 #include "llbuffer.h"
00040 #include "llbufferstream.h"
00041 #include "llhttpnode.h"
00042 #include "lliopipe.h"
00043 #include "lliosocket.h"
00044 #include "llioutil.h"
00045 #include "llmemtype.h"
00046 #include "llmemorystream.h"
00047 #include "llpumpio.h"
00048 #include "llsd.h"
00049 #include "llsdserialize_xml.h"
00050 #include "llstl.h"
00051 #include "lltimer.h"
00052
00053 #include <sstream>
00054
00055 #include <boost/tokenizer.hpp>
00056
00057 static const char HTTP_VERSION_STR[] = "HTTP/1.0";
00058 static const std::string CONTEXT_REQUEST("request");
00059 static const std::string CONTEXT_RESPONSE("response");
00060 static const std::string HTTP_VERB_GET("GET");
00061 static const std::string HTTP_VERB_PUT("PUT");
00062 static const std::string HTTP_VERB_POST("POST");
00063 static const std::string HTTP_VERB_DELETE("DELETE");
00064
00065 static LLIOHTTPServer::timing_callback_t sTimingCallback = NULL;
00066 static void* sTimingCallbackData = NULL;
00067
00068 class LLHTTPPipe : public LLIOPipe
00069 {
00070 public:
00071 LLHTTPPipe(const LLHTTPNode& node)
00072 : mNode(node), mResponse(NULL), mState(STATE_INVOKE), mChainLock(0), mStatusCode(0)
00073 { }
00074 virtual ~LLHTTPPipe()
00075 {
00076 if (mResponse.notNull())
00077 {
00078 mResponse->nullPipe();
00079 }
00080 }
00081
00082 private:
00083
00084 virtual EStatus process_impl(
00085 const LLChannelDescriptors& channels,
00086 LLIOPipe::buffer_ptr_t& buffer,
00087 bool& eos,
00088 LLSD& context,
00089 LLPumpIO* pump);
00090
00091 const LLHTTPNode& mNode;
00092
00093 class Response : public LLHTTPNode::Response
00094 {
00095 public:
00096
00097 static LLPointer<Response> create(LLHTTPPipe* pipe);
00098 virtual ~Response();
00099
00100
00101 virtual void result(const LLSD&);
00102 virtual void status(S32 code, const std::string& message);
00103
00104 void nullPipe();
00105
00106 private:
00107 Response() {;}
00108 LLHTTPPipe* mPipe;
00109 };
00110 friend class Response;
00111
00112 LLPointer<Response> mResponse;
00113
00114 enum State
00115 {
00116 STATE_INVOKE,
00117 STATE_DELAYED,
00118 STATE_LOCKED,
00119 STATE_GOOD_RESULT,
00120 STATE_STATUS_RESULT
00121 };
00122 State mState;
00123
00124 S32 mChainLock;
00125 LLPumpIO* mLockedPump;
00126
00127 void lockChain(LLPumpIO*);
00128 void unlockChain();
00129
00130 LLSD mGoodResult;
00131 S32 mStatusCode;
00132 std::string mStatusMessage;
00133 };
00134
00135 LLIOPipe::EStatus LLHTTPPipe::process_impl(
00136 const LLChannelDescriptors& channels,
00137 buffer_ptr_t& buffer,
00138 bool& eos,
00139 LLSD& context,
00140 LLPumpIO* pump)
00141 {
00142 PUMP_DEBUG;
00143 lldebugs << "LLSDHTTPServer::process_impl" << llendl;
00144
00145
00146
00147
00148 if(!eos) return STATUS_BREAK;
00149 if(!pump || !buffer) return STATUS_PRECONDITION_NOT_MET;
00150
00151 PUMP_DEBUG;
00152 if (mState == STATE_INVOKE)
00153 {
00154 PUMP_DEBUG;
00155 mState = STATE_DELAYED;
00156
00157 mResponse = Response::create(this);
00158
00159
00160 LLBufferStream istr(channels, buffer.get());
00161
00162 static LLTimer timer;
00163 timer.reset();
00164
00165 std::string verb = context[CONTEXT_REQUEST]["verb"];
00166 if(verb == HTTP_VERB_GET)
00167 {
00168 mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
00169 }
00170 else if(verb == HTTP_VERB_PUT)
00171 {
00172 LLSD input;
00173 LLSDSerialize::fromXML(input, istr);
00174
00175 mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input);
00176 }
00177 else if(verb == HTTP_VERB_POST)
00178 {
00179 LLSD input;
00180 LLSDSerialize::fromXML(input, istr);
00181
00182 mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input);
00183 }
00184 else if(verb == HTTP_VERB_DELETE)
00185 {
00186 mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);
00187 }
00188 else
00189 {
00190 mResponse->methodNotAllowed();
00191 }
00192
00193 F32 delta = timer.getElapsedTimeF32();
00194 if (sTimingCallback)
00195 {
00196 LLHTTPNode::Description desc;
00197 mNode.describe(desc);
00198 LLSD info = desc.getInfo();
00199 std::string timing_name = info["description"];
00200 timing_name += " ";
00201 timing_name += verb;
00202 sTimingCallback(timing_name.c_str(), delta, sTimingCallbackData);
00203 }
00204
00205
00206 llinfos << verb << " " << context[CONTEXT_REQUEST]["path"].asString()
00207 << " " << mStatusCode << " " << mStatusMessage << " " << delta
00208 << "s" << llendl;
00209
00210
00211
00212
00213
00214
00215
00216 }
00217
00218 PUMP_DEBUG;
00219 switch (mState)
00220 {
00221 case STATE_DELAYED:
00222 lockChain(pump);
00223 mState = STATE_LOCKED;
00224 return STATUS_BREAK;
00225
00226 case STATE_LOCKED:
00227
00228 return STATUS_ERROR;
00229
00230 case STATE_GOOD_RESULT:
00231 {
00232 context[CONTEXT_RESPONSE]["contentType"] = "application/xml";
00233 LLBufferStream ostr(channels, buffer.get());
00234 LLSDSerialize::toXML(mGoodResult, ostr);
00235
00236 return STATUS_DONE;
00237 }
00238
00239 case STATE_STATUS_RESULT:
00240 {
00241 context[CONTEXT_RESPONSE]["contentType"] = "text/plain";
00242 context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
00243 context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage;
00244 LLBufferStream ostr(channels, buffer.get());
00245 ostr << mStatusMessage << std::ends;
00246
00247 return STATUS_DONE;
00248 }
00249 default:
00250 llwarns << "LLHTTPPipe::process_impl: unexpected state "
00251 << mState << llendl;
00252
00253 return STATUS_BREAK;
00254 }
00255
00256 }
00257
00258 LLPointer<LLHTTPPipe::Response> LLHTTPPipe::Response::create(LLHTTPPipe* pipe)
00259 {
00260 LLPointer<Response> result = new Response();
00261 result->mPipe = pipe;
00262 return result;
00263 }
00264
00265
00266 LLHTTPPipe::Response::~Response()
00267 {
00268 }
00269
00270 void LLHTTPPipe::Response::nullPipe()
00271 {
00272 mPipe = NULL;
00273 }
00274
00275
00276 void LLHTTPPipe::Response::result(const LLSD& r)
00277 {
00278 if(! mPipe)
00279 {
00280 llwarns << "LLHTTPPipe::Response::result: NULL pipe" << llendl;
00281 return;
00282 }
00283
00284 mPipe->mStatusCode = 200;
00285 mPipe->mStatusMessage = "OK";
00286 mPipe->mGoodResult = r;
00287 mPipe->mState = STATE_GOOD_RESULT;
00288 mPipe->unlockChain();
00289 }
00290
00291
00292 void LLHTTPPipe::Response::status(S32 code, const std::string& message)
00293 {
00294 if(! mPipe)
00295 {
00296 llwarns << "LLHTTPPipe::Response::status: NULL pipe" << llendl;
00297 return;
00298 }
00299
00300 mPipe->mStatusCode = code;
00301 mPipe->mStatusMessage = message;
00302 mPipe->mState = STATE_STATUS_RESULT;
00303 mPipe->unlockChain();
00304 }
00305
00306 void LLHTTPPipe::lockChain(LLPumpIO* pump)
00307 {
00308 if (mChainLock != 0) { return; }
00309
00310 mLockedPump = pump;
00311 mChainLock = pump->setLock();
00312 }
00313
00314 void LLHTTPPipe::unlockChain()
00315 {
00316 if (mChainLock == 0) { return; }
00317
00318 mLockedPump->clearLock(mChainLock);
00319 mLockedPump = NULL;
00320 mChainLock = 0;
00321 }
00322
00323
00324
00336 class LLHTTPResponseHeader : public LLIOPipe
00337 {
00338 public:
00339 LLHTTPResponseHeader() {}
00340 virtual ~LLHTTPResponseHeader() {}
00341
00342 protected:
00343
00344
00346
00349 EStatus process_impl(
00350 const LLChannelDescriptors& channels,
00351 buffer_ptr_t& buffer,
00352 bool& eos,
00353 LLSD& context,
00354 LLPumpIO* pump);
00356
00357 protected:
00358 S32 mCode;
00359 };
00360
00361
00365
00366 LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
00367 const LLChannelDescriptors& channels,
00368 buffer_ptr_t& buffer,
00369 bool& eos,
00370 LLSD& context,
00371 LLPumpIO* pump)
00372 {
00373 PUMP_DEBUG;
00374 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00375 if(eos)
00376 {
00377 PUMP_DEBUG;
00378
00379 std::ostringstream ostr;
00380 std::string message = context[CONTEXT_RESPONSE]["statusMessage"];
00381
00382 int code = context[CONTEXT_RESPONSE]["statusCode"];
00383 if (code < 200)
00384 {
00385 code = 200;
00386 message = "OK";
00387 }
00388
00389 ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n";
00390
00391 std::string type = context[CONTEXT_RESPONSE]["contentType"].asString();
00392 if (!type.empty())
00393 {
00394 ostr << "Content-Type: " << type << "\r\n";
00395 }
00396 S32 content_length = buffer->countAfter(channels.in(), NULL);
00397 if(0 < content_length)
00398 {
00399 ostr << "Content-Length: " << content_length << "\r\n";
00400 }
00401 ostr << "\r\n";
00402
00403 LLChangeChannel change(channels.in(), channels.out());
00404 std::for_each(buffer->beginSegment(), buffer->endSegment(), change);
00405 std::string header = ostr.str();
00406 buffer->prepend(channels.out(), (U8*)header.c_str(), header.size());
00407 PUMP_DEBUG;
00408 return STATUS_DONE;
00409 }
00410 PUMP_DEBUG;
00411 return STATUS_OK;
00412 }
00413
00414
00415
00424 class LLHTTPResponder : public LLIOPipe
00425 {
00426 public:
00427 LLHTTPResponder(const LLHTTPNode& tree, const LLSD& ctx);
00428 ~LLHTTPResponder();
00429
00430 protected:
00449 bool readLine(
00450 const LLChannelDescriptors& channels,
00451 buffer_ptr_t buffer,
00452 U8* dest,
00453 S32& len);
00454
00461 void markBad(const LLChannelDescriptors& channels, buffer_ptr_t buffer);
00462
00463 protected:
00464
00465
00467
00470 EStatus process_impl(
00471 const LLChannelDescriptors& channels,
00472 buffer_ptr_t& buffer,
00473 bool& eos,
00474 LLSD& context,
00475 LLPumpIO* pump);
00477
00478 protected:
00479 enum EState
00480 {
00481 STATE_NOTHING,
00482 STATE_READING_HEADERS,
00483 STATE_LOOKING_FOR_EOS,
00484 STATE_DONE,
00485 STATE_SHORT_CIRCUIT
00486 };
00487
00488 LLSD mBuildContext;
00489 EState mState;
00490 U8* mLastRead;
00491 std::string mVerb;
00492 std::string mAbsPathAndQuery;
00493 std::string mPath;
00494 std::string mQuery;
00495 std::string mVersion;
00496 S32 mContentLength;
00497 LLSD mHeaders;
00498
00499
00500 const LLHTTPNode& mRootNode;
00501 };
00502
00503 LLHTTPResponder::LLHTTPResponder(const LLHTTPNode& tree, const LLSD& ctx) :
00504 mBuildContext(ctx),
00505 mState(STATE_NOTHING),
00506 mLastRead(NULL),
00507 mContentLength(0),
00508 mRootNode(tree)
00509 {
00510 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00511 }
00512
00513
00514 LLHTTPResponder::~LLHTTPResponder()
00515 {
00516 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00517
00518 }
00519
00520 bool LLHTTPResponder::readLine(
00521 const LLChannelDescriptors& channels,
00522 buffer_ptr_t buffer,
00523 U8* dest,
00524 S32& len)
00525 {
00526 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00527 --len;
00528 U8* last = buffer->readAfter(channels.in(), mLastRead, dest, len);
00529 dest[len] = '\0';
00530 U8* newline = (U8*)strchr((char*)dest, '\n');
00531 if(!newline)
00532 {
00533 if(len)
00534 {
00535 lldebugs << "readLine failed - too long maybe?" << llendl;
00536 markBad(channels, buffer);
00537 }
00538 return false;
00539 }
00540 S32 offset = -((len - 1) - (newline - dest));
00541 ++newline;
00542 *newline = '\0';
00543 mLastRead = buffer->seek(channels.in(), last, offset);
00544 return true;
00545 }
00546
00547 void LLHTTPResponder::markBad(
00548 const LLChannelDescriptors& channels,
00549 buffer_ptr_t buffer)
00550 {
00551 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00552 mState = STATE_SHORT_CIRCUIT;
00553 LLBufferStream out(channels, buffer.get());
00554 out << HTTP_VERSION_STR << " 400 Bad Request\r\n\r\n<html>\n"
00555 << "<title>Bad Request</title>\n<body>\nBad Request.\n"
00556 << "</body>\n</html>\n";
00557 }
00558
00559
00560 LLIOPipe::EStatus LLHTTPResponder::process_impl(
00561 const LLChannelDescriptors& channels,
00562 buffer_ptr_t& buffer,
00563 bool& eos,
00564 LLSD& context,
00565 LLPumpIO* pump)
00566 {
00567 PUMP_DEBUG;
00568 LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
00569 LLIOPipe::EStatus status = STATUS_OK;
00570
00571
00572 if((STATE_NOTHING == mState) || (STATE_READING_HEADERS == mState))
00573 {
00574 PUMP_DEBUG;
00575 status = STATUS_BREAK;
00576 mState = STATE_READING_HEADERS;
00577 const S32 HEADER_BUFFER_SIZE = 1024;
00578 char buf[HEADER_BUFFER_SIZE + 1];
00579 S32 len = HEADER_BUFFER_SIZE;
00580
00581 #if 0
00582 if(true)
00583 {
00584 LLBufferArray::segment_iterator_t seg_iter = buffer->beginSegment();
00585 char buf[1024];
00586 while(seg_iter != buffer->endSegment())
00587 {
00588 memcpy(buf, (*seg_iter).data(), (*seg_iter).size());
00589 buf[(*seg_iter).size()] = '\0';
00590 llinfos << (*seg_iter).getChannel() << ": " << buf
00591 << llendl;
00592 ++seg_iter;
00593 }
00594 }
00595 #endif
00596
00597 PUMP_DEBUG;
00598 if(readLine(channels, buffer, (U8*)buf, len))
00599 {
00600 bool read_next_line = false;
00601 bool parse_all = true;
00602 if(mVerb.empty())
00603 {
00604 read_next_line = true;
00605 LLMemoryStream header((U8*)buf, len);
00606 header >> mVerb;
00607
00608 if((HTTP_VERB_GET == mVerb)
00609 || (HTTP_VERB_POST == mVerb)
00610 || (HTTP_VERB_PUT == mVerb)
00611 || (HTTP_VERB_DELETE == mVerb))
00612 {
00613 header >> mAbsPathAndQuery;
00614 header >> mVersion;
00615
00616 lldebugs << "http request: "
00617 << mVerb
00618 << " " << mAbsPathAndQuery
00619 << " " << mVersion << llendl;
00620
00621 std::string::size_type delimiter
00622 = mAbsPathAndQuery.find('?');
00623 if (delimiter == std::string::npos)
00624 {
00625 mPath = mAbsPathAndQuery;
00626 mQuery = "";
00627 }
00628 else
00629 {
00630 mPath = mAbsPathAndQuery.substr(0, delimiter);
00631 mQuery = mAbsPathAndQuery.substr(delimiter+1);
00632 }
00633
00634 if(!mAbsPathAndQuery.empty())
00635 {
00636 if(mVersion.empty())
00637 {
00638
00639 parse_all = false;
00640 mState = STATE_DONE;
00641 mVersion.assign("HTTP/1.0");
00642 }
00643 }
00644 }
00645 else
00646 {
00647 read_next_line = false;
00648 parse_all = false;
00649 lldebugs << "unknown http verb: " << mVerb << llendl;
00650 markBad(channels, buffer);
00651 }
00652 }
00653 if(parse_all)
00654 {
00655 bool keep_parsing = true;
00656 while(keep_parsing)
00657 {
00658 if(read_next_line)
00659 {
00660 len = HEADER_BUFFER_SIZE;
00661 readLine(channels, buffer, (U8*)buf, len);
00662 }
00663 if(0 == len)
00664 {
00665 return status;
00666 }
00667 if(buf[0] == '\r' && buf[1] == '\n')
00668 {
00669
00670 keep_parsing = false;
00671 mState = STATE_LOOKING_FOR_EOS;
00672 break;
00673 }
00674 char* pos_colon = strchr(buf, ':');
00675 if(NULL == pos_colon)
00676 {
00677 keep_parsing = false;
00678 lldebugs << "bad header: " << buf << llendl;
00679 markBad(channels, buffer);
00680 break;
00681 }
00682
00683 read_next_line = true;
00684 std::string name(buf, pos_colon - buf);
00685 std::string value(pos_colon + 2);
00686 LLString::toLower(name);
00687 if("content-length" == name)
00688 {
00689 lldebugs << "Content-Length: " << value << llendl;
00690 mContentLength = atoi(value.c_str());
00691 }
00692 else
00693 {
00694 LLString::trimTail(value);
00695 mHeaders[name] = value;
00696 }
00697 }
00698 }
00699 }
00700 }
00701
00702 PUMP_DEBUG;
00703
00704 if(STATE_LOOKING_FOR_EOS == mState)
00705 {
00706 if(0 == mContentLength)
00707 {
00708 mState = STATE_DONE;
00709 }
00710 else if(buffer->countAfter(channels.in(), mLastRead) >= mContentLength)
00711 {
00712 mState = STATE_DONE;
00713 }
00714
00715 }
00716
00717 PUMP_DEBUG;
00718 if(STATE_DONE == mState)
00719 {
00720
00721
00722 context[CONTEXT_REQUEST]["verb"] = mVerb;
00723 const LLHTTPNode* node = mRootNode.traverse(mPath, context);
00724 if(node)
00725 {
00726 llinfos << "LLHTTPResponder::process_impl found node for "
00727 << mAbsPathAndQuery << llendl;
00728
00729
00730 LLBufferArray::segment_iterator_t seg_iter;
00731 seg_iter = buffer->splitAfter(mLastRead);
00732 if(seg_iter != buffer->endSegment())
00733 {
00734 LLChangeChannel change(channels.in(), channels.out());
00735 ++seg_iter;
00736 std::for_each(seg_iter, buffer->endSegment(), change);
00737
00738 #if 0
00739 seg_iter = buffer->beginSegment();
00740 char buf[1024];
00741 while(seg_iter != buffer->endSegment())
00742 {
00743 memcpy(buf, (*seg_iter).data(), (*seg_iter).size());
00744 buf[(*seg_iter).size()] = '\0';
00745 llinfos << (*seg_iter).getChannel() << ": " << buf
00746 << llendl;
00747 ++seg_iter;
00748 }
00749 #endif
00750 }
00751
00752
00753
00754
00755
00756
00757
00758 LLPumpIO::chain_t chain;
00759 chain.push_back(LLIOPipe::ptr_t(new LLIOFlush));
00760 context[CONTEXT_REQUEST]["path"] = mPath;
00761 context[CONTEXT_REQUEST]["query-string"] = mQuery;
00762 context[CONTEXT_REQUEST]["remote-host"]
00763 = mBuildContext["remote-host"];
00764 context[CONTEXT_REQUEST]["remote-port"]
00765 = mBuildContext["remote-port"];
00766 context[CONTEXT_REQUEST]["headers"] = mHeaders;
00767
00768 const LLChainIOFactory* protocolHandler
00769 = node->getProtocolHandler();
00770 if (protocolHandler)
00771 {
00772 protocolHandler->build(chain, context);
00773 }
00774 else
00775 {
00776
00777 chain.push_back(LLIOPipe::ptr_t(new LLHTTPPipe(*node)));
00778 }
00779
00780
00781
00782
00783 LLIOPipe* header = new LLHTTPResponseHeader;
00784 chain.push_back(LLIOPipe::ptr_t(header));
00785
00786
00787
00788 LLPumpIO::links_t current_links;
00789 pump->copyCurrentLinkInfo(current_links);
00790 LLPumpIO::links_t::iterator link_iter = current_links.begin();
00791 LLPumpIO::links_t::iterator links_end = current_links.end();
00792 bool after_this = false;
00793 for(; link_iter < links_end; ++link_iter)
00794 {
00795 if(after_this)
00796 {
00797 chain.push_back((*link_iter).mPipe);
00798 }
00799 else if(this == (*link_iter).mPipe.get())
00800 {
00801 after_this = true;
00802 }
00803 }
00804
00805
00806
00807 LLChannelDescriptors chnl = channels;
00808 LLPumpIO::LLLinkInfo link;
00809 LLPumpIO::links_t links;
00810 LLPumpIO::chain_t::iterator it = chain.begin();
00811 LLPumpIO::chain_t::iterator end = chain.end();
00812 while(it != end)
00813 {
00814 link.mPipe = *it;
00815 link.mChannels = chnl;
00816 links.push_back(link);
00817 chnl = LLBufferArray::makeChannelConsumer(chnl);
00818 ++it;
00819 }
00820 pump->addChain(
00821 links,
00822 buffer,
00823 context,
00824 DEFAULT_CHAIN_EXPIRY_SECS);
00825
00826 status = STATUS_STOP;
00827 }
00828 else
00829 {
00830 llinfos << "LLHTTPResponder::process_impl didn't find a node for "
00831 << mAbsPathAndQuery << llendl;
00832 LLBufferStream str(channels, buffer.get());
00833 mState = STATE_SHORT_CIRCUIT;
00834 str << HTTP_VERSION_STR << " 404 Not Found\r\n\r\n<html>\n"
00835 << "<title>Not Found</title>\n<body>\nNode '" << mAbsPathAndQuery
00836 << "' not found.\n</body>\n</html>\n";
00837 }
00838 }
00839
00840 if(STATE_SHORT_CIRCUIT == mState)
00841 {
00842
00843 status = STATUS_DONE;
00844 }
00845 PUMP_DEBUG;
00846 return status;
00847 }
00848
00849
00850
00851 void LLIOHTTPServer::createPipe(LLPumpIO::chain_t& chain,
00852 const LLHTTPNode& root, const LLSD& ctx)
00853 {
00854 chain.push_back(LLIOPipe::ptr_t(new LLHTTPResponder(root, ctx)));
00855 }
00856
00857
00858 class LLHTTPResponseFactory : public LLChainIOFactory
00859 {
00860 public:
00861 bool build(LLPumpIO::chain_t& chain, LLSD ctx) const
00862 {
00863 LLIOHTTPServer::createPipe(chain, mTree, ctx);
00864 return true;
00865 }
00866
00867 LLHTTPNode& getRootNode() { return mTree; }
00868
00869 private:
00870 LLHTTPNode mTree;
00871 };
00872
00873
00874
00875 LLHTTPNode& LLIOHTTPServer::create(
00876 apr_pool_t* pool, LLPumpIO& pump, U16 port)
00877 {
00878 LLSocket::ptr_t socket = LLSocket::create(
00879 pool,
00880 LLSocket::STREAM_TCP,
00881 port);
00882 if(!socket)
00883 {
00884 llerrs << "Unable to initialize socket" << llendl;
00885 }
00886
00887 LLHTTPResponseFactory* factory = new LLHTTPResponseFactory;
00888 boost::shared_ptr<LLChainIOFactory> factory_ptr(factory);
00889
00890 LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr);
00891
00892 LLPumpIO::chain_t chain;
00893 chain.push_back(LLIOPipe::ptr_t(server));
00894 pump.addChain(chain, NEVER_CHAIN_EXPIRY_SECS);
00895
00896 return factory->getRootNode();
00897 }
00898
00899
00900 void LLIOHTTPServer::setTimingCallback(timing_callback_t callback,
00901 void* data)
00902 {
00903 sTimingCallback = callback;
00904 sTimingCallbackData = data;
00905 }